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.signature.JvmMethodParameterKind;
035 import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
036 import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
037 import org.jetbrains.jet.codegen.state.GenerationState;
038 import org.jetbrains.jet.codegen.state.JetTypeMapper;
039 import org.jetbrains.jet.lang.descriptors.*;
040 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
041 import org.jetbrains.jet.lang.psi.JetNamedFunction;
042 import org.jetbrains.jet.lang.resolve.BindingContext;
043 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
044 import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
045 import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
046 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
047 import org.jetbrains.jet.lang.resolve.constants.JavaClassValue;
048 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
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.BindingContextUtils.descriptorToDeclaration;
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.org.objectweb.asm.Opcodes.*;
077
078 public class FunctionCodegen extends ParentCodegenAwareImpl {
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.getBodyExpression() != null) {
103 generateMethod(function, method, functionDescriptor,
104 new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
105 }
106
107 generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), method, functionDescriptor, kind,
108 DefaultParameterValueLoader.DEFAULT);
109 }
110
111 public void generateMethod(
112 @Nullable PsiElement origin,
113 @NotNull JvmMethodSignature jvmSignature,
114 @NotNull FunctionDescriptor functionDescriptor,
115 @NotNull FunctionGenerationStrategy strategy
116 ) {
117 generateMethod(origin, jvmSignature, functionDescriptor, owner.intoFunction(functionDescriptor), strategy);
118 }
119
120 public void generateMethod(
121 @Nullable PsiElement origin,
122 @NotNull JvmMethodSignature jvmSignature,
123 @NotNull FunctionDescriptor functionDescriptor,
124 @NotNull MethodContext methodContext,
125 @NotNull FunctionGenerationStrategy strategy
126 ) {
127 OwnerKind methodContextKind = methodContext.getContextKind();
128 Method asmMethod = jvmSignature.getAsmMethod();
129
130 MethodVisitor mv = v.newMethod(origin,
131 getMethodAsmFlags(functionDescriptor, methodContextKind),
132 asmMethod.getName(),
133 asmMethod.getDescriptor(),
134 jvmSignature.getGenericsSignature(),
135 getThrownExceptions(functionDescriptor, typeMapper));
136
137 if (owner instanceof PackageFacadeContext) {
138 Type ownerType = ((PackageFacadeContext) owner).getDelegateToClassType();
139 v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, shortNameByAsmType(ownerType));
140 }
141 else {
142 v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
143 }
144
145 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor);
146
147 generateParameterAnnotations(functionDescriptor, mv, jvmSignature);
148
149 generateJetValueParameterAnnotations(mv, functionDescriptor, jvmSignature);
150
151 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES || isAbstractMethod(functionDescriptor, methodContextKind)) {
152 generateLocalVariableTable(
153 mv,
154 jvmSignature,
155 functionDescriptor,
156 getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
157 new Label(),
158 new Label(),
159 methodContextKind
160 );
161 return;
162 }
163
164 generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, getParentCodegen());
165
166 endVisit(mv, null, origin);
167
168 methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
169
170 generateBridges(functionDescriptor);
171 }
172
173 private void generateParameterAnnotations(
174 @NotNull FunctionDescriptor functionDescriptor,
175 @NotNull MethodVisitor mv,
176 @NotNull JvmMethodSignature jvmSignature
177 ) {
178 Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator();
179 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
180
181 for (int i = 0; i < kotlinParameterTypes.size(); i++) {
182 JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind();
183 if (kind.isSkippedInGenericSignature()) {
184 markEnumOrInnerConstructorParameterAsSynthetic(mv, i);
185 continue;
186 }
187
188 if (kind == JvmMethodParameterKind.VALUE) {
189 ValueParameterDescriptor parameter = iterator.next();
190 v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i);
191 AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameter);
192 }
193 }
194 }
195
196 @SuppressWarnings("deprecation")
197 private void generateJetValueParameterAnnotations(
198 @NotNull MethodVisitor mv,
199 @NotNull FunctionDescriptor functionDescriptor,
200 @NotNull JvmMethodSignature jvmSignature
201 ) {
202 Iterator<ValueParameterDescriptor> descriptors = functionDescriptor.getValueParameters().iterator();
203 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
204
205 for (int i = 0; i < kotlinParameterTypes.size(); i++) {
206 JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind();
207 if (kind.isSkippedInGenericSignature()) {
208 markEnumOrInnerConstructorParameterAsSynthetic(mv, i);
209 continue;
210 }
211
212 String name;
213 boolean nullableType;
214 if (kind == JvmMethodParameterKind.VALUE) {
215 ValueParameterDescriptor descriptor = descriptors.next();
216 name = descriptor.getName().asString();
217 nullableType = descriptor.getType().isNullable();
218 }
219 else {
220 String lowercaseKind = kind.name().toLowerCase();
221 if (needIndexForVar(kind)) {
222 name = "$" + lowercaseKind + "$" + i;
223 }
224 else {
225 name = "$" + lowercaseKind;
226 }
227
228 if (kind == JvmMethodParameterKind.RECEIVER) {
229 ReceiverParameterDescriptor receiver = functionDescriptor.getReceiverParameter();
230 nullableType = receiver == null || receiver.getType().isNullable();
231 }
232 else {
233 nullableType = true;
234 }
235 }
236
237 AnnotationVisitor av =
238 mv.visitParameterAnnotation(i, asmDescByFqNameWithoutInnerClasses(OLD_JET_VALUE_PARAMETER_ANNOTATION), true);
239 if (av != null) {
240 av.visit("name", name);
241 if (nullableType) {
242 av.visit("type", "?");
243 }
244 av.visitEnd();
245 }
246 }
247 }
248
249 private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) {
250 // IDEA's ClsPsi builder fails to annotate synthetic parameters
251 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
252
253 // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac:
254 // see MethodWriter.visitParameterAnnotation()
255
256 AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true);
257 if (av != null) {
258 av.visitEnd();
259 }
260 }
261
262 @Nullable
263 private static Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JetTypeMapper typeMapper) {
264 ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
265 if (functionDescriptor instanceof ConstructorDescriptor) {
266 return typeMapper.mapType(functionDescriptor);
267 }
268 else if (expectedThisObject != null) {
269 return typeMapper.mapType(expectedThisObject.getType());
270 }
271 else if (isFunctionLiteral(functionDescriptor) || isLocalNamedFun(functionDescriptor)) {
272 return typeMapper.mapType(context.getThisDescriptor());
273 }
274 else {
275 return null;
276 }
277 }
278
279 public static void generateMethodBody(
280 @NotNull MethodVisitor mv,
281 @NotNull FunctionDescriptor functionDescriptor,
282 @NotNull MethodContext context,
283 @NotNull JvmMethodSignature signature,
284 @NotNull FunctionGenerationStrategy strategy,
285 @NotNull MemberCodegen<?> parentCodegen
286 ) {
287 mv.visitCode();
288
289 Label methodBegin = new Label();
290 mv.visitLabel(methodBegin);
291
292 JetTypeMapper typeMapper = parentCodegen.typeMapper;
293
294 if (context.getParentContext() instanceof PackageFacadeContext) {
295 generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
296 }
297 else {
298 FrameMap frameMap = strategy.getFrameMap(typeMapper, context);
299
300 for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
301 frameMap.enter(parameter, typeMapper.mapType(parameter));
302 }
303
304 Label methodEntry = new Label();
305 mv.visitLabel(methodEntry);
306 context.setMethodStartLabel(methodEntry);
307
308 if (!JetTypeMapper.isAccessor(functionDescriptor)) {
309 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap);
310 }
311
312 strategy.generateBody(mv, signature, context, parentCodegen);
313 }
314
315 Label methodEnd = new Label();
316 mv.visitLabel(methodEnd);
317
318 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
319 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
320 }
321
322 private static void generateLocalVariableTable(
323 @NotNull MethodVisitor mv,
324 @NotNull JvmMethodSignature jvmMethodSignature,
325 @NotNull FunctionDescriptor functionDescriptor,
326 @Nullable Type thisType,
327 @NotNull Label methodBegin,
328 @NotNull Label methodEnd,
329 @NotNull OwnerKind ownerKind
330 ) {
331 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
332 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
333 int shift = 0;
334
335 boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
336 if (!isStatic) {
337 //add this
338 if (thisType != null) {
339 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
340 } else {
341 //TODO: provide thisType for callable reference
342 }
343 shift++;
344 }
345
346 for (int i = 0; i < params.size(); i++) {
347 JvmMethodParameterSignature param = params.get(i);
348 JvmMethodParameterKind kind = param.getKind();
349 String parameterName;
350
351 if (kind == JvmMethodParameterKind.VALUE) {
352 ValueParameterDescriptor parameter = valueParameters.next();
353 parameterName = parameter.getName().asString();
354 }
355 else {
356 String lowercaseKind = kind.name().toLowerCase();
357 parameterName = needIndexForVar(kind)
358 ? "$" + lowercaseKind + "$" + i
359 : "$" + lowercaseKind;
360 }
361
362 Type type = param.getAsmType();
363 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
364 shift += type.getSize();
365 }
366 }
367
368 private static void generateStaticDelegateMethodBody(
369 @NotNull MethodVisitor mv,
370 @NotNull Method asmMethod,
371 @NotNull PackageFacadeContext context
372 ) {
373 InstructionAdapter iv = new InstructionAdapter(mv);
374 Type[] argTypes = asmMethod.getArgumentTypes();
375
376 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it
377 // This is similar to what javac does with bridge methods
378 Label label = new Label();
379 iv.visitLabel(label);
380 iv.visitLineNumber(1, label);
381
382 int k = 0;
383 for (Type argType : argTypes) {
384 iv.load(k, argType);
385 k += argType.getSize();
386 }
387 iv.invokestatic(context.getDelegateToClassType().getInternalName(), asmMethod.getName(), asmMethod.getDescriptor());
388 iv.areturn(asmMethod.getReturnType());
389 }
390
391 private static boolean needIndexForVar(JvmMethodParameterKind kind) {
392 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE || kind == JvmMethodParameterKind.SUPER_OF_ANONYMOUS_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 }
399 catch (ProcessCanceledException e) {
400 throw e;
401 }
402 catch (Throwable t) {
403 String bytecode = renderByteCodeIfAvailable(mv);
404 throw new CompilationException(
405 "wrong code generated" +
406 (description != null ? " for " + description : "") +
407 t.getClass().getName() +
408 " " +
409 t.getMessage() +
410 (bytecode != null ? "\nbytecode:\n" + bytecode : ""),
411 t, method);
412 }
413 mv.visitEnd();
414 }
415
416 private static String renderByteCodeIfAvailable(MethodVisitor mv) {
417 String bytecode = null;
418 if (mv instanceof TraceMethodVisitor) {
419 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv;
420 StringWriter sw = new StringWriter();
421 PrintWriter pw = new PrintWriter(sw);
422 traceMethodVisitor.p.print(pw);
423 pw.close();
424 bytecode = sw.toString();
425 }
426 return bytecode;
427 }
428
429 public void generateBridges(@NotNull FunctionDescriptor descriptor) {
430 if (descriptor instanceof ConstructorDescriptor) return;
431 if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
432 if (isTrait(descriptor.getContainingDeclaration())) return;
433
434 // equals(Any?), hashCode(), toString() never need bridges
435 if (isMethodOfAny(descriptor)) return;
436
437 // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
438 if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return;
439
440 Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor(
441 descriptor,
442 new Function1<FunctionDescriptor, Method>() {
443 @Override
444 public Method invoke(FunctionDescriptor descriptor) {
445 return typeMapper.mapSignature(descriptor).getAsmMethod();
446 }
447 }
448 );
449
450 if (!bridgesToGenerate.isEmpty()) {
451 PsiElement origin = descriptor.getKind() == DECLARATION ? callableDescriptorToDeclaration(bindingContext, descriptor) : null;
452 for (Bridge<Method> bridge : bridgesToGenerate) {
453 generateBridge(origin, bridge.getFrom(), bridge.getTo());
454 }
455 }
456 }
457
458 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
459 String name = descriptor.getName().asString();
460 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
461 if (parameters.isEmpty()) {
462 return name.equals("hashCode") || name.equals("toString");
463 }
464 else if (parameters.size() == 1 && name.equals("equals")) {
465 ValueParameterDescriptor parameter = parameters.get(0);
466 return parameter.getType().equals(KotlinBuiltIns.getInstance().getNullableAnyType());
467 }
468 return false;
469 }
470
471 @NotNull
472 private static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
473 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
474 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
475
476 Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values();
477 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
478
479 Object value = values.iterator().next();
480 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
481 ArrayValue arrayValue = (ArrayValue) value;
482
483 List<String> strings = ContainerUtil.mapNotNull(
484 arrayValue.getValue(),
485 new Function<CompileTimeConstant<?>, String>() {
486 @Override
487 public String fun(CompileTimeConstant<?> constant) {
488 if (constant instanceof JavaClassValue) {
489 JavaClassValue classValue = (JavaClassValue) constant;
490 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
491 return mapper.mapClass(classDescriptor).getInternalName();
492 }
493 return null;
494 }
495 }
496 );
497 return strings.toArray(new String[strings.size()]);
498 }
499
500 static void generateConstructorWithoutParametersIfNeeded(
501 @NotNull GenerationState state,
502 @NotNull CallableMethod method,
503 @NotNull ConstructorDescriptor constructorDescriptor,
504 @NotNull ClassBuilder classBuilder
505 ) {
506 if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
507 return;
508 }
509 int flags = getVisibilityAccessFlag(constructorDescriptor);
510 MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null,
511 getThrownExceptions(constructorDescriptor, state.getTypeMapper()));
512
513 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
514
515 InstructionAdapter v = new InstructionAdapter(mv);
516 mv.visitCode();
517
518 Type methodOwner = method.getOwner();
519 v.load(0, methodOwner); // Load this on stack
520
521 int mask = 0;
522 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
523 Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
524 pushDefaultValueOnStack(paramType, v);
525 mask |= (1 << parameterDescriptor.getIndex());
526 }
527 v.iconst(mask);
528 String desc = method.getAsmMethod().getDescriptor().replace(")", "I)");
529 v.invokespecial(methodOwner.getInternalName(), "<init>", desc);
530 v.areturn(Type.VOID_TYPE);
531 endVisit(mv, "default constructor for " + methodOwner.getInternalName(), null);
532 }
533
534 void generateDefaultIfNeeded(
535 @NotNull MethodContext owner,
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 = getVisibilityAccessFlag(functionDescriptor) | getDeprecatedAccessFlag(functionDescriptor);
558
559 Type ownerType = typeMapper.mapOwner(functionDescriptor, true);
560 String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
561 boolean isConstructor = "<init>".equals(jvmSignature.getName());
562 if (!isStatic && !isConstructor) {
563 descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
564 }
565 MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
566 isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
567 descriptor, null,
568 getThrownExceptions(functionDescriptor, typeMapper));
569
570 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
571 generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy);
572
573 }
574 }
575
576 private void generateDefaultImpl(
577 @NotNull MethodContext methodContext,
578 @NotNull JvmMethodSignature signature,
579 @NotNull FunctionDescriptor functionDescriptor,
580 boolean aStatic,
581 @NotNull MethodVisitor mv,
582 @NotNull DefaultParameterValueLoader loadStrategy
583 ) {
584 mv.visitCode();
585
586 FrameMap frameMap = new FrameMap();
587
588 if (!aStatic) {
589 frameMap.enterTemp(OBJECT_TYPE);
590 }
591
592 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, getParentCodegen());
593
594 Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
595 List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
596 Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator();
597
598 int countOfExtraVarsInMethodArgs = 0;
599
600 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) {
601 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
602 countOfExtraVarsInMethodArgs++;
603 frameMap.enterTemp(parameterSignature.getAsmType());
604 }
605 else {
606 frameMap.enter(iterator.next(), parameterSignature.getAsmType());
607 }
608 }
609
610 int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
611
612 InstructionAdapter iv = new InstructionAdapter(mv);
613 loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature);
614
615 for (int index = 0; index < paramDescrs.size(); index++) {
616 ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
617
618 Type t = argTypes[countOfExtraVarsInMethodArgs + index];
619
620 if (parameterDescriptor.declaresDefaultValue()) {
621 iv.load(maskIndex, Type.INT_TYPE);
622 iv.iconst(1 << index);
623 iv.and(Type.INT_TYPE);
624 Label loadArg = new Label();
625 iv.ifeq(loadArg);
626
627 loadStrategy.putValueOnStack(parameterDescriptor, codegen);
628
629 int ind = frameMap.getIndex(parameterDescriptor);
630 iv.store(ind, t);
631
632 iv.mark(loadArg);
633 }
634
635 iv.load(frameMap.getIndex(parameterDescriptor), t);
636 }
637
638 CallableMethod method;
639 if (functionDescriptor instanceof ConstructorDescriptor) {
640 method = typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
641 } else {
642 method = typeMapper.mapToCallableMethod(functionDescriptor, false, methodContext);
643 }
644
645 iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getAsmMethod().getName(),
646 method.getAsmMethod().getDescriptor());
647
648 iv.areturn(signature.getReturnType());
649
650 endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
651 }
652
653
654 private static void loadExplicitArgumentsOnStack(
655 @NotNull InstructionAdapter iv,
656 @NotNull Type ownerType,
657 boolean isStatic,
658 @NotNull JvmMethodSignature signature
659 ) {
660 int var = 0;
661 if (!isStatic) {
662 iv.load(var, ownerType);
663 var += ownerType.getSize();
664 }
665
666 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) {
667 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
668 Type type = parameterSignature.getAsmType();
669 iv.load(var, type);
670 var += type.getSize();
671 }
672 }
673 }
674
675 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
676 boolean needed = false;
677 if (functionDescriptor != null) {
678 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
679 if (parameterDescriptor.declaresDefaultValue()) {
680 needed = true;
681 break;
682 }
683 }
684 }
685 return needed;
686 }
687
688 private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
689 ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
690
691 if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
692
693 if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
694 constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false;
695
696 if (constructorDescriptor.getValueParameters().isEmpty()) return false;
697
698 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
699 if (!parameterDescriptor.declaresDefaultValue()) {
700 return false;
701 }
702 }
703 return true;
704 }
705
706 private void generateBridge(@Nullable PsiElement origin, @NotNull Method bridge, @NotNull Method delegateTo) {
707 int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
708
709 MethodVisitor mv = v.newMethod(null, flags, delegateTo.getName(), bridge.getDescriptor(), null, null);
710 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
711
712 mv.visitCode();
713
714 Type[] argTypes = bridge.getArgumentTypes();
715 Type[] originalArgTypes = delegateTo.getArgumentTypes();
716
717 InstructionAdapter iv = new InstructionAdapter(mv);
718 iv.load(0, OBJECT_TYPE);
719 for (int i = 0, reg = 1; i < argTypes.length; i++) {
720 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
721 //noinspection AssignmentToForLoopParameter
722 reg += argTypes[i].getSize();
723 }
724
725 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
726
727 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
728 iv.areturn(bridge.getReturnType());
729
730 endVisit(mv, "bridge method", origin);
731 }
732
733 public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
734 genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field,
735 typeMapper.mapSignature(functionDescriptor),
736 typeMapper.mapSignature(overriddenDescriptor.getOriginal())
737 );
738 }
739
740 public void genDelegate(
741 FunctionDescriptor functionDescriptor,
742 ClassDescriptor toClass,
743 StackValue field,
744 JvmMethodSignature jvmDelegateMethodSignature,
745 JvmMethodSignature jvmOverriddenMethodSignature
746 ) {
747 Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
748 Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
749
750 int flags = ACC_PUBLIC;
751
752 MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null,
753 getThrownExceptions(functionDescriptor, typeMapper));
754 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
755
756 mv.visitCode();
757
758 Type[] argTypes = delegateMethod.getArgumentTypes();
759 Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
760
761 InstructionAdapter iv = new InstructionAdapter(mv);
762 iv.load(0, OBJECT_TYPE);
763 field.put(field.type, iv);
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 String internalName = typeMapper.mapType(toClass).getInternalName();
771 if (toClass.getKind() == ClassKind.TRAIT) {
772 iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
773 }
774 else {
775 iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
776 }
777
778 StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
779
780 iv.areturn(delegateMethod.getReturnType());
781 endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
782 descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
783
784 generateBridges(functionDescriptor);
785 }
786 }