588 lines
22 KiB
Java
588 lines
22 KiB
Java
/*
|
|
* 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<ConstantPool.ConstValue> {
|
|
|
|
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", "<Float>");
|
|
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", "<CPINDEX>");
|
|
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", "<CPINDEX>");
|
|
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<ConstantPool.ConstCell> 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
|
|
}
|