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 }