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