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