001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.codegen;
018
019 import com.intellij.openapi.progress.ProcessCanceledException;
020 import com.intellij.psi.PsiElement;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.asm4.AnnotationVisitor;
024 import org.jetbrains.asm4.Label;
025 import org.jetbrains.asm4.MethodVisitor;
026 import org.jetbrains.asm4.Type;
027 import org.jetbrains.asm4.commons.InstructionAdapter;
028 import org.jetbrains.asm4.commons.Method;
029 import org.jetbrains.jet.codegen.binding.CodegenBinding;
030 import org.jetbrains.jet.codegen.context.CodegenContext;
031 import org.jetbrains.jet.codegen.context.MethodContext;
032 import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
033 import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
034 import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
035 import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
036 import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
037 import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter;
038 import org.jetbrains.jet.codegen.state.GenerationState;
039 import org.jetbrains.jet.codegen.state.GenerationStateAware;
040 import org.jetbrains.jet.codegen.state.JetTypeMapper;
041 import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
042 import org.jetbrains.jet.lang.descriptors.*;
043 import org.jetbrains.jet.lang.psi.JetNamedFunction;
044 import org.jetbrains.jet.lang.resolve.BindingContext;
045 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
046 import org.jetbrains.jet.lang.resolve.java.JvmClassName;
047 import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
048 import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
049 import org.jetbrains.jet.lang.resolve.name.Name;
050
051 import java.util.*;
052
053 import static org.jetbrains.asm4.Opcodes.*;
054 import static org.jetbrains.jet.codegen.AsmUtil.*;
055 import static org.jetbrains.jet.codegen.CodegenUtil.*;
056 import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
057 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
058 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
059 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral;
060 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
061
062 public class FunctionCodegen extends GenerationStateAware {
063 private final CodegenContext owner;
064 private final ClassBuilder v;
065
066 public FunctionCodegen(CodegenContext owner, ClassBuilder v, GenerationState state) {
067 super(state);
068 this.owner = owner;
069 this.v = v;
070 }
071
072 public void gen(@NotNull JetNamedFunction function) {
073 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
074 assert functionDescriptor != null;
075
076 OwnerKind kind = owner.getContextKind();
077 JvmMethodSignature method = typeMapper.mapSignature(functionDescriptor, true, kind);
078
079 if (kind != OwnerKind.TRAIT_IMPL || function.getBodyExpression() != null) {
080 boolean needJetAnnotations = kind != OwnerKind.TRAIT_IMPL;
081 generateMethod(function, method, needJetAnnotations, functionDescriptor,
082 new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
083 }
084
085 generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), state, v, method, functionDescriptor, kind,
086 DefaultParameterValueLoader.DEFAULT);
087 }
088
089 public void generateMethod(
090 @Nullable PsiElement origin,
091 @NotNull JvmMethodSignature jvmSignature,
092 boolean needJetAnnotations,
093 @NotNull FunctionDescriptor functionDescriptor,
094 @NotNull FunctionGenerationStrategy strategy
095 ) {
096 generateMethod(origin, jvmSignature, needJetAnnotations, functionDescriptor, owner.intoFunction(functionDescriptor), strategy);
097 }
098
099 public void generateMethod(
100 @Nullable PsiElement origin,
101 @NotNull JvmMethodSignature jvmSignature,
102 boolean needJetAnnotations,
103 @NotNull FunctionDescriptor functionDescriptor,
104 @NotNull MethodContext methodContext,
105 @NotNull FunctionGenerationStrategy strategy
106 ) {
107
108 Method asmMethod = jvmSignature.getAsmMethod();
109
110 MethodVisitor mv = v.newMethod(origin,
111 getMethodAsmFlags(functionDescriptor, methodContext.getContextKind()),
112 asmMethod.getName(),
113 asmMethod.getDescriptor(),
114 jvmSignature.getGenericsSignature(),
115 null);
116
117 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor);
118 if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) return;
119
120 if (needJetAnnotations) {
121 genJetAnnotations(mv, functionDescriptor, jvmSignature);
122 }
123
124 if (isAbstractMethod(functionDescriptor, methodContext.getContextKind())) return;
125
126 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
127 genStubCode(mv);
128 return;
129 }
130
131 generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy);
132
133 endVisit(mv, null, origin);
134
135 generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor);
136
137 methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, typeMapper);
138 }
139
140 @Nullable
141 private Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context) {
142 ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
143 if (functionDescriptor instanceof ConstructorDescriptor) {
144 return typeMapper.mapType(functionDescriptor.getReturnType());
145 }
146 else if (expectedThisObject != null) {
147 return typeMapper.mapType(expectedThisObject.getType());
148 }
149 else if (isFunctionLiteral(functionDescriptor) || isLocalNamedFun(functionDescriptor)) {
150 return typeMapper.mapType(context.getThisDescriptor());
151 }
152 else {
153 return null;
154 }
155 }
156
157 private void generateMethodBody(
158 @NotNull MethodVisitor mv,
159 @NotNull FunctionDescriptor functionDescriptor,
160 @NotNull MethodContext context,
161 @NotNull JvmMethodSignature signature,
162 @NotNull FunctionGenerationStrategy strategy
163 ) {
164 Collection<String> localVariableNames = new HashSet<String>(getParameterNamesAsStrings(functionDescriptor));
165
166 Map<Name, Label> labelsForSharedVars = new HashMap<Name, Label>();
167
168 mv.visitCode();
169
170 Label methodBegin = new Label();
171 mv.visitLabel(methodBegin);
172
173 OwnerKind kind = context.getContextKind();
174 if (kind instanceof OwnerKind.StaticDelegateKind) {
175 generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (OwnerKind.StaticDelegateKind) kind);
176 }
177 else {
178 FrameMap frameMap = strategy.getFrameMap(typeMapper, context);
179
180 for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
181 frameMap.enter(parameter, typeMapper.mapType(parameter));
182 }
183
184 labelsForSharedVars.putAll(createSharedVarsForParameters(mv, functionDescriptor, frameMap));
185
186 if (!JetTypeMapper.isAccessor(functionDescriptor)) {
187 genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
188 }
189
190 strategy.generateBody(mv, signature, context);
191
192 localVariableNames.addAll(strategy.getLocalVariableNames());
193 }
194
195 Label methodEnd = new Label();
196 mv.visitLabel(methodEnd);
197
198
199 Type thisType = getThisTypeForFunction(functionDescriptor, context);
200 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, localVariableNames, labelsForSharedVars, kind);
201 }
202
203 @NotNull
204 private static List<String> getParameterNamesAsStrings(@NotNull FunctionDescriptor functionDescriptor) {
205 List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
206 List<String> result = new ArrayList<String>(parameters.size());
207 for (ValueParameterDescriptor parameter : parameters) {
208 result.add(parameter.getName().asString());
209 }
210 return result;
211 }
212
213 private void generateLocalVariableTable(
214 @NotNull MethodVisitor mv,
215 @NotNull JvmMethodSignature jvmMethodSignature,
216 @NotNull FunctionDescriptor functionDescriptor,
217 @Nullable Type thisType,
218 @NotNull Label methodBegin,
219 @NotNull Label methodEnd,
220 @NotNull Collection<String> localVariableNames,
221 @NotNull Map<Name, Label> labelsForSharedVars,
222 @NotNull OwnerKind ownerKind
223 ) {
224 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
225 List<JvmMethodParameterSignature> params = jvmMethodSignature.getKotlinParameterTypes();
226 int shift = 0;
227
228 boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
229 if (!isStatic) {
230 //add this
231 if (thisType != null) {
232 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
233 } else {
234 //TODO: provide thisType for callable reference
235 }
236 shift++;
237 }
238
239 for (int i = 0; i < params.size(); i++) {
240 JvmMethodParameterSignature param = params.get(i);
241 JvmMethodParameterKind kind = param.getKind();
242 String parameterName = "$" + param.getKind().name().toLowerCase();
243
244 if (needIndexForVar(kind)) {
245 parameterName = parameterName + "$" + i;
246 }
247
248 Type type = param.getAsmType();
249 if (kind == JvmMethodParameterKind.VALUE) {
250 ValueParameterDescriptor parameter = valueParameters.next();
251 Label divideLabel = labelsForSharedVars.get(parameter.getName());
252 parameterName = parameter.getName().asString();
253 if (divideLabel != null) {
254 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, divideLabel, shift);
255
256 String nameForSharedVar = createTmpVariableName(localVariableNames);
257 localVariableNames.add(nameForSharedVar);
258
259 Type sharedVarType = typeMapper.getSharedVarType(parameter);
260 mv.visitLocalVariable(nameForSharedVar, sharedVarType.getDescriptor(), null, divideLabel, methodEnd, shift);
261 shift += Math.max(type.getSize(), sharedVarType.getSize());
262 continue;
263 }
264 }
265
266 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
267 shift += type.getSize();
268 }
269 }
270
271 @NotNull
272 private Map<Name, Label> createSharedVarsForParameters(
273 @NotNull MethodVisitor mv,
274 @NotNull FunctionDescriptor functionDescriptor,
275 @NotNull FrameMap frameMap
276 ) {
277 Map<Name, Label> labelsForSharedVars = new HashMap<Name, Label>();
278
279 for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
280 Type sharedVarType = typeMapper.getSharedVarType(parameter);
281 if (sharedVarType == null) {
282 continue;
283 }
284
285 Type localVarType = typeMapper.mapType(parameter);
286 int index = frameMap.getIndex(parameter);
287 mv.visitTypeInsn(NEW, sharedVarType.getInternalName());
288 mv.visitInsn(DUP);
289 mv.visitInsn(DUP);
290 mv.visitMethodInsn(INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
291 mv.visitVarInsn(localVarType.getOpcode(ILOAD), index);
292 mv.visitFieldInsn(PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
293
294 Label labelForSharedVar = new Label();
295 mv.visitLabel(labelForSharedVar);
296
297 labelsForSharedVars.put(parameter.getName(), labelForSharedVar);
298
299 mv.visitVarInsn(sharedVarType.getOpcode(ISTORE), index);
300 }
301
302 return labelsForSharedVars;
303 }
304
305 private static void generateStaticDelegateMethodBody(
306 @NotNull MethodVisitor mv,
307 @NotNull Method asmMethod,
308 @NotNull OwnerKind.StaticDelegateKind dk
309 ) {
310 InstructionAdapter iv = new InstructionAdapter(mv);
311 Type[] argTypes = asmMethod.getArgumentTypes();
312
313 // The first line of some namespace file is written to the line number attribute of a static delegate to allow to 'step into' it
314 // This is similar to what javac does with bridge methods
315 Label label = new Label();
316 iv.visitLabel(label);
317 iv.visitLineNumber(1, label);
318
319 int k = 0;
320 for (Type argType : argTypes) {
321 iv.load(k, argType);
322 k += argType.getSize();
323 }
324 iv.invokestatic(dk.getOwnerClass(), asmMethod.getName(), asmMethod.getDescriptor());
325 iv.areturn(asmMethod.getReturnType());
326 }
327
328 private void genJetAnnotations(
329 @NotNull MethodVisitor mv,
330 @NotNull FunctionDescriptor functionDescriptor,
331 @NotNull JvmMethodSignature jvmSignature
332 ) {
333
334 if (functionDescriptor instanceof PropertyAccessorDescriptor) {
335 assert jvmSignature instanceof JvmPropertyAccessorSignature : "jvmSignature for property should have JvmPropertyAccessorSignature type";
336 PropertyCodegen.generateJetPropertyAnnotation(mv, (JvmPropertyAccessorSignature) jvmSignature,
337 ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty(), functionDescriptor.getVisibility());
338 }
339 else if (functionDescriptor instanceof SimpleFunctionDescriptor) {
340 assert !(jvmSignature instanceof JvmPropertyAccessorSignature) : "jvmSignature for function shouldn't have JvmPropertyAccessorSignature type";
341
342 Modality modality = functionDescriptor.getModality();
343 JetMethodAnnotationWriter aw = JetMethodAnnotationWriter.visitAnnotation(mv);
344 int kotlinFlags = getFlagsForVisibility(functionDescriptor.getVisibility());
345 if (isInterface(functionDescriptor.getContainingDeclaration()) && modality != Modality.ABSTRACT) {
346 kotlinFlags |= modality == Modality.FINAL
347 ? JvmStdlibNames.FLAG_FORCE_FINAL_BIT
348 : JvmStdlibNames.FLAG_FORCE_OPEN_BIT;
349 }
350 kotlinFlags |= DescriptorKindUtils.kindToFlags(functionDescriptor.getKind());
351 aw.writeFlags(kotlinFlags);
352 if (jvmSignature.getKotlinTypeParameter() != null) {
353 aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
354 }
355 aw.writeReturnType(jvmSignature.getKotlinReturnType());
356 aw.visitEnd();
357 }
358 else if (functionDescriptor instanceof ConstructorDescriptor) {
359 AnnotationVisitor jetConstructorVisitor = mv.visitAnnotation(JvmStdlibNames.JET_CONSTRUCTOR.getDescriptor(), true);
360
361 int flagsValue = getFlagsForVisibility(functionDescriptor.getVisibility());
362 if (JvmStdlibNames.FLAGS_DEFAULT_VALUE != flagsValue) {
363 jetConstructorVisitor.visit(JvmStdlibNames.JET_FLAGS_FIELD, flagsValue);
364 }
365
366 jetConstructorVisitor.visitEnd();
367 }
368 else {
369 throw new IllegalStateException();
370 }
371
372 generateMethodParametersAnnotations(mv, functionDescriptor, jvmSignature);
373 }
374
375 void generateMethodParametersAnnotations(
376 MethodVisitor mv,
377 FunctionDescriptor functionDescriptor,
378 JvmMethodSignature jvmSignature
379 ) {
380 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
381 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getKotlinParameterTypes();
382
383 assert kotlinParameterTypes != null;
384
385 for (int i = 0; i < kotlinParameterTypes.size(); i++) {
386 JvmMethodParameterSignature param = kotlinParameterTypes.get(i);
387 JvmMethodParameterKind kind = param.getKind();
388 String parameterName = "$" + param.getKind().name().toLowerCase();
389
390 ValueParameterDescriptor parameterDescriptor = null;
391 if (kind == JvmMethodParameterKind.VALUE) {
392 parameterDescriptor = valueParameters.next();
393 parameterName = parameterDescriptor.getName().asString();
394 } else if (kind == JvmMethodParameterKind.ENUM_NAME || kind == JvmMethodParameterKind.ENUM_ORDINAL) {
395 //we shouldn't generate annotations for invisible in runtime parameters otherwise we get bad RuntimeInvisibleParameterAnnotations error in javac
396 continue;
397 } else if (needIndexForVar(kind)) {
398 parameterName = parameterName + "$" + i;
399 }
400
401 AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameterDescriptor);
402 JetValueParameterAnnotationWriter av = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i);
403 av.writeName(parameterName);
404 if (kind == JvmMethodParameterKind.RECEIVER) {
405 av.writeReceiver();
406 }
407 if (parameterDescriptor != null) {
408 av.writeHasDefaultValue(parameterDescriptor.declaresDefaultValue());
409 av.writeVararg(parameterDescriptor.getVarargElementType() != null);
410 }
411 av.writeType(param.getKotlinSignature());
412 av.visitEnd();
413 }
414 }
415
416 private boolean needIndexForVar(JvmMethodParameterKind kind) {
417 return kind == JvmMethodParameterKind.SHARED_VAR || kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
418 }
419
420 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
421 try {
422 mv.visitMaxs(-1, -1);
423 }
424 catch (ProcessCanceledException e) {
425 throw e;
426 }
427 catch (Throwable t) {
428 throw new CompilationException(
429 "wrong code generated" +
430 (description != null ? " for " + description : "") +
431 t.getClass().getName() +
432 " " +
433 t.getMessage(),
434 t, method);
435 }
436 mv.visitEnd();
437 }
438
439 static void generateBridgeIfNeeded(
440 CodegenContext owner,
441 GenerationState state,
442 ClassBuilder v,
443 Method jvmSignature,
444 FunctionDescriptor functionDescriptor
445 ) {
446 if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
447 return;
448 }
449
450 Method method =
451 state.getTypeMapper().mapSignature(functionDescriptor).getAsmMethod();
452
453 Queue<FunctionDescriptor> bfsQueue = new LinkedList<FunctionDescriptor>();
454 Set<FunctionDescriptor> visited = new HashSet<FunctionDescriptor>();
455
456 bfsQueue.offer(functionDescriptor.getOriginal());
457 visited.add(functionDescriptor.getOriginal());
458 for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
459 FunctionDescriptor orig = overriddenDescriptor.getOriginal();
460 if (!visited.contains(orig)) {
461 bfsQueue.offer(overriddenDescriptor);
462 visited.add(overriddenDescriptor);
463 }
464 }
465
466 Set<Method> bridgesToGenerate = new HashSet<Method>();
467 while (!bfsQueue.isEmpty()) {
468 FunctionDescriptor descriptor = bfsQueue.poll();
469 if (descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
470 Method overridden =
471 state.getTypeMapper().mapSignature(descriptor.getOriginal()).getAsmMethod();
472 if (differentMethods(method, overridden)) {
473 bridgesToGenerate.add(overridden);
474 }
475 continue;
476 }
477
478 for (FunctionDescriptor overriddenDescriptor : descriptor.getOverriddenDescriptors()) {
479 FunctionDescriptor orig = overriddenDescriptor.getOriginal();
480 if (!visited.contains(orig)) {
481 bfsQueue.offer(orig);
482 visited.add(orig);
483 }
484 }
485 }
486
487 for (Method overridden : bridgesToGenerate) {
488 generateBridge(owner, state, v, jvmSignature, functionDescriptor, overridden);
489 }
490 }
491
492 static void generateConstructorWithoutParametersIfNeeded(
493 @NotNull GenerationState state,
494 @NotNull CallableMethod method,
495 @NotNull ConstructorDescriptor constructorDescriptor,
496 @NotNull ClassBuilder classBuilder
497 ) {
498 if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
499 return;
500 }
501 int flags = getVisibilityAccessFlag(constructorDescriptor);
502 MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null);
503
504 if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) {
505 return;
506 }
507 else if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
508 genStubCode(mv);
509 }
510 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
511 InstructionAdapter v = new InstructionAdapter(mv);
512 mv.visitCode();
513
514 JvmClassName ownerInternalName = method.getOwner();
515 Method jvmSignature = method.getSignature().getAsmMethod();
516 v.load(0, ownerInternalName.getAsmType()); // Load this on stack
517
518 int mask = 0;
519 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
520 Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
521 pushDefaultValueOnStack(paramType, v);
522 mask |= (1 << parameterDescriptor.getIndex());
523 }
524 v.iconst(mask);
525 String desc = jvmSignature.getDescriptor().replace(")", "I)");
526 v.invokespecial(ownerInternalName.getInternalName(), "<init>", desc);
527 v.areturn(Type.VOID_TYPE);
528 endVisit(mv, "default constructor for " + ownerInternalName.getInternalName(), null);
529 }
530 }
531
532 static void generateDefaultIfNeeded(
533 @NotNull MethodContext owner,
534 @NotNull GenerationState state,
535 @NotNull ClassBuilder v,
536 @NotNull JvmMethodSignature signature,
537 @NotNull FunctionDescriptor functionDescriptor,
538 @NotNull OwnerKind kind,
539 @NotNull DefaultParameterValueLoader loadStrategy
540 ) {
541 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
542
543 if (kind != OwnerKind.TRAIT_IMPL &&
544 contextClass instanceof ClassDescriptor &&
545 ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) {
546 return;
547 }
548
549 if (!isDefaultNeeded(functionDescriptor)) {
550 return;
551 }
552
553 boolean isStatic = isStatic(kind);
554
555 Method jvmSignature = signature.getAsmMethod();
556
557 int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
558
559 JvmClassName ownerInternalName;
560 if (contextClass instanceof NamespaceDescriptor) {
561 ownerInternalName = state.getTypeMapper().getOwner(functionDescriptor, kind, true);
562 }
563 else {
564 ownerInternalName = JvmClassName.byType(state.getTypeMapper()
565 .mapType(((ClassDescriptor) contextClass).getDefaultType(),
566 JetTypeMapperMode.IMPL));
567 }
568
569 String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
570 boolean isConstructor = "<init>".equals(jvmSignature.getName());
571 if (!isStatic && !isConstructor) {
572 descriptor = descriptor.replace("(", "(" + ownerInternalName.getDescriptor());
573 }
574 MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
575 isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
576 descriptor, null, null);
577
578 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
579 genStubCode(mv);
580 }
581 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
582 generateDefaultImpl(owner, state, signature, functionDescriptor, kind, isStatic, mv, loadStrategy);
583 }
584 }
585
586 private static void generateDefaultImpl(
587 @NotNull MethodContext methodContext,
588 @NotNull GenerationState state,
589 @NotNull JvmMethodSignature signature,
590 @NotNull FunctionDescriptor functionDescriptor,
591 @NotNull OwnerKind kind,
592 boolean aStatic,
593 @NotNull MethodVisitor mv,
594 @NotNull DefaultParameterValueLoader loadStrategy
595 ) {
596 mv.visitCode();
597
598 FrameMap frameMap = new FrameMap();
599
600 if (!aStatic) {
601 frameMap.enterTemp(OBJECT_TYPE);
602 }
603
604 Method jvmSignature = signature.getAsmMethod();
605 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state);
606
607 Type[] argTypes = jvmSignature.getArgumentTypes();
608 List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
609 Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator();
610
611 int countOfExtraVarsInMethodArgs = 0;
612 List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
613
614 for (int i = 0; i < params.size(); i++) {
615 JvmMethodParameterSignature parameterSignature = params.get(i);
616 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
617 countOfExtraVarsInMethodArgs++;
618 frameMap.enterTemp(parameterSignature.getAsmType());
619 } else {
620 frameMap.enter(iterator.next(), parameterSignature.getAsmType());
621 }
622 }
623
624 int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
625
626 InstructionAdapter iv = new InstructionAdapter(mv);
627 loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature);
628
629 for (int index = 0; index < paramDescrs.size(); index++) {
630 ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
631
632 Type t = argTypes[countOfExtraVarsInMethodArgs + index];
633
634 if (parameterDescriptor.declaresDefaultValue()) {
635 iv.load(maskIndex, Type.INT_TYPE);
636 iv.iconst(1 << index);
637 iv.and(Type.INT_TYPE);
638 Label loadArg = new Label();
639 iv.ifeq(loadArg);
640
641 loadStrategy.putValueOnStack(parameterDescriptor, codegen);
642
643 int ind = frameMap.getIndex(parameterDescriptor);
644 iv.store(ind, t);
645
646 iv.mark(loadArg);
647 }
648
649 iv.load(frameMap.getIndex(parameterDescriptor), t);
650 }
651
652 CallableMethod method = null;
653 if (functionDescriptor instanceof ConstructorDescriptor) {
654 method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
655 } else {
656 method = state.getTypeMapper()
657 .mapToCallableMethod(functionDescriptor, false, isCallInsideSameClassAsDeclared(functionDescriptor, methodContext),
658 isCallInsideSameModuleAsDeclared(functionDescriptor, methodContext), OwnerKind.IMPLEMENTATION);
659 }
660
661 iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getSignature().getAsmMethod().getName(),
662 method.getSignature().getAsmMethod().getDescriptor());
663
664 iv.areturn(jvmSignature.getReturnType());
665
666 endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
667 mv.visitEnd();
668 }
669
670
671 private static void loadExplicitArgumentsOnStack(
672 @NotNull InstructionAdapter iv,
673 @NotNull Type ownerType,
674 boolean isStatic,
675 @NotNull JvmMethodSignature signature
676 ) {
677 int var = 0;
678 if (!isStatic) {
679 iv.load(var, ownerType);
680 var += ownerType.getSize();
681 }
682
683 List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
684 for (int i = 0; i < params.size(); i++) {
685 JvmMethodParameterSignature parameterSignature = params.get(i);
686 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
687 Type type = parameterSignature.getAsmType();
688 iv.load(var, type);
689 var += type.getSize();
690 }
691 }
692 }
693
694 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
695 boolean needed = false;
696 if (functionDescriptor != null) {
697 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
698 if (parameterDescriptor.declaresDefaultValue()) {
699 needed = true;
700 break;
701 }
702 }
703 }
704 return needed;
705 }
706
707 private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
708 ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
709
710 if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
711
712 if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
713 constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false;
714
715 if (constructorDescriptor.getValueParameters().isEmpty()) return false;
716
717 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
718 if (!parameterDescriptor.declaresDefaultValue()) {
719 return false;
720 }
721 }
722 return true;
723 }
724
725 private static boolean differentMethods(Method method, Method overridden) {
726 if (!method.getReturnType().equals(overridden.getReturnType())) {
727 return true;
728 }
729 Type[] methodArgumentTypes = method.getArgumentTypes();
730 Type[] overriddenArgumentTypes = overridden.getArgumentTypes();
731 if (methodArgumentTypes.length != overriddenArgumentTypes.length) {
732 return true;
733 }
734 for (int i = 0; i != methodArgumentTypes.length; ++i) {
735 if (!methodArgumentTypes[i].equals(overriddenArgumentTypes[i])) {
736 return true;
737 }
738 }
739 return false;
740 }
741
742 private static void generateBridge(
743 CodegenContext owner,
744 GenerationState state,
745 ClassBuilder v,
746 Method jvmSignature,
747 FunctionDescriptor functionDescriptor,
748 Method overridden
749 ) {
750 int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
751
752 MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null);
753 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
754 genStubCode(mv);
755 }
756 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
757 mv.visitCode();
758
759 Type[] argTypes = overridden.getArgumentTypes();
760 Type[] originalArgTypes = jvmSignature.getArgumentTypes();
761
762 InstructionAdapter iv = new InstructionAdapter(mv);
763 iv.load(0, OBJECT_TYPE);
764 for (int i = 0, reg = 1; i < argTypes.length; i++) {
765 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
766 //noinspection AssignmentToForLoopParameter
767 reg += argTypes[i].getSize();
768 }
769
770 iv.invokevirtual(v.getThisName(), jvmSignature.getName(), jvmSignature.getDescriptor());
771
772 StackValue.onStack(jvmSignature.getReturnType()).put(overridden.getReturnType(), iv);
773
774 iv.areturn(overridden.getReturnType());
775 endVisit(mv, "bridge method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
776 }
777 }
778
779 public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
780 genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field,
781 typeMapper.mapSignature(functionDescriptor),
782 typeMapper.mapSignature(overriddenDescriptor.getOriginal())
783 );
784 }
785
786 public void genDelegate(
787 FunctionDescriptor functionDescriptor,
788 ClassDescriptor toClass,
789 StackValue field,
790 JvmMethodSignature jvmDelegateMethodSignature,
791 JvmMethodSignature jvmOverriddenMethodSignature
792 ) {
793 Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
794 Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
795
796 int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
797
798 MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null, null);
799 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
800 genStubCode(mv);
801 }
802 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
803 mv.visitCode();
804
805 Type[] argTypes = delegateMethod.getArgumentTypes();
806 Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
807
808 InstructionAdapter iv = new InstructionAdapter(mv);
809 iv.load(0, OBJECT_TYPE);
810 field.put(field.type, iv);
811 for (int i = 0, reg = 1; i < argTypes.length; i++) {
812 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
813 //noinspection AssignmentToForLoopParameter
814 reg += argTypes[i].getSize();
815 }
816
817 String internalName = typeMapper.mapType(toClass).getInternalName();
818 if (toClass.getKind() == ClassKind.TRAIT) {
819 iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
820 }
821 else {
822 iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
823 }
824
825 StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
826
827 iv.areturn(delegateMethod.getReturnType());
828 endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
829 descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
830
831 generateBridgeIfNeeded(owner, state, v, jvmDelegateMethodSignature.getAsmMethod(), functionDescriptor);
832 }
833 }
834 }