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