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_anewarray:
245 case opc_instanceof:
246 case opc_checkcast:
247 arg = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
248 break;
249 case opc_bipush:
250 arg = parser.parseInt(1);
251 break;
252 case opc_sipush:
253 arg = parser.parseInt(2);
254 break;
255 case opc_ldc:
256 case opc_ldc_w:
257 case opc_ldc2_w:
258 arg = cpParser.parseConstRef(null);
259 break;
260 case opc_putstatic:
261 case opc_getstatic:
262 case opc_putfield:
263 case opc_getfield:
264 arg = cpParser.parseConstRef(ConstType.CONSTANT_FIELD);
265 break;
266 case opc_invokevirtual:
267 arg = cpParser.parseConstRef(ConstType.CONSTANT_METHOD);
268 break;
269 case opc_invokestatic:
270 case opc_invokespecial:
271 ConstType ctype01 = ConstType.CONSTANT_METHOD;
272 ConstType ctype02 = ConstType.CONSTANT_INTERFACEMETHOD;
273 if(Modifier.isInterface(this.parser.cd.access)) {
274 ctype01 = ConstType.CONSTANT_INTERFACEMETHOD;
275 ctype02 = ConstType.CONSTANT_METHOD;
276 }
277 arg = cpParser.parseConstRef(ctype01, ctype02);
278 break;
279 case opc_jsr:
280 case opc_goto:
281 case opc_ifeq:
282 case opc_ifge:
283 case opc_ifgt:
284 case opc_ifle:
285 case opc_iflt:
286 case opc_ifne:
287 case opc_if_icmpeq:
288 case opc_if_icmpne:
289 case opc_if_icmpge:
290 case opc_if_icmpgt:
291 case opc_if_icmple:
292 case opc_if_icmplt:
293 case opc_if_acmpeq:
294 case opc_if_acmpne:
295 case opc_ifnull:
296 case opc_ifnonnull:
297 case opc_jsr_w:
298 case opc_goto_w:
299 arg = parseLabelRef();
300 break;
301
302 case opc_invokeinterface:
303 arg = cpParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHOD);
304 scanner.expect(Token.COMMA);
305 arg2 = parser.parseUInt(1);
306 break;
307 case opc_invokedynamic:
308 arg = cpParser.parseConstRef(ConstType.CONSTANT_INVOKEDYNAMIC);
309 break;
310
311 case opc_multianewarray:
312 arg = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
313 scanner.expect(Token.COMMA);
314 arg2 = parser.parseUInt(1);
315 break;
316 case opc_wide:
317 case opc_nonpriv:
318 case opc_priv:
319 int opc2 = (opcode.value() << 8) | parser.parseUInt(1).arg;
320 opcode = opcode(opc2);
321 break;
322 }
323 break;
324 case WIDE:
325 arg = parser.parseLocVarRef();
326 if (opcode == Opcode.opc_iinc_w) { // loc var, const
327 scanner.expect(Token.COMMA);
328 arg2 = parser.parseInt(2);
329 }
330 break;
331 case NONPRIVELEGED:
332 case PRIVELEGED:
333 break;
334 default:
335 env.error(scanner.prevPos, "wrong.mnemocode", mnemocode);
336 throw new Scanner.SyntaxError();
337 }
338 // env.traceln(" [ParserInstr.parseInstr] ===============> Adding Instruction: [" + mnenoc_pos + "]: instr: "+ mnemocode /* opcNamesTab[opc] */);
339 parser.curCode.addInstr(mnenoc_pos, opcode, arg, arg2);
340 } //end parseInstr
341
342 /**
343 * Parse a Switch Table. return value: SwitchTable.
344 */
345 protected SwitchTable parseSwitchTable() throws Scanner.SyntaxError, IOException {
346 scanner.expect(Token.LBRACE);
347 Argument label;
348 int numpairs = 0, key;
349 SwitchTable table = new SwitchTable(env);
350 tableScan:
351 {
352 while (numpairs < 1000) {
353 // env.traceln("start tableScan:" + token);
354 switch (scanner.token) {
355 case INTVAL:
356 // env.traceln("enter tableScan:" + token);
357 key = scanner.intValue * scanner.sign;
358 scanner.scan();
359 scanner.expect(Token.COLON);
360 table.addEntry(key, parseLabelRef());
361 numpairs++;
362 if (scanner.token != Token.SEMICOLON) {
363 // env.traceln("break tableScan1:" + token);
364 break tableScan;
365 }
366 scanner.scan();
367 break;
368 case DEFAULT:
369 scanner.scan();
370 scanner.expect(Token.COLON);
371 if (table.deflabel != null) {
372 env.error("default.redecl");
373 }
374 table.deflabel = parseLabelRef();
375 if (scanner.token != Token.SEMICOLON) {
376 // env.traceln("break tableScan2:" + token);
377 break tableScan;
378 }
379 scanner.scan();
380 break;
381 default:
382 // env.traceln("break tableScan3:" + token + "val=" + intValue);
383 break tableScan;
384 } // end switch
385 } // while (numpairs<1000)
386 env.error("long.switchtable", "1000");
387 } // end tableScan
388 scanner.expect(Token.RBRACE);
389 return table;
390 } // end parseSwitchTable
391
392 /**
393 * Parse a label instruction argument
394 */
395 protected Argument parseLabelRef() throws Scanner.SyntaxError, IOException {
396 switch (scanner.token) {
397 case INTVAL: {
398 int v = scanner.intValue * scanner.sign;
399 scanner.scan();
400 return new Argument(v);
401 }
402 case IDENT: {
403 String label = scanner.stringValue;
404 scanner.scan();
405 return parser.curCode.LabelRef(label);
406 }
407 }
408 env.error("label.expected");
409 throw new Scanner.SyntaxError();
410 }
411
412 }