Search in sources :

Example 31 with ObjectKlass

use of com.oracle.truffle.espresso.impl.ObjectKlass in project graal by oracle.

the class Target_sun_misc_Unsafe method objectFieldOffset1.

@Substitution(hasReceiver = true, nameProvider = Unsafe11.class)
@SuppressWarnings("unused")
public static long objectFieldOffset1(@JavaType(Unsafe.class) StaticObject self, @JavaType(value = Class.class) StaticObject cl, @JavaType(value = String.class) StaticObject guestName, @Inject Meta meta) {
    Klass k = cl.getMirrorKlass();
    String hostName = meta.toHostString(guestName);
    if (k instanceof ObjectKlass) {
        ObjectKlass kl = (ObjectKlass) k;
        for (Field f : kl.getFieldTable()) {
            if (!f.isRemoved() && f.getNameAsString().equals(hostName)) {
                return SAFETY_FIELD_OFFSET + f.getSlot();
            }
        }
        for (Field f : kl.getStaticFieldTable()) {
            if (!f.isRemoved() && f.getNameAsString().equals(hostName)) {
                return SAFETY_FIELD_OFFSET + f.getSlot();
            }
        }
    }
    throw meta.throwException(meta.java_lang_InternalError);
}
Also used : Field(com.oracle.truffle.espresso.impl.Field) Klass(com.oracle.truffle.espresso.impl.Klass) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass) ArrayKlass(com.oracle.truffle.espresso.impl.ArrayKlass) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass)

Example 32 with ObjectKlass

use of com.oracle.truffle.espresso.impl.ObjectKlass in project graal by oracle.

the class JDWPContextImpl method doRedefine.

private void doRedefine(List<RedefineInfo> redefineInfos, List<ObjectKlass> changedKlasses) throws RedefintionNotSupportedException {
    // list to hold removed inner classes that must be marked removed
    List<ObjectKlass> removedInnerClasses = new ArrayList<>(0);
    // list of classes that need to refresh due to
    // changes in other classes for things like vtable
    List<ObjectKlass> invalidatedClasses = new ArrayList<>();
    // list of all classes that have been redefined within this transaction
    List<ObjectKlass> redefinedClasses = new ArrayList<>();
    // match anon inner classes with previous state
    HotSwapClassInfo[] matchedInfos = innerClassRedefiner.matchAnonymousInnerClasses(redefineInfos, removedInnerClasses);
    // detect all changes to all classes, throws if redefinition cannot be completed
    // due to the nature of the changes
    List<ChangePacket> changePackets = classRedefinition.detectClassChanges(matchedInfos);
    // We have to redefine super classes prior to subclasses
    Collections.sort(changePackets, new HierarchyComparator());
    for (ChangePacket packet : changePackets) {
        JDWP.LOGGER.fine(() -> "Redefining class " + packet.info.getNewName());
        int result = classRedefinition.redefineClass(packet, invalidatedClasses, redefinedClasses);
        if (result != 0) {
            throw new RedefintionNotSupportedException(result);
        }
    }
    // refresh invalidated classes if not already redefined
    Collections.sort(invalidatedClasses, new SubClassHierarchyComparator());
    for (ObjectKlass invalidatedClass : invalidatedClasses) {
        if (!redefinedClasses.contains(invalidatedClass)) {
            JDWP.LOGGER.fine(() -> "Updating invalidated class " + invalidatedClass.getName());
            invalidatedClass.swapKlassVersion(ids);
        }
    }
    // include invalidated classes in all changed classes list
    changedKlasses.addAll(invalidatedClasses);
    // update the JWDP IDs for renamed inner classes
    for (ChangePacket changePacket : changePackets) {
        ObjectKlass klass = changePacket.info.getKlass();
        changedKlasses.add(klass);
        if (changePacket.info.isRenamed()) {
            if (klass != null) {
                ids.updateId(klass);
            }
        }
    }
    // tell the InnerClassRedefiner to commit the changes to cache
    innerClassRedefiner.commit(matchedInfos);
    for (ObjectKlass removed : removedInnerClasses) {
        removed.removeByRedefinition();
    }
}
Also used : ChangePacket(com.oracle.truffle.espresso.redefinition.ChangePacket) ArrayList(java.util.ArrayList) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass) HotSwapClassInfo(com.oracle.truffle.espresso.redefinition.HotSwapClassInfo) RedefintionNotSupportedException(com.oracle.truffle.espresso.redefinition.RedefintionNotSupportedException)

