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