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