/* * 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 java.io.IOException; import java.util.ArrayList; /** * ParserCP * * ParseCP is a parser class owned by Parser.java. It is primarily responsible for parsing * the constant pool and constant declarations. */ public class ParserCP extends ParseBase { /** * local handles on the scanner, main parser, and the error reporting env */ /** * Visitor object */ private ParserCPVisitor pConstVstr; /** * main constructor * * @param scanner * @param parser * @param env */ protected ParserCP(Scanner scanner, Parser parser, Environment env) { super.init(scanner, parser, env); pConstVstr = new ParserCPVisitor(); } /** * ParserCPVisitor * * This inner class overrides a constant pool visitor to provide specific parsing * instructions (per method) for each type of Constant. * * Note: since the generic visitor throws no exceptions, this derived class tunnels * the exceptions, rethrown in the visitEcept method. */ class ParserCPVisitor extends ConstantPool.CPTagVisitor { private IOException IOProb; private Scanner.SyntaxError SyProb; public ParserCPVisitor() { IOProb = null; SyProb = null; } //This is the entry point for a visitor that tunnels exceptions public ConstantPool.ConstValue visitExcept(ConstType tag) throws IOException, Scanner.SyntaxError { IOProb = null; SyProb = null; debugStr("------- [ParserCPVisitor.visitExcept]: "); ConstantPool.ConstValue ret = visit(tag); if (IOProb != null) { throw IOProb; } if (SyProb != null) { throw SyProb; } return ret; } @Override public ConstantPool.ConstValue visitUTF8(ConstType tag) { debugStr("------- [ParserCPVisitor.visitUTF8]: "); try { scanner.expect(Token.STRINGVAL); } catch (IOException e) { IOProb = e; } ConstantPool.ConstValue_String obj = new ConstantPool.ConstValue_String(scanner.stringValue); return obj; } @Override public ConstantPool.ConstValue visitInteger(ConstType tag) { debugStr("------- [ParserCPVisitor.visitInteger]: "); ConstantPool.ConstValue_Integer obj; int v = 0; try { if (scanner.token == Token.BITS) { scanner.scan(); scanner.inBits = true; } v = scanner.intValue * scanner.sign; scanner.expect(Token.INTVAL); } catch (IOException e) { IOProb = e; } obj = new ConstantPool.ConstValue_Integer(tag, new Integer(v)); return obj; } @Override public ConstantPool.ConstValue visitLong(ConstType tag) { debugStr("------- [ParserCPVisitor.visitLong]: "); ConstantPool.ConstValue_Long obj = null; try { long v; if (scanner.token == Token.BITS) { scanner.scan(); scanner.inBits = true; } switch (scanner.token) { case INTVAL: v = scanner.intValue; break; case LONGVAL: v = scanner.longValue; break; default: env.error(scanner.prevPos, "token.expected", "Integer"); throw new Scanner.SyntaxError(); } obj = new ConstantPool.ConstValue_Long(tag, new Long(v * scanner.sign)); scanner.scan(); } catch (IOException e) { IOProb = e; } catch (Scanner.SyntaxError e) { SyProb = e; } return obj; } @Override public ConstantPool.ConstValue visitFloat(ConstType tag) { debugStr("------- [ParserCPVisitor.visitFloat]: "); ConstantPool.ConstValue_Integer obj = null; try { int v; float f; scanner.inBits = false; // this needs to be initialized for each float! if (scanner.token == Token.BITS) { scanner.scan(); scanner.inBits = true; } i2f: { switch (scanner.token) { case INTVAL: if (scanner.inBits) { v = scanner.intValue; break i2f; } else { f = (float) scanner.intValue; break; } case FLOATVAL: f = scanner.floatValue; break; case DOUBLEVAL: f = (float) scanner.doubleValue; // to be excluded? break; case INF: f = Float.POSITIVE_INFINITY; break; case NAN: f = Float.NaN; break; default: env.traceln("token=" + scanner.token); env.error(scanner.pos, "token.expected", ""); throw new Scanner.SyntaxError(); } v = Float.floatToIntBits(f); } if (scanner.sign == -1) { v = v ^ 0x80000000; } obj = new ConstantPool.ConstValue_Integer(tag, new Integer(v)); scanner.scan(); } catch (IOException e) { IOProb = e; } catch (Scanner.SyntaxError e) { SyProb = e; } return obj; } @Override public ConstantPool.ConstValue visitDouble(ConstType tag) { debugStr("------- [ParserCPVisitor.visitDouble]: "); ConstantPool.ConstValue_Long obj = null; try { long v; double d; if (scanner.token == Token.BITS) { scanner.scan(); scanner.inBits = true; } d2l: { switch (scanner.token) { case INTVAL: if (scanner.inBits) { v = scanner.intValue; break d2l; } else { d = (double) scanner.intValue; break; } case LONGVAL: if (scanner.inBits) { v = scanner.longValue; break d2l; } else { d = (double) scanner.longValue; break; } case FLOATVAL: d = scanner.floatValue; break; case DOUBLEVAL: d = scanner.doubleValue; break; case INF: d = Double.POSITIVE_INFINITY; break; case NAN: d = Double.NaN; break; default: env.error(scanner.pos, "token.expected", "Double"); throw new Scanner.SyntaxError(); } v = Double.doubleToLongBits(d); } if (scanner.sign == -1) { v = v ^ 0x8000000000000000L; } obj = new ConstantPool.ConstValue_Long(tag, new Long(v)); scanner.scan(); } catch (IOException e) { IOProb = e; } catch (Scanner.SyntaxError e) { SyProb = e; } return obj; } private ConstantPool.ConstCell visitName(ConstType tag) { debugStr("------- [ParserCPVisitor.visitName]: "); ConstantPool.ConstCell obj = null; try { obj = parser.parseName(); } catch (IOException e) { IOProb = e; } return obj; } @Override public ConstantPool.ConstValue visitMethodtype(ConstType tag) { debugStr("------- [ParserCPVisitor.visitMethodtype]: "); ConstantPool.ConstValue_Cell obj = null; ConstantPool.ConstCell cell = visitName(tag); if (IOProb == null) { obj = new ConstantPool.ConstValue_Cell(tag, cell); } return obj; } @Override public ConstantPool.ConstValue visitString(ConstType tag) { debugStr("------- [ParserCPVisitor.visitString]: "); ConstantPool.ConstValue_Cell obj = null; ConstantPool.ConstCell cell = visitName(tag); if (IOProb == null) { obj = new ConstantPool.ConstValue_Cell(tag, cell); } return obj; } @Override public ConstantPool.ConstValue visitClass(ConstType tag) { debugStr("------- [ParserCPVisitor.visitClass]: "); ConstantPool.ConstValue_Cell obj = null; try { ConstantPool.ConstCell cell = parser.parseClassName(true); obj = new ConstantPool.ConstValue_Cell(tag, cell); } catch (IOException e) { IOProb = e; } return obj; } @Override public ConstantPool.ConstValue visitMethodhandle(ConstType tag) { debugStr("------- [ParserCPVisitor.visitMethodHandle]: "); ConstantPool.ConstValue_Pair obj = null; try { ConstantPool.ConstCell refCell; ConstantPool.ConstCell subtagCell; SubTag subtag; if (scanner.token == Token.INTVAL) { // Handle explicit constant pool form subtag = subtag(scanner.intValue); subtagCell = new ConstantPool.ConstCell(subtag.value()); scanner.scan(); scanner.expect(Token.COLON); if (scanner.token != Token.CPINDEX) { env.traceln("token=" + scanner.token); env.error(scanner.pos, "token.expected", ""); throw new Scanner.SyntaxError(); } int cpx = scanner.intValue; refCell = parser.pool.getCell(cpx); scanner.scan(); } else { // normal JASM subtag = parser.parseSubtag(); subtagCell = new ConstantPool.ConstCell(subtag.value()); scanner.expect(Token.COLON); refCell = parser.parseMethodHandle(subtag); } obj = new ConstantPool.ConstValue_Pair(tag, subtagCell, refCell); } catch (IOException e) { IOProb = e; } return obj; } private ConstantPool.ConstValue_Pair visitMember(ConstType tag) { debugStr("------- [ParserCPVisitor.visitMember]: "); ConstantPool.ConstValue_Pair obj = null; try { Token prevtoken = scanner.token; ConstantPool.ConstCell firstName, ClassCell, NameCell, NapeCell; firstName = parser.parseClassName(false); if (scanner.token == Token.FIELD) { // DOT scanner.scan(); if (prevtoken == Token.CPINDEX) { ClassCell = firstName; } else { ClassCell = parser.pool.FindCell(ConstType.CONSTANT_CLASS, firstName); } NameCell = parser.parseName(); } else { // no class provided - assume current class ClassCell = parser.cd.me; NameCell = firstName; } if (scanner.token == Token.COLON) { // name and type separately scanner.scan(); NapeCell = parser.pool.FindCell(ConstType.CONSTANT_NAMEANDTYPE, NameCell, parser.parseName()); } else { // name and type as single name NapeCell = NameCell; } obj = new ConstantPool.ConstValue_Pair(tag, ClassCell, NapeCell); } catch (IOException e) { IOProb = e; } return obj; } @Override public ConstantPool.ConstValue visitField(ConstType tag) { debugStr("------- [ParserCPVisitor.visitField]: "); return visitMember(tag); } @Override public ConstantPool.ConstValue visitMethod(ConstType tag) { debugStr("------- [ParserCPVisitor.visitMethod]: "); return visitMember(tag); } @Override public ConstantPool.ConstValue visitInterfacemethod(ConstType tag) { debugStr("------- [ParserCPVisitor.visitInterfacemethod]: "); return visitMember(tag); } @Override public ConstantPool.ConstValue visitNameandtype(ConstType tag) { debugStr("------- [ParserCPVisitor.visitNameandtype]: "); ConstantPool.ConstValue_Pair obj = null; try { ConstantPool.ConstCell NameCell = parser.parseName(), TypeCell; scanner.expect(Token.COLON); TypeCell = parser.parseName(); obj = new ConstantPool.ConstValue_Pair(tag, NameCell, TypeCell); } catch (IOException e) { IOProb = e; } return obj; } @Override public ConstantPool.ConstValue_IndyPair visitInvokedynamic(ConstType tag) { debugStr("------- [ParserCPVisitor.visitInvokeDynamic]: "); ConstantPool.ConstValue_IndyPair obj = null; try { if (scanner.token == Token.INTVAL) { // Handle explicit constant pool form int bsmIndex = scanner.intValue; scanner.scan(); scanner.expect(Token.COLON); if (scanner.token != Token.CPINDEX) { env.traceln("token=" + scanner.token); env.error(scanner.pos, "token.expected", ""); throw new Scanner.SyntaxError(); } int cpx = scanner.intValue; scanner.scan(); // Put a placeholder in place of BSM. // resolve placeholder after the attributes are scanned. BootstrapMethodData bsmData = new BootstrapMethodData(bsmIndex); obj = new ConstantPool.ConstValue_IndyPair(bsmData, parser.pool.getCell(cpx)); } else { // Handle full form ConstantPool.ConstCell MHCell = parser.pool.FindCell(parseConstValue(ConstType.CONSTANT_METHODHANDLE)); scanner.expect(Token.COLON); ConstantPool.ConstCell NapeCell = parser.pool.FindCell(parseConstValue(ConstType.CONSTANT_NAMEANDTYPE)); ArrayList bsm_args = new ArrayList<>(256); while (scanner.token != Token.SEMICOLON) { if (scanner.token == Token.COMMA) { scanner.scan(); } bsm_args.add(parseConstRef(null)); } BootstrapMethodData bsmData = new BootstrapMethodData(MHCell, bsm_args); parser.cd.addBootstrapMethod(bsmData); obj = new ConstantPool.ConstValue_IndyPair(bsmData, NapeCell); } } catch (IOException e) { IOProb = e; } return obj; } } // End Visitor /** * Parse CONSTVALUE */ protected ConstantPool.ConstValue parseConstValue(ConstType tag) throws IOException, Scanner.SyntaxError { return pConstVstr.visitExcept(tag); } /** * Parse [TAG] CONSTVALUE */ protected ConstantPool.ConstValue parseTagConstValue(ConstType defaultTag) throws Scanner.SyntaxError, IOException { return parseTagConstValue(defaultTag, null, false); } private ConstType scanConstByID(boolean ignoreKeywords) { ConstType tag = null; if (!ignoreKeywords) { ConstType tg = Tables.tag(scanner.idValue); if (tg != null) { tag = tg; } debugStr(" *^*^*^*^ [ParserCP.scanConst]: {TAG = " + (tg == null ? "null" : tg.toString()) + " "); } return tag; } private ConstType scanConstPrimVal() throws Scanner.SyntaxError, IOException { ConstType tag = null; switch (scanner.token) { case INTVAL: tag = ConstType.CONSTANT_INTEGER; break; case LONGVAL: tag = ConstType.CONSTANT_LONG; break; case FLOATVAL: tag = ConstType.CONSTANT_FLOAT; break; case DOUBLEVAL: tag = ConstType.CONSTANT_DOUBLE; break; case STRINGVAL: case BITS: case IDENT: tag = ConstType.CONSTANT_STRING; break; default: // problem - no constant value System.err.println("NEAR: " + scanner.token.printval()); env.error(scanner.pos, "value.expected"); throw new Scanner.SyntaxError(); } return tag; } private void checkWrongTag(ConstType tag, ConstType defaultTag, ConstType default2Tag) throws Scanner.SyntaxError, IOException { if (defaultTag != null) { if (tag != defaultTag) { if (default2Tag == null) { env.error("warn.wrong.tag", defaultTag.parseKey()); } else if (tag != default2Tag) { env.error("warn.wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey()); } } } } protected ConstantPool.ConstValue parseTagConstValue(ConstType defaultTag, ConstType default2Tag, boolean ignoreKeywords) throws Scanner.SyntaxError, IOException { debugScan(" *^*^*^*^ [ParserCP.parseTagConstValue]: Begin default_tag: ignoreKeywords: " + (ignoreKeywords ? "true" : "false")); // Lookup the Tag from the scanner ConstType tag = scanConstByID(ignoreKeywords); debugStr(" *^*^*^*^ [ParserCP.parseTagConstValue]: {tag = " + tag + ", defaulttag = " + defaultTag + "} "); // If the scanned tag is null if (tag == null) { // and, if the expected tag is null if (defaultTag == null) { // return some other type of constant as the tag tag = scanConstPrimVal(); } else { // otherwise, make the scanned-tag the same constant-type // as the expected tag. tag = defaultTag; } } else { // If the scanned tag is some constant type // and the scanned type does not equal the expected type checkWrongTag(tag, defaultTag, default2Tag); scanner.scan(); } return parseConstValue(tag); } // end parseTagConstValue protected ConstantPool.ConstCell parseConstRef(ConstType defaultTag) throws Scanner.SyntaxError, IOException { return parseConstRef(defaultTag, null, false); } protected ConstantPool.ConstCell parseConstRef(ConstType defaultTag, ConstType default2Tag) throws Scanner.SyntaxError, IOException { return parseConstRef(defaultTag, default2Tag, false); } /** * Parse an instruction argument, one of: * #NUMBER, #NAME, [TAG] CONSTVALUE */ protected ConstantPool.ConstCell parseConstRef(ConstType defaultTag, ConstType default2Tag, boolean ignoreKeywords) throws Scanner.SyntaxError, IOException { if (scanner.token == Token.CPINDEX) { int cpx = scanner.intValue; scanner.scan(); return parser.pool.getCell(cpx); } else { ConstantPool.ConstValue ref = null; ref = parseTagConstValue(defaultTag, default2Tag, ignoreKeywords); return parser.pool.FindCell(ref); } } // end parseConstRef }