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