use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.
the class MethodInliner method putStackValuesIntoLocals.
private static void putStackValuesIntoLocals(@NotNull List<Type> directOrder, int shift, @NotNull InstructionAdapter iv, @NotNull String descriptor) {
Type[] actualParams = Type.getArgumentTypes(descriptor);
assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
int size = 0;
for (Type next : directOrder) {
size += next.getSize();
}
shift += size;
int index = directOrder.size();
for (Type next : Lists.reverse(directOrder)) {
shift -= next.getSize();
Type typeOnStack = actualParams[--index];
if (!typeOnStack.equals(next)) {
StackValue.onStack(typeOnStack).put(next, iv);
}
iv.store(shift, next);
}
}
use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.
the class MethodInliner method doInline.
@NotNull
private MethodNode doInline(@NotNull MethodNode node) {
final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);
final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
final Iterator<TransformationInfo> iterator = transformations.iterator();
final TypeRemapper remapper = TypeRemapper.createFrom(currentTypeMapping);
final RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode, new AsmTypeRemapper(remapper, inliningContext.getRoot().typeParameterMappings == null, result));
final int markerShift = InlineCodegenUtil.calcMarkerShift(parameters, node);
InlineAdapter lambdaInliner = new InlineAdapter(remappingMethodAdapter, parameters.getArgsSizeOnStack(), sourceMapper) {
private TransformationInfo transformationInfo;
private void handleAnonymousObjectRegeneration() {
transformationInfo = iterator.next();
String oldClassName = transformationInfo.getOldClassName();
if (transformationInfo.shouldRegenerate(isSameModule)) {
//TODO: need poping of type but what to do with local funs???
String newClassName = transformationInfo.getNewClassName();
remapper.addMapping(oldClassName, newClassName);
InliningContext childInliningContext = inliningContext.subInlineWithClassRegeneration(inliningContext.nameGenerator, currentTypeMapping, inlineCallSiteInfo);
ObjectTransformer transformer = transformationInfo.createTransformer(childInliningContext, isSameModule);
InlineResult transformResult = transformer.doTransform(nodeRemapper);
result.merge(transformResult);
result.addChangedType(oldClassName, newClassName);
if (inliningContext.isInliningLambda && transformationInfo.canRemoveAfterTransformation()) {
// this class is transformed and original not used so we should remove original one after inlining
result.addClassToRemove(oldClassName);
}
if (transformResult.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
ReifiedTypeInliner.putNeedClassReificationMarker(mv);
result.getReifiedTypeParametersUsages().mergeAll(transformResult.getReifiedTypeParametersUsages());
}
} else if (!transformationInfo.getWasAlreadyRegenerated()) {
result.addNotChangedClass(oldClassName);
}
}
@Override
public void anew(@NotNull Type type) {
if (isAnonymousClass(type.getInternalName())) {
handleAnonymousObjectRegeneration();
}
//in case of regenerated transformationInfo type would be remapped to new one via remappingMethodAdapter
super.anew(type);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (/*INLINE_RUNTIME.equals(owner) &&*/
isInvokeOnLambda(owner, name)) {
//TODO add method
assert !currentInvokes.isEmpty();
InvokeCall invokeCall = currentInvokes.remove();
LambdaInfo info = invokeCall.lambdaInfo;
if (info == null) {
//noninlinable lambda
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
//NB: don't inline cause it changes
int valueParamShift = Math.max(getNextLocalIndex(), markerShift);
putStackValuesIntoLocals(info.getInvokeParamsWithoutCaptured(), valueParamShift, this, desc);
if (invokeCall.lambdaInfo.getFunctionDescriptor().getValueParameters().isEmpty()) {
// There won't be no parameters processing and line call can be left without actual instructions.
// Note: if function is called on the line with other instructions like 1 + foo(), 'nop' will still be generated.
visitInsn(Opcodes.NOP);
}
addInlineMarker(this, true);
Parameters lambdaParameters = info.addAllParameters(nodeRemapper);
InlinedLambdaRemapper newCapturedRemapper = new InlinedLambdaRemapper(info.getLambdaClassType().getInternalName(), nodeRemapper, lambdaParameters);
setLambdaInlining(true);
SMAP lambdaSMAP = info.getNode().getClassSMAP();
//noinspection ConstantConditions
SourceMapper mapper = inliningContext.classRegeneration && !inliningContext.isInliningLambda ? new NestedSourceMapper(sourceMapper, lambdaSMAP.getIntervals(), lambdaSMAP.getSourceInfo()) : new InlineLambdaSourceMapper(sourceMapper.getParent(), info.getNode());
MethodInliner inliner = new MethodInliner(info.getNode().getNode(), lambdaParameters, inliningContext.subInlineLambda(info), newCapturedRemapper, true, /*cause all calls in same module as lambda*/
"Lambda inlining " + info.getLambdaClassType().getInternalName(), mapper, inlineCallSiteInfo, null);
LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift);
//TODO add skipped this and receiver
InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift);
result.mergeWithNotChangeInfo(lambdaResult);
result.getReifiedTypeParametersUsages().mergeAll(lambdaResult.getReifiedTypeParametersUsages());
//return value boxing/unboxing
Method bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()));
Method delegate = typeMapper.mapAsmMethod(info.getFunctionDescriptor());
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
setLambdaInlining(false);
addInlineMarker(this, false);
mapper.endMapping();
if (inlineOnlySmapSkipper != null) {
inlineOnlySmapSkipper.markCallSiteLineNumber(remappingMethodAdapter);
}
} else if (isAnonymousConstructorCall(owner, name)) {
//TODO add proper message
assert transformationInfo instanceof AnonymousObjectTransformationInfo : "<init> call doesn't correspond to object transformation info: " + owner + "." + name + ", info " + transformationInfo;
InliningContext parent = inliningContext.getParent();
boolean shouldRegenerate = transformationInfo.shouldRegenerate(isSameModule);
boolean isContinuation = parent != null && parent.isContinuation();
if (shouldRegenerate || isContinuation) {
assert shouldRegenerate || inlineCallSiteInfo.getOwnerClassName().equals(transformationInfo.getOldClassName()) : "Only coroutines can call their own constructors";
//put additional captured parameters on stack
AnonymousObjectTransformationInfo info = (AnonymousObjectTransformationInfo) transformationInfo;
AnonymousObjectTransformationInfo oldInfo = inliningContext.findAnonymousObjectTransformationInfo(owner);
if (oldInfo != null && isContinuation) {
info = oldInfo;
}
for (CapturedParamDesc capturedParamDesc : info.getAllRecapturedParameters()) {
visitFieldInsn(Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(), "$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor());
}
super.visitMethodInsn(opcode, info.getNewClassName(), name, info.getNewConstructorDescriptor(), itf);
//TODO: add new inner class also for other contexts
if (inliningContext.getParent() instanceof RegeneratedClassContext) {
inliningContext.getParent().typeRemapper.addAdditionalMappings(transformationInfo.getOldClassName(), transformationInfo.getNewClassName());
}
transformationInfo = null;
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
} else if (!inliningContext.isInliningLambda && ReifiedTypeInliner.isNeedClassReificationMarker(new MethodInsnNode(opcode, owner, name, desc, false))) {
//we shouldn't process here content of inlining lambda it should be reified at external level
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
@Override
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
if (opcode == Opcodes.GETSTATIC && (isAnonymousSingletonLoad(owner, name) || isWhenMappingAccess(owner, name))) {
handleAnonymousObjectRegeneration();
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitMaxs(int stack, int locals) {
lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
super.visitMaxs(stack, locals);
}
};
node.accept(lambdaInliner);
return resultNode;
}
use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.
the class MethodInliner method prepareNode.
@NotNull
private MethodNode prepareNode(@NotNull MethodNode node, int finallyDeepShift) {
final int capturedParamsSize = parameters.getCapturedParametersSizeOnStack();
final int realParametersSize = parameters.getRealParametersSizeOnStack();
Type[] types = Type.getArgumentTypes(node.desc);
Type returnType = Type.getReturnType(node.desc);
List<Type> capturedTypes = parameters.getCapturedTypes();
Type[] allTypes = ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()]));
node.instructions.resetLabels();
MethodNode transformedNode = new MethodNode(InlineCodegenUtil.API, node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null) {
@SuppressWarnings("ConstantConditions")
private final boolean GENERATE_DEBUG_INFO = InlineCodegenUtil.GENERATE_SMAP && inlineOnlySmapSkipper == null;
private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda();
private int getNewIndex(int var) {
return var + (var < realParametersSize ? 0 : capturedParamsSize);
}
@Override
public void visitVarInsn(int opcode, int var) {
super.visitVarInsn(opcode, getNewIndex(var));
}
@Override
public void visitIincInsn(int var, int increment) {
super.visitIincInsn(getNewIndex(var), increment);
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(maxStack, maxLocals + capturedParamsSize);
}
@Override
public void visitLineNumber(int line, @NotNull Label start) {
if (isInliningLambda || GENERATE_DEBUG_INFO) {
super.visitLineNumber(line, start);
}
}
@Override
public void visitLocalVariable(@NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index) {
if (isInliningLambda || GENERATE_DEBUG_INFO) {
String varSuffix = inliningContext.isRoot() && !InlineCodegenUtil.isFakeLocalVariableForInline(name) ? INLINE_FUN_VAR_SUFFIX : "";
String varName = !varSuffix.isEmpty() && name.equals("this") ? name + "_" : name;
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index));
}
}
};
node.accept(transformedNode);
transformCaptured(transformedNode);
transformFinallyDeepIndex(transformedNode, finallyDeepShift);
return transformedNode;
}
use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.
the class KotlinTypeMapper method mapToCallableMethod.
@NotNull
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall) {
if (descriptor instanceof ConstructorDescriptor) {
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal());
Type owner = mapOwner(descriptor);
String defaultImplDesc = mapDefaultMethod(descriptor.getOriginal(), OwnerKind.IMPLEMENTATION).getDescriptor();
return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null, false);
}
if (descriptor instanceof LocalVariableAccessorDescriptor) {
ResolvedCall<FunctionDescriptor> delegateAccessorResolvedCall = bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, (VariableAccessorDescriptor) descriptor);
//noinspection ConstantConditions
return mapToCallableMethod(delegateAccessorResolvedCall.getResultingDescriptor(), false);
}
DeclarationDescriptor functionParent = descriptor.getOriginal().getContainingDeclaration();
FunctionDescriptor functionDescriptor = findSuperDeclaration(descriptor.getOriginal(), superCall);
JvmMethodSignature signature;
Type owner;
Type ownerForDefaultImpl;
FunctionDescriptor baseMethodDescriptor;
int invokeOpcode;
Type thisClass;
boolean isInterfaceMember = false;
if (functionParent instanceof ClassDescriptor) {
FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
boolean originalIsInterface = isJvmInterface(declarationOwner);
boolean currentIsInterface = isJvmInterface(currentOwner);
boolean isInterface = currentIsInterface && originalIsInterface;
baseMethodDescriptor = findBaseDeclaration(functionDescriptor).getOriginal();
ClassDescriptor ownerForDefault = (ClassDescriptor) baseMethodDescriptor.getContainingDeclaration();
ownerForDefaultImpl = isJvmInterface(ownerForDefault) && !isJvm8InterfaceWithDefaults(ownerForDefault) ? mapDefaultImpls(ownerForDefault) : mapClass(ownerForDefault);
if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) {
thisClass = mapClass(currentOwner);
if (declarationOwner instanceof JavaClassDescriptor || isJvm8InterfaceWithDefaults(declarationOwner)) {
invokeOpcode = INVOKESPECIAL;
signature = mapSignatureSkipGeneric(functionDescriptor);
owner = thisClass;
isInterfaceMember = true;
} else {
invokeOpcode = INVOKESTATIC;
signature = mapSignatureSkipGeneric(descriptor.getOriginal(), OwnerKind.DEFAULT_IMPLS);
owner = mapDefaultImpls(currentOwner);
}
} else {
boolean isStaticInvocation = (isStaticDeclaration(functionDescriptor) && !(functionDescriptor instanceof ImportedFromObjectCallableDescriptor)) || isStaticAccessor(functionDescriptor) || CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
if (isStaticInvocation) {
invokeOpcode = INVOKESTATIC;
isInterfaceMember = currentIsInterface && currentOwner instanceof JavaClassDescriptor;
} else if (isInterface) {
invokeOpcode = INVOKEINTERFACE;
isInterfaceMember = true;
} else {
boolean isPrivateFunInvocation = Visibilities.isPrivate(functionDescriptor.getVisibility());
invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
isInterfaceMember = superCall && currentIsInterface;
}
FunctionDescriptor overriddenSpecialBuiltinFunction = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(functionDescriptor.getOriginal());
FunctionDescriptor functionToCall = overriddenSpecialBuiltinFunction != null && !superCall ? overriddenSpecialBuiltinFunction.getOriginal() : functionDescriptor.getOriginal();
signature = mapSignatureSkipGeneric(functionToCall);
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor ? declarationOwner : currentOwner;
owner = mapClass(receiver);
thisClass = owner;
}
} else {
signature = mapSignatureSkipGeneric(functionDescriptor.getOriginal());
owner = mapOwner(functionDescriptor);
ownerForDefaultImpl = owner;
baseMethodDescriptor = functionDescriptor;
if (functionParent instanceof PackageFragmentDescriptor) {
invokeOpcode = INVOKESTATIC;
thisClass = null;
} else if (functionDescriptor instanceof ConstructorDescriptor) {
invokeOpcode = INVOKESPECIAL;
thisClass = null;
} else {
invokeOpcode = INVOKEVIRTUAL;
thisClass = owner;
}
}
Type calleeType = isLocalFunction(functionDescriptor) ? owner : null;
Type receiverParameterType;
ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getExtensionReceiverParameter();
if (receiverParameter != null) {
receiverParameterType = mapType(receiverParameter.getType());
} else {
receiverParameterType = null;
}
String defaultImplDesc = mapDefaultMethod(baseMethodDescriptor, getKindForDefaultImplCall(baseMethodDescriptor)).getDescriptor();
return new CallableMethod(owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode, thisClass, receiverParameterType, calleeType, isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE);
}
use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.
the class KotlinTypeMapper method mapDefaultMethod.
@NotNull
public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind) {
Method jvmSignature = mapAsmMethod(functionDescriptor, kind);
Type ownerType = mapOwner(functionDescriptor);
boolean isConstructor = isConstructor(jvmSignature);
String descriptor = getDefaultDescriptor(jvmSignature, isStaticMethod(kind, functionDescriptor) || isConstructor ? null : ownerType.getDescriptor(), CodegenUtilKt.unwrapFrontendVersion(functionDescriptor));
return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
}
Aggregations