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