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