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 }