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); }
@NotNull public StackValue putInstanceOnStack( @NotNull final ExpressionCodegen codegen, @Nullable final FunctionDescriptor functionReferenceTarget) { return StackValue.operation( asmType, new Function1<InstructionAdapter, Unit>() { @Override public Unit invoke(InstructionAdapter v) { if (isConst(closure)) { v.getstatic( asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); } else { v.anew(asmType); v.dup(); codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator); v.invokespecial( asmType.getInternalName(), "<init>", constructor.getDescriptor(), false); } if (functionReferenceTarget != null) { equipFunctionReferenceWithReflection(v, functionReferenceTarget); } return Unit.INSTANCE$; } }); }
@Override public void putCapturedValueOnStack( @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) { if (shouldPutValue(stackValue.type, stackValue, null)) { stackValue.put(stackValue.type, codegen.v); } putCapturedInLocal(stackValue.type, stackValue, null, paramIndex); }
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); }
@Override public void putValueIfNeeded( @Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) { if (shouldPutValue(parameterType, value, valueParameterDescriptor)) { value.put(parameterType, codegen.v); } afterParameterPut(parameterType, value, valueParameterDescriptor); }
private void putParameterOnStack(ParameterInfo... infos) { int[] index = new int[infos.length]; for (int i = 0; i < infos.length; i++) { ParameterInfo info = infos[i]; if (!info.isSkippedOrRemapped()) { index[i] = codegen.getFrameMap().enterTemp(info.getType()); } else { index[i] = -1; } } for (int i = infos.length - 1; i >= 0; i--) { ParameterInfo info = infos[i]; if (!info.isSkippedOrRemapped()) { Type type = info.type; StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v); } } }
private static void loadExplicitArgumentsOnStack( @NotNull Type ownerType, boolean isStatic, @NotNull JvmMethodSignature signature, @NotNull CallGenerator callGenerator) { int var = 0; if (!isStatic) { callGenerator.putValueIfNeeded(ownerType, StackValue.local(var, ownerType)); var += ownerType.getSize(); } for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) { if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { Type type = parameterSignature.getAsmType(); callGenerator.putValueIfNeeded(type, StackValue.local(var, type)); var += type.getSize(); } } }
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); }
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); }
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()); }