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.asm4.tree.VarInsnNode; 026 027 import java.util.Collection; 028 import java.util.List; 029 030 import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelNoLine; 031 032 public class LambdaFieldRemapper { 033 034 private String lambdaInternalName; 035 036 protected LambdaFieldRemapper parent; 037 038 private final Parameters params; 039 040 public LambdaFieldRemapper(@Nullable String lambdaInternalName, @Nullable LambdaFieldRemapper parent, @NotNull Parameters methodParams) { 041 this.lambdaInternalName = lambdaInternalName; 042 this.parent = parent; 043 params = methodParams; 044 } 045 046 public AbstractInsnNode doTransform(MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField) { 047 AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode); 048 049 int opcode = fieldInsnNode.getOpcode() == Opcodes.GETFIELD ? capturedField.getType().getOpcode(Opcodes.ILOAD) : capturedField.getType().getOpcode(Opcodes.ISTORE); 050 VarInsnNode newInstruction = new VarInsnNode(opcode, capturedField.getIndex()); 051 052 node.instructions.remove(loadThis); //remove aload this 053 node.instructions.insertBefore(fieldInsnNode, newInstruction); 054 node.instructions.remove(fieldInsnNode); //remove aload field 055 056 return newInstruction; 057 } 058 059 protected static AbstractInsnNode getPreviousThis(FieldInsnNode fieldInsnNode) { 060 AbstractInsnNode loadThis = getPreviousNoLabelNoLine(fieldInsnNode); 061 062 assert loadThis.getType() == AbstractInsnNode.VAR_INSN || loadThis.getType() == AbstractInsnNode.FIELD_INSN : 063 "Field access instruction should go after load this but goes after " + loadThis; 064 assert loadThis.getOpcode() == Opcodes.ALOAD || loadThis.getOpcode() == Opcodes.GETSTATIC : 065 "This should be loaded by ALOAD or GETSTATIC but " + loadThis.getOpcode(); 066 return loadThis; 067 } 068 069 public List<CapturedParamInfo> markRecaptured(List<CapturedParamInfo> originalCaptured, LambdaInfo lambda) { 070 return originalCaptured; 071 } 072 073 074 public boolean canProcess(@NotNull String owner, @NotNull String currentLambdaType) { 075 return owner.equals(currentLambdaType); 076 } 077 078 @Nullable 079 public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection<CapturedParamInfo> captured) { 080 for (CapturedParamInfo valueDescriptor : captured) { 081 if (valueDescriptor.getFieldName().equals(fieldInsnNode.name)) { 082 return valueDescriptor; 083 } 084 } 085 return null; 086 } 087 088 public LambdaFieldRemapper getParent() { 089 return parent; 090 } 091 public String getLambdaInternalName() { 092 return lambdaInternalName; 093 } 094 095 public boolean isRoot() { 096 return parent == null; 097 } 098 099 public boolean shouldPatch(@NotNull FieldInsnNode node) { 100 return !isRoot() && parent.shouldPatch(node); 101 } 102 103 @NotNull 104 public AbstractInsnNode patch(@NotNull FieldInsnNode field, @NotNull MethodNode node) { 105 //parent is inlined so we need patch instruction chain 106 if (!isRoot()){ 107 return parent.patch(field, node); 108 } 109 throw new IllegalStateException("Should be invoked"); 110 } 111 }