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