Example 33 with ObjectKlass

use of com.oracle.truffle.espresso.impl.ObjectKlass 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)

Example 34 with ObjectKlass

use of com.oracle.truffle.espresso.impl.ObjectKlass in project graal by oracle.

the class ClassRedefinition method detectClassChanges.

// detect all types of class changes, but return early when a change that require arbitrary
// changes
private static ClassChange detectClassChanges(ParserKlass newParserKlass, ObjectKlass oldKlass, DetectedChange collectedChanges, ParserKlass finalParserKlass) throws RedefintionNotSupportedException {
    ClassChange result = ClassChange.NO_CHANGE;
    ParserKlass oldParserKlass = oldKlass.getLinkedKlass().getParserKlass();
    boolean isPatched = finalParserKlass != null;
    // detect method changes (including constructors)
    ParserMethod[] newParserMethods = newParserKlass.getMethods();
    List<Method> oldMethods = new ArrayList<>(Arrays.asList(oldKlass.getDeclaredMethods()));
    List<ParserMethod> newMethods = new ArrayList<>(Arrays.asList(newParserMethods));
    Map<Method, ParserMethod> bodyChanges = new HashMap<>();
    List<ParserMethod> newSpecialMethods = new ArrayList<>(1);
    boolean constantPoolChanged = false;
    if (!Arrays.equals(oldParserKlass.getConstantPool().getRawBytes(), newParserKlass.getConstantPool().getRawBytes())) {
        constantPoolChanged = true;
    }
    Iterator<Method> oldIt = oldMethods.iterator();
    Iterator<ParserMethod> newIt;
    while (oldIt.hasNext()) {
        Method oldMethod = oldIt.next();
        ParserMethod oldParserMethod = oldMethod.getLinkedMethod().getParserMethod();
        // verify that there is a new corresponding method
        newIt = newMethods.iterator();
        while (newIt.hasNext()) {
            ParserMethod newMethod = newIt.next();
            if (isSameMethod(oldParserMethod, newMethod)) {
                // detect method changes
                ClassChange change = detectMethodChanges(oldParserMethod, newMethod);
                switch(change) {
                    case NO_CHANGE:
                        if (isPatched) {
                            checkForSpecialConstructor(collectedChanges, bodyChanges, newSpecialMethods, oldMethod, oldParserMethod, newMethod);
                        } else if (constantPoolChanged) {
                            if (isObsolete(oldParserMethod, newMethod, oldParserKlass.getConstantPool(), newParserKlass.getConstantPool())) {
                                result = ClassChange.CONSTANT_POOL_CHANGE;
                                collectedChanges.addMethodBodyChange(oldMethod, newMethod);
                            } else {
                                collectedChanges.addUnchangedMethod(oldMethod);
                            }
                        } else {
                            collectedChanges.addUnchangedMethod(oldMethod);
                        }
                        break;
                    case METHOD_BODY_CHANGE:
                        result = change;
                        if (isPatched) {
                            checkForSpecialConstructor(collectedChanges, bodyChanges, newSpecialMethods, oldMethod, oldParserMethod, newMethod);
                        } else {
                            collectedChanges.addMethodBodyChange(oldMethod, newMethod);
                        }
                        break;
                    default:
                        return change;
                }
                newIt.remove();
                oldIt.remove();
                break;
            }
        }
    }
    if (isPatched) {
        ParserMethod[] finalMethods = finalParserKlass.getMethods();
        // map found changed methods
        for (Map.Entry<Method, ParserMethod> entry : bodyChanges.entrySet()) {
            Method oldMethod = entry.getKey();
            ParserMethod changed = entry.getValue();
            for (int i = 0; i < newParserMethods.length; i++) {
                if (newParserMethods[i] == changed) {
                    collectedChanges.addMethodBodyChange(oldMethod, finalMethods[i]);
                    break;
                }
            }
        }
        // map found new methods
        newMethods.addAll(newSpecialMethods);
        for (ParserMethod changed : newMethods) {
            for (int i = 0; i < newParserMethods.length; i++) {
                if (newParserMethods[i] == changed) {
                    collectedChanges.addNewMethod(finalMethods[i]);
                    break;
                }
            }
        }
    } else {
        collectedChanges.addNewMethods(newMethods);
    }
    for (Method oldMethod : oldMethods) {
        collectedChanges.addRemovedMethod(oldMethod.getMethodVersion());
    }
    if (!oldMethods.isEmpty()) {
        result = ClassChange.REMOVE_METHOD;
    } else if (!newMethods.isEmpty()) {
        result = ClassChange.ADD_METHOD;
    }
    if (isPatched) {
        result = ClassChange.CLASS_NAME_CHANGED;
    }
    // detect field changes
    Field[] oldFields = oldKlass.getDeclaredFields();
    ParserField[] newFields = newParserKlass.getFields();
    ArrayList<Field> oldFieldsList = new ArrayList<>(Arrays.asList(oldFields));
    ArrayList<ParserField> newFieldsList = new ArrayList<>(Arrays.asList(newFields));
    Map<ParserField, Field> compatibleFields = new HashMap<>();
    Iterator<Field> oldFieldsIt = oldFieldsList.iterator();
    Iterator<ParserField> newFieldsIt;
    while (oldFieldsIt.hasNext()) {
        Field oldField = oldFieldsIt.next();
        newFieldsIt = newFieldsList.iterator();
        // search for a new corresponding field
        while (newFieldsIt.hasNext()) {
            ParserField newField = newFieldsIt.next();
            // first look for a perfect match
            if (isUnchangedField(oldField, newField, compatibleFields)) {
                // A nested anonymous inner class may contain a field reference to the outer
                // class instance. Since we match against the patched (inner class rename rules
                // applied) if the current class was patched (renamed) the resulting outer
                // field pointer will have a changed type. Hence we should mark it as a new
                // field.
                Matcher matcher = InnerClassRedefiner.ANON_INNER_CLASS_PATTERN.matcher(oldField.getType().toString());
                if (isPatched && matcher.matches()) {
                    break;
                }
                oldFieldsIt.remove();
                newFieldsIt.remove();
                break;
            }
        }
    }
    if (!newFieldsList.isEmpty()) {
        if (isPatched) {
            ParserField[] finalFields = finalParserKlass.getFields();
            // lookup the final new field based on the index in the parser field array
            for (ParserField parserField : newFieldsList) {
                for (int i = 0; i < newFields.length; i++) {
                    if (parserField == newFields[i]) {
                        collectedChanges.addNewField(finalFields[i]);
                        break;
                    }
                }
            }
        } else {
            collectedChanges.addNewFields(newFieldsList);
        }
        result = ClassChange.SCHEMA_CHANGE;
    }
    if (!oldFieldsList.isEmpty()) {
        collectedChanges.addRemovedFields(oldFieldsList);
        result = ClassChange.SCHEMA_CHANGE;
    }
    // detect class-level changes
    if (newParserKlass.getFlags() != oldParserKlass.getFlags()) {
        result = ClassChange.SCHEMA_CHANGE;
    }
    collectedChanges.addCompatibleFields(compatibleFields);
    // detect changes to superclass and implemented interfaces
    Klass superKlass = oldKlass.getSuperKlass();
    if (!newParserKlass.getSuperKlass().equals(oldParserKlass.getSuperKlass())) {
        result = ClassChange.CLASS_HIERARCHY_CHANGED;
        superKlass = getLoadedKlass(newParserKlass.getSuperKlass(), oldKlass);
    }
    collectedChanges.addSuperKlass((ObjectKlass) superKlass);
    ObjectKlass[] newSuperInterfaces = oldKlass.getSuperInterfaces();
    if (!Arrays.equals(newParserKlass.getSuperInterfaces(), oldParserKlass.getSuperInterfaces())) {
        result = ClassChange.CLASS_HIERARCHY_CHANGED;
        newSuperInterfaces = new ObjectKlass[newParserKlass.getSuperInterfaces().length];
        for (int i = 0; i < newParserKlass.getSuperInterfaces().length; i++) {
            newSuperInterfaces[i] = (ObjectKlass) getLoadedKlass(newParserKlass.getSuperInterfaces()[i], oldKlass);
        }
    }
    collectedChanges.addSuperInterfaces(newSuperInterfaces);
    return result;
}
Also used : HashMap(java.util.HashMap) Matcher(java.util.regex.Matcher) ArrayList(java.util.ArrayList) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass) RedefineAddedField(com.oracle.truffle.espresso.impl.RedefineAddedField) Field(com.oracle.truffle.espresso.impl.Field) ParserField(com.oracle.truffle.espresso.impl.ParserField) ParserKlass(com.oracle.truffle.espresso.impl.ParserKlass) ParserMethod(com.oracle.truffle.espresso.impl.ParserMethod) ParserMethod(com.oracle.truffle.espresso.impl.ParserMethod) Method(com.oracle.truffle.espresso.impl.Method) ParserField(com.oracle.truffle.espresso.impl.ParserField) Klass(com.oracle.truffle.espresso.impl.Klass) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass) ParserKlass(com.oracle.truffle.espresso.impl.ParserKlass) HashMap(java.util.HashMap) EconomicMap(org.graalvm.collections.EconomicMap) Map(java.util.Map)

