001 /*
002 /*
003 * Copyright 2010-2013 JetBrains s.r.o.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.jetbrains.jet.codegen;
019
020 import com.intellij.openapi.progress.ProcessCanceledException;
021 import com.intellij.psi.PsiElement;
022 import com.intellij.util.ArrayUtil;
023 import com.intellij.util.Function;
024 import com.intellij.util.containers.ContainerUtil;
025 import kotlin.Function1;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.codegen.binding.CodegenBinding;
029 import org.jetbrains.jet.codegen.bridges.Bridge;
030 import org.jetbrains.jet.codegen.bridges.BridgesPackage;
031 import org.jetbrains.jet.codegen.context.CodegenContext;
032 import org.jetbrains.jet.codegen.context.MethodContext;
033 import org.jetbrains.jet.codegen.context.PackageFacadeContext;
034 import org.jetbrains.jet.codegen.optimization.OptimizationMethodVisitor;
035 import org.jetbrains.jet.codegen.state.GenerationState;
036 import org.jetbrains.jet.codegen.state.JetTypeMapper;
037 import org.jetbrains.jet.lang.descriptors.*;
038 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
039 import org.jetbrains.jet.lang.psi.JetNamedFunction;
040 import org.jetbrains.jet.lang.resolve.BindingContext;
041 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
042 import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
043 import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
044 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
045 import org.jetbrains.jet.lang.resolve.constants.JavaClassValue;
046 import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
047 import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
048 import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
049 import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
050 import org.jetbrains.jet.lang.resolve.name.FqName;
051 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
052 import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
053 import org.jetbrains.org.objectweb.asm.Label;
054 import org.jetbrains.org.objectweb.asm.MethodVisitor;
055 import org.jetbrains.org.objectweb.asm.Type;
056 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
057 import org.jetbrains.org.objectweb.asm.commons.Method;
058 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
059
060 import java.io.PrintWriter;
061 import java.io.StringWriter;
062 import java.util.Collection;
063 import java.util.Iterator;
064 import java.util.List;
065 import java.util.Set;
066
067 import static org.jetbrains.jet.codegen.AsmUtil.*;
068 import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
069 import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
070 import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
071 import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.callableDescriptorToDeclaration;
072 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral;
073 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
074 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
075 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.OLD_JET_VALUE_PARAMETER_ANNOTATION;
076 import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin;
077 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
078
079 public class FunctionCodegen extends ParentCodegenAware {
080 private final CodegenContext owner;
081
082 private final ClassBuilder v;
083
084 public FunctionCodegen(
085 @NotNull CodegenContext owner,
086 @NotNull ClassBuilder v,
087 @NotNull GenerationState state,
088 MemberCodegen<?> parentCodegen
089 ) {
090 super(state, parentCodegen);
091 this.owner = owner;
092 this.v = v;
093 }
094
095 public void gen(@NotNull JetNamedFunction function) {
096 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
097 assert functionDescriptor != null : "No descriptor for function " + function.getText() + "\n" +
098 "in " + function.getContainingFile().getVirtualFile();
099
100 OwnerKind kind = owner.getContextKind();
101 JvmMethodSignature method = typeMapper.mapSignature(functionDescriptor, kind);
102
103 if (kind != OwnerKind.TRAIT_IMPL || function.hasBody()) {
104 generateMethod(OtherOrigin(function, functionDescriptor),
105 method, functionDescriptor,
106 new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
107 }
108
109 generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), method, functionDescriptor, kind,
110 DefaultParameterValueLoader.DEFAULT, function);
111 }
112
113 public void generateMethod(
114 @NotNull JvmDeclarationOrigin origin,
115 @NotNull JvmMethodSignature jvmSignature,
116 @NotNull FunctionDescriptor functionDescriptor,
117 @NotNull FunctionGenerationStrategy strategy
118 ) {
119 generateMethod(origin, jvmSignature, functionDescriptor, owner.intoFunction(functionDescriptor), strategy);
120 }
121
122 public void generateMethod(
123 @NotNull JvmDeclarationOrigin origin,
124 @NotNull JvmMethodSignature jvmSignature,
125 @NotNull FunctionDescriptor functionDescriptor,
126 @NotNull MethodContext methodContext,
127 @NotNull FunctionGenerationStrategy strategy
128 ) {
129 OwnerKind methodContextKind = methodContext.getContextKind();
130 Method asmMethod = jvmSignature.getAsmMethod();
131
132 MethodVisitor mv = v.newMethod(origin,
133 getMethodAsmFlags(functionDescriptor, methodContextKind),
134 asmMethod.getName(),
135 asmMethod.getDescriptor(),
136 jvmSignature.getGenericsSignature(),
137 getThrownExceptions(functionDescriptor, typeMapper));
138
139 if (owner instanceof PackageFacadeContext) {
140 Type ownerType = ((PackageFacadeContext) owner).getDelegateToClassType();
141 v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, shortNameByAsmType(ownerType));
142 }
143 else {
144 v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
145 }
146
147 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, asmMethod.getReturnType());
148
149 generateParameterAnnotations(functionDescriptor, mv, jvmSignature);
150
151 generateJetValueParameterAnnotations(mv, functionDescriptor, jvmSignature);
152
153 generateBridges(functionDescriptor);
154
155 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES || isAbstractMethod(functionDescriptor, methodContextKind)) {
156 generateLocalVariableTable(
157 mv,
158 jvmSignature,
159 functionDescriptor,
160 getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
161 new Label(),
162 new Label(),
163 methodContextKind
164 );
165
166 mv.visitEnd();
167 return;
168 }
169
170 generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, getParentCodegen());
171
172 endVisit(mv, null, origin.getElement());
173
174 methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
175 }
176
177 private void generateParameterAnnotations(
178 @NotNull FunctionDescriptor functionDescriptor,
179 @NotNull MethodVisitor mv,
180 @NotNull JvmMethodSignature jvmSignature
181 ) {
182 Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator();
183 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
184
185 for (int i = 0; i < kotlinParameterTypes.size(); i++) {
186 JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i);
187 JvmMethodParameterKind kind = parameterSignature.getKind();
188 if (kind.isSkippedInGenericSignature()) {
189 markEnumOrInnerConstructorParameterAsSynthetic(mv, i);
190 continue;
191 }
192
193 if (kind == JvmMethodParameterKind.VALUE) {
194 ValueParameterDescriptor parameter = iterator.next();
195 v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i);
196 AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameter, parameterSignature.getAsmType());
197 }
198 }
199 }
200
201 @SuppressWarnings("deprecation")
202 private static void generateJetValueParameterAnnotations(
203 @NotNull MethodVisitor mv,
204 @NotNull FunctionDescriptor functionDescriptor,
205 @NotNull JvmMethodSignature jvmSignature
206 ) {
207 Iterator<ValueParameterDescriptor> descriptors = functionDescriptor.getValueParameters().iterator();
208 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
209
210 for (int i = 0; i < kotlinParameterTypes.size(); i++) {
211 JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind();
212 if (kind.isSkippedInGenericSignature()) continue;
213
214 String name;
215 boolean nullableType;
216 if (kind == JvmMethodParameterKind.VALUE) {
217 ValueParameterDescriptor descriptor = descriptors.next();
218 name = descriptor.getName().asString();
219 nullableType = descriptor.getType().isNullable();
220 }
221 else {
222 String lowercaseKind = kind.name().toLowerCase();
223 if (needIndexForVar(kind)) {
224 name = "$" + lowercaseKind + "$" + i;
225 }
226 else {
227 name = "$" + lowercaseKind;
228 }
229
230 if (kind == JvmMethodParameterKind.RECEIVER) {
231 ReceiverParameterDescriptor receiver = functionDescriptor.getReceiverParameter();
232 nullableType = receiver == null || receiver.getType().isNullable();
233 }
234 else {
235 nullableType = true;
236 }
237 }
238
239 AnnotationVisitor av =
240 mv.visitParameterAnnotation(i, asmDescByFqNameWithoutInnerClasses(OLD_JET_VALUE_PARAMETER_ANNOTATION), true);
241 if (av != null) {
242 av.visit("name", name);
243 if (nullableType) {
244 av.visit("type", "?");
245 }
246 av.visitEnd();
247 }
248 }
249 }
250
251 private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) {
252 // IDEA's ClsPsi builder fails to annotate synthetic parameters
253 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
254
255 // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac:
256 // see MethodWriter.visitParameterAnnotation()
257
258 AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true);
259 if (av != null) {
260 av.visitEnd();
261 }
262 }
263
264 @Nullable
265 private static Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JetTypeMapper typeMapper) {
266 ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
267 if (functionDescriptor instanceof ConstructorDescriptor) {
268 return typeMapper.mapType(functionDescriptor);
269 }
270 else if (expectedThisObject != null) {
271 return typeMapper.mapType(expectedThisObject.getType());
272 }
273 else if (isFunctionLiteral(functionDescriptor) || isLocalNamedFun(functionDescriptor)) {
274 return typeMapper.mapType(context.getThisDescriptor());
275 }
276 else {
277 return null;
278 }
279 }
280
281 public static void generateMethodBody(
282 @NotNull MethodVisitor mv,
283 @NotNull FunctionDescriptor functionDescriptor,
284 @NotNull MethodContext context,
285 @NotNull JvmMethodSignature signature,
286 @NotNull FunctionGenerationStrategy strategy,
287 @NotNull MemberCodegen<?> parentCodegen
288 ) {
289 mv.visitCode();
290
291 Label methodBegin = new Label();
292 mv.visitLabel(methodBegin);
293
294 JetTypeMapper typeMapper = parentCodegen.typeMapper;
295
296 if (context.getParentContext() instanceof PackageFacadeContext) {
297 generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
298 }
299 else {
300 FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStatic(context.getContextKind()));
301
302 Label methodEntry = new Label();
303 mv.visitLabel(methodEntry);
304 context.setMethodStartLabel(methodEntry);
305
306 if (!JetTypeMapper.isAccessor(functionDescriptor)) {
307 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap);
308 }
309
310 strategy.generateBody(mv, frameMap, signature, context, parentCodegen);
311 }
312
313 Label methodEnd = new Label();
314 mv.visitLabel(methodEnd);
315
316 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
317 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
318 }
319
320 private static void generateLocalVariableTable(
321 @NotNull MethodVisitor mv,
322 @NotNull JvmMethodSignature jvmMethodSignature,
323 @NotNull FunctionDescriptor functionDescriptor,
324 @Nullable Type thisType,
325 @NotNull Label methodBegin,
326 @NotNull Label methodEnd,
327 @NotNull OwnerKind ownerKind
328 ) {
329 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
330 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
331 int shift = 0;
332
333 boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
334 if (!isStatic) {
335 //add this
336 if (thisType != null) {
337 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
338 } else {
339 //TODO: provide thisType for callable reference
340 }
341 shift++;
342 }
343
344 for (int i = 0; i < params.size(); i++) {
345 JvmMethodParameterSignature param = params.get(i);
346 JvmMethodParameterKind kind = param.getKind();
347 String parameterName;
348
349 if (kind == JvmMethodParameterKind.VALUE) {
350 ValueParameterDescriptor parameter = valueParameters.next();
351 parameterName = parameter.getName().asString();
352 }
353 else {
354 String lowercaseKind = kind.name().toLowerCase();
355 parameterName = needIndexForVar(kind)
356 ? "$" + lowercaseKind + "$" + i
357 : "$" + lowercaseKind;
358 }
359
360 Type type = param.getAsmType();
361 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
362 shift += type.getSize();
363 }
364 }
365
366 private static void generateStaticDelegateMethodBody(
367 @NotNull MethodVisitor mv,
368 @NotNull Method asmMethod,
369 @NotNull PackageFacadeContext context
370 ) {
371 InstructionAdapter iv = new InstructionAdapter(mv);
372 Type[] argTypes = asmMethod.getArgumentTypes();
373
374 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it
375 // This is similar to what javac does with bridge methods
376 Label label = new Label();
377 iv.visitLabel(label);
378 iv.visitLineNumber(1, label);
379
380 int k = 0;
381 for (Type argType : argTypes) {
382 iv.load(k, argType);
383 k += argType.getSize();
384 }
385 iv.invokestatic(context.getDelegateToClassType().getInternalName(), asmMethod.getName(), asmMethod.getDescriptor(), false);
386 iv.areturn(asmMethod.getReturnType());
387 }
388
389 private static boolean needIndexForVar(JvmMethodParameterKind kind) {
390 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE ||
391 kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL ||
392 kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
393 }
394
395 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
396 try {
397 mv.visitMaxs(-1, -1);
398 mv.visitEnd();
399 }
400 catch (ProcessCanceledException e) {
401 throw e;
402 }
403 catch (Throwable t) {
404 String bytecode = renderByteCodeIfAvailable(mv);
405 throw new CompilationException(
406 "wrong code generated" +
407 (description != null ? " for " + description : "") +
408 t.getClass().getName() +
409 " " +
410 t.getMessage() +
411 (bytecode != null ? "\nbytecode:\n" + bytecode : ""),
412 t, method);
413 }
414 }
415
416 private static String renderByteCodeIfAvailable(MethodVisitor mv) {
417 String bytecode = null;
418
419 if (mv instanceof OptimizationMethodVisitor) {
420 mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible();
421 }
422
423 if (mv instanceof TraceMethodVisitor) {
424 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv;
425 StringWriter sw = new StringWriter();
426 PrintWriter pw = new PrintWriter(sw);
427 traceMethodVisitor.p.print(pw);
428 pw.close();
429 bytecode = sw.toString();
430 }
431 return bytecode;
432 }
433
434 public void generateBridges(@NotNull FunctionDescriptor descriptor) {
435 if (descriptor instanceof ConstructorDescriptor) return;
436 if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
437 if (isTrait(descriptor.getContainingDeclaration())) return;
438
439 // equals(Any?), hashCode(), toString() never need bridges
440 if (isMethodOfAny(descriptor)) return;
441
442 // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
443 if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return;
444
445 Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor(
446 descriptor,
447 new Function1<FunctionDescriptor, Method>() {
448 @Override
449 public Method invoke(FunctionDescriptor descriptor) {
450 return typeMapper.mapSignature(descriptor).getAsmMethod();
451 }
452 }
453 );
454
455 if (!bridgesToGenerate.isEmpty()) {
456 PsiElement origin = descriptor.getKind() == DECLARATION ? callableDescriptorToDeclaration(descriptor) : null;
457 for (Bridge<Method> bridge : bridgesToGenerate) {
458 generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo());
459 }
460 }
461 }
462
463 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
464 String name = descriptor.getName().asString();
465 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
466 if (parameters.isEmpty()) {
467 return name.equals("hashCode") || name.equals("toString");
468 }
469 else if (parameters.size() == 1 && name.equals("equals")) {
470 ValueParameterDescriptor parameter = parameters.get(0);
471 return parameter.getType().equals(KotlinBuiltIns.getInstance().getNullableAnyType());
472 }
473 return false;
474 }
475
476 @NotNull
477 private static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
478 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
479 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
480
481 Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values();
482 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
483
484 Object value = values.iterator().next();
485 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
486 ArrayValue arrayValue = (ArrayValue) value;
487
488 List<String> strings = ContainerUtil.mapNotNull(
489 arrayValue.getValue(),
490 new Function<CompileTimeConstant<?>, String>() {
491 @Override
492 public String fun(CompileTimeConstant<?> constant) {
493 if (constant instanceof JavaClassValue) {
494 JavaClassValue classValue = (JavaClassValue) constant;
495 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
496 return mapper.mapClass(classDescriptor).getInternalName();
497 }
498 return null;
499 }
500 }
501 );
502 return ArrayUtil.toStringArray(strings);
503 }
504
505 static void generateConstructorWithoutParametersIfNeeded(
506 @NotNull GenerationState state,
507 @NotNull CallableMethod method,
508 @NotNull ConstructorDescriptor constructorDescriptor,
509 @NotNull ClassBuilder classBuilder
510 ) {
511 if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
512 return;
513 }
514 int flags = getVisibilityAccessFlag(constructorDescriptor);
515 MethodVisitor mv = classBuilder.newMethod(OtherOrigin(constructorDescriptor), flags, "<init>", "()V", null,
516 getThrownExceptions(constructorDescriptor, state.getTypeMapper()));
517
518 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
519
520 InstructionAdapter v = new InstructionAdapter(mv);
521 mv.visitCode();
522
523 Type methodOwner = method.getOwner();
524 v.load(0, methodOwner); // Load this on stack
525
526 int mask = 0;
527 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
528 Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
529 pushDefaultValueOnStack(paramType, v);
530 mask |= (1 << parameterDescriptor.getIndex());
531 }
532 v.iconst(mask);
533 String desc = method.getAsmMethod().getDescriptor().replace(")", "I)");
534 v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false);
535 v.areturn(Type.VOID_TYPE);
536 endVisit(mv, "default constructor for " + methodOwner.getInternalName(), null);
537 }
538
539 void generateDefaultIfNeeded(
540 @NotNull MethodContext owner,
541 @NotNull JvmMethodSignature signature,
542 @NotNull FunctionDescriptor functionDescriptor,
543 @NotNull OwnerKind kind,
544 @NotNull DefaultParameterValueLoader loadStrategy,
545 @Nullable JetNamedFunction function
546 ) {
547 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
548
549 if (kind != OwnerKind.TRAIT_IMPL &&
550 contextClass instanceof ClassDescriptor &&
551 ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) {
552 return;
553 }
554
555 if (!isDefaultNeeded(functionDescriptor)) {
556 return;
557 }
558
559 Method jvmSignature = signature.getAsmMethod();
560
561 int flags = getVisibilityAccessFlag(functionDescriptor) | getDeprecatedAccessFlag(functionDescriptor);
562
563 boolean isConstructor = "<init>".equals(jvmSignature.getName());
564
565 Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind, owner);
566
567 MethodVisitor mv = v.newMethod(OtherOrigin(functionDescriptor), flags | (isConstructor ? 0 : ACC_STATIC),
568 defaultMethod.getName(),
569 defaultMethod.getDescriptor(), null,
570 getThrownExceptions(functionDescriptor, typeMapper));
571
572 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
573 if (this.owner instanceof PackageFacadeContext) {
574 mv.visitCode();
575 generateStaticDelegateMethodBody(mv, defaultMethod, (PackageFacadeContext) this.owner);
576 endVisit(mv, "default method delegation", callableDescriptorToDeclaration(functionDescriptor));
577 }
578 else {
579 generateDefaultImpl(owner, signature, functionDescriptor, isStatic(kind), mv, loadStrategy, function);
580 }
581 }
582 }
583
584 private void generateDefaultImpl(
585 @NotNull MethodContext methodContext,
586 @NotNull JvmMethodSignature signature,
587 @NotNull FunctionDescriptor functionDescriptor,
588 boolean isStatic,
589 @NotNull MethodVisitor mv,
590 @NotNull DefaultParameterValueLoader loadStrategy,
591 @Nullable JetNamedFunction function
592 ) {
593 mv.visitCode();
594 generateDefaultImplBody(methodContext, signature, functionDescriptor, isStatic, mv, loadStrategy, function, getParentCodegen(), state);
595 endVisit(mv, "default method", callableDescriptorToDeclaration(functionDescriptor));
596 }
597
598 public static void generateDefaultImplBody(
599 @NotNull MethodContext methodContext,
600 @NotNull JvmMethodSignature signature,
601 @NotNull FunctionDescriptor functionDescriptor,
602 boolean isStatic,
603 @NotNull MethodVisitor mv,
604 @NotNull DefaultParameterValueLoader loadStrategy,
605 @Nullable JetNamedFunction function,
606 @NotNull MemberCodegen<?> parentCodegen,
607 @NotNull GenerationState state
608 ) {
609 FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic);
610
611 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);
612
613 int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
614
615 CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function);
616
617 InstructionAdapter iv = new InstructionAdapter(mv);
618 loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, isStatic, signature);
619 generator.putHiddenParams();
620
621 List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters();
622 int capturedArgumentsCount = 0;
623 while (capturedArgumentsCount < mappedParameters.size() &&
624 mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) {
625 capturedArgumentsCount++;
626 }
627
628 List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
629 for (int index = 0; index < valueParameters.size(); index++) {
630 ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
631 Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();
632
633 int parameterIndex = frameMap.getIndex(parameterDescriptor);
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 iv.store(parameterIndex, type);
644
645 iv.mark(loadArg);
646 }
647
648 generator.putValueIfNeeded(parameterDescriptor, type, StackValue.local(parameterIndex, type));
649 }
650
651 CallableMethod method;
652 if (functionDescriptor instanceof ConstructorDescriptor) {
653 method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
654 }
655 else {
656 method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false, methodContext);
657 }
658
659 generator.genCallWithoutAssertions(method, codegen);
660
661 iv.areturn(signature.getReturnType());
662 }
663
664 @NotNull
665 private static FrameMap createFrameMap(
666 @NotNull GenerationState state,
667 @NotNull FunctionDescriptor function,
668 @NotNull JvmMethodSignature signature,
669 boolean isStatic
670 ) {
671 FrameMap frameMap = new FrameMap();
672 if (!isStatic) {
673 frameMap.enterTemp(OBJECT_TYPE);
674 }
675
676 for (JvmMethodParameterSignature parameter : signature.getValueParameters()) {
677 if (parameter.getKind() != JvmMethodParameterKind.VALUE) {
678 frameMap.enterTemp(parameter.getAsmType());
679 }
680 }
681
682 for (ValueParameterDescriptor parameter : function.getValueParameters()) {
683 frameMap.enter(parameter, state.getTypeMapper().mapType(parameter));
684 }
685
686 return frameMap;
687 }
688
689 private static void loadExplicitArgumentsOnStack(
690 @NotNull InstructionAdapter iv,
691 @NotNull Type ownerType,
692 boolean isStatic,
693 @NotNull JvmMethodSignature signature
694 ) {
695 int var = 0;
696 if (!isStatic) {
697 iv.load(var, ownerType);
698 var += ownerType.getSize();
699 }
700
701 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) {
702 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
703 Type type = parameterSignature.getAsmType();
704 iv.load(var, type);
705 var += type.getSize();
706 }
707 }
708 }
709
710 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
711 boolean needed = false;
712 if (functionDescriptor != null) {
713 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
714 if (parameterDescriptor.declaresDefaultValue()) {
715 needed = true;
716 break;
717 }
718 }
719 }
720 return needed;
721 }
722
723 private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
724 ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
725
726 if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
727
728 if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
729 constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false;
730
731 if (constructorDescriptor.getValueParameters().isEmpty()) return false;
732
733 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
734 if (!parameterDescriptor.declaresDefaultValue()) {
735 return false;
736 }
737 }
738 return true;
739 }
740
741 private void generateBridge(
742 @Nullable PsiElement origin,
743 @NotNull FunctionDescriptor descriptor,
744 @NotNull Method bridge,
745 @NotNull Method delegateTo
746 ) {
747 int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
748
749 MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, delegateTo.getName(), bridge.getDescriptor(), null, null);
750 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
751
752 mv.visitCode();
753
754 Type[] argTypes = bridge.getArgumentTypes();
755 Type[] originalArgTypes = delegateTo.getArgumentTypes();
756
757 InstructionAdapter iv = new InstructionAdapter(mv);
758 iv.load(0, OBJECT_TYPE);
759 for (int i = 0, reg = 1; i < argTypes.length; i++) {
760 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
761 //noinspection AssignmentToForLoopParameter
762 reg += argTypes[i].getSize();
763 }
764
765 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
766
767 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
768 iv.areturn(bridge.getReturnType());
769
770 endVisit(mv, "bridge method", origin);
771 }
772
773 public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
774 genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field,
775 typeMapper.mapSignature(functionDescriptor),
776 typeMapper.mapSignature(overriddenDescriptor.getOriginal())
777 );
778 }
779
780 public void genDelegate(
781 FunctionDescriptor functionDescriptor,
782 final ClassDescriptor toClass,
783 final StackValue field,
784 final JvmMethodSignature jvmDelegateMethodSignature,
785 final JvmMethodSignature jvmOverriddenMethodSignature
786 ) {
787 generateMethod(
788 OtherOrigin(functionDescriptor), jvmDelegateMethodSignature, functionDescriptor,
789 new FunctionGenerationStrategy() {
790 @Override
791 public void generateBody(
792 @NotNull MethodVisitor mv,
793 @NotNull FrameMap frameMap,
794 @NotNull JvmMethodSignature signature,
795 @NotNull MethodContext context,
796 @NotNull MemberCodegen<?> parentCodegen
797 ) {
798 Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
799 Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
800
801 Type[] argTypes = delegateMethod.getArgumentTypes();
802 Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
803
804 InstructionAdapter iv = new InstructionAdapter(mv);
805 iv.load(0, OBJECT_TYPE);
806 field.put(field.type, iv);
807 for (int i = 0, reg = 1; i < argTypes.length; i++) {
808 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
809 //noinspection AssignmentToForLoopParameter
810 reg += argTypes[i].getSize();
811 }
812
813 String internalName = typeMapper.mapType(toClass).getInternalName();
814 if (toClass.getKind() == ClassKind.TRAIT) {
815 iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
816 }
817 else {
818 iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
819 }
820
821 StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
822
823 iv.areturn(delegateMethod.getReturnType());
824 }
825 }
826 );
827 }
828 }