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.org.objectweb.asm.Opcodes; 022 import org.jetbrains.org.objectweb.asm.Type; 023 import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode; 024 import org.jetbrains.jet.codegen.StackValue; 025 026 import java.util.Collection; 027 import java.util.Map; 028 029 public class RegeneratedLambdaFieldRemapper extends FieldRemapper { 030 031 private final String oldOwnerType; 032 033 private final String newOwnerType; 034 035 private final Parameters parameters; 036 037 private final Map<String, LambdaInfo> recapturedLambdas; 038 039 public RegeneratedLambdaFieldRemapper( 040 String oldOwnerType, 041 String newOwnerType, 042 Parameters parameters, 043 Map<String, LambdaInfo> recapturedLambdas, 044 FieldRemapper remapper 045 ) { 046 super(oldOwnerType, remapper, parameters); 047 this.oldOwnerType = oldOwnerType; 048 this.newOwnerType = newOwnerType; 049 this.parameters = parameters; 050 this.recapturedLambdas = recapturedLambdas; 051 } 052 053 @Override 054 public boolean canProcess(@NotNull String fieldOwner, String fieldName, boolean isFolding) { 055 return super.canProcess(fieldOwner, fieldName, isFolding) || isRecapturedLambdaType(fieldOwner); 056 } 057 058 private boolean isRecapturedLambdaType(String owner) { 059 return recapturedLambdas.containsKey(owner); 060 } 061 062 @Nullable 063 @Override 064 public CapturedParamInfo findField(@NotNull FieldInsnNode fieldInsnNode, @NotNull Collection<CapturedParamInfo> captured) { 065 boolean searchInParent = !canProcess(fieldInsnNode.owner, fieldInsnNode.name, false); 066 if (searchInParent) { 067 return parent.findField(fieldInsnNode); 068 } else { 069 return findFieldInMyCaptured(fieldInsnNode); 070 } 071 } 072 073 @Nullable 074 public CapturedParamInfo findFieldInMyCaptured(@NotNull FieldInsnNode fieldInsnNode) { 075 return super.findField(fieldInsnNode, parameters.getCaptured()); 076 } 077 078 @Nullable 079 @Override 080 public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) { 081 assert node.name.startsWith("$$$") : "Captured field template should start with $$$ prefix"; 082 FieldInsnNode fin = new FieldInsnNode(node.getOpcode(), node.owner, node.name.substring(3), node.desc); 083 CapturedParamInfo field = findFieldInMyCaptured(fin); 084 085 boolean searchInParent = false; 086 if (field == null) { 087 field = findFieldInMyCaptured(new FieldInsnNode(Opcodes.GETSTATIC, oldOwnerType, "this$0", Type.getObjectType(parent.getLambdaInternalName()).getDescriptor())); 088 searchInParent = true; 089 if (field == null) { 090 throw new IllegalStateException("Couldn't find captured this " + getLambdaInternalName() + " for " + node.name); 091 } 092 } 093 094 StackValue result = 095 StackValue.composed(prefix == null ? StackValue.local(0, Type.getObjectType(getLambdaInternalName())) : prefix, 096 StackValue.field(field.getType(), 097 Type.getObjectType(newOwnerType), /*TODO owner type*/ 098 field.getNewFieldName(), false) 099 ); 100 101 return searchInParent ? parent.getFieldForInline(node, result) : result; 102 } 103 }