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