use of com.oracle.truffle.espresso.classfile.ClassfileStream in project graal by oracle.
the class ConstantPoolPatcher method patchConstantPool.
public static byte[] patchConstantPool(byte[] bytes, Map<Symbol<Symbol.Name>, Symbol<Symbol.Name>> rules, EspressoContext context) throws ClassFormatError {
byte[] result = Arrays.copyOf(bytes, bytes.length);
ClassfileStream stream = new ClassfileStream(bytes, null);
// skip magic and version - 8 bytes
stream.skip(8);
final int length = stream.readU2();
int byteArrayGrowth = 0;
int i = 1;
while (i < length) {
final int tagByte = stream.readU1();
final ConstantPool.Tag tag = ConstantPool.Tag.fromValue(tagByte);
switch(tag) {
case UTF8:
// utfLength is first two bytes
int position = stream.getPosition() + 2;
ByteSequence byteSequence = stream.readByteSequenceUTF();
Symbol<Symbol.Name> asSymbol = context.getNames().getOrCreate(byteSequence);
if (rules.containsKey(asSymbol)) {
int originalLegth = byteSequence.length();
Symbol<Symbol.Name> replacedSymbol = rules.get(asSymbol);
if (originalLegth == replacedSymbol.length()) {
replacedSymbol.writeTo(result, position + byteArrayGrowth);
} else {
int diff = replacedSymbol.length() - originalLegth;
byteArrayGrowth += diff;
// make room for the longer class name
result = Arrays.copyOf(result, result.length + diff);
int currentPosition = stream.getPosition();
// shift the tail of array
System.arraycopy(bytes, currentPosition, result, currentPosition + byteArrayGrowth, bytes.length - currentPosition);
// update utfLength
char utfLength = (char) replacedSymbol.length();
int utfLengthPosition = position - 2 + byteArrayGrowth - diff;
result[utfLengthPosition] = (byte) (utfLength >> 8);
result[utfLengthPosition + 1] = (byte) (utfLength);
// insert patched byte array
replacedSymbol.writeTo(result, utfLengthPosition + 2);
}
}
break;
case CLASS:
case STRING:
case METHODTYPE:
stream.readU2();
break;
case FIELD_REF:
case METHOD_REF:
case INTERFACE_METHOD_REF:
case NAME_AND_TYPE:
case DYNAMIC:
case INVOKEDYNAMIC:
stream.readU2();
stream.readU2();
break;
case INTEGER:
stream.readS4();
break;
case FLOAT:
stream.readFloat();
break;
case LONG:
stream.readS8();
++i;
break;
case DOUBLE:
stream.readDouble();
++i;
break;
case METHODHANDLE:
stream.readU1();
stream.readU2();
break;
default:
throw new ClassFormatError();
}
i++;
}
return result;
}
use of com.oracle.truffle.espresso.classfile.ClassfileStream in project graal by oracle.
the class ClassInfo method create.
public static HotSwapClassInfo create(ObjectKlass klass, Symbol<Name> name, byte[] bytes, StaticObject definingLoader, EspressoContext context) {
Symbol<Type> type = context.getTypes().fromName(name);
ParserKlass parserKlass = ClassfileParser.parse(new ClassfileStream(bytes, null), definingLoader, type, context);
StringBuilder hierarchy = new StringBuilder();
StringBuilder methods = new StringBuilder();
StringBuilder fields = new StringBuilder();
StringBuilder enclosing = new StringBuilder();
Matcher matcher = InnerClassRedefiner.ANON_INNER_CLASS_PATTERN.matcher(name.toString());
if (matcher.matches()) {
// fingerprints are only relevant for inner classes
hierarchy.append(parserKlass.getSuperKlass().toString()).append(";");
for (Symbol<Type> itf : parserKlass.getSuperInterfaces()) {
hierarchy.append(itf.toString()).append(";");
}
for (ParserMethod method : parserKlass.getMethods()) {
methods.append(method.getName().toString()).append(";");
methods.append(method.getSignature().toString()).append(";");
}
for (ParserField field : parserKlass.getFields()) {
fields.append(field.getType().toString()).append(";");
fields.append(field.getName().toString()).append(";");
}
ConstantPool pool = parserKlass.getConstantPool();
EnclosingMethodAttribute attr = (EnclosingMethodAttribute) parserKlass.getAttribute(EnclosingMethodAttribute.NAME);
NameAndTypeConstant nmt = pool.nameAndTypeAt(attr.getMethodIndex());
enclosing.append(nmt.getName(pool)).append(";").append(nmt.getDescriptor(pool));
}
return new HotSwapClassInfo(klass, name, definingLoader, hierarchy.toString(), methods.toString(), fields.toString(), enclosing.toString(), new ArrayList<>(1), bytes);
}
use of com.oracle.truffle.espresso.classfile.ClassfileStream in project graal by oracle.
the class ClassRegistry method getParserKlass.
private ParserKlass getParserKlass(byte[] bytes, Symbol<Type> typeOrNull, ClassDefinitionInfo info) {
// May throw guest ClassFormatError, NoClassDefFoundError.
ParserKlass parserKlass = ClassfileParser.parse(new ClassfileStream(bytes, null), getClassLoader(), typeOrNull, context, info);
Meta meta = getMeta();
if (!loaderIsBootOrPlatform(getClassLoader(), meta) && parserKlass.getName().toString().startsWith("java/")) {
throw meta.throwExceptionWithMessage(meta.java_lang_SecurityException, "Define class in prohibited package name: " + parserKlass.getName());
}
return parserKlass;
}
use of com.oracle.truffle.espresso.classfile.ClassfileStream in project graal by oracle.
the class ConstantPoolPatcher method getDirectInnerClassNames.
public static void getDirectInnerClassNames(Symbol<Symbol.Name> fileSystemName, byte[] bytes, ArrayList<Symbol<Symbol.Name>> innerNames, EspressoContext context) throws ClassFormatError {
ClassfileStream stream = new ClassfileStream(bytes, null);
ByteSequence fileNameBytes = fileSystemName.subSequence(0, fileSystemName.length());
// skip magic and version - 8 bytes
stream.skip(8);
final int length = stream.readU2();
int i = 1;
while (i < length) {
final int tagByte = stream.readU1();
final ConstantPool.Tag tag = ConstantPool.Tag.fromValue(tagByte);
switch(tag) {
case UTF8:
ByteSequence byteSequence = stream.readByteSequenceUTF();
if (byteSequence.contentStartsWith(fileNameBytes) && !byteSequence.contentEquals(fileNameBytes)) {
if (InnerClassRedefiner.ANON_INNER_CLASS_PATTERN.matcher(byteSequence.toString()).matches()) {
innerNames.add(context.getNames().getOrCreate(byteSequence));
}
}
break;
case CLASS:
case STRING:
case METHODTYPE:
stream.readU2();
break;
case FIELD_REF:
case METHOD_REF:
case INTERFACE_METHOD_REF:
case NAME_AND_TYPE:
case DYNAMIC:
case INVOKEDYNAMIC:
stream.readU2();
stream.readU2();
break;
case INTEGER:
stream.readS4();
break;
case FLOAT:
stream.readFloat();
break;
case LONG:
stream.readS8();
++i;
break;
case DOUBLE:
stream.readDouble();
++i;
break;
case METHODHANDLE:
stream.readU1();
stream.readU2();
break;
default:
throw new ClassFormatError();
}
i++;
}
}
use of com.oracle.truffle.espresso.classfile.ClassfileStream in project graal by oracle.
the class ClassRedefinition method detectClassChanges.
public List<ChangePacket> detectClassChanges(HotSwapClassInfo[] classInfos) throws RedefintionNotSupportedException {
List<ChangePacket> result = new ArrayList<>(classInfos.length);
EconomicMap<ObjectKlass, ChangePacket> temp = EconomicMap.create(1);
EconomicSet<ObjectKlass> superClassChanges = EconomicSet.create(1);
for (HotSwapClassInfo hotSwapInfo : classInfos) {
ObjectKlass klass = hotSwapInfo.getKlass();
if (klass == null) {
// New anonymous inner class
result.add(new ChangePacket(hotSwapInfo, ClassChange.NEW_CLASS));
continue;
}
byte[] bytes = hotSwapInfo.getBytes();
ParserKlass parserKlass;
ParserKlass newParserKlass = null;
ClassChange classChange;
DetectedChange detectedChange = new DetectedChange();
StaticObject loader = klass.getDefiningClassLoader();
Types types = klass.getContext().getTypes();
parserKlass = ClassfileParser.parse(new ClassfileStream(bytes, null), loader, types.fromName(hotSwapInfo.getName()), context);
if (hotSwapInfo.isPatched()) {
byte[] patched = hotSwapInfo.getPatchedBytes();
newParserKlass = parserKlass;
// we detect changes against the patched bytecode
parserKlass = ClassfileParser.parse(new ClassfileStream(patched, null), loader, types.fromName(hotSwapInfo.getNewName()), context);
}
classChange = detectClassChanges(parserKlass, klass, detectedChange, newParserKlass);
if (classChange == ClassChange.CLASS_HIERARCHY_CHANGED && detectedChange.getSuperKlass() != null) {
// keep track of unhandled changed super classes
ObjectKlass superKlass = detectedChange.getSuperKlass();
ObjectKlass oldSuperKlass = klass.getSuperKlass();
ObjectKlass commonSuperKlass = (ObjectKlass) oldSuperKlass.findLeastCommonAncestor(superKlass);
while (superKlass != commonSuperKlass) {
superClassChanges.add(superKlass);
superKlass = superKlass.getSuperKlass();
}
}
ChangePacket packet = new ChangePacket(hotSwapInfo, newParserKlass != null ? newParserKlass : parserKlass, classChange, detectedChange);
result.add(packet);
temp.put(klass, packet);
}
// add superclass change information to result
for (ObjectKlass superKlass : superClassChanges) {
ChangePacket packet = temp.get(superKlass);
if (packet != null) {
// update changed super klass
packet.detectedChange.markChangedSuperClass();
} else {
// create new packet to signal a subclass was changed but the superclass didn't
DetectedChange change = new DetectedChange();
change.markChangedSuperClass();
packet = new ChangePacket(HotSwapClassInfo.createForSuperClassChanged(superKlass), null, ClassChange.CLASS_HIERARCHY_CHANGED, change);
result.add(packet);
}
}
return result;
}
Aggregations