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