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