001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.codegen.inline; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.kotlin.codegen.StackValue; 022 import org.jetbrains.org.objectweb.asm.Opcodes; 023 import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; 024 import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode; 025 import org.jetbrains.org.objectweb.asm.tree.MethodNode; 026 027 import java.util.Collection; 028 import java.util.List; 029 030 public class FieldRemapper { 031 protected FieldRemapper parent; 032 private final String lambdaInternalName; 033 private final Parameters params; 034 035 public FieldRemapper(@Nullable String lambdaInternalName, @Nullable FieldRemapper parent, @NotNull Parameters methodParams) { 036 this.lambdaInternalName = lambdaInternalName; 037 this.parent = parent; 038 this.params = methodParams; 039 } 040 041 protected boolean canProcess(@NotNull String fieldOwner, @NotNull String fieldName, boolean isFolding) { 042 return fieldOwner.equals(getLambdaInternalName()) && 043 //don't process general field of anonymous objects 044 InlineCodegenUtil.isCapturedFieldName(fieldName); 045 } 046 047 @Nullable 048 public AbstractInsnNode foldFieldAccessChainIfNeeded(@NotNull List<AbstractInsnNode> capturedFieldAccess, @NotNull MethodNode node) { 049 if (capturedFieldAccess.size() == 1) { 050 //just aload 051 return null; 052 } 053 054 return foldFieldAccessChainIfNeeded(capturedFieldAccess, 1, node); 055 } 056 057 //TODO: seems that this method is redundant but it added from safety purposes before new milestone 058 public boolean processNonAload0FieldAccessChains(boolean isInlinedLambda) { 059 return false; 060 } 061 062 @Nullable 063 private AbstractInsnNode foldFieldAccessChainIfNeeded( 064 @NotNull List<AbstractInsnNode> capturedFieldAccess, 065 int currentInstruction, 066 @NotNull MethodNode node 067 ) { 068 boolean checkParent = !isRoot() && currentInstruction < capturedFieldAccess.size() - 1; 069 if (checkParent) { 070 AbstractInsnNode transformed = parent.foldFieldAccessChainIfNeeded(capturedFieldAccess, currentInstruction + 1, node); 071 if (transformed != null) { 072 return transformed; 073 } 074 } 075 076 FieldInsnNode insnNode = (FieldInsnNode) capturedFieldAccess.get(currentInstruction); 077 if (canProcess(insnNode.owner, insnNode.name, true)) { 078 insnNode.name = "$$$" + insnNode.name; 079 insnNode.setOpcode(Opcodes.GETSTATIC); 080 081 AbstractInsnNode next = capturedFieldAccess.get(0); 082 while (next != insnNode) { 083 AbstractInsnNode toDelete = next; 084 next = next.getNext(); 085 node.instructions.remove(toDelete); 086 } 087 088 return capturedFieldAccess.get(capturedFieldAccess.size() - 1); 089 } 090 091 return null; 092 } 093 094 @Nullable 095 public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode) { 096 return findField(fieldInsnNode, params.getCaptured()); 097 } 098 099 @Nullable 100 protected CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection<CapturedParamInfo> captured) { 101 for (CapturedParamInfo valueDescriptor : captured) { 102 if (valueDescriptor.getOriginalFieldName().equals(fieldInsnNode.name) && 103 valueDescriptor.getContainingLambdaName().equals(fieldInsnNode.owner)) { 104 return valueDescriptor; 105 } 106 } 107 return null; 108 } 109 110 @NotNull 111 public FieldRemapper getParent() { 112 return parent; 113 } 114 115 public String getLambdaInternalName() { 116 return lambdaInternalName; 117 } 118 119 public String getNewLambdaInternalName() { 120 return lambdaInternalName; 121 } 122 123 public boolean isRoot() { 124 return parent == null; 125 } 126 127 @Nullable 128 public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) { 129 return MethodInliner.findCapturedField(node, this).getRemapValue(); 130 } 131 132 public boolean isInsideInliningLambda() { 133 return !isRoot() && parent.isInsideInliningLambda(); 134 } 135 }