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.JasmTokens.*; 26 import static org.openjdk.asmtools.jasm.Tables.*; 27 import static org.openjdk.asmtools.jasm.OpcodeTables.*; 28 import java.io.IOException; 29 import java.lang.reflect.Modifier; 30 31 /** 32 * ParserInstr 33 * 34 * ParserInstr is a parser class owned by Parser.java. It is primarily responsible for 35 * parsing instruction byte codes. 36 */ 37 public class ParserInstr extends ParseBase { 38 39 /** 40 * local handle for the constant parser - needed for parsing constants during 41 * instruction construction. 42 */ 43 private ParserCP cpParser = null; 44 45 /** 46 * main constructor 47 * 48 * @param scanner 49 * @param parser 50 * @param env 51 */ 52 protected ParserInstr(Scanner scanner, Parser parser, ParserCP cpParser, Environment env) { 53 super.init(scanner, parser, env); 54 this.cpParser = cpParser; 55 } 56 57 /** 58 * Parse an instruction. 59 */ 60 protected void parseInstr() throws Scanner.SyntaxError, IOException { 61 // ignore possible line numbers after java disassembler 62 if (scanner.token == Token.INTVAL) { 63 scanner.scan(); 64 } 65 // ignore possible numeric labels after java disassembler 66 if (scanner.token == Token.INTVAL) { 67 scanner.scan(); 68 } 69 if (scanner.token == Token.COLON) { 70 scanner.scan(); 71 } 72 73 String mnemocode; 74 int mnenoc_pos; 75 for (;;) { // read labels 76 if (scanner.token != Token.IDENT) { 77 return; 78 } 79 mnemocode = scanner.idValue; 80 mnenoc_pos = scanner.pos; 81 scanner.scan(); 82 if (scanner.token != Token.COLON) { 83 break; 84 } 85 // actually it was a label 86 scanner.scan(); 87 parser.curCode.LabelDef(mnenoc_pos, mnemocode); 88 } 89 90 Opcode opcode = OpcodeTables.opcode(mnemocode); 91 if (opcode == null) { 92 debugScan(" Error: mnemocode = '" + mnemocode + "'. "); 93 } 94 OpcodeType optype = opcode.type(); 95 96 Argument arg = null; 97 Object arg2 = null; 98 StackMapData sMap = null; 99 100 debugScan(" --IIIII---[ParserInstr:[parseInstr]: (Pos: " + mnenoc_pos + ") mnemocode: '" + opcode.parsekey() + "' "); 101 102 switch (optype) { 103 case NORMAL: 104 switch (opcode) { 105 106 // pseudo-instructions: 107 case opc_bytecode: 108 for (;;) { 109 parser.curCode.addInstr(mnenoc_pos, Opcode.opc_bytecode, parser.parseUInt(1), null); 110 if (scanner.token != Token.COMMA) { 111 return; 112 } 113 scanner.scan(); 114 } 115 case opc_try: 116 for (;;) { 117 parser.curCode.beginTrap(scanner.pos, parser.parseIdent()); 118 if (scanner.token != Token.COMMA) { 119 return; 120 } 121 scanner.scan(); 122 } 123 case opc_endtry: 124 for (;;) { 125 parser.curCode.endTrap(scanner.pos, parser.parseIdent()); 126 if (scanner.token != Token.COMMA) { 127 return; 128 } 129 scanner.scan(); 130 } 131 case opc_catch: 132 parser.curCode.trapHandler(scanner.pos, parser.parseIdent(), 133 cpParser.parseConstRef(ConstType.CONSTANT_CLASS)); 134 return; 135 case opc_var: 136 for (;;) { 137 parser.parseLocVarDef(); 138 if (scanner.token != Token.COMMA) { 139 return; 140 } 141 scanner.scan(); 142 } 143 case opc_endvar: 144 for (;;) { 145 parser.parseLocVarEnd(); 146 if (scanner.token != Token.COMMA) { 147 return; 148 } 149 scanner.scan(); 150 } 151 case opc_locals_map: 152 sMap = parser.curCode.getStackMap(); 153 if (sMap.localsMap != null) { 154 env.error(scanner.pos, "localsmap.repeated"); 155 } 156 ; 157 DataVector localsMap = new DataVector(); 158 sMap.localsMap = localsMap; 159 if (scanner.token == Token.SEMICOLON) { 160 return; // empty locals_map allowed 161 } 162 for (;;) { 163 parser.parseMapItem(localsMap); 164 if (scanner.token != Token.COMMA) { 165 return; 166 } 167 scanner.scan(); 168 } 169 case opc_stack_map: 170 sMap = parser.curCode.getStackMap(); 171 if (sMap.stackMap != null) { 172 env.error(scanner.pos, "stackmap.repeated"); 173 } 174 ; 175 DataVector stackMap = new DataVector(); 176 sMap.stackMap = stackMap; 177 if (scanner.token == Token.SEMICOLON) { 178 return; // empty stack_map allowed 179 } 180 for (;;) { 181 parser.parseMapItem(stackMap); 182 if (scanner.token != Token.COMMA) { 183 return; 184 } 185 scanner.scan(); 186 } 187 case opc_stack_frame_type: 188 sMap = parser.curCode.getStackMap(); 189 if (sMap.stackFrameType != null) { 190 env.error(scanner.pos, "frametype.repeated"); 191 } 192 ; 193 sMap.setStackFrameType(parser.parseIdent()); 194 return; 195 196 // normal instructions: 197 case opc_aload: 198 case opc_astore: 199 case opc_fload: 200 case opc_fstore: 201 case opc_iload: 202 case opc_istore: 203 case opc_lload: 204 case opc_lstore: 205 case opc_dload: 206 case opc_dstore: 207 case opc_ret: 208 case opc_aload_w: 209 case opc_astore_w: 210 case opc_fload_w: 211 case opc_fstore_w: 212 case opc_iload_w: 213 case opc_istore_w: 214 case opc_lload_w: 215 case opc_lstore_w: 216 case opc_dload_w: 217 case opc_dstore_w: 218 case opc_ret_w: 219 // loc var 220 arg = parser.parseLocVarRef(); 221 break; 222 case opc_iinc: // loc var, const 223 arg = parser.parseLocVarRef(); 224 scanner.expect(Token.COMMA); 225 arg2 = parser.parseInt(1); 226 break; 227 case opc_tableswitch: 228 case opc_lookupswitch: 229 arg2 = parseSwitchTable(); 230 break; 231 case opc_newarray: { 232 int type; 233 if (scanner.token == Token.INTVAL) { 234 type = scanner.intValue; 235 } else if ((type = Tables.basictypeValue(scanner.idValue)) == -1) { 236 env.error(scanner.pos, "type.expected"); 237 throw new Scanner.SyntaxError(); 238 } 239 scanner.scan(); 240 arg = new Argument(type); 241 break; 242 } 243 case opc_new: 244 case opc_aconst_init: 245 case opc_anewarray: 246 case opc_instanceof: 247 case opc_checkcast: 248 arg = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 249 break; 250 case opc_bipush: 251 arg = parser.parseInt(1); 252 break; 253 case opc_sipush: 254 arg = parser.parseInt(2); 255 break; 256 case opc_ldc: 257 case opc_ldc_w: 258 case opc_ldc2_w: 259 arg = cpParser.parseConstRef(null); 260 break; 261 case opc_putstatic: 262 case opc_getstatic: 263 case opc_putfield: 264 case opc_getfield: 265 case opc_withfield: 266 arg = cpParser.parseConstRef(ConstType.CONSTANT_FIELD); 267 break; 268 case opc_invokevirtual: 269 arg = cpParser.parseConstRef(ConstType.CONSTANT_METHOD); 270 break; 271 case opc_invokestatic: 272 case opc_invokespecial: 273 ConstType ctype01 = ConstType.CONSTANT_METHOD; 274 ConstType ctype02 = ConstType.CONSTANT_INTERFACEMETHOD; 275 if(Modifier.isInterface(this.parser.cd.access)) { 276 ctype01 = ConstType.CONSTANT_INTERFACEMETHOD; 277 ctype02 = ConstType.CONSTANT_METHOD; 278 } 279 arg = cpParser.parseConstRef(ctype01, ctype02); 280 break; 281 case opc_jsr: 282 case opc_goto: 283 case opc_ifeq: 284 case opc_ifge: 285 case opc_ifgt: 286 case opc_ifle: 287 case opc_iflt: 288 case opc_ifne: 289 case opc_if_icmpeq: 290 case opc_if_icmpne: 291 case opc_if_icmpge: 292 case opc_if_icmpgt: 293 case opc_if_icmple: 294 case opc_if_icmplt: 295 case opc_if_acmpeq: 296 case opc_if_acmpne: 297 case opc_ifnull: 298 case opc_ifnonnull: 299 case opc_jsr_w: 300 case opc_goto_w: 301 arg = parseLabelRef(); 302 break; 303 304 case opc_invokeinterface: 305 arg = cpParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHOD); 306 scanner.expect(Token.COMMA); 307 arg2 = parser.parseUInt(1); 308 break; 309 case opc_invokedynamic: 310 arg = cpParser.parseConstRef(ConstType.CONSTANT_INVOKEDYNAMIC); 311 break; 312 313 case opc_multianewarray: 314 arg = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); 315 scanner.expect(Token.COMMA); 316 arg2 = parser.parseUInt(1); 317 break; 318 case opc_wide: 319 case opc_nonpriv: 320 case opc_priv: 321 int opc2 = (opcode.value() << 8) | parser.parseUInt(1).arg; 322 opcode = opcode(opc2); 323 break; 324 } 325 break; 326 case WIDE: 327 arg = parser.parseLocVarRef(); 328 if (opcode == Opcode.opc_iinc_w) { // loc var, const 329 scanner.expect(Token.COMMA); 330 arg2 = parser.parseInt(2); 331 } 332 break; 333 case NONPRIVELEGED: 334 case PRIVELEGED: 335 break; 336 default: 337 env.error(scanner.prevPos, "wrong.mnemocode", mnemocode); 338 throw new Scanner.SyntaxError(); 339 } 340 // env.traceln(" [ParserInstr.parseInstr] ===============> Adding Instruction: [" + mnenoc_pos + "]: instr: "+ mnemocode /* opcNamesTab[opc] */); 341 parser.curCode.addInstr(mnenoc_pos, opcode, arg, arg2); 342 } //end parseInstr 343 344 /** 345 * Parse a Switch Table. return value: SwitchTable. 346 */ 347 protected SwitchTable parseSwitchTable() throws Scanner.SyntaxError, IOException { 348 scanner.expect(Token.LBRACE); 349 Argument label; 350 int numpairs = 0, key; 351 SwitchTable table = new SwitchTable(env); 352 tableScan: 353 { 354 while (numpairs < 1000) { 355 // env.traceln("start tableScan:" + token); 356 switch (scanner.token) { 357 case INTVAL: 358 // env.traceln("enter tableScan:" + token); 359 key = scanner.intValue * scanner.sign; 360 scanner.scan(); 361 scanner.expect(Token.COLON); 362 table.addEntry(key, parseLabelRef()); 363 numpairs++; 364 if (scanner.token != Token.SEMICOLON) { 365 // env.traceln("break tableScan1:" + token); 366 break tableScan; 367 } 368 scanner.scan(); 369 break; 370 case DEFAULT: 371 scanner.scan(); 372 scanner.expect(Token.COLON); 373 if (table.deflabel != null) { 374 env.error("default.redecl"); 375 } 376 table.deflabel = parseLabelRef(); 377 if (scanner.token != Token.SEMICOLON) { 378 // env.traceln("break tableScan2:" + token); 379 break tableScan; 380 } 381 scanner.scan(); 382 break; 383 default: 384 // env.traceln("break tableScan3:" + token + "val=" + intValue); 385 break tableScan; 386 } // end switch 387 } // while (numpairs<1000) 388 env.error("long.switchtable", "1000"); 389 } // end tableScan 390 scanner.expect(Token.RBRACE); 391 return table; 392 } // end parseSwitchTable 393 394 /** 395 * Parse a label instruction argument 396 */ 397 protected Argument parseLabelRef() throws Scanner.SyntaxError, IOException { 398 switch (scanner.token) { 399 case INTVAL: { 400 int v = scanner.intValue * scanner.sign; 401 scanner.scan(); 402 return new Argument(v); 403 } 404 case IDENT: { 405 String label = scanner.stringValue; 406 scanner.scan(); 407 return parser.curCode.LabelRef(label); 408 } 409 } 410 env.error("label.expected"); 411 throw new Scanner.SyntaxError(); 412 } 413 414 }