001 /* 002 * Copyright 2010-2013 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.jet.codegen.inline; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.asm4.Opcodes; 022 import org.jetbrains.asm4.tree.AbstractInsnNode; 023 import org.jetbrains.asm4.tree.FieldInsnNode; 024 import org.jetbrains.asm4.tree.MethodNode; 025 import org.jetbrains.jet.codegen.StackValue; 026 027 import java.util.Collection; 028 import java.util.List; 029 030 public class FieldRemapper { 031 032 private final String lambdaInternalName; 033 034 protected FieldRemapper parent; 035 036 private final Parameters params; 037 038 public FieldRemapper(@Nullable String lambdaInternalName, @Nullable FieldRemapper parent, @NotNull Parameters methodParams) { 039 this.lambdaInternalName = lambdaInternalName; 040 this.parent = parent; 041 params = methodParams; 042 } 043 044 public void addCapturedFields(LambdaInfo lambdaInfo, ParametersBuilder builder) { 045 for (CapturedParamInfo info : lambdaInfo.getCapturedVars()) { 046 builder.addCapturedParam(info, info); 047 } 048 } 049 050 public boolean canProcess(@NotNull String fieldOwner) { 051 return fieldOwner.equals(getLambdaInternalName()); 052 } 053 054 @Nullable 055 public AbstractInsnNode transformIfNeeded( 056 @NotNull List<AbstractInsnNode> capturedFieldAccess, 057 @NotNull MethodNode node 058 ) { 059 if (capturedFieldAccess.size() == 1) { 060 //just aload 061 return null; 062 } 063 064 return transformIfNeeded(capturedFieldAccess, 1, node); 065 } 066 067 @Nullable 068 private AbstractInsnNode transformIfNeeded( 069 @NotNull List<AbstractInsnNode> capturedFieldAccess, 070 int currentInstruction, 071 @NotNull MethodNode node 072 ) { 073 AbstractInsnNode transformed = null; 074 boolean checkParent = !isRoot() && currentInstruction < capturedFieldAccess.size() - 1; 075 if (checkParent) { 076 transformed = parent.transformIfNeeded(capturedFieldAccess, currentInstruction + 1, node); 077 } 078 079 if (transformed == null) { 080 //if parent couldn't transform 081 FieldInsnNode insnNode = (FieldInsnNode) capturedFieldAccess.get(currentInstruction); 082 if (canProcess(insnNode.owner)) { 083 insnNode.name = "$$$" + insnNode.name; 084 insnNode.setOpcode(Opcodes.GETSTATIC); 085 086 AbstractInsnNode next = capturedFieldAccess.get(0); 087 while (next != insnNode) { 088 AbstractInsnNode toDelete = next; 089 next = next.getNext(); 090 node.instructions.remove(toDelete); 091 } 092 093 transformed = capturedFieldAccess.get(capturedFieldAccess.size() - 1); 094 } 095 } 096 097 return transformed; 098 } 099 100 public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode) { 101 return findField(fieldInsnNode, params.getCaptured()); 102 } 103 104 @Nullable 105 public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection<CapturedParamInfo> captured) { 106 for (CapturedParamInfo valueDescriptor : captured) { 107 if (valueDescriptor.getFieldName().equals(fieldInsnNode.name) && fieldInsnNode.owner.equals(valueDescriptor.getContainingLambdaName())) { 108 return valueDescriptor; 109 } 110 } 111 return null; 112 } 113 114 public FieldRemapper getParent() { 115 return parent; 116 } 117 118 public String getLambdaInternalName() { 119 return lambdaInternalName; 120 } 121 122 public boolean isRoot() { 123 return parent == null; 124 } 125 126 @Nullable 127 public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) { 128 CapturedParamInfo field = MethodInliner.findCapturedField(node, this); 129 return field.getRemapValue(); 130 } 131 }