Search in sources :

Example 1 with ClassfileStream

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;
}
Also used : ClassfileStream(com.oracle.truffle.espresso.classfile.ClassfileStream) ConstantPool(com.oracle.truffle.espresso.classfile.ConstantPool) ByteSequence(com.oracle.truffle.espresso.descriptors.ByteSequence)

Example 2 with ClassfileStream

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);
}
Also used : ClassfileStream(com.oracle.truffle.espresso.classfile.ClassfileStream) Matcher(java.util.regex.Matcher) ParserMethod(com.oracle.truffle.espresso.impl.ParserMethod) NameAndTypeConstant(com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant) ParserField(com.oracle.truffle.espresso.impl.ParserField) Type(com.oracle.truffle.espresso.descriptors.Symbol.Type) ConstantPool(com.oracle.truffle.espresso.classfile.ConstantPool) ParserKlass(com.oracle.truffle.espresso.impl.ParserKlass) EnclosingMethodAttribute(com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute)

Example 3 with ClassfileStream

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;
}
Also used : Meta(com.oracle.truffle.espresso.meta.Meta) ClassfileStream(com.oracle.truffle.espresso.classfile.ClassfileStream)

Example 4 with ClassfileStream

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++;
    }
}
Also used : ClassfileStream(com.oracle.truffle.espresso.classfile.ClassfileStream) ConstantPool(com.oracle.truffle.espresso.classfile.ConstantPool) ByteSequence(com.oracle.truffle.espresso.descriptors.ByteSequence)

Example 5 with ClassfileStream

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;
}
Also used : Types(com.oracle.truffle.espresso.descriptors.Types) ClassfileStream(com.oracle.truffle.espresso.classfile.ClassfileStream) ArrayList(java.util.ArrayList) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass) StaticObject(com.oracle.truffle.espresso.runtime.StaticObject) ParserKlass(com.oracle.truffle.espresso.impl.ParserKlass)

Aggregations

ClassfileStream (com.oracle.truffle.espresso.classfile.ClassfileStream)5 ConstantPool (com.oracle.truffle.espresso.classfile.ConstantPool)3 ByteSequence (com.oracle.truffle.espresso.descriptors.ByteSequence)2 ParserKlass (com.oracle.truffle.espresso.impl.ParserKlass)2 EnclosingMethodAttribute (com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute)1 NameAndTypeConstant (com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant)1 Type (com.oracle.truffle.espresso.descriptors.Symbol.Type)1 Types (com.oracle.truffle.espresso.descriptors.Types)1 ObjectKlass (com.oracle.truffle.espresso.impl.ObjectKlass)1 ParserField (com.oracle.truffle.espresso.impl.ParserField)1 ParserMethod (com.oracle.truffle.espresso.impl.ParserMethod)1 Meta (com.oracle.truffle.espresso.meta.Meta)1 StaticObject (com.oracle.truffle.espresso.runtime.StaticObject)1 ArrayList (java.util.ArrayList)1 Matcher (java.util.regex.Matcher)1