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