Example 35 with ObjectKlass

use of com.oracle.truffle.espresso.impl.ObjectKlass in project graal by oracle.

the class EspressoInterop method getMembers.

@ExportMessage
@TruffleBoundary
static Object getMembers(StaticObject receiver, @SuppressWarnings("unused") boolean includeInternal) {
    receiver.checkNotForeign();
    if (isNull(receiver)) {
        return EmptyKeysArray.INSTANCE;
    }
    ArrayList<String> members = new ArrayList<>();
    if (receiver.getKlass() == receiver.getKlass().getMeta().java_lang_Class) {
        // SVM does not like ArrayList.addAll(). Do manual copy.
        for (String s : CLASS_KEYS) {
            members.add(s);
        }
    }
    ObjectKlass k = getInteropKlass(receiver);
    for (Field f : k.getFieldTable()) {
        if (f.isPublic() && !f.isRemoved()) {
            members.add(f.getNameAsString());
        }
    }
    for (Method.MethodVersion m : k.getVTable()) {
        if (LookupVirtualMethodNode.isCandidate(m.getMethod())) {
            // Note: If there are overloading, the same key may appear twice.
            // TODO: Cache the keys array in the Klass.
            members.add(m.getMethod().getInteropString());
        }
    }
    // SVM does not like ArrayList.toArray(). Do manual copy.
    String[] array = new String[members.size()];
    int pos = 0;
    for (String str : members) {
        array[pos++] = str;
    }
    return new KeysArray(array);
}
Also used : Field(com.oracle.truffle.espresso.impl.Field) ArrayList(java.util.ArrayList) EmptyKeysArray(com.oracle.truffle.espresso.impl.EmptyKeysArray) KeysArray(com.oracle.truffle.espresso.impl.KeysArray) ObjectKlass(com.oracle.truffle.espresso.impl.ObjectKlass) Method(com.oracle.truffle.espresso.impl.Method) ExportMessage(com.oracle.truffle.api.library.ExportMessage) TruffleBoundary(com.oracle.truffle.api.CompilerDirectives.TruffleBoundary)

