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