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);
}
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();
}
}
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;
}
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;
}
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);
}
Aggregations