001 /* 002 * Copyright 2010-2015 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.kotlin.codegen; 018 019 import com.intellij.openapi.progress.ProcessCanceledException; 020 import com.intellij.psi.PsiElement; 021 import com.intellij.util.ArrayUtil; 022 import kotlin.KotlinPackage; 023 import kotlin.Unit; 024 import kotlin.jvm.functions.Function0; 025 import kotlin.jvm.functions.Function1; 026 import kotlin.jvm.functions.Function2; 027 import org.jetbrains.annotations.NotNull; 028 import org.jetbrains.annotations.Nullable; 029 import org.jetbrains.kotlin.backend.common.CodegenUtil; 030 import org.jetbrains.kotlin.backend.common.CodegenUtilKt; 031 import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator; 032 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 033 import org.jetbrains.kotlin.codegen.binding.MutableClosure; 034 import org.jetbrains.kotlin.codegen.context.*; 035 import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; 036 import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil; 037 import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; 038 import org.jetbrains.kotlin.codegen.state.GenerationState; 039 import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 040 import org.jetbrains.kotlin.descriptors.*; 041 import org.jetbrains.kotlin.lexer.JetTokens; 042 import org.jetbrains.kotlin.load.java.JvmAbi; 043 import org.jetbrains.kotlin.load.java.JvmAnnotationNames; 044 import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass; 045 import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; 046 import org.jetbrains.kotlin.name.FqName; 047 import org.jetbrains.kotlin.name.Name; 048 import org.jetbrains.kotlin.psi.*; 049 import org.jetbrains.kotlin.resolve.BindingContext; 050 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; 051 import org.jetbrains.kotlin.resolve.DescriptorUtils; 052 import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; 053 import org.jetbrains.kotlin.resolve.calls.CallResolverUtil; 054 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; 055 import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument; 056 import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument; 057 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 058 import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument; 059 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage; 060 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; 061 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature; 062 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; 063 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; 064 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; 065 import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; 066 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; 067 import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver; 068 import org.jetbrains.kotlin.serialization.*; 069 import org.jetbrains.kotlin.serialization.deserialization.NameResolver; 070 import org.jetbrains.kotlin.serialization.jvm.BitEncoding; 071 import org.jetbrains.kotlin.types.JetType; 072 import org.jetbrains.kotlin.types.checker.JetTypeChecker; 073 import org.jetbrains.org.objectweb.asm.*; 074 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 075 import org.jetbrains.org.objectweb.asm.commons.Method; 076 077 import java.util.*; 078 079 import static kotlin.KotlinPackage.firstOrNull; 080 import static org.jetbrains.kotlin.codegen.AsmUtil.*; 081 import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; 082 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass; 083 import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall; 084 import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull; 085 import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; 086 import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; 087 import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall; 088 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns; 089 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getSecondaryConstructors; 090 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; 091 import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.*; 092 import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; 093 import static org.jetbrains.kotlin.types.Variance.INVARIANT; 094 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 095 096 public class ImplementationBodyCodegen extends ClassBodyCodegen { 097 private static final String ENUM_VALUES_FIELD_NAME = "$VALUES"; 098 private Type superClassAsmType; 099 @Nullable // null means java/lang/Object 100 private JetType superClassType; 101 private final Type classAsmType; 102 103 private List<PropertyAndDefaultValue> companionObjectPropertiesToCopy; 104 105 private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks = 106 new ArrayList<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>>(); 107 108 public ImplementationBodyCodegen( 109 @NotNull JetClassOrObject aClass, 110 @NotNull ClassContext context, 111 @NotNull ClassBuilder v, 112 @NotNull GenerationState state, 113 @Nullable MemberCodegen<?> parentCodegen 114 ) { 115 super(aClass, context, v, state, parentCodegen); 116 this.classAsmType = typeMapper.mapClass(descriptor); 117 } 118 119 @Override 120 protected void generateDeclaration() { 121 getSuperClass(); 122 123 JvmClassSignature signature = signature(); 124 125 boolean isAbstract = false; 126 boolean isInterface = false; 127 boolean isFinal = false; 128 boolean isStatic; 129 boolean isAnnotation = false; 130 boolean isEnum = false; 131 132 if (myClass instanceof JetClass) { 133 JetClass jetClass = (JetClass) myClass; 134 if (jetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { 135 isAbstract = true; 136 } 137 if (jetClass.isInterface()) { 138 isAbstract = true; 139 isInterface = true; 140 } 141 else if (jetClass.isAnnotation()) { 142 isAbstract = true; 143 isInterface = true; 144 isAnnotation = true; 145 } 146 else if (jetClass.isEnum()) { 147 isAbstract = hasAbstractMembers(descriptor); 148 isEnum = true; 149 } 150 151 if (isObject(descriptor)) { 152 isFinal = true; 153 } 154 155 if (!jetClass.hasModifier(JetTokens.OPEN_KEYWORD) && !isAbstract) { 156 // Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from 157 isFinal = !(jetClass.isEnum() && state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES); 158 } 159 isStatic = !jetClass.isInner(); 160 } 161 else { 162 isStatic = isCompanionObject(descriptor); 163 isFinal = true; 164 } 165 166 int access = 0; 167 168 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) { 169 // ClassBuilderMode.LIGHT_CLASSES means we are generating light classes & looking at a nested or inner class 170 // Light class generation is implemented so that Cls-classes only read bare code of classes, 171 // without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY) 172 // Thus we must write full accessibility flags on inner classes in this mode 173 access |= getVisibilityAccessFlag(descriptor); 174 // Same for STATIC 175 if (isStatic) { 176 access |= ACC_STATIC; 177 } 178 } 179 else { 180 access |= getVisibilityAccessFlagForClass(descriptor); 181 } 182 if (isAbstract) { 183 access |= ACC_ABSTRACT; 184 } 185 if (isInterface) { 186 access |= ACC_INTERFACE; // ACC_SUPER 187 } 188 else { 189 access |= ACC_SUPER; 190 } 191 if (isFinal) { 192 access |= ACC_FINAL; 193 } 194 if (isAnnotation) { 195 access |= ACC_ANNOTATION; 196 } 197 if (KotlinBuiltIns.isDeprecated(descriptor)) { 198 access |= ACC_DEPRECATED; 199 } 200 if (isEnum) { 201 for (JetDeclaration declaration : myClass.getDeclarations()) { 202 if (declaration instanceof JetEnumEntry) { 203 if (enumEntryNeedSubclass(bindingContext, (JetEnumEntry) declaration)) { 204 access &= ~ACC_FINAL; 205 } 206 } 207 } 208 access |= ACC_ENUM; 209 } 210 211 v.defineClass( 212 myClass, V1_6, 213 access, 214 signature.getName(), 215 signature.getJavaGenericSignature(), 216 signature.getSuperclassName(), 217 ArrayUtil.toStringArray(signature.getInterfaces()) 218 ); 219 220 v.visitSource(myClass.getContainingFile().getName(), null); 221 222 InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state); 223 224 writeEnclosingMethod(); 225 226 AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null); 227 228 generateReflectionObjectFieldIfNeeded(); 229 230 generateEnumEntries(); 231 } 232 233 @Override 234 protected void generateKotlinAnnotation() { 235 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 236 237 KotlinClass.Kind kind; 238 if (isAnonymousObject(descriptor)) { 239 kind = KotlinClass.Kind.ANONYMOUS_OBJECT; 240 } 241 else if (isTopLevelOrInnerClass(descriptor)) { 242 kind = KotlinClass.Kind.CLASS; 243 } 244 else { 245 // LOCAL_CLASS is also written to inner classes of local classes 246 kind = KotlinClass.Kind.LOCAL_CLASS; 247 } 248 249 DescriptorSerializer serializer = 250 DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), typeMapper)); 251 252 ProtoBuf.Class classProto = serializer.classProto(descriptor).build(); 253 254 StringTable strings = serializer.getStringTable(); 255 NameResolver nameResolver = new NameResolver(strings.serializeSimpleNames(), strings.serializeQualifiedNames()); 256 ClassData data = new ClassData(nameResolver, classProto); 257 258 AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true); 259 av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); 260 av.visitEnum( 261 JvmAnnotationNames.KIND_FIELD_NAME, 262 Type.getObjectType(KotlinClass.KIND_INTERNAL_NAME).getDescriptor(), 263 kind.toString() 264 ); 265 AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME); 266 for (String string : BitEncoding.encodeBytes(SerializationUtil.serializeClassData(data))) { 267 array.visit(null, string); 268 } 269 array.visitEnd(); 270 av.visitEnd(); 271 } 272 273 private void writeEnclosingMethod() { 274 // Do not emit enclosing method in "light-classes mode" since currently we generate local light classes as if they're top level 275 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) { 276 return; 277 } 278 279 //JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class. 280 if (isAnonymousObject(descriptor) || !(descriptor.getContainingDeclaration() instanceof ClassOrPackageFragmentDescriptor)) { 281 writeOuterClassAndEnclosingMethod(); 282 } 283 } 284 285 @NotNull 286 private JvmClassSignature signature() { 287 BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); 288 289 typeMapper.writeFormalTypeParameters(descriptor.getTypeConstructor().getParameters(), sw); 290 291 sw.writeSuperclass(); 292 if (superClassType == null) { 293 sw.writeClassBegin(superClassAsmType); 294 sw.writeClassEnd(); 295 } 296 else { 297 typeMapper.mapSupertype(superClassType, sw); 298 } 299 sw.writeSuperclassEnd(); 300 301 LinkedHashSet<String> superInterfaces = new LinkedHashSet<String>(); 302 303 for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) { 304 if (isInterface(supertype.getConstructor().getDeclarationDescriptor())) { 305 sw.writeInterface(); 306 Type jvmName = typeMapper.mapSupertype(supertype, sw); 307 sw.writeInterfaceEnd(); 308 superInterfaces.add(jvmName.getInternalName()); 309 } 310 } 311 312 return new JvmClassSignature(classAsmType.getInternalName(), superClassAsmType.getInternalName(), 313 new ArrayList<String>(superInterfaces), sw.makeJavaGenericSignature()); 314 } 315 316 protected void getSuperClass() { 317 superClassAsmType = OBJECT_TYPE; 318 superClassType = null; 319 320 if (descriptor.getKind() == ClassKind.INTERFACE) { 321 return; 322 } 323 324 for (JetType supertype : descriptor.getTypeConstructor().getSupertypes()) { 325 ClassifierDescriptor superClass = supertype.getConstructor().getDeclarationDescriptor(); 326 if (superClass != null && !isInterface(superClass)) { 327 superClassAsmType = typeMapper.mapClass(superClass); 328 superClassType = supertype; 329 return; 330 } 331 } 332 } 333 334 @Override 335 protected void generateSyntheticParts() { 336 generatePropertyMetadataArrayFieldIfNeeded(classAsmType); 337 338 generateFieldForSingleton(); 339 340 generateCompanionObjectBackingFieldCopies(); 341 342 DelegationFieldsInfo delegationFieldsInfo = getDelegationFieldsInfo(myClass.getDelegationSpecifiers()); 343 try { 344 lookupConstructorExpressionsInClosureIfPresent(); 345 generatePrimaryConstructor(delegationFieldsInfo); 346 for (ConstructorDescriptor secondaryConstructor : getSecondaryConstructors(descriptor)) { 347 generateSecondaryConstructor(secondaryConstructor); 348 } 349 } 350 catch (CompilationException e) { 351 throw e; 352 } 353 catch (ProcessCanceledException e) { 354 throw e; 355 } 356 catch (RuntimeException e) { 357 throw new RuntimeException("Error generating constructors of class " + myClass.getName() + " with kind " + kind, e); 358 } 359 360 generateTraitMethods(); 361 362 generateDelegates(delegationFieldsInfo); 363 364 generateSyntheticAccessors(); 365 366 generateEnumMethods(); 367 368 generateFunctionsForDataClasses(); 369 370 new CollectionStubMethodGenerator(state, descriptor, functionCodegen, v).generate(); 371 372 generateToArray(); 373 374 genClosureFields(context.closure, v, typeMapper); 375 376 for (ExpressionCodegenExtension extension : ExpressionCodegenExtension.Companion.getInstances(state.getProject())) { 377 extension.generateClassSyntheticParts(v, state, myClass, descriptor); 378 } 379 } 380 381 private void generateReflectionObjectFieldIfNeeded() { 382 if (isAnnotationClass(descriptor)) { 383 // There's a bug in JDK 6 and 7 that prevents us from generating a static field in an annotation class: 384 // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6857918 385 // TODO: make reflection work on annotation classes somehow 386 return; 387 } 388 389 generateReflectionObjectField(state, classAsmType, v, method("createKotlinClass", K_CLASS_TYPE, getType(Class.class)), 390 JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v); 391 } 392 393 private boolean isGenericToArrayPresent() { 394 Collection<FunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier("toArray")); 395 for (FunctionDescriptor function : functions) { 396 if (CallResolverUtil.isOrOverridesSynthesized(function)) { 397 continue; 398 } 399 400 if (function.getValueParameters().size() != 1 || function.getTypeParameters().size() != 1) { 401 continue; 402 } 403 404 JetType returnType = function.getReturnType(); 405 assert returnType != null : function.toString(); 406 JetType paramType = function.getValueParameters().get(0).getType(); 407 if (KotlinBuiltIns.isArray(returnType) && KotlinBuiltIns.isArray(paramType)) { 408 JetType elementType = function.getTypeParameters().get(0).getDefaultType(); 409 if (JetTypeChecker.DEFAULT.equalTypes(elementType, getBuiltIns(descriptor).getArrayElementType(returnType)) 410 && JetTypeChecker.DEFAULT.equalTypes(elementType, getBuiltIns(descriptor).getArrayElementType(paramType))) { 411 return true; 412 } 413 } 414 } 415 return false; 416 417 } 418 419 private void generateToArray() { 420 KotlinBuiltIns builtIns = getBuiltIns(descriptor); 421 if (!isSubclass(descriptor, builtIns.getCollection())) return; 422 423 int access = descriptor.getKind() == ClassKind.INTERFACE ? 424 ACC_PUBLIC | ACC_ABSTRACT : 425 ACC_PUBLIC; 426 if (CodegenUtil.getDeclaredFunctionByRawSignature(descriptor, Name.identifier("toArray"), builtIns.getArray()) == null) { 427 MethodVisitor mv = v.newMethod(NO_ORIGIN, access, "toArray", "()[Ljava/lang/Object;", null, null); 428 429 if (descriptor.getKind() != ClassKind.INTERFACE) { 430 InstructionAdapter iv = new InstructionAdapter(mv); 431 mv.visitCode(); 432 433 iv.load(0, classAsmType); 434 iv.invokestatic("kotlin/jvm/internal/CollectionToArray", "toArray", "(Ljava/util/Collection;)[Ljava/lang/Object;", false); 435 iv.areturn(Type.getType("[Ljava/lang/Object;")); 436 437 FunctionCodegen.endVisit(mv, "toArray", myClass); 438 } 439 } 440 441 if (!isGenericToArrayPresent()) { 442 MethodVisitor mv = v.newMethod(NO_ORIGIN, access, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;", null, null); 443 444 if (descriptor.getKind() != ClassKind.INTERFACE) { 445 InstructionAdapter iv = new InstructionAdapter(mv); 446 mv.visitCode(); 447 448 iv.load(0, classAsmType); 449 iv.load(1, Type.getType("[Ljava/lang/Object;")); 450 451 iv.invokestatic("kotlin/jvm/internal/CollectionToArray", "toArray", 452 "(Ljava/util/Collection;[Ljava/lang/Object;)[Ljava/lang/Object;", false); 453 iv.areturn(Type.getType("[Ljava/lang/Object;")); 454 455 FunctionCodegen.endVisit(mv, "toArray", myClass); 456 } 457 } 458 } 459 460 private void generateFunctionsForDataClasses() { 461 if (!KotlinBuiltIns.isData(descriptor)) return; 462 463 new DataClassMethodGeneratorImpl(myClass, bindingContext).generate(); 464 } 465 466 private class DataClassMethodGeneratorImpl extends DataClassMethodGenerator { 467 DataClassMethodGeneratorImpl( 468 JetClassOrObject klass, 469 BindingContext bindingContext 470 ) { 471 super(klass, bindingContext); 472 } 473 474 @Override 475 public void generateEqualsMethod(@NotNull List<PropertyDescriptor> properties) { 476 KotlinBuiltIns builtins = getBuiltIns(descriptor); 477 FunctionDescriptor equalsFunction = CodegenUtil.getDeclaredFunctionByRawSignature( 478 descriptor, Name.identifier(CodegenUtil.EQUALS_METHOD_NAME), builtins.getBoolean(), builtins.getAny() 479 ); 480 481 assert equalsFunction != null : String.format("Should be called only for classes with non-trivial '%s'. In %s, %s", 482 CodegenUtil.EQUALS_METHOD_NAME, descriptor.getName(), descriptor); 483 484 MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(equalsFunction); 485 MethodVisitor mv = v.newMethod(OtherOrigin(equalsFunction), ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); 486 InstructionAdapter iv = new InstructionAdapter(mv); 487 488 mv.visitCode(); 489 Label eq = new Label(); 490 Label ne = new Label(); 491 492 iv.load(0, OBJECT_TYPE); 493 iv.load(1, OBJECT_TYPE); 494 iv.ifacmpeq(eq); 495 496 iv.load(1, OBJECT_TYPE); 497 iv.instanceOf(classAsmType); 498 iv.ifeq(ne); 499 500 iv.load(1, OBJECT_TYPE); 501 iv.checkcast(classAsmType); 502 iv.store(2, OBJECT_TYPE); 503 504 for (PropertyDescriptor propertyDescriptor : properties) { 505 Type asmType = typeMapper.mapType(propertyDescriptor); 506 507 genPropertyOnStack(iv, context, propertyDescriptor, 0); 508 genPropertyOnStack(iv, context, propertyDescriptor, 2); 509 510 if (asmType.getSort() == Type.ARRAY) { 511 Type elementType = correctElementType(asmType); 512 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 513 iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z", false); 514 } 515 else { 516 iv.invokestatic("java/util/Arrays", "equals", 517 "(" + asmType.getDescriptor() + asmType.getDescriptor() + ")Z", false); 518 } 519 iv.ifeq(ne); 520 } 521 else if (asmType.getSort() == Type.FLOAT) { 522 iv.invokestatic("java/lang/Float", "compare", "(FF)I", false); 523 iv.ifne(ne); 524 } 525 else if (asmType.getSort() == Type.DOUBLE) { 526 iv.invokestatic("java/lang/Double", "compare", "(DD)I", false); 527 iv.ifne(ne); 528 } 529 else { 530 StackValue value = genEqualsForExpressionsOnStack(JetTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType)); 531 value.put(Type.BOOLEAN_TYPE, iv); 532 iv.ifeq(ne); 533 } 534 } 535 536 iv.mark(eq); 537 iv.iconst(1); 538 iv.areturn(Type.INT_TYPE); 539 540 iv.mark(ne); 541 iv.iconst(0); 542 iv.areturn(Type.INT_TYPE); 543 544 FunctionCodegen.endVisit(mv, "equals", myClass); 545 } 546 547 @Override 548 public void generateHashCodeMethod(@NotNull List<PropertyDescriptor> properties) { 549 FunctionDescriptor hashCodeFunction = CodegenUtil.getDeclaredFunctionByRawSignature( 550 descriptor, Name.identifier(CodegenUtil.HASH_CODE_METHOD_NAME), getBuiltIns(descriptor).getInt() 551 ); 552 553 assert hashCodeFunction != null : String.format("Should be called only for classes with non-trivial '%s'. In %s, %s", 554 CodegenUtil.HASH_CODE_METHOD_NAME, descriptor.getName(), descriptor); 555 556 MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(hashCodeFunction); 557 MethodVisitor mv = v.newMethod(OtherOrigin(hashCodeFunction), ACC_PUBLIC, "hashCode", "()I", null, null); 558 InstructionAdapter iv = new InstructionAdapter(mv); 559 560 mv.visitCode(); 561 boolean first = true; 562 for (PropertyDescriptor propertyDescriptor : properties) { 563 if (!first) { 564 iv.iconst(31); 565 iv.mul(Type.INT_TYPE); 566 } 567 568 genPropertyOnStack(iv, context, propertyDescriptor, 0); 569 570 Label ifNull = null; 571 Type asmType = typeMapper.mapType(propertyDescriptor); 572 if (!isPrimitive(asmType)) { 573 ifNull = new Label(); 574 iv.dup(); 575 iv.ifnull(ifNull); 576 } 577 578 genHashCode(mv, iv, asmType); 579 580 if (ifNull != null) { 581 Label end = new Label(); 582 iv.goTo(end); 583 iv.mark(ifNull); 584 iv.pop(); 585 iv.iconst(0); 586 iv.mark(end); 587 } 588 589 if (first) { 590 first = false; 591 } 592 else { 593 iv.add(Type.INT_TYPE); 594 } 595 } 596 597 mv.visitInsn(IRETURN); 598 599 FunctionCodegen.endVisit(mv, "hashCode", myClass); 600 } 601 602 @Override 603 public void generateToStringMethod(@NotNull List<PropertyDescriptor> properties) { 604 FunctionDescriptor toString = CodegenUtil.getDeclaredFunctionByRawSignature( 605 descriptor, Name.identifier(CodegenUtil.TO_STRING_METHOD_NAME), getBuiltIns(descriptor).getString() 606 ); 607 608 assert toString != null : String.format("Should be called only for classes with non-trivial '%s'. In %s, %s", 609 CodegenUtil.TO_STRING_METHOD_NAME, descriptor.getName(), descriptor); 610 611 MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(toString); 612 MethodVisitor mv = v.newMethod(OtherOrigin(toString), ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); 613 InstructionAdapter iv = new InstructionAdapter(mv); 614 615 mv.visitCode(); 616 genStringBuilderConstructor(iv); 617 618 boolean first = true; 619 for (PropertyDescriptor propertyDescriptor : properties) { 620 if (first) { 621 iv.aconst(descriptor.getName() + "(" + propertyDescriptor.getName().asString()+"="); 622 first = false; 623 } 624 else { 625 iv.aconst(", " + propertyDescriptor.getName().asString() + "="); 626 } 627 genInvokeAppendMethod(iv, JAVA_STRING_TYPE); 628 629 Type type = genPropertyOnStack(iv, context, propertyDescriptor, 0); 630 631 if (type.getSort() == Type.ARRAY) { 632 Type elementType = correctElementType(type); 633 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { 634 iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false); 635 type = JAVA_STRING_TYPE; 636 } 637 else { 638 if (elementType.getSort() != Type.CHAR) { 639 iv.invokestatic("java/util/Arrays", "toString", "(" + type.getDescriptor() + ")Ljava/lang/String;", false); 640 type = JAVA_STRING_TYPE; 641 } 642 } 643 } 644 genInvokeAppendMethod(iv, type); 645 } 646 647 iv.aconst(")"); 648 genInvokeAppendMethod(iv, JAVA_STRING_TYPE); 649 650 iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); 651 iv.areturn(JAVA_STRING_TYPE); 652 653 FunctionCodegen.endVisit(mv, "toString", myClass); 654 } 655 656 private Type genPropertyOnStack(InstructionAdapter iv, MethodContext context, @NotNull PropertyDescriptor propertyDescriptor, int index) { 657 iv.load(index, classAsmType); 658 if (couldUseDirectAccessToProperty(propertyDescriptor, /* forGetter = */ true, /* isDelegated = */ false, context)) { 659 Type type = typeMapper.mapType(propertyDescriptor.getType()); 660 String fieldName = ((FieldOwnerContext) context.getParentContext()).getFieldName(propertyDescriptor, false); 661 iv.getfield(classAsmType.getInternalName(), fieldName, type.getDescriptor()); 662 return type.getReturnType(); 663 } 664 else { 665 //noinspection ConstantConditions 666 Method method = typeMapper.mapSignature(propertyDescriptor.getGetter()).getAsmMethod(); 667 iv.invokevirtual(classAsmType.getInternalName(), method.getName(), method.getDescriptor(), false); 668 return method.getReturnType(); 669 } 670 } 671 672 @Override 673 public void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull final ValueParameterDescriptor parameter) { 674 PsiElement originalElement = DescriptorToSourceUtils.descriptorToDeclaration(parameter); 675 functionCodegen.generateMethod(OtherOrigin(originalElement, function), function, new FunctionGenerationStrategy() { 676 @Override 677 public void generateBody( 678 @NotNull MethodVisitor mv, 679 @NotNull FrameMap frameMap, 680 @NotNull JvmMethodSignature signature, 681 @NotNull MethodContext context, 682 @NotNull MemberCodegen<?> parentCodegen 683 ) { 684 Type componentType = signature.getReturnType(); 685 InstructionAdapter iv = new InstructionAdapter(mv); 686 if (!componentType.equals(Type.VOID_TYPE)) { 687 PropertyDescriptor property = 688 bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, descriptorToDeclaration(parameter)); 689 assert property != null : "Property descriptor is not found for primary constructor parameter: " + parameter; 690 691 genPropertyOnStack(iv, context, property, 0); 692 } 693 iv.areturn(componentType); 694 } 695 }); 696 } 697 698 @Override 699 public void generateCopyFunction(@NotNull final FunctionDescriptor function, @NotNull List<JetParameter> constructorParameters) { 700 final Type thisDescriptorType = typeMapper.mapType(descriptor); 701 702 functionCodegen.generateMethod(OtherOrigin(myClass, function), function, new FunctionGenerationStrategy() { 703 @Override 704 public void generateBody( 705 @NotNull MethodVisitor mv, 706 @NotNull FrameMap frameMap, 707 @NotNull JvmMethodSignature signature, 708 @NotNull MethodContext context, 709 @NotNull MemberCodegen<?> parentCodegen 710 ) { 711 InstructionAdapter iv = new InstructionAdapter(mv); 712 713 iv.anew(thisDescriptorType); 714 iv.dup(); 715 716 ConstructorDescriptor constructor = getPrimaryConstructorOfDataClass(descriptor); 717 assert function.getValueParameters().size() == constructor.getValueParameters().size() : 718 "Number of parameters of copy function and constructor are different. " + 719 "Copy: " + function.getValueParameters().size() + ", " + 720 "constructor: " + constructor.getValueParameters().size(); 721 722 MutableClosure closure = ImplementationBodyCodegen.this.context.closure; 723 if (closure != null) { 724 ClassDescriptor captureThis = closure.getCaptureThis(); 725 if (captureThis != null) { 726 iv.load(0, classAsmType); 727 Type type = typeMapper.mapType(captureThis); 728 iv.getfield(classAsmType.getInternalName(), CAPTURED_THIS_FIELD, type.getDescriptor()); 729 } 730 } 731 732 int parameterIndex = 1; // localVariable 0 = this 733 for (ValueParameterDescriptor parameterDescriptor : function.getValueParameters()) { 734 Type type = typeMapper.mapType(parameterDescriptor.getType()); 735 iv.load(parameterIndex, type); 736 parameterIndex += type.getSize(); 737 } 738 739 Method constructorAsmMethod = typeMapper.mapSignature(constructor).getAsmMethod(); 740 iv.invokespecial(thisDescriptorType.getInternalName(), "<init>", constructorAsmMethod.getDescriptor(), false); 741 742 iv.areturn(thisDescriptorType); 743 } 744 }); 745 746 functionCodegen.generateDefaultIfNeeded( 747 context.intoFunction(function), function, OwnerKind.IMPLEMENTATION, 748 new DefaultParameterValueLoader() { 749 @Override 750 public StackValue genValue(ValueParameterDescriptor valueParameter, ExpressionCodegen codegen) { 751 assert KotlinBuiltIns.isData((ClassDescriptor) function.getContainingDeclaration()) 752 : "Function container should be annotated with [data]: " + function; 753 PropertyDescriptor property = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameter); 754 assert property != null : "Copy function doesn't correspond to any property: " + function; 755 return codegen.intermediateValueForProperty(property, false, null, StackValue.LOCAL_0); 756 } 757 }, 758 null 759 ); 760 } 761 } 762 763 @NotNull 764 private static ConstructorDescriptor getPrimaryConstructorOfDataClass(@NotNull ClassDescriptor classDescriptor) { 765 ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); 766 assert constructor != null : "Data class must have primary constructor: " + classDescriptor; 767 return constructor; 768 } 769 770 private void generateEnumMethods() { 771 if (isEnumClass(descriptor)) { 772 generateEnumValuesMethod(); 773 generateEnumValueOfMethod(); 774 } 775 } 776 777 private void generateEnumValuesMethod() { 778 Type type = typeMapper.mapType(getBuiltIns(descriptor).getArrayType(INVARIANT, descriptor.getDefaultType())); 779 780 FunctionDescriptor valuesFunction = 781 KotlinPackage.single(descriptor.getStaticScope().getFunctions(ENUM_VALUES), new Function1<FunctionDescriptor, Boolean>() { 782 @Override 783 public Boolean invoke(FunctionDescriptor descriptor) { 784 return CodegenUtil.isEnumValuesMethod(descriptor); 785 } 786 }); 787 MethodVisitor mv = v.newMethod(OtherOrigin(myClass, valuesFunction), ACC_PUBLIC | ACC_STATIC, ENUM_VALUES.asString(), 788 "()" + type.getDescriptor(), null, null); 789 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 790 791 mv.visitCode(); 792 mv.visitFieldInsn(GETSTATIC, classAsmType.getInternalName(), ENUM_VALUES_FIELD_NAME, type.getDescriptor()); 793 mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), "clone", "()Ljava/lang/Object;", false); 794 mv.visitTypeInsn(CHECKCAST, type.getInternalName()); 795 mv.visitInsn(ARETURN); 796 FunctionCodegen.endVisit(mv, "values()", myClass); 797 } 798 799 private void generateEnumValueOfMethod() { 800 FunctionDescriptor valueOfFunction = 801 KotlinPackage.single(descriptor.getStaticScope().getFunctions(ENUM_VALUE_OF), new Function1<FunctionDescriptor, Boolean>() { 802 @Override 803 public Boolean invoke(FunctionDescriptor descriptor) { 804 return CodegenUtil.isEnumValueOfMethod(descriptor); 805 } 806 }); 807 MethodVisitor mv = v.newMethod(OtherOrigin(myClass, valueOfFunction), ACC_PUBLIC | ACC_STATIC, ENUM_VALUE_OF.asString(), 808 "(Ljava/lang/String;)" + classAsmType.getDescriptor(), null, null); 809 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 810 811 mv.visitCode(); 812 mv.visitLdcInsn(classAsmType); 813 mv.visitVarInsn(ALOAD, 0); 814 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;", false); 815 mv.visitTypeInsn(CHECKCAST, classAsmType.getInternalName()); 816 mv.visitInsn(ARETURN); 817 FunctionCodegen.endVisit(mv, "valueOf()", myClass); 818 } 819 820 protected void generateSyntheticAccessors() { 821 Map<DeclarationDescriptor, DeclarationDescriptor> accessors = ((CodegenContext<?>) context).getAccessors(); 822 for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) { 823 generateSyntheticAccessor(entry); 824 } 825 } 826 827 private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) { 828 if (entry.getValue() instanceof FunctionDescriptor) { 829 FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue(); 830 final FunctionDescriptor original = (FunctionDescriptor) entry.getKey(); 831 functionCodegen.generateMethod( 832 Synthetic(null, original), bridge, 833 new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) { 834 @Override 835 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 836 markLineNumberForSyntheticFunction(descriptor, codegen.v); 837 838 generateMethodCallTo(original, codegen.v); 839 codegen.v.areturn(signature.getReturnType()); 840 } 841 } 842 ); 843 } 844 else if (entry.getValue() instanceof PropertyDescriptor) { 845 final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue(); 846 final PropertyDescriptor original = (PropertyDescriptor) entry.getKey(); 847 848 class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> { 849 public PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) { 850 super(ImplementationBodyCodegen.this.state, callableDescriptor); 851 } 852 853 @Override 854 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 855 boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && 856 !isCompanionObject(bridge.getContainingDeclaration()); 857 StackValue property = 858 codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR, 859 StackValue.none()); 860 861 InstructionAdapter iv = codegen.v; 862 863 markLineNumberForSyntheticFunction(descriptor, iv); 864 865 Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); 866 for (int i = 0, reg = 0; i < argTypes.length; i++) { 867 Type argType = argTypes[i]; 868 iv.load(reg, argType); 869 //noinspection AssignmentToForLoopParameter 870 reg += argType.getSize(); 871 } 872 873 if (callableDescriptor instanceof PropertyGetterDescriptor) { 874 property.put(property.type, iv); 875 } 876 else { 877 property.store(StackValue.onStack(property.type), iv, true); 878 } 879 880 iv.areturn(signature.getReturnType()); 881 } 882 } 883 884 PropertyGetterDescriptor getter = bridge.getGetter(); 885 assert getter != null; 886 functionCodegen.generateMethod(Synthetic(null, original.getGetter() != null ? original.getGetter() : original), 887 getter, new PropertyAccessorStrategy(getter)); 888 889 890 if (bridge.isVar()) { 891 PropertySetterDescriptor setter = bridge.getSetter(); 892 assert setter != null; 893 894 functionCodegen.generateMethod(Synthetic(null, original.getSetter() != null ? original.getSetter() : original), 895 setter, new PropertyAccessorStrategy(setter)); 896 } 897 } 898 else { 899 throw new UnsupportedOperationException(); 900 } 901 } 902 903 public static void markLineNumberForSyntheticFunction(@Nullable ClassDescriptor declarationDescriptor, @NotNull InstructionAdapter v) { 904 if (declarationDescriptor == null) { 905 return; 906 } 907 908 PsiElement classElement = DescriptorToSourceUtils.getSourceFromDescriptor(declarationDescriptor); 909 if (classElement != null) { 910 Integer lineNumber = CodegenUtil.getLineNumberForElement(classElement, false); 911 if (lineNumber != null) { 912 Label label = new Label(); 913 v.visitLabel(label); 914 v.visitLineNumber(lineNumber, label); 915 } 916 } 917 } 918 919 private void generateMethodCallTo(FunctionDescriptor functionDescriptor, InstructionAdapter iv) { 920 boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor; 921 boolean callFromAccessor = !JetTypeMapper.isAccessor(functionDescriptor); 922 CallableMethod callableMethod = isConstructor ? 923 typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) : 924 typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor, context); 925 926 int reg = 1; 927 if (isConstructor) { 928 iv.anew(callableMethod.getOwner()); 929 iv.dup(); 930 reg = 0; 931 } 932 else if (callFromAccessor) { 933 if (!AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor)) { 934 iv.load(0, OBJECT_TYPE); 935 } 936 } 937 938 for (Type argType : callableMethod.getParameterTypes()) { 939 iv.load(reg, argType); 940 reg += argType.getSize(); 941 } 942 callableMethod.genInvokeInstruction(iv); 943 } 944 945 private void generateFieldForSingleton() { 946 if (isEnumEntry(descriptor) || isCompanionObject(descriptor)) return; 947 948 if (isNonCompanionObject(descriptor)) { 949 StackValue.Field field = StackValue.singleton(descriptor, typeMapper); 950 v.newField(OtherOrigin(myClass), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null); 951 952 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 953 954 // Invoke the object constructor but ignore the result because INSTANCE$ will be initialized in the first line of <init> 955 InstructionAdapter v = createOrGetClInitCodegen().v; 956 v.anew(classAsmType); 957 v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false); 958 return; 959 } 960 961 ClassDescriptor companionObjectDescriptor = descriptor.getCompanionObjectDescriptor(); 962 if (companionObjectDescriptor == null) { 963 return; 964 } 965 966 JetObjectDeclaration companionObject = firstOrNull(((JetClass) myClass).getCompanionObjects()); 967 assert companionObject != null : "Companion object not found: " + myClass.getText(); 968 969 StackValue.Field field = StackValue.singleton(companionObjectDescriptor, typeMapper); 970 v.newField(OtherOrigin(companionObject), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null); 971 972 StackValue.Field deprecatedField = StackValue.deprecatedCompanionObjectAccessor(companionObjectDescriptor, typeMapper); 973 FieldVisitor fv = v.newField(OtherOrigin(companionObject), ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_DEPRECATED, 974 deprecatedField.name, deprecatedField.type.getDescriptor(), null, null); 975 976 fv.visitAnnotation(asmDescByFqNameWithoutInnerClasses(new FqName("java.lang.Deprecated")), true).visitEnd(); 977 978 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 979 980 if (!isCompanionObjectWithBackingFieldsInOuter(companionObjectDescriptor)) { 981 generateCompanionObjectInitializer(companionObjectDescriptor); 982 } 983 } 984 985 private void generateCompanionObjectBackingFieldCopies() { 986 if (companionObjectPropertiesToCopy == null) return; 987 988 for (PropertyAndDefaultValue info : companionObjectPropertiesToCopy) { 989 PropertyDescriptor property = info.descriptor; 990 991 Type type = typeMapper.mapType(property); 992 FieldVisitor fv = v.newField(Synthetic(DescriptorToSourceUtils.descriptorToDeclaration(property), property), 993 ACC_STATIC | ACC_FINAL | ACC_PUBLIC, context.getFieldName(property, false), 994 type.getDescriptor(), typeMapper.mapFieldSignature(property.getType()), 995 info.defaultValue); 996 997 AnnotationCodegen.forField(fv, typeMapper).genAnnotations(property, type); 998 999 //This field are always static and final so if it has constant initializer don't do anything in clinit, 1000 //field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4 1001 // TODO: test this code 1002 if (state.getClassBuilderMode() == ClassBuilderMode.FULL && info.defaultValue == null) { 1003 ExpressionCodegen codegen = createOrGetClInitCodegen(); 1004 int companionObjectIndex = putCompanionObjectInLocalVar(codegen); 1005 StackValue.local(companionObjectIndex, OBJECT_TYPE).put(OBJECT_TYPE, codegen.v); 1006 copyFieldFromCompanionObject(property); 1007 } 1008 } 1009 } 1010 1011 private int putCompanionObjectInLocalVar(ExpressionCodegen codegen) { 1012 FrameMap frameMap = codegen.myFrameMap; 1013 ClassDescriptor companionObjectDescriptor = descriptor.getCompanionObjectDescriptor(); 1014 int companionObjectIndex = frameMap.getIndex(companionObjectDescriptor); 1015 if (companionObjectIndex == -1) { 1016 companionObjectIndex = frameMap.enter(companionObjectDescriptor, OBJECT_TYPE); 1017 StackValue companionObject = StackValue.singleton(companionObjectDescriptor, typeMapper); 1018 StackValue.local(companionObjectIndex, companionObject.type).store(companionObject, codegen.v); 1019 } 1020 return companionObjectIndex; 1021 } 1022 1023 private void copyFieldFromCompanionObject(PropertyDescriptor propertyDescriptor) { 1024 ExpressionCodegen codegen = createOrGetClInitCodegen(); 1025 StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null, StackValue.none()); 1026 StackValue.Field field = StackValue 1027 .field(property.type, classAsmType, propertyDescriptor.getName().asString(), true, StackValue.none(), propertyDescriptor); 1028 field.store(property, codegen.v); 1029 } 1030 1031 private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) { 1032 ExpressionCodegen codegen = createOrGetClInitCodegen(); 1033 FunctionDescriptor constructor = context.accessibleFunctionDescriptor(KotlinPackage.single(companionObject.getConstructors())); 1034 generateMethodCallTo(constructor, codegen.v); 1035 codegen.v.dup(); 1036 StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject)); 1037 StackValue.singleton(companionObject, typeMapper).store(instance, codegen.v, true); 1038 StackValue.deprecatedCompanionObjectAccessor(companionObject, typeMapper).store(instance, codegen.v, true); 1039 } 1040 1041 private void generatePrimaryConstructor(final DelegationFieldsInfo delegationFieldsInfo) { 1042 if (isTrait(descriptor) || isAnnotationClass(descriptor)) return; 1043 1044 ConstructorDescriptor constructorDescriptor = descriptor.getUnsubstitutedPrimaryConstructor(); 1045 if (constructorDescriptor == null) return; 1046 1047 ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); 1048 1049 functionCodegen.generateMethod(OtherOrigin(myClass, constructorDescriptor), constructorDescriptor, constructorContext, 1050 new FunctionGenerationStrategy.CodegenBased<ConstructorDescriptor>(state, constructorDescriptor) { 1051 @Override 1052 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 1053 generatePrimaryConstructorImpl(callableDescriptor, codegen, delegationFieldsInfo); 1054 } 1055 } 1056 ); 1057 1058 functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION, 1059 DefaultParameterValueLoader.DEFAULT, null); 1060 1061 new DefaultParameterValueSubstitutor(state).generateConstructorOverloadsIfNeeded(constructorDescriptor, v, 1062 constructorContext, myClass); 1063 1064 if (isCompanionObject(descriptor)) { 1065 context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext); 1066 } 1067 } 1068 1069 private void generateSecondaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { 1070 if (!canHaveDeclaredConstructors(descriptor)) return; 1071 1072 ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); 1073 1074 functionCodegen.generateMethod(OtherOrigin(descriptorToDeclaration(constructorDescriptor), constructorDescriptor), 1075 constructorDescriptor, constructorContext, 1076 new FunctionGenerationStrategy.CodegenBased<ConstructorDescriptor>(state, constructorDescriptor) { 1077 @Override 1078 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 1079 generateSecondaryConstructorImpl(callableDescriptor, codegen); 1080 } 1081 } 1082 ); 1083 1084 functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION, 1085 DefaultParameterValueLoader.DEFAULT, null); 1086 1087 new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded(myClass, constructorDescriptor, constructorDescriptor, 1088 constructorContext, v); 1089 } 1090 1091 private void generatePrimaryConstructorImpl( 1092 @NotNull ConstructorDescriptor constructorDescriptor, 1093 @NotNull ExpressionCodegen codegen, 1094 @NotNull DelegationFieldsInfo fieldsInfo 1095 ) { 1096 InstructionAdapter iv = codegen.v; 1097 1098 generateClosureInitialization(iv); 1099 1100 generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, 1101 getDelegationConstructorCall(bindingContext, constructorDescriptor)); 1102 1103 if (isNonCompanionObject(descriptor)) { 1104 StackValue.singleton(descriptor, typeMapper).store(StackValue.LOCAL_0, iv); 1105 } 1106 1107 for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { 1108 if (specifier instanceof JetDelegatorByExpressionSpecifier) { 1109 genCallToDelegatorByExpressionSpecifier(iv, codegen, (JetDelegatorByExpressionSpecifier) specifier, fieldsInfo); 1110 } 1111 } 1112 1113 int curParam = 0; 1114 List<ValueParameterDescriptor> parameters = constructorDescriptor.getValueParameters(); 1115 for (JetParameter parameter : getPrimaryConstructorParameters()) { 1116 if (parameter.hasValOrVarNode()) { 1117 VariableDescriptor descriptor = parameters.get(curParam); 1118 Type type = typeMapper.mapType(descriptor); 1119 iv.load(0, classAsmType); 1120 iv.load(codegen.myFrameMap.getIndex(descriptor), type); 1121 PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter); 1122 assert propertyDescriptor != null : "Property descriptor is not found for primary constructor parameter: " + parameter; 1123 iv.putfield(classAsmType.getInternalName(), context.getFieldName(propertyDescriptor, false), type.getDescriptor()); 1124 } 1125 curParam++; 1126 } 1127 1128 if (isCompanionObjectWithBackingFieldsInOuter(descriptor)) { 1129 final ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen(); 1130 parentCodegen.generateCompanionObjectInitializer(descriptor); 1131 generateInitializers(new Function0<ExpressionCodegen>() { 1132 @Override 1133 public ExpressionCodegen invoke() { 1134 return parentCodegen.createOrGetClInitCodegen(); 1135 } 1136 }); 1137 } 1138 else { 1139 generateInitializers(codegen); 1140 } 1141 1142 iv.visitInsn(RETURN); 1143 } 1144 1145 private void generateSecondaryConstructorImpl( 1146 @NotNull ConstructorDescriptor constructorDescriptor, 1147 @NotNull ExpressionCodegen codegen 1148 ) { 1149 InstructionAdapter iv = codegen.v; 1150 1151 ResolvedCall<ConstructorDescriptor> constructorDelegationCall = 1152 getDelegationConstructorCall(bindingContext, constructorDescriptor); 1153 ConstructorDescriptor delegateConstructor = constructorDelegationCall == null ? null : 1154 constructorDelegationCall.getResultingDescriptor(); 1155 1156 generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, constructorDelegationCall); 1157 if (!isSameClassConstructor(delegateConstructor)) { 1158 // Initialization happens only for constructors delegating to super 1159 generateClosureInitialization(iv); 1160 generateInitializers(codegen); 1161 } 1162 1163 JetSecondaryConstructor constructor = 1164 (JetSecondaryConstructor) DescriptorToSourceUtils.descriptorToDeclaration(constructorDescriptor); 1165 assert constructor != null; 1166 if (constructor.hasBody()) { 1167 codegen.gen(constructor.getBodyExpression(), Type.VOID_TYPE); 1168 } 1169 1170 iv.visitInsn(RETURN); 1171 } 1172 1173 private void generateInitializers(@NotNull final ExpressionCodegen codegen) { 1174 generateInitializers(new Function0<ExpressionCodegen>() { 1175 @Override 1176 public ExpressionCodegen invoke() { 1177 return codegen; 1178 } 1179 }); 1180 } 1181 1182 private void generateClosureInitialization(@NotNull InstructionAdapter iv) { 1183 MutableClosure closure = context.closure; 1184 if (closure != null) { 1185 List<FieldInfo> argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, closure, classAsmType); 1186 int k = 1; 1187 for (FieldInfo info : argsFromClosure) { 1188 k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv); 1189 } 1190 } 1191 } 1192 1193 private void genSimpleSuperCall(InstructionAdapter iv) { 1194 iv.load(0, superClassAsmType); 1195 if (descriptor.getKind() == ClassKind.ENUM_CLASS || descriptor.getKind() == ClassKind.ENUM_ENTRY) { 1196 iv.load(1, JAVA_STRING_TYPE); 1197 iv.load(2, Type.INT_TYPE); 1198 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(Ljava/lang/String;I)V", false); 1199 } 1200 else { 1201 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false); 1202 } 1203 } 1204 1205 private class DelegationFieldsInfo { 1206 private class Field { 1207 public final Type type; 1208 public final String name; 1209 public final boolean generateField; 1210 1211 private Field(Type type, String name, boolean generateField) { 1212 this.type = type; 1213 this.name = name; 1214 this.generateField = generateField; 1215 } 1216 1217 @NotNull 1218 public StackValue getStackValue() { 1219 return StackValue.field(type, classAsmType, name, false, StackValue.none()); 1220 } 1221 } 1222 private final Map<JetDelegatorByExpressionSpecifier, Field> fields = new HashMap<JetDelegatorByExpressionSpecifier, Field>(); 1223 1224 @NotNull 1225 public Field getInfo(JetDelegatorByExpressionSpecifier specifier) { 1226 return fields.get(specifier); 1227 } 1228 1229 private void addField(JetDelegatorByExpressionSpecifier specifier, PropertyDescriptor propertyDescriptor) { 1230 fields.put(specifier, 1231 new Field(typeMapper.mapType(propertyDescriptor), propertyDescriptor.getName().asString(), false)); 1232 } 1233 1234 private void addField(JetDelegatorByExpressionSpecifier specifier, Type type, String name) { 1235 fields.put(specifier, new Field(type, name, true)); 1236 } 1237 } 1238 1239 @NotNull 1240 private DelegationFieldsInfo getDelegationFieldsInfo(@NotNull List<JetDelegationSpecifier> delegationSpecifiers) { 1241 DelegationFieldsInfo result = new DelegationFieldsInfo(); 1242 int n = 0; 1243 for (JetDelegationSpecifier specifier : delegationSpecifiers) { 1244 if (specifier instanceof JetDelegatorByExpressionSpecifier) { 1245 JetExpression expression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); 1246 PropertyDescriptor propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext); 1247 1248 1249 if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext)) { 1250 result.addField((JetDelegatorByExpressionSpecifier) specifier, propertyDescriptor); 1251 } 1252 else { 1253 JetType expressionType = expression != null ? bindingContext.getType(expression) : null; 1254 Type asmType = 1255 expressionType != null ? typeMapper.mapType(expressionType) : typeMapper.mapType(getSuperClass(specifier)); 1256 result.addField((JetDelegatorByExpressionSpecifier) specifier, asmType, "$delegate_" + n); 1257 } 1258 n++; 1259 } 1260 } 1261 return result; 1262 } 1263 1264 @NotNull 1265 private ClassDescriptor getSuperClass(@NotNull JetDelegationSpecifier specifier) { 1266 return CodegenUtil.getSuperClassByDelegationSpecifier(specifier, bindingContext); 1267 } 1268 1269 private void genCallToDelegatorByExpressionSpecifier( 1270 InstructionAdapter iv, 1271 ExpressionCodegen codegen, 1272 JetDelegatorByExpressionSpecifier specifier, 1273 DelegationFieldsInfo fieldsInfo 1274 ) { 1275 JetExpression expression = specifier.getDelegateExpression(); 1276 1277 DelegationFieldsInfo.Field fieldInfo = fieldsInfo.getInfo(specifier); 1278 if (fieldInfo.generateField) { 1279 iv.load(0, classAsmType); 1280 fieldInfo.getStackValue().store(codegen.gen(expression), iv); 1281 } 1282 } 1283 1284 private void lookupConstructorExpressionsInClosureIfPresent() { 1285 if (state.getClassBuilderMode() != ClassBuilderMode.FULL || descriptor.getConstructors().isEmpty()) return; 1286 1287 JetVisitorVoid visitor = new JetVisitorVoid() { 1288 @Override 1289 public void visitJetElement(@NotNull JetElement e) { 1290 e.acceptChildren(this); 1291 } 1292 1293 @Override 1294 public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expr) { 1295 DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr); 1296 1297 if (isLocalFunction(descriptor)) { 1298 lookupInContext(descriptor); 1299 } 1300 else if (descriptor instanceof CallableMemberDescriptor) { 1301 ResolvedCall<? extends CallableDescriptor> call = getResolvedCall(expr, bindingContext); 1302 if (call != null) { 1303 lookupReceiver(call.getDispatchReceiver()); 1304 lookupReceiver(call.getExtensionReceiver()); 1305 } 1306 } 1307 else if (descriptor instanceof VariableDescriptor) { 1308 if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) { 1309 ClassDescriptor classDescriptor = 1310 (ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration(); 1311 if (classDescriptor == ImplementationBodyCodegen.this.descriptor) return; 1312 } 1313 lookupInContext(descriptor); 1314 } 1315 } 1316 1317 private void lookupReceiver(@NotNull ReceiverValue value) { 1318 if (value instanceof ThisReceiver) { 1319 if (value instanceof ExtensionReceiver) { 1320 ReceiverParameterDescriptor parameter = 1321 ((ExtensionReceiver) value).getDeclarationDescriptor().getExtensionReceiverParameter(); 1322 assert parameter != null : "Extension receiver should exist: " + ((ExtensionReceiver) value).getDeclarationDescriptor(); 1323 lookupInContext(parameter); 1324 } 1325 else { 1326 lookupInContext(((ThisReceiver) value).getDeclarationDescriptor()); 1327 } 1328 } 1329 } 1330 1331 1332 private void lookupInContext(@NotNull DeclarationDescriptor toLookup) { 1333 context.lookupInContext(toLookup, StackValue.LOCAL_0, state, true); 1334 } 1335 1336 @Override 1337 public void visitThisExpression(@NotNull JetThisExpression expression) { 1338 DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); 1339 assert descriptor instanceof CallableDescriptor || 1340 descriptor instanceof ClassDescriptor : "'This' reference target should be class or callable descriptor but was " + descriptor; 1341 if (descriptor instanceof ClassDescriptor) { 1342 lookupInContext(descriptor); 1343 } 1344 1345 if (descriptor instanceof CallableDescriptor) { 1346 ReceiverParameterDescriptor parameter = ((CallableDescriptor) descriptor).getExtensionReceiverParameter(); 1347 if (parameter != null) { 1348 lookupInContext(parameter); 1349 } 1350 } 1351 } 1352 }; 1353 1354 for (JetDeclaration declaration : myClass.getDeclarations()) { 1355 if (declaration instanceof JetProperty) { 1356 JetProperty property = (JetProperty) declaration; 1357 JetExpression initializer = property.getInitializer(); 1358 if (initializer != null) { 1359 initializer.accept(visitor); 1360 } 1361 } 1362 else if (declaration instanceof JetClassInitializer) { 1363 JetClassInitializer initializer = (JetClassInitializer) declaration; 1364 initializer.accept(visitor); 1365 } 1366 else if (declaration instanceof JetSecondaryConstructor) { 1367 JetSecondaryConstructor constructor = (JetSecondaryConstructor) declaration; 1368 constructor.accept(visitor); 1369 } 1370 } 1371 1372 for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { 1373 if (specifier instanceof JetDelegatorByExpressionSpecifier) { 1374 JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); 1375 assert delegateExpression != null; 1376 delegateExpression.accept(visitor); 1377 } 1378 } 1379 1380 ClassDescriptor superClass = DescriptorUtilPackage.getSuperClassNotAny(descriptor); 1381 if (superClass != null) { 1382 if (superClass.isInner()) { 1383 context.lookupInContext(superClass.getContainingDeclaration(), StackValue.LOCAL_0, state, true); 1384 } 1385 1386 ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); 1387 if (primaryConstructor != null && !isAnonymousObject(descriptor)) { 1388 ResolvedCall<ConstructorDescriptor> delegationCall = getDelegationConstructorCall(bindingContext, primaryConstructor); 1389 JetValueArgumentList argumentList = delegationCall != null ? delegationCall.getCall().getValueArgumentList() : null; 1390 if (argumentList != null) { 1391 argumentList.accept(visitor); 1392 } 1393 } 1394 } 1395 } 1396 1397 private void generateTraitMethods() { 1398 if (isTrait(descriptor)) return; 1399 1400 for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getTraitMethods(descriptor).entrySet()) { 1401 FunctionDescriptor traitFun = entry.getKey(); 1402 //skip java 8 default methods 1403 if (!(traitFun instanceof JavaCallableMemberDescriptor)) { 1404 generateDelegationToTraitImpl(traitFun, entry.getValue()); 1405 } 1406 } 1407 } 1408 1409 private void generateDelegationToTraitImpl(@NotNull final FunctionDescriptor traitFun, @NotNull FunctionDescriptor inheritedFun) { 1410 functionCodegen.generateMethod( 1411 DelegationToTraitImpl(descriptorToDeclaration(traitFun), traitFun), 1412 inheritedFun, 1413 new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, inheritedFun) { 1414 @Override 1415 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 1416 DeclarationDescriptor containingDeclaration = traitFun.getContainingDeclaration(); 1417 if (!DescriptorUtils.isTrait(containingDeclaration)) return; 1418 ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration; 1419 Type traitImplType = typeMapper.mapTraitImpl(containingTrait); 1420 1421 Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal(), OwnerKind.TRAIT_IMPL).getAsmMethod(); 1422 1423 Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); 1424 Type[] originalArgTypes = traitMethod.getArgumentTypes(); 1425 assert originalArgTypes.length == argTypes.length + 1 : 1426 "Invalid trait implementation signature: " + signature + " vs " + traitMethod + " for " + traitFun; 1427 1428 InstructionAdapter iv = codegen.v; 1429 iv.load(0, OBJECT_TYPE); 1430 for (int i = 0, reg = 1; i < argTypes.length; i++) { 1431 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i + 1], iv); 1432 //noinspection AssignmentToForLoopParameter 1433 reg += argTypes[i].getSize(); 1434 } 1435 1436 if (KotlinBuiltIns.isCloneable(containingTrait) && traitMethod.getName().equals("clone")) { 1437 // A special hack for Cloneable: there's no kotlin/Cloneable$$TImpl class at runtime, 1438 // and its 'clone' method is actually located in java/lang/Object 1439 iv.invokespecial("java/lang/Object", "clone", "()Ljava/lang/Object;", false); 1440 } 1441 else { 1442 iv.invokestatic(traitImplType.getInternalName(), traitMethod.getName(), traitMethod.getDescriptor(), false); 1443 } 1444 1445 Type returnType = signature.getReturnType(); 1446 StackValue.onStack(traitMethod.getReturnType()).put(returnType, iv); 1447 iv.areturn(returnType); 1448 } 1449 } 1450 ); 1451 } 1452 1453 private void generateDelegatorToConstructorCall( 1454 @NotNull InstructionAdapter iv, 1455 @NotNull ExpressionCodegen codegen, 1456 @NotNull ConstructorDescriptor constructorDescriptor, 1457 @Nullable ResolvedCall<ConstructorDescriptor> delegationConstructorCall 1458 ) { 1459 if (delegationConstructorCall == null) { 1460 genSimpleSuperCall(iv); 1461 return; 1462 } 1463 iv.load(0, OBJECT_TYPE); 1464 ConstructorDescriptor delegateConstructor = SamCodegenUtil.resolveSamAdapter(delegationConstructorCall.getResultingDescriptor()); 1465 1466 CallableMethod delegateConstructorCallable = typeMapper.mapToCallableMethod(delegateConstructor); 1467 CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor); 1468 1469 List<JvmMethodParameterSignature> delegatingParameters = delegateConstructorCallable.getValueParameters(); 1470 List<JvmMethodParameterSignature> parameters = callable.getValueParameters(); 1471 1472 ArgumentGenerator argumentGenerator; 1473 if (isSameClassConstructor(delegateConstructor)) { 1474 // if it's the same class constructor we should just pass all synthetic parameters 1475 argumentGenerator = 1476 generateThisCallImplicitArguments(iv, codegen, delegateConstructor, delegateConstructorCallable, delegatingParameters, 1477 parameters); 1478 } 1479 else { 1480 argumentGenerator = 1481 generateSuperCallImplicitArguments(iv, codegen, constructorDescriptor, delegateConstructor, delegateConstructorCallable, 1482 delegatingParameters, 1483 parameters); 1484 } 1485 1486 codegen.invokeMethodWithArguments( 1487 delegateConstructorCallable, delegationConstructorCall, StackValue.none(), codegen.defaultCallGenerator, argumentGenerator); 1488 } 1489 1490 private boolean isSameClassConstructor(@Nullable ConstructorDescriptor delegatingConstructor) { 1491 return delegatingConstructor != null && delegatingConstructor.getContainingDeclaration() == descriptor; 1492 } 1493 1494 @NotNull 1495 private ArgumentGenerator generateSuperCallImplicitArguments( 1496 @NotNull InstructionAdapter iv, 1497 @NotNull ExpressionCodegen codegen, 1498 @NotNull ConstructorDescriptor constructorDescriptor, 1499 @NotNull ConstructorDescriptor superConstructor, 1500 @NotNull CallableMethod superCallable, 1501 @NotNull List<JvmMethodParameterSignature> superParameters, 1502 @NotNull List<JvmMethodParameterSignature> parameters 1503 ) { 1504 int offset = 1; 1505 int superIndex = 0; 1506 1507 // Here we match all the super constructor parameters except those with kind VALUE to the derived constructor parameters, push 1508 // them all onto the stack and update "offset" variable so that in the end it points to the slot of the first VALUE argument 1509 for (JvmMethodParameterSignature parameter : parameters) { 1510 if (superIndex >= superParameters.size()) break; 1511 1512 JvmMethodParameterKind superKind = superParameters.get(superIndex).getKind(); 1513 JvmMethodParameterKind kind = parameter.getKind(); 1514 Type type = parameter.getAsmType(); 1515 1516 if (superKind == JvmMethodParameterKind.VALUE && kind == JvmMethodParameterKind.SUPER_CALL_PARAM) { 1517 // Stop when we reach the actual value parameters present in the code; they will be generated via ResolvedCall below 1518 break; 1519 } 1520 1521 if (superKind == JvmMethodParameterKind.OUTER) { 1522 assert kind == JvmMethodParameterKind.OUTER || kind == JvmMethodParameterKind.SUPER_CALL_PARAM : 1523 String.format("Non-outer parameter incorrectly mapped to outer for %s: %s vs %s", 1524 constructorDescriptor, parameters, superParameters); 1525 // Super constructor requires OUTER parameter, but our OUTER instance may be different from what is expected by the super 1526 // constructor. We need to traverse our outer classes from the bottom up, to find the needed class 1527 // TODO: isSuper should be "true" but this makes some tests on inner classes extending outer fail 1528 // See innerExtendsOuter.kt, semantics of inner classes extending their outer should be changed to be as in Java 1529 ClassDescriptor outerForSuper = (ClassDescriptor) superConstructor.getContainingDeclaration().getContainingDeclaration(); 1530 StackValue outer = codegen.generateThisOrOuter(outerForSuper, false); 1531 outer.put(outer.type, codegen.v); 1532 superIndex++; 1533 } 1534 else if (kind == JvmMethodParameterKind.SUPER_CALL_PARAM || kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL) { 1535 iv.load(offset, type); 1536 superIndex++; 1537 } 1538 1539 offset += type.getSize(); 1540 } 1541 1542 if (isAnonymousObject(descriptor)) { 1543 List<JvmMethodParameterSignature> superValues = superParameters.subList(superIndex, superParameters.size()); 1544 return new ObjectSuperCallArgumentGenerator(superValues, iv, offset); 1545 } 1546 else { 1547 return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, superConstructor.getValueParameters(), 1548 superCallable.getValueParameterTypes()); 1549 } 1550 } 1551 1552 @NotNull 1553 private static ArgumentGenerator generateThisCallImplicitArguments( 1554 @NotNull InstructionAdapter iv, 1555 @NotNull ExpressionCodegen codegen, 1556 @NotNull ConstructorDescriptor delegatingConstructor, 1557 @NotNull CallableMethod delegatingCallable, 1558 @NotNull List<JvmMethodParameterSignature> delegatingParameters, 1559 @NotNull List<JvmMethodParameterSignature> parameters 1560 ) { 1561 int offset = 1; 1562 int index = 0; 1563 for (; index < delegatingParameters.size(); index++) { 1564 JvmMethodParameterKind delegatingKind = delegatingParameters.get(index).getKind(); 1565 if (delegatingKind == JvmMethodParameterKind.VALUE) { 1566 assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE: 1567 "Delegating constructor has not enough implicit parameters"; 1568 break; 1569 } 1570 assert index < parameters.size() && parameters.get(index).getKind() == delegatingKind : 1571 "Constructors of the same class should have the same set of implicit arguments"; 1572 JvmMethodParameterSignature parameter = parameters.get(index); 1573 1574 iv.load(offset, parameter.getAsmType()); 1575 offset += parameter.getAsmType().getSize(); 1576 } 1577 1578 assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE : 1579 "Delegating constructor has not enough parameters"; 1580 1581 return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, delegatingConstructor.getValueParameters(), 1582 delegatingCallable.getValueParameterTypes()); 1583 } 1584 1585 private static class ObjectSuperCallArgumentGenerator extends ArgumentGenerator { 1586 private final List<JvmMethodParameterSignature> parameters; 1587 private final InstructionAdapter iv; 1588 private int offset; 1589 1590 public ObjectSuperCallArgumentGenerator( 1591 @NotNull List<JvmMethodParameterSignature> superParameters, 1592 @NotNull InstructionAdapter iv, 1593 int firstValueParamOffset 1594 ) { 1595 this.parameters = superParameters; 1596 this.iv = iv; 1597 this.offset = firstValueParamOffset; 1598 } 1599 1600 @Override 1601 public void generateExpression(int i, @NotNull ExpressionValueArgument argument) { 1602 generateSuperCallArgument(i); 1603 } 1604 1605 @Override 1606 public void generateDefault(int i, @NotNull DefaultValueArgument argument) { 1607 pushDefaultValueOnStack(parameters.get(i).getAsmType(), iv); 1608 } 1609 1610 @Override 1611 public void generateVararg(int i, @NotNull VarargValueArgument argument) { 1612 generateSuperCallArgument(i); 1613 } 1614 1615 private void generateSuperCallArgument(int i) { 1616 Type type = parameters.get(i).getAsmType(); 1617 iv.load(offset, type); 1618 offset += type.getSize(); 1619 } 1620 } 1621 1622 private void generateEnumEntries() { 1623 if (descriptor.getKind() != ClassKind.ENUM_CLASS) return; 1624 1625 List<JetEnumEntry> enumEntries = KotlinPackage.filterIsInstance(element.getDeclarations(), JetEnumEntry.class); 1626 1627 for (JetEnumEntry enumEntry : enumEntries) { 1628 ClassDescriptor descriptor = getNotNull(bindingContext, BindingContext.CLASS, enumEntry); 1629 FieldVisitor fv = v.newField(OtherOrigin(enumEntry, descriptor), ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, 1630 descriptor.getName().asString(), classAsmType.getDescriptor(), null, null); 1631 AnnotationCodegen.forField(fv, typeMapper).genAnnotations(descriptor, null); 1632 } 1633 1634 initializeEnumConstants(enumEntries); 1635 } 1636 1637 private void initializeEnumConstants(@NotNull List<JetEnumEntry> enumEntries) { 1638 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 1639 1640 ExpressionCodegen codegen = createOrGetClInitCodegen(); 1641 InstructionAdapter iv = codegen.v; 1642 1643 Type arrayAsmType = typeMapper.mapType(getBuiltIns(descriptor).getArrayType(INVARIANT, descriptor.getDefaultType())); 1644 v.newField(OtherOrigin(myClass), ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, ENUM_VALUES_FIELD_NAME, 1645 arrayAsmType.getDescriptor(), null, null); 1646 1647 iv.iconst(enumEntries.size()); 1648 iv.newarray(classAsmType); 1649 1650 if (!enumEntries.isEmpty()) { 1651 iv.dup(); 1652 for (int ordinal = 0, size = enumEntries.size(); ordinal < size; ordinal++) { 1653 initializeEnumConstant(enumEntries, ordinal); 1654 } 1655 } 1656 1657 iv.putstatic(classAsmType.getInternalName(), ENUM_VALUES_FIELD_NAME, arrayAsmType.getDescriptor()); 1658 } 1659 1660 private void initializeEnumConstant(@NotNull List<JetEnumEntry> enumEntries, int ordinal) { 1661 ExpressionCodegen codegen = createOrGetClInitCodegen(); 1662 InstructionAdapter iv = codegen.v; 1663 JetEnumEntry enumEntry = enumEntries.get(ordinal); 1664 1665 iv.dup(); 1666 iv.iconst(ordinal); 1667 1668 ClassDescriptor classDescriptor = getNotNull(bindingContext, BindingContext.CLASS, enumEntry); 1669 Type implClass = typeMapper.mapClass(classDescriptor); 1670 1671 iv.anew(implClass); 1672 iv.dup(); 1673 1674 iv.aconst(enumEntry.getName()); 1675 iv.iconst(ordinal); 1676 1677 List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers(); 1678 if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(bindingContext, enumEntry)) { 1679 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCallWithAssert(delegationSpecifiers.get(0), bindingContext); 1680 1681 CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) resolvedCall.getResultingDescriptor()); 1682 1683 codegen.invokeMethodWithArguments(method, resolvedCall, StackValue.none()); 1684 } 1685 else { 1686 iv.invokespecial(implClass.getInternalName(), "<init>", "(Ljava/lang/String;I)V", false); 1687 } 1688 1689 iv.dup(); 1690 iv.putstatic(classAsmType.getInternalName(), enumEntry.getName(), classAsmType.getDescriptor()); 1691 iv.astore(OBJECT_TYPE); 1692 } 1693 1694 private void generateDelegates(DelegationFieldsInfo delegationFieldsInfo) { 1695 for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { 1696 if (specifier instanceof JetDelegatorByExpressionSpecifier) { 1697 DelegationFieldsInfo.Field field = delegationFieldsInfo.getInfo((JetDelegatorByExpressionSpecifier) specifier); 1698 generateDelegateField(field); 1699 JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); 1700 JetType delegateExpressionType = delegateExpression != null ? bindingContext.getType(delegateExpression) : null; 1701 generateDelegates(getSuperClass(specifier), delegateExpressionType, field); 1702 } 1703 } 1704 } 1705 1706 private void generateDelegateField(DelegationFieldsInfo.Field fieldInfo) { 1707 if (!fieldInfo.generateField) return; 1708 1709 v.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_PRIVATE | ACC_FINAL | ACC_SYNTHETIC, 1710 fieldInfo.name, fieldInfo.type.getDescriptor(), /*TODO*/null, null); 1711 } 1712 1713 protected void generateDelegates(ClassDescriptor toTrait, JetType delegateExpressionType, DelegationFieldsInfo.Field field) { 1714 for (Map.Entry<CallableMemberDescriptor, CallableDescriptor> entry : CodegenUtilKt.getDelegates(descriptor, toTrait, delegateExpressionType).entrySet()) { 1715 CallableMemberDescriptor callableMemberDescriptor = entry.getKey(); 1716 CallableDescriptor delegateTo = entry.getValue(); 1717 if (callableMemberDescriptor instanceof PropertyDescriptor) { 1718 propertyCodegen 1719 .genDelegate((PropertyDescriptor) callableMemberDescriptor, (PropertyDescriptor) delegateTo, field.getStackValue()); 1720 } 1721 else if (callableMemberDescriptor instanceof FunctionDescriptor) { 1722 functionCodegen 1723 .genDelegate((FunctionDescriptor) callableMemberDescriptor, (FunctionDescriptor) delegateTo, field.getStackValue()); 1724 } 1725 } 1726 } 1727 1728 public void addCompanionObjectPropertyToCopy(@NotNull PropertyDescriptor descriptor, Object defaultValue) { 1729 if (companionObjectPropertiesToCopy == null) { 1730 companionObjectPropertiesToCopy = new ArrayList<PropertyAndDefaultValue>(); 1731 } 1732 companionObjectPropertiesToCopy.add(new PropertyAndDefaultValue(descriptor, defaultValue)); 1733 } 1734 1735 @Override 1736 protected void done() { 1737 for (Function2<ImplementationBodyCodegen, ClassBuilder, Unit> task : additionalTasks) { 1738 task.invoke(this, v); 1739 } 1740 1741 super.done(); 1742 } 1743 1744 private static class PropertyAndDefaultValue { 1745 public final PropertyDescriptor descriptor; 1746 public final Object defaultValue; 1747 1748 public PropertyAndDefaultValue(@NotNull PropertyDescriptor descriptor, Object defaultValue) { 1749 this.descriptor = descriptor; 1750 this.defaultValue = defaultValue; 1751 } 1752 } 1753 1754 public void addAdditionalTask(Function2<ImplementationBodyCodegen, ClassBuilder, Unit> additionalTask) { 1755 additionalTasks.add(additionalTask); 1756 } 1757 }