001// Copyright 2011 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.internal.plastic; 016 017import java.util.Map; 018 019import org.apache.tapestry5.internal.plastic.asm.Label; 020import org.apache.tapestry5.internal.plastic.asm.MethodVisitor; 021import org.apache.tapestry5.internal.plastic.asm.Opcodes; 022import org.apache.tapestry5.plastic.LocalVariable; 023import org.apache.tapestry5.plastic.MethodDescription; 024 025/** 026 * Stores information about the method whose instructions are being constructed, to make it easier 027 * to share data across multiple instances. 028 */ 029public class InstructionBuilderState implements Opcodes 030{ 031 final MethodDescription description; 032 033 final MethodVisitor visitor; 034 035 final NameCache nameCache; 036 037 int localIndex; 038 039 int varSuffix; 040 041 static class LVInfo 042 { 043 final int width, offset, loadOpcode, storeOpcode; 044 045 final Label end; 046 047 public LVInfo(int width, int offset, int loadOpcode, int storeOpcode, Label end) 048 { 049 this.width = width; 050 this.offset = offset; 051 this.loadOpcode = loadOpcode; 052 this.storeOpcode = storeOpcode; 053 this.end = end; 054 } 055 } 056 057 /** Map from LocalVariable to Integer offset. */ 058 final Map<LocalVariable, LVInfo> locals = PlasticInternalUtils.newMap(); 059 060 /** Index for argument (0 is first true argument); allows for double-width primitive types. */ 061 final int[] argumentIndex; 062 063 /** Opcode used to load argument (0 is first true argument). */ 064 final int[] argumentLoadOpcode; 065 066 protected InstructionBuilderState(MethodDescription description, MethodVisitor visitor, NameCache nameCache) 067 { 068 this.description = description; 069 this.visitor = visitor; 070 this.nameCache = nameCache; 071 072 // TODO: Account for static methods? 073 074 int argCount = description.argumentTypes.length; 075 076 argumentIndex = new int[argCount]; 077 argumentLoadOpcode = new int[argCount]; 078 079 // first argument index is for "this" 080 081 int offset = 1; 082 083 for (int i = 0; i < argCount; i++) 084 { 085 PrimitiveType type = PrimitiveType.getByName(description.argumentTypes[i]); 086 087 argumentIndex[i] = offset++; 088 argumentLoadOpcode[i] = type == null ? ALOAD : type.loadOpcode; 089 090 if (type != null && type.isWide()) 091 offset++; 092 } 093 094 localIndex = offset; 095 } 096 097 /** Creates a new Label and adds it to the method. */ 098 Label newLabel() 099 { 100 Label result = new Label(); 101 102 visitor.visitLabel(result); 103 104 return result; 105 } 106 107 LocalVariable startVariable(String type) 108 { 109 Label start = newLabel(); 110 Label end = new Label(); 111 112 PrimitiveType ptype = PrimitiveType.getByName(type); 113 114 int width = (ptype != null && ptype.isWide()) ? 2 : 1; 115 116 int loadOpcode = ptype == null ? ALOAD : ptype.loadOpcode; 117 int storeOpcode = ptype == null ? ASTORE : ptype.storeOpcode; 118 119 LVInfo info = new LVInfo(width, localIndex, loadOpcode, storeOpcode, end); 120 121 localIndex += width; 122 123 LocalVariable var = new LocalVariableImpl(type); 124 125 locals.put(var, info); 126 127 visitor.visitLocalVariable(nextVarName(), nameCache.toDesc(type), null, start, end, info.offset); 128 129 return var; 130 } 131 132 void load(LocalVariable var) 133 { 134 LVInfo info = locals.get(var); 135 136 visitor.visitVarInsn(info.loadOpcode, info.offset); 137 } 138 139 void store(LocalVariable var) 140 { 141 LVInfo info = locals.get(var); 142 143 visitor.visitVarInsn(info.storeOpcode, info.offset); 144 } 145 146 void stopVariable(LocalVariable variable) 147 { 148 LVInfo info = locals.get(variable); 149 150 visitor.visitLabel(info.end); 151 152 locals.remove(variable); 153 154 localIndex -= info.width; 155 } 156 157 private String nextVarName() 158 { 159 return "var" + varSuffix++; 160 } 161}