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