Aggregations

ObjectKlass (com.oracle.truffle.espresso.impl.ObjectKlass)35 Klass (com.oracle.truffle.espresso.impl.Klass)15 StaticObject (com.oracle.truffle.espresso.runtime.StaticObject)12 JavaType (com.oracle.truffle.espresso.substitutions.JavaType)10 ArrayKlass (com.oracle.truffle.espresso.impl.ArrayKlass)9 ArrayList (java.util.ArrayList)8 Method (com.oracle.truffle.espresso.impl.Method)7 TruffleBoundary (com.oracle.truffle.api.CompilerDirectives.TruffleBoundary)6 RuntimeConstantPool (com.oracle.truffle.espresso.classfile.RuntimeConstantPool)5 Field (com.oracle.truffle.espresso.impl.Field)5 ParserKlass (com.oracle.truffle.espresso.impl.ParserKlass)5 NoSafepoint (com.oracle.truffle.espresso.jni.NoSafepoint)5 Symbol (com.oracle.truffle.espresso.descriptors.Symbol)4 Name (com.oracle.truffle.espresso.descriptors.Symbol.Name)4 ClassRegistry (com.oracle.truffle.espresso.impl.ClassRegistry)4 Meta (com.oracle.truffle.espresso.meta.Meta)4 Matcher (java.util.regex.Matcher)4 InnerClassesAttribute (com.oracle.truffle.espresso.classfile.attributes.InnerClassesAttribute)3 EspressoException (com.oracle.truffle.espresso.runtime.EspressoException)3 FrameInstance (com.oracle.truffle.api.frame.FrameInstance)2