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 }