1 /* 2 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jasm; 24 25 import static org.openjdk.asmtools.jasm.Tables.*; 26 import java.io.IOException; 27 28 /** 29 * 30 */ 31 public class StackMapData implements Data { 32 33 /** 34 * 35 */ 36 static public class StackMapItem1 implements Data { 37 38 StackMapType itemType; 39 40 StackMapItem1(StackMapType itemType) { 41 this.itemType = itemType; 42 } 43 44 @Override 45 public int getLength() { 46 return 1; 47 } 48 49 @Override 50 public void write(CheckedDataOutputStream out) throws IOException { 51 out.writeByte(itemType.value()); 52 } 53 } 54 55 /** 56 * 57 */ 58 static public class StackMapItem2 implements Data { 59 60 StackMapType itemType; 61 Argument arg; 62 63 StackMapItem2(StackMapType itemType, Argument arg) { 64 this.itemType = itemType; 65 this.arg = arg; 66 } 67 68 @Override 69 public int getLength() { 70 return 3; 71 } 72 73 @Override 74 public void write(CheckedDataOutputStream out) throws IOException { 75 out.writeByte(itemType.value()); 76 out.writeShort(arg.arg); 77 } 78 } 79 80 int pc; 81 int offset; 82 int type; 83 String stackFrameType = null; 84 boolean isStackMapTable = false; 85 DataVector localsMap, stackMap; 86 Environment env; 87 88 StackMapData(Environment env) { 89 this.env = env; 90 } 91 92 void setPC(int pc) { 93 this.pc = pc; 94 } 95 96 void setOffset(int offset) { 97 this.offset = offset; 98 } 99 100 void setOffset(StackMapData prevFrame) { 101 offset = (prevFrame == null) ? pc : (pc - prevFrame.pc - 1); 102 } 103 104 void setStackFrameType(String stackFrameType) { 105 this.stackFrameType = stackFrameType; 106 107 if (stackFrameType != null) { 108 type = stackMapFrameTypeValue(stackFrameType); 109 } 110 111 if (stackFrameType == null || type == -1) { 112 env.error(pc, "invalid.stack.frame.type", stackFrameType, "" + type); 113 } 114 } 115 116 void setIsStackMapTable(boolean isStackMapTable) { 117 this.isStackMapTable = isStackMapTable; 118 } 119 120 void setLocalsMap(DataVector localsMap) { 121 this.localsMap = localsMap; 122 } 123 124 void setStackMap(DataVector stackMap) { 125 this.stackMap = stackMap; 126 } 127 128 @Override 129 public int getLength() { 130 int res = 0; 131 StackMapFrameType frame_type = StackMapFrameType.FULL_FRAME; 132 // int frame_type = FULL_FRAME; 133 134 if (isStackMapTable) { 135 if (stackFrameType != null) { 136 frame_type = stackMapFrameType(type); 137 } 138 res += 1; 139 } 140 141 switch (frame_type) { 142 case SAME_FRAME: 143 break; 144 case SAME_LOCALS_1_STACK_ITEM_FRAME: 145 res += stackMap.getLength() - 2; 146 break; 147 case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME: 148 res += stackMap.getLength(); 149 break; 150 case CHOP_1_FRAME: 151 case CHOP_2_FRAME: 152 case CHOP_3_FRAME: 153 res += 2; 154 break; 155 case SAME_FRAME_EX: 156 res += 2; 157 break; 158 case APPEND_FRAME: 159 res += 2 + (localsMap == null ? 0 : (localsMap.getLength() - 2)); 160 break; 161 case FULL_FRAME: 162 res += 2; 163 res += (localsMap == null ? 2 : localsMap.getLength()); 164 res += (stackMap == null ? 2 : stackMap.getLength()); 165 break; 166 default: 167 ; 168 } 169 return res; 170 } 171 172 @Override 173 public void write(CheckedDataOutputStream out) throws IOException { 174 StackMapFrameType frame_type = StackMapFrameType.FULL_FRAME; 175 176 if (isStackMapTable) { 177 if (stackFrameType != null) { 178 frame_type = stackMapFrameType(type); 179 } 180 } 181 182 switch (frame_type) { 183 case SAME_FRAME: 184 if (offset >= 64) { 185 env.error(pc, "invalid.offset.same.frame", "" + offset); 186 } 187 out.writeByte(offset); 188 break; 189 case SAME_LOCALS_1_STACK_ITEM_FRAME: 190 if (stackMap == null) { 191 env.error(pc, "no.stack.map.same.locals"); 192 break; 193 } 194 195 if (stackMap.elements.size() != 1) { 196 env.error(pc, "should.be.only.one.stack.map.element"); 197 break; 198 } 199 200 if (offset >= 64) { 201 env.error(pc, "invalid.offset.same.locals", "" + offset); 202 break; 203 } 204 out.writeByte(frame_type.value() + offset); 205 stackMap.writeElements(out); 206 break; 207 case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME: 208 if (stackMap == null) { 209 env.error(pc, "no.stack.map.same.locals"); 210 break; 211 } 212 213 if (stackMap.elements.size() != 1) { 214 env.error(pc, "should.be.only.one.stack.map.element"); 215 break; 216 } 217 out.writeByte(frame_type.value()); 218 out.writeShort(offset); 219 stackMap.writeElements(out); 220 break; 221 case CHOP_1_FRAME: 222 case CHOP_2_FRAME: 223 case CHOP_3_FRAME: 224 case SAME_FRAME_EX: 225 boolean error = false; 226 227 if (stackMap != null) { 228 env.error(pc, "unexpected.stack.maps"); 229 error = true; 230 } 231 232 if (localsMap != null) { 233 env.error(pc, "unexpected.locals.maps"); 234 error = true; 235 } 236 237 if (error) { 238 break; 239 } 240 out.writeByte(frame_type.value()); 241 out.writeShort(offset); 242 break; 243 case APPEND_FRAME: 244 if (localsMap == null) { 245 env.error(pc, "no.locals.map.append"); 246 break; 247 } 248 249 if (localsMap.elements.size() > 3) { 250 env.error(pc, "more.locals.map.elements"); 251 break; 252 } 253 out.writeByte(frame_type.value() + localsMap.elements.size() - 1); 254 out.writeShort(offset); 255 localsMap.writeElements(out); 256 break; 257 case FULL_FRAME: 258 if (isStackMapTable) { 259 out.writeByte(frame_type.value()); 260 out.writeShort(offset); 261 } else { 262 out.writeShort(pc); 263 } 264 265 if (localsMap == null) { 266 out.writeShort(0); 267 } else { 268 localsMap.write(out); 269 } 270 271 if (stackMap == null) { 272 out.writeShort(0); 273 } else { 274 stackMap.write(out); 275 } 276 break; 277 default: 278 env.error(pc, "invalid.stack.frame.type", "" + frame_type); 279 } 280 } 281 }