001    /*
002     * Copyright 2010-2015 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.kotlin.codegen;
018    
019    import com.intellij.openapi.progress.ProcessCanceledException;
020    import com.intellij.psi.PsiElement;
021    import kotlin.Unit;
022    import kotlin.jvm.functions.Function0;
023    import kotlin.jvm.functions.Function1;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.kotlin.backend.common.CodegenUtil;
027    import org.jetbrains.kotlin.codegen.context.*;
028    import org.jetbrains.kotlin.codegen.inline.*;
029    import org.jetbrains.kotlin.codegen.state.GenerationState;
030    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
031    import org.jetbrains.kotlin.descriptors.*;
032    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
033    import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
034    import org.jetbrains.kotlin.fileClasses.FileClasses;
035    import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
036    import org.jetbrains.kotlin.load.java.JvmAbi;
037    import org.jetbrains.kotlin.name.Name;
038    import org.jetbrains.kotlin.name.SpecialNames;
039    import org.jetbrains.kotlin.psi.*;
040    import org.jetbrains.kotlin.resolve.*;
041    import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
042    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
043    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
044    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
045    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
046    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
047    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
048    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
049    import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
050    import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
051    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
052    import org.jetbrains.kotlin.storage.NotNullLazyValue;
053    import org.jetbrains.kotlin.types.ErrorUtils;
054    import org.jetbrains.kotlin.types.KotlinType;
055    import org.jetbrains.org.objectweb.asm.Label;
056    import org.jetbrains.org.objectweb.asm.MethodVisitor;
057    import org.jetbrains.org.objectweb.asm.Type;
058    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
059    import org.jetbrains.org.objectweb.asm.commons.Method;
060    
061    import java.util.*;
062    
063    import static org.jetbrains.kotlin.codegen.AsmUtil.calculateInnerClassAccessFlags;
064    import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
065    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
066    import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
067    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
068    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration;
069    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
070    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
071    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic;
072    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
073    
074    public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclarationContainer*/> {
075        protected final GenerationState state;
076        protected final T element;
077        protected final FieldOwnerContext context;
078        protected final ClassBuilder v;
079        protected final FunctionCodegen functionCodegen;
080        protected final PropertyCodegen propertyCodegen;
081        protected final JetTypeMapper typeMapper;
082        protected final BindingContext bindingContext;
083        protected final JvmFileClassesProvider fileClassesProvider;
084        private final MemberCodegen<?> parentCodegen;
085        private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages();
086        protected final Collection<ClassDescriptor> innerClasses = new LinkedHashSet<ClassDescriptor>();
087    
088        protected ExpressionCodegen clInit;
089        private NameGenerator inlineNameGenerator;
090    
091        private SourceMapper sourceMapper;
092        private final ConstantExpressionEvaluator constantExpressionEvaluator;
093    
094        public MemberCodegen(
095                @NotNull GenerationState state,
096                @Nullable MemberCodegen<?> parentCodegen,
097                @NotNull FieldOwnerContext context,
098                T element,
099                @NotNull ClassBuilder builder
100        ) {
101            this.state = state;
102            this.typeMapper = state.getTypeMapper();
103            this.bindingContext = state.getBindingContext();
104            this.fileClassesProvider = state.getFileClassesProvider();
105            this.element = element;
106            this.context = context;
107            this.v = builder;
108            this.functionCodegen = new FunctionCodegen(context, v, state, this);
109            this.propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this);
110            this.parentCodegen = parentCodegen;
111            this.constantExpressionEvaluator = new ConstantExpressionEvaluator(state.getModule().getBuiltIns());
112        }
113    
114        protected MemberCodegen(@NotNull MemberCodegen<T> wrapped, T declaration, FieldOwnerContext codegenContext) {
115            this(wrapped.state, wrapped.getParentCodegen(), codegenContext, declaration, wrapped.v);
116        }
117    
118        public void generate() {
119            generateDeclaration();
120    
121            generateBody();
122    
123            generateSyntheticParts();
124    
125            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
126                generateKotlinAnnotation();
127            }
128    
129            done();
130        }
131    
132        protected abstract void generateDeclaration();
133    
134        protected abstract void generateBody();
135    
136        protected void generateSyntheticParts() {
137        }
138    
139        protected abstract void generateKotlinAnnotation();
140    
141        @Nullable
142        protected ClassDescriptor classForInnerClassRecord() {
143            return null;
144        }
145    
146        public static void markLineNumberForSyntheticFunction(@Nullable ClassDescriptor declarationDescriptor, @NotNull InstructionAdapter v) {
147            if (declarationDescriptor == null) {
148                return;
149            }
150    
151            PsiElement classElement = DescriptorToSourceUtils.getSourceFromDescriptor(declarationDescriptor);
152            if (classElement != null) {
153                markLineNumberForSyntheticFunction(classElement, v);
154            }
155        }
156    
157        public static void markLineNumberForSyntheticFunction(@NotNull PsiElement element, @NotNull InstructionAdapter v) {
158            Integer lineNumber = CodegenUtil.getLineNumberForElement(element, false);
159            if (lineNumber != null) {
160                Label label = new Label();
161                v.visitLabel(label);
162                v.visitLineNumber(lineNumber, label);
163            }
164        }
165    
166        protected void done() {
167            if (clInit != null) {
168                clInit.v.visitInsn(RETURN);
169                FunctionCodegen.endVisit(clInit.v, "static initializer", element);
170            }
171    
172            writeInnerClasses();
173    
174            if (sourceMapper != null) {
175                SourceMapper.Companion.flushToClassBuilder(sourceMapper, v);
176            }
177    
178            v.done();
179        }
180    
181        public void genFunctionOrProperty(@NotNull KtDeclaration functionOrProperty) {
182            if (functionOrProperty instanceof KtNamedFunction) {
183                try {
184                    functionCodegen.gen((KtNamedFunction) functionOrProperty);
185                }
186                catch (ProcessCanceledException e) {
187                    throw e;
188                }
189                catch (CompilationException e) {
190                    throw e;
191                }
192                catch (Exception e) {
193                    throw new CompilationException("Failed to generate function " + functionOrProperty.getName(), e, functionOrProperty);
194                }
195            }
196            else if (functionOrProperty instanceof KtProperty) {
197                try {
198                    propertyCodegen.gen((KtProperty) functionOrProperty);
199                }
200                catch (ProcessCanceledException e) {
201                    throw e;
202                }
203                catch (CompilationException e) {
204                    throw e;
205                }
206                catch (Exception e) {
207                    throw new CompilationException("Failed to generate property " + functionOrProperty.getName(), e, functionOrProperty);
208                }
209            }
210            else {
211                throw new IllegalArgumentException("Unknown parameter: " + functionOrProperty);
212            }
213        }
214    
215        public static void genClassOrObject(
216                @NotNull CodegenContext parentContext,
217                @NotNull KtClassOrObject aClass,
218                @NotNull GenerationState state,
219                @Nullable MemberCodegen<?> parentCodegen
220        ) {
221            ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
222    
223            if (descriptor == null || ErrorUtils.isError(descriptor)) {
224                badDescriptor(descriptor, state.getClassBuilderMode());
225                return;
226            }
227    
228            if (descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED)) {
229                badDescriptor(descriptor, state.getClassBuilderMode());
230            }
231    
232            Type classType = state.getTypeMapper().mapClass(descriptor);
233            ClassBuilder classBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(aClass, descriptor), classType, aClass.getContainingFile());
234            ClassContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
235            new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, parentCodegen, false).generate();
236        }
237    
238        private static void badDescriptor(ClassDescriptor descriptor, ClassBuilderMode mode) {
239            if (mode != ClassBuilderMode.LIGHT_CLASSES) {
240                throw new IllegalStateException("Generating bad descriptor in ClassBuilderMode = " + mode + ": " + descriptor);
241            }
242        }
243    
244        public void genClassOrObject(KtClassOrObject aClass) {
245            genClassOrObject(context, aClass, state, this);
246        }
247    
248        private void writeInnerClasses() {
249            // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
250            // for each enclosing class and for each immediate member
251            ClassDescriptor classDescriptor = classForInnerClassRecord();
252            if (classDescriptor != null) {
253                if (parentCodegen != null) {
254                    parentCodegen.innerClasses.add(classDescriptor);
255                }
256    
257                for (MemberCodegen<?> codegen = this; codegen != null; codegen = codegen.getParentCodegen()) {
258                    ClassDescriptor outerClass = codegen.classForInnerClassRecord();
259                    if (outerClass != null) {
260                        innerClasses.add(outerClass);
261                    }
262                }
263            }
264    
265            for (ClassDescriptor innerClass : innerClasses) {
266                writeInnerClass(innerClass);
267            }
268        }
269    
270        private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
271            DeclarationDescriptor containing = innerClass.getContainingDeclaration();
272            String outerClassInternalName = null;
273            if (containing instanceof ClassDescriptor) {
274                outerClassInternalName = typeMapper.mapClass((ClassDescriptor) containing).getInternalName();
275            } /* disabled cause of KT-7775
276            else if (containing instanceof ScriptDescriptor) {
277                outerClassInternalName = asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) containing).getInternalName();
278            }*/
279    
280            String innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
281    
282            String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
283            v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
284        }
285    
286        protected void writeOuterClassAndEnclosingMethod() {
287            CodegenContext context = this.context.getParentContext();
288            while (context instanceof MethodContext && ((MethodContext) context).isInliningLambda()) {
289                // If this is a lambda which will be inlined, skip its MethodContext and enclosing ClosureContext
290                //noinspection ConstantConditions
291                context = context.getParentContext().getParentContext();
292            }
293            assert context != null : "Outermost context can't be null: " + this.context;
294    
295            Type enclosingAsmType = computeOuterClass(context);
296            if (enclosingAsmType != null) {
297                Method method = computeEnclosingMethod(context);
298    
299                v.visitOuterClass(
300                        enclosingAsmType.getInternalName(),
301                        method == null ? null : method.getName(),
302                        method == null ? null : method.getDescriptor()
303                );
304            }
305        }
306    
307        @Nullable
308        private Type computeOuterClass(@NotNull CodegenContext<?> context) {
309            CodegenContext<? extends ClassOrPackageFragmentDescriptor> outermost = context.getClassOrPackageParentContext();
310            if (outermost instanceof ClassContext) {
311                return typeMapper.mapType(((ClassContext) outermost).getContextDescriptor());
312            }
313            else if (outermost instanceof DelegatingFacadeContext || outermost instanceof DelegatingToPartContext) {
314                Type implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(outermost);
315                if (implementationOwnerType != null) {
316                    return implementationOwnerType;
317                }
318                else {
319                    return FileClasses.getFileClassType(fileClassesProvider, element.getContainingJetFile());
320                }
321            }
322            /*disabled cause of KT-7775
323            else if (outermost instanceof ScriptContext) {
324                return asmTypeForScriptDescriptor(bindingContext, ((ScriptContext) outermost).getScriptDescriptor());
325            }*/
326            return null;
327        }
328    
329        @Nullable
330        private Method computeEnclosingMethod(@NotNull CodegenContext context) {
331            if (context instanceof MethodContext) {
332                Method method = typeMapper.mapSignature(((MethodContext) context).getFunctionDescriptor()).getAsmMethod();
333                if (!method.getName().equals("<clinit>")) {
334                    return method;
335                }
336            }
337            return null;
338        }
339    
340        @NotNull
341        public NameGenerator getInlineNameGenerator() {
342            if (inlineNameGenerator == null) {
343                String prefix = InlineCodegenUtil.getInlineName(context, typeMapper, fileClassesProvider);
344                inlineNameGenerator = new NameGenerator(prefix);
345            }
346            return inlineNameGenerator;
347        }
348    
349        @NotNull
350        protected ExpressionCodegen createOrGetClInitCodegen() {
351            DeclarationDescriptor descriptor = context.getContextDescriptor();
352            if (clInit == null) {
353                MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), ACC_STATIC, "<clinit>", "()V", null, null);
354                SimpleFunctionDescriptorImpl clInit =
355                        SimpleFunctionDescriptorImpl.create(descriptor, Annotations.Companion.getEMPTY(), Name.special("<clinit>"), SYNTHESIZED,
356                                                            KotlinSourceElementKt.toSourceElement(element));
357                clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
358                                  Collections.<ValueParameterDescriptor>emptyList(),
359                                  DescriptorUtilsKt.getModule(descriptor).getBuiltIns().getUnitType(),
360                                  null, Visibilities.PRIVATE);
361    
362                this.clInit = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state, this);
363            }
364            return clInit;
365        }
366    
367        protected void generateInitializers(@NotNull Function0<ExpressionCodegen> createCodegen) {
368            NotNullLazyValue<ExpressionCodegen> codegen = LockBasedStorageManager.NO_LOCKS.createLazyValue(createCodegen);
369            for (KtDeclaration declaration : ((KtDeclarationContainer) element).getDeclarations()) {
370                if (declaration instanceof KtProperty) {
371                    if (shouldInitializeProperty((KtProperty) declaration)) {
372                        initializeProperty(codegen.invoke(), (KtProperty) declaration);
373                    }
374                }
375                else if (declaration instanceof KtClassInitializer) {
376                    KtExpression body = ((KtClassInitializer) declaration).getBody();
377                    if (body != null) {
378                        codegen.invoke().gen(body, Type.VOID_TYPE);
379                    }
380                }
381            }
382        }
383    
384        private void initializeProperty(@NotNull ExpressionCodegen codegen, @NotNull KtProperty property) {
385            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(VARIABLE, property);
386            assert propertyDescriptor != null;
387    
388            KtExpression initializer = property.getDelegateExpressionOrInitializer();
389            assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
390    
391            StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, true, StackValue.LOCAL_0);
392    
393            propValue.store(codegen.gen(initializer), codegen.v);
394        }
395    
396        private boolean shouldInitializeProperty(@NotNull KtProperty property) {
397            if (!property.hasDelegateExpressionOrInitializer()) return false;
398    
399            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(VARIABLE, property);
400            assert propertyDescriptor != null;
401    
402            if (propertyDescriptor.isConst()) {
403                //const initializer always inlined
404                return false;
405            }
406    
407            KtExpression initializer = property.getInitializer();
408    
409            ConstantValue<?> initializerValue = computeInitializerValue(property, propertyDescriptor, initializer);
410            // we must write constant values for fields in light classes,
411            // because Java's completion for annotation arguments uses this information
412            if (initializerValue == null) return state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES;
413    
414            //TODO: OPTIMIZATION: don't initialize static final fields
415            KotlinType jetType = getPropertyOrDelegateType(property, propertyDescriptor);
416            Type type = typeMapper.mapType(jetType);
417            return !skipDefaultValue(propertyDescriptor, initializerValue.getValue(), type);
418        }
419    
420        @Nullable
421        private ConstantValue<?> computeInitializerValue(
422                @NotNull KtProperty property,
423                @NotNull PropertyDescriptor propertyDescriptor,
424                @Nullable KtExpression initializer
425        ) {
426            if (property.isVar() && initializer != null) {
427                BindingTrace tempTrace = TemporaryBindingTrace.create(state.getBindingTrace(), "property initializer");
428                return constantExpressionEvaluator.evaluateToConstantValue(initializer, tempTrace, propertyDescriptor.getType());
429            }
430            return propertyDescriptor.getCompileTimeInitializer();
431        }
432    
433        @NotNull
434        private KotlinType getPropertyOrDelegateType(@NotNull KtProperty property, @NotNull PropertyDescriptor descriptor) {
435            KtExpression delegateExpression = property.getDelegateExpression();
436            if (delegateExpression != null) {
437                KotlinType delegateType = bindingContext.getType(delegateExpression);
438                assert delegateType != null : "Type of delegate expression should be recorded";
439                return delegateType;
440            }
441            return descriptor.getType();
442        }
443    
444        private static boolean skipDefaultValue(@NotNull PropertyDescriptor propertyDescriptor, Object value, @NotNull Type type) {
445            if (isPrimitive(type)) {
446                if (!propertyDescriptor.getType().isMarkedNullable() && value instanceof Number) {
447                    if (type == Type.INT_TYPE && ((Number) value).intValue() == 0) {
448                        return true;
449                    }
450                    if (type == Type.BYTE_TYPE && ((Number) value).byteValue() == 0) {
451                        return true;
452                    }
453                    if (type == Type.LONG_TYPE && ((Number) value).longValue() == 0L) {
454                        return true;
455                    }
456                    if (type == Type.SHORT_TYPE && ((Number) value).shortValue() == 0) {
457                        return true;
458                    }
459                    if (type == Type.DOUBLE_TYPE && ((Number) value).doubleValue() == 0d) {
460                        return true;
461                    }
462                    if (type == Type.FLOAT_TYPE && ((Number) value).floatValue() == 0f) {
463                        return true;
464                    }
465                }
466                if (type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean) value)) {
467                    return true;
468                }
469                if (type == Type.CHAR_TYPE && value instanceof Character && ((Character) value) == 0) {
470                    return true;
471                }
472            }
473            else {
474                if (value == null) {
475                    return true;
476                }
477            }
478            return false;
479        }
480    
481        public static void generateModuleNameField(
482                @NotNull GenerationState state,
483                @NotNull ClassBuilder classBuilder
484        ) {
485            classBuilder.newField(NO_ORIGIN, ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.MODULE_NAME_FIELD,
486                                  AsmTypes.JAVA_STRING_TYPE.getDescriptor(), null, state.getModuleName());
487        }
488    
489        protected void generatePropertyMetadataArrayFieldIfNeeded(@NotNull Type thisAsmType) {
490            List<KtProperty> delegatedProperties = new ArrayList<KtProperty>();
491            for (KtDeclaration declaration : ((KtDeclarationContainer) element).getDeclarations()) {
492                if (declaration instanceof KtProperty) {
493                    KtProperty property = (KtProperty) declaration;
494                    if (property.hasDelegate()) {
495                        delegatedProperties.add(property);
496                    }
497                }
498            }
499            if (delegatedProperties.isEmpty()) return;
500    
501            v.newField(NO_ORIGIN, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
502                       "[" + PROPERTY_METADATA_TYPE, null, null);
503    
504            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
505    
506            InstructionAdapter iv = createOrGetClInitCodegen().v;
507            iv.iconst(delegatedProperties.size());
508            iv.newarray(PROPERTY_METADATA_TYPE);
509    
510            for (int i = 0, size = delegatedProperties.size(); i < size; i++) {
511                PropertyDescriptor property =
512                        (PropertyDescriptor) BindingContextUtils.getNotNull(bindingContext, VARIABLE, delegatedProperties.get(i));
513    
514                iv.dup();
515                iv.iconst(i);
516    
517                StackValue value;
518                // TODO: remove this option and always generate PropertyReferenceNImpl creation
519                if ("true".equalsIgnoreCase(System.getProperty("kotlin.jvm.optimize.delegated.properties"))) {
520                    int receiverCount = (property.getDispatchReceiverParameter() != null ? 1 : 0) +
521                                        (property.getExtensionReceiverParameter() != null ? 1 : 0);
522                    Type implType = property.isVar() ? MUTABLE_PROPERTY_REFERENCE_IMPL[receiverCount] : PROPERTY_REFERENCE_IMPL[receiverCount];
523                    iv.anew(implType);
524                    iv.dup();
525                    // TODO: generate the container once and save to a local field instead
526                    ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
527                    iv.aconst(property.getName().asString());
528                    iv.aconst(PropertyReferenceCodegen.getPropertyReferenceSignature(property, state));
529                    iv.invokespecial(
530                            implType.getInternalName(), "<init>",
531                            Type.getMethodDescriptor(Type.VOID_TYPE, K_DECLARATION_CONTAINER_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE), false
532                    );
533                    value = StackValue.onStack(implType);
534                    Method wrapper = PropertyReferenceCodegen.getWrapperMethodForPropertyReference(property, receiverCount);
535                    iv.invokestatic(REFLECTION, wrapper.getName(), wrapper.getDescriptor(), false);
536                }
537                else {
538                    ReceiverParameterDescriptor dispatchReceiver = property.getDispatchReceiverParameter();
539    
540                    //noinspection ConstantConditions
541                    value = createOrGetClInitCodegen().generatePropertyReference(
542                            delegatedProperties.get(i).getDelegate(), property, property,
543                            dispatchReceiver != null ? new TransientReceiver(dispatchReceiver.getType()) : ReceiverValue.NO_RECEIVER
544                    );
545                }
546    
547                value.put(PROPERTY_METADATA_TYPE, iv);
548    
549                iv.astore(PROPERTY_METADATA_TYPE);
550            }
551    
552            iv.putstatic(thisAsmType.getInternalName(), JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
553        }
554    
555        public String getClassName() {
556            return v.getThisName();
557        }
558    
559        @NotNull
560        public FieldOwnerContext<?> getContext() {
561            return context;
562        }
563    
564        @NotNull
565        public ReifiedTypeParametersUsages getReifiedTypeParametersUsages() {
566            return reifiedTypeParametersUsages;
567        }
568    
569        public MemberCodegen<?> getParentCodegen() {
570            return parentCodegen;
571        }
572    
573        @Override
574        public String toString() {
575            return context.toString();
576        }
577    
578        @NotNull
579        public SourceMapper getOrCreateSourceMapper() {
580            if (sourceMapper == null) {
581                sourceMapper = new DefaultSourceMapper(SourceInfo.Companion.createInfo(element, getClassName()), null);
582            }
583            return sourceMapper;
584        }
585    
586        protected void generateConstInstance(
587                @NotNull Type thisAsmType,
588                @NotNull Type fieldAsmType,
589                @NotNull Function1<InstructionAdapter, Unit> initialization
590        ) {
591            v.newField(JvmDeclarationOriginKt.OtherOrigin(element), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, fieldAsmType.getDescriptor(),
592                       null, null);
593    
594            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
595                InstructionAdapter iv = createOrGetClInitCodegen().v;
596                iv.anew(thisAsmType);
597                iv.dup();
598                iv.invokespecial(thisAsmType.getInternalName(), "<init>", "()V", false);
599                initialization.invoke(iv);
600                iv.putstatic(thisAsmType.getInternalName(), JvmAbi.INSTANCE_FIELD, fieldAsmType.getDescriptor());
601            }
602        }
603    
604        protected void generateSyntheticAccessors() {
605            for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) {
606                generateSyntheticAccessor(accessor);
607            }
608        }
609    
610        private void generateSyntheticAccessor(@NotNull AccessorForCallableDescriptor<?> accessorForCallableDescriptor) {
611            if (accessorForCallableDescriptor instanceof FunctionDescriptor) {
612                final FunctionDescriptor accessor = (FunctionDescriptor) accessorForCallableDescriptor;
613                final FunctionDescriptor original = (FunctionDescriptor) accessorForCallableDescriptor.getCalleeDescriptor();
614                functionCodegen.generateMethod(
615                        Synthetic(null, original), accessor,
616                        new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, accessor) {
617                            @Override
618                            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
619                                markLineNumberForSyntheticFunction(element, codegen.v);
620    
621                                generateMethodCallTo(original, accessor, codegen.v);
622                                codegen.v.areturn(signature.getReturnType());
623                            }
624                        }
625                );
626            }
627            else if (accessorForCallableDescriptor instanceof AccessorForPropertyDescriptor) {
628                final AccessorForPropertyDescriptor accessor = (AccessorForPropertyDescriptor) accessorForCallableDescriptor;
629                final PropertyDescriptor original = accessor.getCalleeDescriptor();
630    
631                class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
632                    public PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) {
633                        super(MemberCodegen.this.state, callableDescriptor);
634                    }
635    
636                    @Override
637                    public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
638                        boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
639                                             !isCompanionObject(accessor.getContainingDeclaration());
640                        StackValue property = codegen.intermediateValueForProperty(
641                                original, forceField, accessor.getSuperCallExpression(), true, StackValue.none()
642                        );
643    
644                        InstructionAdapter iv = codegen.v;
645    
646                        markLineNumberForSyntheticFunction(element, iv);
647    
648                        Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
649                        for (int i = 0, reg = 0; i < argTypes.length; i++) {
650                            Type argType = argTypes[i];
651                            iv.load(reg, argType);
652                            //noinspection AssignmentToForLoopParameter
653                            reg += argType.getSize();
654                        }
655    
656                        if (callableDescriptor instanceof PropertyGetterDescriptor) {
657                            property.put(property.type, iv);
658                        }
659                        else {
660                            property.store(StackValue.onStack(property.type), iv, true);
661                        }
662    
663                        iv.areturn(signature.getReturnType());
664                    }
665                }
666    
667                PropertyGetterDescriptor getter = accessor.getGetter();
668                assert getter != null;
669                functionCodegen.generateMethod(Synthetic(null, original.getGetter() != null ? original.getGetter() : original),
670                                               getter, new PropertyAccessorStrategy(getter));
671    
672    
673                if (accessor.isVar()) {
674                    PropertySetterDescriptor setter = accessor.getSetter();
675                    assert setter != null;
676    
677                    functionCodegen.generateMethod(Synthetic(null, original.getSetter() != null ? original.getSetter() : original),
678                                                   setter, new PropertyAccessorStrategy(setter));
679                }
680            }
681            else {
682                throw new UnsupportedOperationException();
683            }
684        }
685    
686        private void generateMethodCallTo(
687                @NotNull FunctionDescriptor functionDescriptor,
688                @Nullable FunctionDescriptor accessorDescriptor,
689                @NotNull InstructionAdapter iv
690        ) {
691            CallableMethod callableMethod = typeMapper.mapToCallableMethod(
692                    functionDescriptor,
693                    accessorDescriptor instanceof AccessorForCallableDescriptor &&
694                    ((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallExpression() != null
695            );
696    
697            boolean isTopLevelDeclaration = isTopLevelDeclaration(functionDescriptor);
698            int reg = isTopLevelDeclaration ? 0 : 1;
699            boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
700            if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {
701                iv.anew(callableMethod.getOwner());
702                iv.dup();
703                reg = 0;
704            }
705            else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor) && !isTopLevelDeclaration)) {
706                if (!AnnotationUtilKt.isPlatformStaticInObjectOrClass(functionDescriptor)) {
707                    iv.load(0, OBJECT_TYPE);
708                }
709            }
710    
711            for (Type argType : callableMethod.getParameterTypes()) {
712                if (AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.equals(argType)) {
713                    iv.aconst(null);
714                }
715                else {
716                    iv.load(reg, argType);
717                    reg += argType.getSize();
718                }
719            }
720    
721            callableMethod.genInvokeInstruction(iv);
722        }
723    }