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