@NotNull private static FrameMap createFrameMap( @NotNull GenerationState state, @NotNull FunctionDescriptor function, @NotNull JvmMethodSignature signature, boolean isStatic) { FrameMap frameMap = new FrameMap(); if (!isStatic) { frameMap.enterTemp(OBJECT_TYPE); } for (JvmMethodParameterSignature parameter : signature.getValueParameters()) { if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) { ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter(); if (receiverParameter != null) { frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter)); } } else if (parameter.getKind() != JvmMethodParameterKind.VALUE) { frameMap.enterTemp(parameter.getAsmType()); } } for (ValueParameterDescriptor parameter : function.getValueParameters()) { frameMap.enter(parameter, state.getTypeMapper().mapType(parameter)); } return frameMap; }
private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { String name = descriptor.getName().asString(); List<ValueParameterDescriptor> parameters = descriptor.getValueParameters(); if (parameters.isEmpty()) { return name.equals("hashCode") || name.equals("toString"); } else if (parameters.size() == 1 && name.equals("equals")) { return isNullableAny(parameters.get(0).getType()); } return false; }
private void generateParameterAnnotations( @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodVisitor mv, @NotNull JvmMethodSignature jvmSignature) { Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator(); List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters(); for (int i = 0; i < kotlinParameterTypes.size(); i++) { JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i); JvmMethodParameterKind kind = parameterSignature.getKind(); if (kind.isSkippedInGenericSignature()) { markEnumOrInnerConstructorParameterAsSynthetic(mv, i); continue; } if (kind == JvmMethodParameterKind.VALUE) { ValueParameterDescriptor parameter = iterator.next(); if (parameter.getIndex() != i) { v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i); } AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper); if (functionDescriptor instanceof PropertySetterDescriptor) { PropertyDescriptor propertyDescriptor = ((PropertySetterDescriptor) functionDescriptor).getCorrespondingProperty(); Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(propertyDescriptor); annotationCodegen.genAnnotations( targetedAnnotations, parameterSignature.getAsmType(), SETTER_PARAMETER); } if (functionDescriptor instanceof ConstructorDescriptor) { annotationCodegen.genAnnotations( parameter, parameterSignature.getAsmType(), CONSTRUCTOR_PARAMETER); } else { annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType()); } } else if (kind == JvmMethodParameterKind.RECEIVER) { ReceiverParameterDescriptor receiver = ((functionDescriptor instanceof PropertyAccessorDescriptor) ? ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty() : functionDescriptor) .getExtensionReceiverParameter(); if (receiver != null) { AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper); Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(receiver.getType()); annotationCodegen.genAnnotations( targetedAnnotations, parameterSignature.getAsmType(), RECEIVER); } } } }
private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) { boolean needed = false; if (functionDescriptor != null) { for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { if (parameterDescriptor.declaresDefaultValue()) { needed = true; break; } } } return needed; }
@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); }
private static void generateTypeCheckBarrierIfNeeded( @NotNull InstructionAdapter iv, @NotNull FunctionDescriptor descriptor, @NotNull Type returnType, @Nullable final Type delegateParameterType) { BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction( descriptor); if (defaultValue == null) return; assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor; boolean isCheckForAny = delegateParameterType == null || OBJECT_TYPE.equals(delegateParameterType); final KotlinType kotlinType = descriptor.getValueParameters().get(0).getType(); if (isCheckForAny && TypeUtils.isNullableType(kotlinType)) return; iv.load(1, OBJECT_TYPE); Label afterBarrier = new Label(); if (isCheckForAny) { assert !TypeUtils.isNullableType(kotlinType) : "Only bridges for not-nullable types are necessary"; iv.ifnonnull(afterBarrier); } else { CodegenUtilKt.generateIsCheck(iv, kotlinType, boxType(delegateParameterType)); iv.ifne(afterBarrier); } StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv); iv.areturn(returnType); iv.visitLabel(afterBarrier); }
@NotNull public static FunctionDescriptor getErasedInvokeFunction( @NotNull FunctionDescriptor elementDescriptor) { int arity = elementDescriptor.getValueParameters().size(); ClassDescriptor elementClass = elementDescriptor.getExtensionReceiverParameter() == null ? getBuiltIns(elementDescriptor).getFunction(arity) : getBuiltIns(elementDescriptor).getExtensionFunction(arity); return elementClass .getDefaultType() .getMemberScope() .getFunctions(OperatorConventions.INVOKE) .iterator() .next(); }
private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) { if (bridge.equals(delegate)) return; MethodVisitor mv = v.newMethod( OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); ImplementationBodyCodegen.markLineNumberForSyntheticFunction( DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv); iv.load(0, asmType); ReceiverParameterDescriptor receiver = funDescriptor.getExtensionReceiverParameter(); int count = 1; if (receiver != null) { StackValue.local(count, bridge.getArgumentTypes()[count - 1]) .put(typeMapper.mapType(receiver.getType()), iv); count++; } List<ValueParameterDescriptor> params = funDescriptor.getValueParameters(); for (ValueParameterDescriptor param : params) { StackValue.local(count, bridge.getArgumentTypes()[count - 1]) .put(typeMapper.mapType(param.getType()), iv); count++; } iv.invokevirtual( asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false); StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); iv.areturn(bridge.getReturnType()); FunctionCodegen.endVisit(mv, "bridge", element); }
private static void generateLocalVariableTable( @NotNull MethodVisitor mv, @NotNull JvmMethodSignature jvmMethodSignature, @NotNull FunctionDescriptor functionDescriptor, @Nullable Type thisType, @NotNull Label methodBegin, @NotNull Label methodEnd, @NotNull OwnerKind ownerKind) { Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator(); List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters(); int shift = 0; boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor); if (!isStatic) { // add this if (thisType != null) { mv.visitLocalVariable( "this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift); } else { // TODO: provide thisType for callable reference } shift++; } for (int i = 0; i < params.size(); i++) { JvmMethodParameterSignature param = params.get(i); JvmMethodParameterKind kind = param.getKind(); String parameterName; if (kind == JvmMethodParameterKind.VALUE) { ValueParameterDescriptor parameter = valueParameters.next(); parameterName = parameter.getName().asString(); } else { String lowercaseKind = kind.name().toLowerCase(); parameterName = needIndexForVar(kind) ? "$" + lowercaseKind + "$" + i : "$" + lowercaseKind; } Type type = param.getAsmType(); mv.visitLocalVariable( parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); shift += type.getSize(); } }
@NotNull private Method generateConstructor(@NotNull Type superClassAsmType) { List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); Type[] argTypes = fieldListToTypeArray(args); Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); MethodVisitor mv = v.newMethod( OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); int k = 1; for (FieldInfo fieldInfo : args) { k = genAssignInstanceFieldFromParam(fieldInfo, k, iv); } iv.load(0, superClassAsmType); if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE)) { int arity = funDescriptor.getValueParameters().size(); if (funDescriptor.getExtensionReceiverParameter() != null) arity++; if (funDescriptor.getDispatchReceiverParameter() != null) arity++; iv.iconst(arity); iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false); } else { iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false); } iv.visitInsn(RETURN); FunctionCodegen.endVisit(iv, "constructor", element); } return constructor; }
public static void generateDefaultImplBody( @NotNull MethodContext methodContext, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodVisitor mv, @NotNull DefaultParameterValueLoader loadStrategy, @Nullable KtNamedFunction function, @NotNull MemberCodegen<?> parentCodegen, @NotNull Method defaultMethod) { GenerationState state = parentCodegen.state; JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind()); boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor); FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic); ExpressionCodegen codegen = new ExpressionCodegen( mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen); CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function); InstructionAdapter iv = new InstructionAdapter(mv); genDefaultSuperCallCheckIfNeeded(iv, defaultMethod); loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters(); int capturedArgumentsCount = 0; while (capturedArgumentsCount < mappedParameters.size() && mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) { capturedArgumentsCount++; } int maskIndex = 0; List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); for (int index = 0; index < valueParameters.size(); index++) { if (index % Integer.SIZE == 0) { maskIndex = frameMap.enterTemp(Type.INT_TYPE); } ValueParameterDescriptor parameterDescriptor = valueParameters.get(index); Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType(); int parameterIndex = frameMap.getIndex(parameterDescriptor); if (parameterDescriptor.declaresDefaultValue()) { iv.load(maskIndex, Type.INT_TYPE); iv.iconst(1 << (index % Integer.SIZE)); iv.and(Type.INT_TYPE); Label loadArg = new Label(); iv.ifeq(loadArg); StackValue.local(parameterIndex, type) .store(loadStrategy.genValue(parameterDescriptor, codegen), iv); iv.mark(loadArg); } generator.putValueIfNeeded(type, StackValue.local(parameterIndex, type)); } CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false); generator.genCallWithoutAssertions(method, codegen); iv.areturn(signature.getReturnType()); }