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