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