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