/* * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.openjdk.asmtools.jasm; import static org.openjdk.asmtools.jasm.JasmTokens.*; import static org.openjdk.asmtools.jasm.Tables.*; import static org.openjdk.asmtools.jasm.OpcodeTables.*; import java.io.IOException; /** * ParserInstr * * ParserInstr is a parser class owned by Parser.java. It is primarily responsible for * parsing instruction byte codes. */ public class ParserInstr extends ParseBase { /** * local handle for the constant parser - needed for parsing constants during * instruction construction. */ private ParserCP cpParser = null; /** * main constructor * * @param scanner * @param parser * @param env */ protected ParserInstr(Scanner scanner, Parser parser, ParserCP cpParser, Environment env) { super.init(scanner, parser, env); this.cpParser = cpParser; } /** * Parse an instruction. */ protected void parseInstr() throws Scanner.SyntaxError, IOException { // ignore possible line numbers after java disassembler if (scanner.token == Token.INTVAL) { scanner.scan(); } // ignore possible numeric labels after java disassembler if (scanner.token == Token.INTVAL) { scanner.scan(); } if (scanner.token == Token.COLON) { scanner.scan(); } String mnemocode; int mnenoc_pos; for (;;) { // read labels if (scanner.token != Token.IDENT) { return; } mnemocode = scanner.idValue; mnenoc_pos = scanner.pos; scanner.scan(); if (scanner.token != Token.COLON) { break; } // actually it was a label scanner.scan(); parser.curCode.LabelDef(mnenoc_pos, mnemocode); } Opcode opcode = OpcodeTables.opcode(mnemocode); if (opcode == null) { debugScan(" %%error%%error%%% $$$$$$$$$$$$$$$ mnemocode = '" + mnemocode + "'. "); } OpcodeType optype = opcode.type(); Argument arg = null; Object arg2 = null; StackMapData sMap = null; debugScan(" --IIIII---[ParserInstr:[parseInstr]: (Pos: " + mnenoc_pos + ") mnemocode: '" + opcode.parsekey() + "' "); switch (optype) { case NORMAL: switch (opcode) { // pseudo-instructions: case opc_bytecode: for (;;) { parser.curCode.addInstr(mnenoc_pos, Opcode.opc_bytecode, parser.parseUInt(1), null); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_try: for (;;) { parser.curCode.beginTrap(scanner.pos, parser.parseIdent()); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_endtry: for (;;) { parser.curCode.endTrap(scanner.pos, parser.parseIdent()); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_catch: parser.curCode.trapHandler(scanner.pos, parser.parseIdent(), cpParser.parseConstRef(ConstType.CONSTANT_CLASS)); return; case opc_var: for (;;) { parser.parseLocVarDef(); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_endvar: for (;;) { parser.parseLocVarEnd(); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_locals_map: sMap = parser.curCode.getStackMap(); if (sMap.localsMap != null) { env.error(scanner.pos, "localsmap.repeated"); } ; DataVector localsMap = new DataVector(); sMap.localsMap = localsMap; if (scanner.token == Token.SEMICOLON) { return; // empty locals_map allowed } for (;;) { parser.parseMapItem(localsMap); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_stack_map: sMap = parser.curCode.getStackMap(); if (sMap.stackMap != null) { env.error(scanner.pos, "stackmap.repeated"); } ; DataVector stackMap = new DataVector(); sMap.stackMap = stackMap; if (scanner.token == Token.SEMICOLON) { return; // empty stack_map allowed } for (;;) { parser.parseMapItem(stackMap); if (scanner.token != Token.COMMA) { return; } scanner.scan(); } case opc_stack_frame_type: sMap = parser.curCode.getStackMap(); if (sMap.stackFrameType != null) { env.error(scanner.pos, "frametype.repeated"); } ; sMap.setStackFrameType(parser.parseIdent()); return; // normal instructions: case opc_aload: case opc_astore: case opc_fload: case opc_fstore: case opc_iload: case opc_istore: case opc_lload: case opc_lstore: case opc_dload: case opc_dstore: case opc_ret: case opc_aload_w: case opc_astore_w: case opc_fload_w: case opc_fstore_w: case opc_iload_w: case opc_istore_w: case opc_lload_w: case opc_lstore_w: case opc_dload_w: case opc_dstore_w: case opc_ret_w: // loc var arg = parser.parseLocVarRef(); break; case opc_iinc: // loc var, const arg = parser.parseLocVarRef(); scanner.expect(Token.COMMA); arg2 = parser.parseInt(1); break; case opc_tableswitch: case opc_lookupswitch: arg2 = parseSwitchTable(); break; case opc_newarray: { int type; if (scanner.token == Token.INTVAL) { type = scanner.intValue; } else if ((type = Tables.basictypeValue(scanner.idValue)) == -1) { env.error(scanner.pos, "type.expected"); throw new Scanner.SyntaxError(); } scanner.scan(); arg = new Argument(type); break; } case opc_new: case opc_anewarray: case opc_instanceof: case opc_checkcast: arg = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); break; case opc_bipush: arg = parser.parseInt(1); break; case opc_sipush: arg = parser.parseInt(2); break; case opc_ldc: case opc_ldc_w: case opc_ldc2_w: arg = cpParser.parseConstRef(null); break; case opc_putstatic: case opc_getstatic: case opc_putfield: case opc_getfield: arg = cpParser.parseConstRef(ConstType.CONSTANT_FIELD); break; case opc_invokevirtual: arg = cpParser.parseConstRef(ConstType.CONSTANT_METHOD); break; case opc_invokestatic: case opc_invokespecial: arg = cpParser.parseConstRef(ConstType.CONSTANT_METHOD, ConstType.CONSTANT_INTERFACEMETHOD); break; case opc_jsr: case opc_goto: case opc_ifeq: case opc_ifge: case opc_ifgt: case opc_ifle: case opc_iflt: case opc_ifne: case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt: case opc_if_acmpeq: case opc_if_acmpne: case opc_ifnull: case opc_ifnonnull: case opc_jsr_w: case opc_goto_w: arg = parseLabelRef(); break; case opc_invokeinterface: arg = cpParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHOD); scanner.expect(Token.COMMA); arg2 = parser.parseUInt(1); break; case opc_invokedynamic: arg = cpParser.parseConstRef(ConstType.CONSTANT_INVOKEDYNAMIC); break; case opc_multianewarray: arg = cpParser.parseConstRef(ConstType.CONSTANT_CLASS); scanner.expect(Token.COMMA); arg2 = parser.parseUInt(1); break; case opc_wide: case opc_nonpriv: case opc_priv: int opc2 = (opcode.value() << 8) | parser.parseUInt(1).arg; opcode = opcode(opc2); break; } break; case WIDE: arg = parser.parseLocVarRef(); if (opcode == Opcode.opc_iinc_w) { // loc var, const scanner.expect(Token.COMMA); arg2 = parser.parseInt(2); } break; case NONPRIVELEGED: case PRIVELEGED: break; default: env.error(scanner.prevPos, "wrong.mnemocode", mnemocode); throw new Scanner.SyntaxError(); } // env.traceln(" [ParserInstr.parseInstr] ===============> Adding Instruction: [" + mnenoc_pos + "]: instr: "+ mnemocode /* opcNamesTab[opc] */); parser.curCode.addInstr(mnenoc_pos, opcode, arg, arg2); } //end parseInstr /** * Parse a Switch Table. return value: SwitchTable. */ protected SwitchTable parseSwitchTable() throws Scanner.SyntaxError, IOException { scanner.expect(Token.LBRACE); Argument label; int numpairs = 0, key; SwitchTable table = new SwitchTable(env); tableScan: { while (numpairs < 1000) { // env.traceln("start tableScan:" + token); switch (scanner.token) { case INTVAL: // env.traceln("enter tableScan:" + token); key = scanner.intValue * scanner.sign; scanner.scan(); scanner.expect(Token.COLON); table.addEntry(key, parseLabelRef()); numpairs++; if (scanner.token != Token.SEMICOLON) { // env.traceln("break tableScan1:" + token); break tableScan; } scanner.scan(); break; case DEFAULT: scanner.scan(); scanner.expect(Token.COLON); if (table.deflabel != null) { env.error("default.redecl"); } table.deflabel = parseLabelRef(); if (scanner.token != Token.SEMICOLON) { // env.traceln("break tableScan2:" + token); break tableScan; } scanner.scan(); break; default: // env.traceln("break tableScan3:" + token + "val=" + intValue); break tableScan; } // end switch } // while (numpairs<1000) env.error("long.switchtable", "1000"); } // end tableScan scanner.expect(Token.RBRACE); return table; } // end parseSwitchTable /** * Parse a label instruction argument */ protected Argument parseLabelRef() throws Scanner.SyntaxError, IOException { switch (scanner.token) { case INTVAL: { int v = scanner.intValue * scanner.sign; scanner.scan(); return new Argument(v); } case IDENT: { String label = scanner.stringValue; scanner.scan(); return parser.curCode.LabelRef(label); } } env.error("label.expected"); throw new Scanner.SyntaxError(); } }