org.jetbrains.kotlin.codegen.inline.FieldRemapper Maven / Gradle / Ivy
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.StackValue;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import java.util.Collection;
import java.util.List;
public class FieldRemapper {
private final String lambdaInternalName;
protected FieldRemapper parent;
private final Parameters params;
public FieldRemapper(@Nullable String lambdaInternalName, @Nullable FieldRemapper parent, @NotNull Parameters methodParams) {
this.lambdaInternalName = lambdaInternalName;
this.parent = parent;
params = methodParams;
}
protected boolean canProcess(@NotNull String fieldOwner, String fieldName, boolean isFolding) {
return fieldOwner.equals(getLambdaInternalName()) &&
//don't process general field of anonymous objects
InlineCodegenUtil.isCapturedFieldName(fieldName);
}
@Nullable
public AbstractInsnNode foldFieldAccessChainIfNeeded(
@NotNull List capturedFieldAccess,
@NotNull MethodNode node
) {
if (capturedFieldAccess.size() == 1) {
//just aload
return null;
}
return foldFieldAccessChainIfNeeded(capturedFieldAccess, 1, node);
}
//TODO: seems that this method is redundant but it added from safety purposes before new milestone
public boolean processNonAload0FieldAccessChains(boolean isInlinedLambda) {
return false;
}
@Nullable
private AbstractInsnNode foldFieldAccessChainIfNeeded(
@NotNull List capturedFieldAccess,
int currentInstruction,
@NotNull MethodNode node
) {
AbstractInsnNode transformed = null;
boolean checkParent = !isRoot() && currentInstruction < capturedFieldAccess.size() - 1;
if (checkParent) {
transformed = parent.foldFieldAccessChainIfNeeded(capturedFieldAccess, currentInstruction + 1, node);
}
if (transformed == null) {
//if parent couldn't transform
FieldInsnNode insnNode = (FieldInsnNode) capturedFieldAccess.get(currentInstruction);
if (canProcess(insnNode.owner, insnNode.name, true)) {
insnNode.name = "$$$" + insnNode.name;
insnNode.setOpcode(Opcodes.GETSTATIC);
AbstractInsnNode next = capturedFieldAccess.get(0);
while (next != insnNode) {
AbstractInsnNode toDelete = next;
next = next.getNext();
node.instructions.remove(toDelete);
}
transformed = capturedFieldAccess.get(capturedFieldAccess.size() - 1);
}
}
return transformed;
}
public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode) {
return findField(fieldInsnNode, params.getCaptured());
}
@Nullable
protected CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection captured) {
for (CapturedParamInfo valueDescriptor : captured) {
if (valueDescriptor.getOriginalFieldName().equals(fieldInsnNode.name) && fieldInsnNode.owner.equals(valueDescriptor.getContainingLambdaName())) {
return valueDescriptor;
}
}
return null;
}
public FieldRemapper getParent() {
return parent;
}
public String getLambdaInternalName() {
return lambdaInternalName;
}
public String getNewLambdaInternalName() {
return lambdaInternalName;
}
public boolean isRoot() {
return parent == null;
}
@Nullable
public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) {
CapturedParamInfo field = MethodInliner.findCapturedField(node, this);
return field.getRemapValue();
}
public boolean isInsideInliningLambda() {
return !isRoot() && parent.isInsideInliningLambda();
}
}