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