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 }