private void generateBridge( @Nullable PsiElement origin, @NotNull FunctionDescriptor descriptor, @NotNull Method bridge, @NotNull Method delegateTo, boolean isSpecialBridge, boolean isStubDeclarationWithDelegationToSuper) { boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper; int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO. MethodVisitor mv = v.newMethod( JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null); if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; mv.visitCode(); Type[] argTypes = bridge.getArgumentTypes(); Type[] originalArgTypes = delegateTo.getArgumentTypes(); InstructionAdapter iv = new InstructionAdapter(mv); MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv); if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) { generateTypeCheckBarrierIfNeeded( iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]); } iv.load(0, OBJECT_TYPE); for (int i = 0, reg = 1; i < argTypes.length; i++) { StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); //noinspection AssignmentToForLoopParameter reg += argTypes[i].getSize(); } if (isStubDeclarationWithDelegationToSuper) { ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration()); assert parentClass != null; String parentInternalName = typeMapper.mapClass(parentClass).getInternalName(); iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor()); } else { iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); } StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); iv.areturn(bridge.getReturnType()); endVisit(mv, "bridge method", origin); }
private ClassDescriptor recordClassForFunction(FunctionDescriptor funDescriptor) { ClassDescriptor classDescriptor; int arity = funDescriptor.getValueParameters().size(); classDescriptor = new ClassDescriptorImpl( funDescriptor.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), Modality.FINAL, Name.special("<closure>")); ((ClassDescriptorImpl) classDescriptor) .initialize( false, Collections.<TypeParameterDescriptor>emptyList(), Collections.singleton( (funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)) .getDefaultType()), JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null); assert PsiCodegenPredictor.checkPredictedClassNameForFun( bindingContext, funDescriptor, classDescriptor); bindingTrace.record(CLASS_FOR_FUNCTION, funDescriptor, classDescriptor); return classDescriptor; }
public boolean isMain(@NotNull JetNamedFunction function) { if (!"main".equals(function.getName())) return false; FunctionDescriptor functionDescriptor = getFunctionDescriptor.fun(function); List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters(); if (parameters.size() != 1) return false; ValueParameterDescriptor parameter = parameters.get(0); JetType parameterType = parameter.getType(); if (!KotlinBuiltIns.isArray(parameterType)) return false; List<TypeProjection> typeArguments = parameterType.getArguments(); if (typeArguments.size() != 1) return false; JetType typeArgument = typeArguments.get(0).getType(); if (!JetTypeChecker.DEFAULT.equalTypes( typeArgument, getBuiltIns(functionDescriptor).getStringType())) return false; if (DescriptorUtils.isTopLevelDeclaration(functionDescriptor)) return true; DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); return containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind().isSingleton() && AnnotationsPackage.hasPlatformStaticAnnotation(functionDescriptor); }
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { int flags = getCommonCallableFlags(functionDescriptor); if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) { DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); if (!(containingDeclaration instanceof ClassDescriptor) || ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.TRAIT) { flags |= ACC_FINAL; } } if (isStaticMethod(kind, functionDescriptor)) { flags |= ACC_STATIC; } if (isAbstractMethod(functionDescriptor, kind)) { flags |= ACC_ABSTRACT; } if (JetTypeMapper.isAccessor(functionDescriptor)) { flags |= ACC_SYNTHETIC; } return flags; }
public void genDelegate( @NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { genDelegate( functionDescriptor, overriddenDescriptor.getOriginal(), (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field); }
@Override protected void generateBody() { FunctionDescriptor erasedInterfaceFunction; if (samType == null) { erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor); } else { erasedInterfaceFunction = samType.getAbstractMethod().getOriginal(); } generateBridge( typeMapper.mapSignature(erasedInterfaceFunction).getAsmMethod(), typeMapper.mapSignature(funDescriptor).getAsmMethod()); functionCodegen.generateMethod(OtherOrigin(element, funDescriptor), funDescriptor, strategy); // TODO: rewrite cause ugly hack if (samType != null) { SimpleFunctionDescriptorImpl descriptorForBridges = SimpleFunctionDescriptorImpl.create( funDescriptor.getContainingDeclaration(), funDescriptor.getAnnotations(), erasedInterfaceFunction.getName(), CallableMemberDescriptor.Kind.DECLARATION, funDescriptor.getSource()); descriptorForBridges.initialize( null, erasedInterfaceFunction.getDispatchReceiverParameter(), erasedInterfaceFunction.getTypeParameters(), erasedInterfaceFunction.getValueParameters(), erasedInterfaceFunction.getReturnType(), Modality.OPEN, erasedInterfaceFunction.getVisibility()); descriptorForBridges.addOverriddenDescriptor(erasedInterfaceFunction); functionCodegen.generateBridges(descriptorForBridges); } this.constructor = generateConstructor(superClassAsmType); if (isConst(closure)) { generateConstInstance(); } genClosureFields(closure, v, typeMapper); functionCodegen.generateDefaultIfNeeded( context.intoFunction(funDescriptor), funDescriptor, context.getContextKind(), DefaultParameterValueLoader.DEFAULT, null); }
@NotNull @Override public String getText() { if (functionsToAdd.size() == 1) { FunctionDescriptor newFunction = functionsToAdd.get(0); ClassDescriptor supertype = (ClassDescriptor) newFunction.getContainingDeclaration(); return JetBundle.message( "add.function.to.type.action.single", IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(newFunction), supertype.getName().toString()); } else { return JetBundle.message("add.function.to.supertype.action.multiple"); } }
@NotNull private static FunctionDescriptor substituteSuperFunction( @NotNull Map<ClassDescriptor, JetType> superclassToSupertype, @NotNull FunctionDescriptor superFun) { DeclarationDescriptor superFunContainer = superFun.getContainingDeclaration(); assert superFunContainer instanceof ClassDescriptor : superFunContainer; JetType supertype = superclassToSupertype.get(superFunContainer); assert supertype != null : "Couldn't find super type for super function: " + superFun; TypeSubstitutor supertypeSubstitutor = TypeSubstitutor.create(supertype); FunctionDescriptor substitutedSuperFun = superFun.substitute(supertypeSubstitutor); assert substitutedSuperFun != null; return substitutedSuperFun; }
private static List<FunctionDescriptor> generateFunctionsToAdd(JetNamedFunction functionElement) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) ResolvePackage.resolveToDescriptor(functionElement); DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); if (!(containingDeclaration instanceof ClassDescriptor)) return Collections.emptyList(); List<FunctionDescriptor> functions = Lists.newArrayList(); ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; // TODO: filter out impossible supertypes (for example when argument's type isn't visible in a // superclass). for (ClassDescriptor supertypeDescriptor : getSupertypes(classDescriptor)) { if (KotlinBuiltIns.isAnyOrNullableAny(supertypeDescriptor.getDefaultType())) continue; functions.add(generateFunctionSignatureForType(functionDescriptor, supertypeDescriptor)); } return functions; }
private static void equipFunctionReferenceWithReflection( @NotNull InstructionAdapter v, @NotNull FunctionDescriptor target) { DeclarationDescriptor container = target.getContainingDeclaration(); Type type; if (container instanceof PackageFragmentDescriptor) { type = target.getExtensionReceiverParameter() != null ? K_TOP_LEVEL_EXTENSION_FUNCTION : K_TOP_LEVEL_FUNCTION; } else if (container instanceof ClassDescriptor) { type = K_MEMBER_FUNCTION; } else { type = K_LOCAL_FUNCTION; } Method method = method("function", K_FUNCTION, FUNCTION_REFERENCE); v.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false); StackValue.coerce(K_FUNCTION, type, v); }
@Override public void visitNamedFunction(JetNamedFunction function) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); // working around a problem with shallow analysis if (functionDescriptor == null) return; DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); if (containingDeclaration instanceof ClassDescriptor) { nameStack.push(peekFromStack(nameStack) + '$' + function.getName()); super.visitNamedFunction(function); nameStack.pop(); } else if (containingDeclaration instanceof NamespaceDescriptor) { String peek = peekFromStack(nameStack); if (peek.isEmpty()) { peek = JvmAbi.PACKAGE_CLASS; } else { peek += "/" + JvmAbi.PACKAGE_CLASS; } nameStack.push(peek + '$' + function.getName()); super.visitNamedFunction(function); nameStack.pop(); } else { String name = inventAnonymousClassName(function); ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor); recordClosure( bindingTrace, function, classDescriptor, peekFromStack(classStack), JvmClassName.byInternalName(name), true); classStack.push(classDescriptor); nameStack.push(name); super.visitNamedFunction(function); nameStack.pop(); classStack.pop(); } }
public void generateBridges(@NotNull FunctionDescriptor descriptor) { if (descriptor instanceof ConstructorDescriptor) return; if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return; if (isInterface(descriptor.getContainingDeclaration())) return; // equals(Any?), hashCode(), toString() never need bridges if (isMethodOfAny(descriptor)) return; // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter // or alike and doesn't need bridges if (CallResolverUtilKt.isOrOverridesSynthesized(descriptor)) return; boolean isSpecial = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) != null; Set<Bridge<Method>> bridgesToGenerate; if (!isSpecial) { bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor(descriptor, getSignatureMapper(typeMapper)); if (!bridgesToGenerate.isEmpty()) { PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; boolean isSpecialBridge = BuiltinMethodsWithSpecialGenericSignature .getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null; for (Bridge<Method> bridge : bridgesToGenerate) { generateBridge( origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false); } } } else { Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial( descriptor, getSignatureMapper(typeMapper)); if (!specials.isEmpty()) { PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; for (BridgeForBuiltinSpecial<Method> bridge : specials) { generateBridge( origin, descriptor, bridge.getFrom(), bridge.getTo(), bridge.isSpecial(), bridge.isDelegateToSuper()); } } if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) { CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor); assert overridden != null; Method method = typeMapper.mapSignature(descriptor).getAsmMethod(); int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor); v.newMethod( JvmDeclarationOriginKt.OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null); } } }
public void generateMethod( @NotNull JvmDeclarationOrigin origin, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext methodContext, @NotNull FunctionGenerationStrategy strategy) { OwnerKind contextKind = methodContext.getContextKind(); if (isInterface(functionDescriptor.getContainingDeclaration()) && functionDescriptor.getVisibility() == Visibilities.PRIVATE && contextKind != OwnerKind.DEFAULT_IMPLS) { return; } JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, contextKind); Method asmMethod = jvmSignature.getAsmMethod(); int flags = getMethodAsmFlags(functionDescriptor, contextKind); boolean isNative = NativeKt.hasNativeAnnotation(functionDescriptor); if (isNative && owner instanceof MultifileClassFacadeContext) { // Native methods are only defined in facades and do not need package part implementations return; } MethodVisitor mv = v.newMethod( origin, flags, asmMethod.getName(), asmMethod.getDescriptor(), jvmSignature.getGenericsSignature(), getThrownExceptions(functionDescriptor, typeMapper)); if (CodegenContextUtil.isImplClassOwner(owner)) { v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod); } generateMethodAnnotations(functionDescriptor, asmMethod, mv); generateParameterAnnotations( functionDescriptor, mv, typeMapper.mapSignature(functionDescriptor)); generateBridges(functionDescriptor); boolean staticInCompanionObject = AnnotationUtilKt.isPlatformStaticInCompanionObject(functionDescriptor); if (staticInCompanionObject) { ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); parentBodyCodegen.addAdditionalTask( new JvmStaticGenerator(functionDescriptor, origin, state)); } if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES || isAbstractMethod(functionDescriptor, contextKind)) { generateLocalVariableTable( mv, jvmSignature, functionDescriptor, getThisTypeForFunction(functionDescriptor, methodContext, typeMapper), new Label(), new Label(), contextKind); mv.visitEnd(); return; } if (!isNative) { generateMethodBody( mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen); } else if (staticInCompanionObject) { // native @JvmStatic foo() in companion object should delegate to the static native function // moved to the outer class mv.visitCode(); FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor); JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature( memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null)); Type owningType = typeMapper.mapClass( (ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration()); generateDelegateToMethodBody( false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName()); } endVisit(mv, null, origin.getElement()); }
public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { return (functionDescriptor.getModality() == Modality.ABSTRACT || isInterface(functionDescriptor.getContainingDeclaration())) && !isStaticMethod(kind, functionDescriptor); }