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