diff --git a/.gitignore b/.gitignore
index 0483f5409..201e4ab1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,6 @@ traces
/tests/streams/*.txt
npm-debug.log*
/.metadata
+.DS_Store
+/SOMns.iml
+/libs/black-diamonds
diff --git a/build.xml b/build.xml
index 3fec34f04..d72c556f4 100644
--- a/build.xml
+++ b/build.xml
@@ -529,4 +529,14 @@ kernel: ${kernel}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/som/VM.java b/src/som/VM.java
index 90f5e59fc..22390d4c8 100644
--- a/src/som/VM.java
+++ b/src/som/VM.java
@@ -409,6 +409,8 @@ public void setupInstruments(final Env env) {
: "Currently, CandidateIdentifer and Snapshots are not compatible";
structuralProbe = SnapshotBackend.getProbe();
}
+
+ structuralProbe = new StructuralProbe<>();
}
public SClass loadExtensionModule(final String filename) {
@@ -419,6 +421,13 @@ public MixinDefinition loadModule(final String filename) throws IOException {
return objectSystem.loadModule(filename);
}
+ public MixinDefinition loadModule(final String filename,MixinDefinition oldModule) throws IOException {
+ if (oldModule == null) {
+ return objectSystem.loadModule(filename);
+ }
+ return objectSystem.reLoadModule(filename,oldModule);
+ }
+
public MixinDefinition loadModule(final Source source) throws IOException {
return objectSystem.loadModule(source);
}
@@ -443,4 +452,8 @@ public static void resetClassReferences(final boolean callFromUnitTest) {
ChannelPrimitives.resetClassReferences();
}
+
+ public StructuralProbe getStructuralProbe(){
+ return structuralProbe;
+ }
}
diff --git a/src/som/compiler/MixinBuilder.java b/src/som/compiler/MixinBuilder.java
index 458ae6b43..7f7b57365 100644
--- a/src/som/compiler/MixinBuilder.java
+++ b/src/som/compiler/MixinBuilder.java
@@ -157,6 +157,29 @@ public MixinBuilder(final ScopeBuilder> outer, final AccessModifier accessModi
this.structuralProbe = structuralProbe;
}
+ public MixinBuilder(final ScopeBuilder> outer, final AccessModifier accessModifier,
+ final SSymbol name, final SourceSection nameSection,
+ final StructuralProbe structuralProbe,
+ final SomLanguage language, final MixinDefinitionId mixinId){
+ super(outer, outer == null ? null : outer.getScope());
+ this.name = name;
+ this.nameSection = nameSection;
+ this.mixinId = mixinId;
+
+ this.classSide = false;
+ this.language = language;
+
+ this.classScope = createScope(scope);
+
+ this.initializer = new MethodBuilder(this, structuralProbe);
+ this.primaryFactoryMethod =
+ new MethodBuilder(this, classScope, false, language, structuralProbe);
+ this.superclassAndMixinResolutionBuilder = createSuperclassResolutionBuilder();
+
+ this.accessModifier = accessModifier;
+ this.structuralProbe = structuralProbe;
+ }
+
public static class MixinDefinitionError extends SemanticDefinitionError {
private static final long serialVersionUID = 5030639383869198851L;
@@ -493,7 +516,7 @@ protected boolean isImmutable() {
return true;
}
- private void setHolders(final MixinDefinition clsDef) {
+ public void setHolders(final MixinDefinition clsDef) {
assert clsDef != null;
for (Dispatchable disp : dispatchables.getValues()) {
if (disp instanceof SInvokable) {
@@ -675,6 +698,10 @@ public void addNestedMixin(final MixinDefinition nestedMixin)
slots.put(name, cacheSlot);
}
+ public void addSlotsUnsafe(EconomicMap newSlots){
+ slots.putAll(newSlots);
+ }
+
public MixinDefinitionId getMixinId() {
return mixinId;
}
diff --git a/src/som/compiler/MixinDefinition.java b/src/som/compiler/MixinDefinition.java
index c12ad50ea..86e0892a8 100644
--- a/src/som/compiler/MixinDefinition.java
+++ b/src/som/compiler/MixinDefinition.java
@@ -291,7 +291,7 @@ protected static boolean sameClassConstruction(final Object a, final Object b) {
return sameClassConstruction(aC.getSuperClass(), bC.getSuperClass());
}
- private final ArrayList cache = new ArrayList<>(2);
+ public final ArrayList cache = new ArrayList<>(2);
private ClassFactory getCached(final Object superclassAndMixins) {
if (superclassAndMixins == null) {
@@ -907,4 +907,5 @@ public SSymbol getIdentifier() {
return identifier;
}
+
}
diff --git a/src/som/compiler/Parser.java b/src/som/compiler/Parser.java
index b5324953b..a134e67ed 100644
--- a/src/som/compiler/Parser.java
+++ b/src/som/compiler/Parser.java
@@ -335,6 +335,13 @@ public MixinBuilder moduleDeclaration() throws ProgramDefinitionError {
return classDeclaration(null, AccessModifier.PUBLIC);
}
+ public MixinBuilder moduleDeclaration(MixinBuilder.MixinDefinitionId mixinDefinitionId) throws ProgramDefinitionError {
+ compatibilityNewspeakVersionAndFileCategory();
+
+ comments();
+ return classDeclaration(null, AccessModifier.PUBLIC, mixinDefinitionId);
+ }
+
protected String className() throws ParseError {
String mixinName = text;
expect(Identifier, IdentifierTag.class);
@@ -380,6 +387,45 @@ private MixinBuilder classDeclaration(final MixinBuilder outerBuilder,
return mxnBuilder;
}
+ private MixinBuilder classDeclaration(final MixinBuilder outerBuilder,
+ final AccessModifier accessModifier, MixinBuilder.MixinDefinitionId mixinDefinitionId) throws ProgramDefinitionError {
+ expectIdentifier("class", "Found unexpected token %(found)s. " +
+ "Tried parsing a class declaration and expected 'class' instead.",
+ KeywordTag.class);
+
+ int coord = getStartIndex();
+ String mixinName = className();
+ SourceSection nameSS = getSource(coord);
+
+ MixinBuilder mxnBuilder = new MixinBuilder(outerBuilder, accessModifier,
+ symbolFor(mixinName), nameSS, structuralProbe, language,mixinDefinitionId);
+
+ MethodBuilder primaryFactory = mxnBuilder.getPrimaryFactoryMethodBuilder();
+ coord = getStartIndex();
+
+ // Newspeak-spec: this is not strictly sufficient for Newspeak
+ // it could also parse a binary selector here, I think
+ // but, doesn't seem so useful, so, let's keep it simple
+ if (sym == Identifier || sym == Keyword) {
+ messagePattern(primaryFactory);
+ } else {
+ // in the standard case, the primary factory method is #new
+ primaryFactory.addArgument(Symbols.SELF, getEmptySource());
+ primaryFactory.setSignature(Symbols.NEW);
+ }
+ mxnBuilder.setupInitializerBasedOnPrimaryFactory(getSource(coord));
+
+ comments();
+
+ expect(Equal, "Unexpected symbol %(found)s."
+ + " Tried to parse the class declaration of " + mixinName
+ + " and expect '=' before the (optional) inheritance declaration.",
+ KeywordTag.class);
+
+ inheritanceListAndOrBody(mxnBuilder);
+ return mxnBuilder;
+ }
+
private void inheritanceListAndOrBody(final MixinBuilder mxnBuilder)
throws ProgramDefinitionError {
if (sym == NewTerm) {
diff --git a/src/som/compiler/SourcecodeCompiler.java b/src/som/compiler/SourcecodeCompiler.java
index 0d26ffad2..57eed172f 100644
--- a/src/som/compiler/SourcecodeCompiler.java
+++ b/src/som/compiler/SourcecodeCompiler.java
@@ -62,4 +62,21 @@ protected final MixinDefinition compile(final Parser parser,
language.getVM().reportLoadedSource(source);
return result;
}
+
+ public MixinDefinition recompileModule(Source source, StructuralProbe structuralProbe) throws ProgramDefinitionError {
+ Parser parser = new Parser(source.getCharacters().toString(), source, null, language);
+ int coord = parser.getStartIndex();
+ MixinBuilder mxnBuilder = parser.moduleDeclaration();
+ MixinDefinition result = mxnBuilder.assemble(parser.getSource(coord));
+ return result;
+ }
+
+ public MixinDefinition recompileModule(Source source, StructuralProbe structuralProbe, MixinDefinition oldModule) throws ProgramDefinitionError {
+ Parser parser = new Parser(source.getCharacters().toString(), source, null, language);
+ int coord = parser.getStartIndex();
+ MixinBuilder mxnBuilder = parser.moduleDeclaration(oldModule.getMixinId());
+ //mxnBuilder.addSlotsUnsafe(oldModule.getSlots());
+ MixinDefinition result = mxnBuilder.assemble(parser.getSource(coord));
+ return result;
+ }
}
diff --git a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java
index 51109b072..96f6c769c 100644
--- a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java
+++ b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java
@@ -87,6 +87,9 @@ public SClass read(final SObject rcvr) {
if (cachedValue == Nil.nilObject) {
return instantiateAndWriteUnsynced(rcvr);
} else {
+ if (cachedValue == null) {
+ return instantiateAndWriteUnsynced(rcvr);
+ }
assert cachedValue instanceof SClass;
return (SClass) cachedValue;
}
diff --git a/src/som/interpreter/nodes/dispatch/DispatchGuard.java b/src/som/interpreter/nodes/dispatch/DispatchGuard.java
index 6b5129b3b..5f1b753f9 100644
--- a/src/som/interpreter/nodes/dispatch/DispatchGuard.java
+++ b/src/som/interpreter/nodes/dispatch/DispatchGuard.java
@@ -1,5 +1,9 @@
package som.interpreter.nodes.dispatch;
+import com.oracle.truffle.api.Assumption;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleRuntime;
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import som.compiler.MixinDefinition.SlotDefinition;
@@ -14,6 +18,15 @@
public abstract class DispatchGuard {
+
+ @CompilerDirectives.CompilationFinal
+ private static Assumption noModuleReloaded = Truffle.getRuntime().createAssumption("noMoRel");
+
+ public static void invalidateAssumption() {
+ noModuleReloaded.invalidate();
+ noModuleReloaded = Truffle.getRuntime().createAssumption("noMoRel");
+ }
+
public abstract boolean entryMatches(Object obj)
throws InvalidAssumptionException;
@@ -58,6 +71,7 @@ public static CheckSObject createSObjectCheck(final SObject obj) {
private static final class CheckClass extends DispatchGuard {
private final Class> expected;
+ private final Assumption noLoad = noModuleReloaded;
CheckClass(final Class> expectedClass) {
this.expected = expectedClass;
@@ -65,20 +79,29 @@ private static final class CheckClass extends DispatchGuard {
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
return obj.getClass() == expected;
}
}
private static final class CheckTrue extends DispatchGuard {
+
+ private final Assumption noLoad = noModuleReloaded;
+
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
return obj == Boolean.TRUE;
}
}
private static final class CheckFalse extends DispatchGuard {
+
+ private final Assumption noLoad = noModuleReloaded;
+
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
return obj == Boolean.FALSE;
}
}
@@ -86,6 +109,7 @@ public boolean entryMatches(final Object obj) throws InvalidAssumptionException
private static final class CheckObjectWithoutFields extends DispatchGuard {
private final ClassFactory expected;
+ private final Assumption noLoad = noModuleReloaded;
CheckObjectWithoutFields(final ClassFactory expected) {
this.expected = expected;
@@ -93,6 +117,7 @@ private static final class CheckObjectWithoutFields extends DispatchGuard {
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
return obj instanceof SObjectWithoutFields &&
((SObjectWithoutFields) obj).getFactory() == expected;
}
@@ -101,6 +126,7 @@ public boolean entryMatches(final Object obj) throws InvalidAssumptionException
private static final class CheckSClass extends DispatchGuard {
private final ClassFactory expected;
+ private final Assumption noLoad = noModuleReloaded;
CheckSClass(final ClassFactory expected) {
this.expected = expected;
@@ -108,6 +134,7 @@ private static final class CheckSClass extends DispatchGuard {
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
return obj instanceof SClass &&
((SClass) obj).getFactory() == expected;
}
@@ -115,6 +142,7 @@ public boolean entryMatches(final Object obj) throws InvalidAssumptionException
public abstract static class CheckSObject extends DispatchGuard {
protected final ObjectLayout expected;
+ protected final Assumption noLoad = noModuleReloaded;
CheckSObject(final ObjectLayout expected) {
this.expected = expected;
@@ -136,6 +164,7 @@ private static final class CheckSMutableObject extends CheckSObject {
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
expected.checkIsLatest();
return obj instanceof SMutableObject &&
((SMutableObject) obj).getObjectLayout() == expected;
@@ -155,6 +184,7 @@ private static final class CheckSImmutableObject extends CheckSObject {
@Override
public boolean entryMatches(final Object obj) throws InvalidAssumptionException {
+ noLoad.check();
expected.checkIsLatest();
return obj instanceof SImmutableObject &&
((SImmutableObject) obj).getObjectLayout() == expected;
diff --git a/src/som/interpreter/objectstorage/ClassFactory.java b/src/som/interpreter/objectstorage/ClassFactory.java
index 639764042..4bcda3bbe 100644
--- a/src/som/interpreter/objectstorage/ClassFactory.java
+++ b/src/som/interpreter/objectstorage/ClassFactory.java
@@ -53,7 +53,7 @@ public final class ClassFactory {
private final MixinDefinition mixinDef;
private final EconomicSet instanceSlots;
- private final EconomicMap dispatchables;
+ public final EconomicMap dispatchables;
private final boolean hasOnlyImmutableFields;
diff --git a/src/som/interpreter/objectstorage/StorageLocation.java b/src/som/interpreter/objectstorage/StorageLocation.java
index a933cddf0..0291c0ed6 100644
--- a/src/som/interpreter/objectstorage/StorageLocation.java
+++ b/src/som/interpreter/objectstorage/StorageLocation.java
@@ -54,16 +54,20 @@ public static StorageLocation createForObject(final ObjectLayout layout,
}
protected final ObjectLayout layout;
- protected final SlotDefinition slot;
+ protected SlotDefinition slot;
protected StorageLocation(final ObjectLayout layout, final SlotDefinition slot) {
this.layout = layout;
this.slot = slot;
}
+
public SlotDefinition getSlot() {
return slot;
}
+ public void setSlot(SlotDefinition slot) {
+ this.slot = slot;
+ }
/**
* @return true, if it is an object location, false otherwise.
diff --git a/src/som/vm/ObjectSystem.java b/src/som/vm/ObjectSystem.java
index abf9a8ce3..0cf465481 100644
--- a/src/som/vm/ObjectSystem.java
+++ b/src/som/vm/ObjectSystem.java
@@ -150,10 +150,39 @@ public MixinDefinition loadModule(final String filename) throws IOException {
return loadModule(source);
}
+ public MixinDefinition reLoadModule(final String filename, MixinDefinition oldModule) throws IOException{
+ File file = new File(filename);
+
+ if (!file.exists()) {
+ throw new FileNotFoundException(filename);
+ }
+
+ if (!file.isFile()) {
+ throw new NotAFileException(filename);
+ }
+
+ Source source = SomLanguage.getSource(file);
+ return reLoadModule(source,oldModule);
+ }
+
+ public MixinDefinition reLoadModule(final Source source, MixinDefinition oldModule) throws IOException {
+ try {
+ return compiler.recompileModule(source,null,oldModule);
+ } catch (ProgramDefinitionError programDefinitionError) {
+ programDefinitionError.printStackTrace();
+ }
+ return null;
+ }
+
public MixinDefinition loadModule(final Source source) throws IOException {
URI uri = source.getURI();
if (loadedModules.containsKey(uri)) {
- return loadedModules.get(uri);
+ System.out.println("UPDATING MODULE");
+ try {
+ return compiler.recompileModule(source,null);
+ } catch (ProgramDefinitionError programDefinitionError) {
+ programDefinitionError.printStackTrace();
+ }
}
MixinDefinition module;
diff --git a/src/som/vmobjects/SObject.java b/src/som/vmobjects/SObject.java
index a12f4ee87..d793b6881 100644
--- a/src/som/vmobjects/SObject.java
+++ b/src/som/vmobjects/SObject.java
@@ -25,6 +25,8 @@
package som.vmobjects;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.MapCursor;
@@ -34,9 +36,12 @@
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.nodes.ExplodeLoop;
+import org.graalvm.collections.Pair;
import som.compiler.MixinDefinition.SlotDefinition;
+import som.interpreter.nodes.dispatch.DispatchGuard;
import som.interpreter.objectstorage.ClassFactory;
import som.interpreter.objectstorage.ObjectLayout;
+import som.interpreter.objectstorage.ObjectTransitionSafepoint;
import som.interpreter.objectstorage.StorageLocation;
import som.interpreter.objectstorage.StorageLocation.DoubleStorageLocation;
import som.interpreter.objectstorage.StorageLocation.LongStorageLocation;
@@ -226,7 +231,7 @@ private boolean txMutObjLocEquals(final SMutableObject o) {
// need to ignore mutators and class slots
// ignore primitives, have been checked separately before
if (e.getKey().getClass() == SlotDefinition.class && e.getValue().isObjectLocation() &&
- e.getValue().read(this) != oLocs.get(e.getKey()).read(o)) {
+ e.getValue().read(this) != oLocs.get(e.getKey()).read(this)) {
return false;
}
}
@@ -394,7 +399,6 @@ private EconomicMap getAllFields() {
private void setAllFields(final EconomicMap fieldValues) {
resetFields();
primitiveUsedMap = 0;
-
MapCursor entry = fieldValues.getEntries();
while (entry.advance()) {
if (entry.getValue() != null) {
@@ -424,12 +428,56 @@ private void setLayoutAndTransferFields(final ObjectLayout layoutAtClass) {
CompilerDirectives.transferToInterpreterAndInvalidate();
EconomicMap fieldValues = getAllFields();
+ //fieldValues = fixFieldsToNewSlots(layoutAtClass, fieldValues);
+ ObjectLayout oldObjectLayout = objectLayout;
+ objectLayout = layoutAtClass;
+ assert oldObjectLayout != objectLayout;
+ extensionPrimFields = getExtendedPrimStorage(layoutAtClass);
+ extensionObjFields = getExtendedObjectStorage(layoutAtClass);
+ try {
+ setAllFields(fieldValues);
+ } catch ( ArithmeticException error){
+ objectLayout = oldObjectLayout;
+ this.setLayoutAndTransferFieldsOnClassUpdate(layoutAtClass, fieldValues);
+ }
+ }
+ private void setLayoutAndTransferFieldsOnClassUpdate(final ObjectLayout layoutAtClass,EconomicMap fieldValues) {
+ CompilerDirectives.transferToInterpreterAndInvalidate();
+ EconomicMap newSlots = fixFieldsToNewSlots(layoutAtClass, fieldValues);
objectLayout = layoutAtClass;
extensionPrimFields = getExtendedPrimStorage(layoutAtClass);
extensionObjFields = getExtendedObjectStorage(layoutAtClass);
- setAllFields(fieldValues);
+ setAllFields(newSlots);
+ DispatchGuard.invalidateAssumption();
+ }
+
+ private EconomicMap fixFieldsToNewSlots(ObjectLayout layoutAtClass, EconomicMap fieldValues ) {
+ EconomicMap oldSlots = objectLayout.getStorageLocations();
+ EconomicMap newSlots = layoutAtClass.getStorageLocations();
+ Map> layoutLocations = new HashMap<>();
+ EconomicMap newFieldValues = EconomicMap.create();
+ for (SlotDefinition newSlot : newSlots.getKeys()){
+ for (SlotDefinition oldSlot : oldSlots.getKeys()){
+ if(oldSlot.getName() == newSlot.getName()){
+ StorageLocation newLoc = newSlots.get(newSlot);
+ if (newLoc.isObjectLocation()){
+ layoutLocations.put(oldSlot, Pair.create(newSlot,fieldValues.get(oldSlot)));
+ break;
+ }
+ }
+ }
+
+ }
+ for (SlotDefinition slot : fieldValues.getKeys()) {
+ //StorageLocation location = oldSlots.get(slot);
+ Pair newSlotDef = layoutLocations.get(slot);
+ if (newSlotDef != null) {
+ newFieldValues.put(newSlotDef.getLeft(),newSlotDef.getRight());
+ }
+ }
+ return newFieldValues;
}
/**
@@ -483,7 +531,12 @@ public static int getPrimitiveFieldMask(final int fieldIndex) {
private StorageLocation getLocation(final SlotDefinition slot) {
StorageLocation location = objectLayout.getStorageLocation(slot);
- assert location != null;
+ // TODO: added here a division by 0 to be able to debug this when it happens.
+ // I do not recall what it is due to, but probably it is about reloading nested classes
+ // assert location != null;
+ if (location == null) {
+ int a = 1 / 0;
+ }
return location;
}
diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java
index 98522f88f..8de15643f 100644
--- a/src/tools/debugger/FrontendConnector.java
+++ b/src/tools/debugger/FrontendConnector.java
@@ -4,14 +4,17 @@
import java.net.BindException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
+import com.oracle.truffle.api.debug.DebugStackFrame;
+import com.oracle.truffle.api.debug.DebugValue;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
import org.java_websocket.WebSocket;
import com.google.gson.Gson;
@@ -24,7 +27,16 @@
import bd.source.SourceCoordinate;
import bd.source.TaggedSourceCoordinate;
+import bd.tools.structure.StructuralProbe;
+import som.VM;
+import som.compiler.MixinDefinition;
+import som.compiler.Variable;
+import som.interpreter.nodes.dispatch.DispatchGuard;
+import som.interpreter.nodes.dispatch.Dispatchable;
+import som.interpreter.objectstorage.ClassFactory;
+import som.interpreter.objectstorage.StorageLocation;
import som.vm.VmSettings;
+import som.vmobjects.SInvokable;
import som.vmobjects.SSymbol;
import tools.Tagging;
import tools.TraceData;
@@ -189,6 +201,7 @@ private void ensureConnectionIsAvailable() {
private static TaggedSourceCoordinate[] createSourceSections(final Source source,
final Map>>> sourcesTags,
final Instrumenter instrumenter, final Set rootNodes) {
+
Set sections = new HashSet<>();
Map>> tagsForSections = sourcesTags.get(source);
@@ -349,4 +362,78 @@ private void closeAllSockets() {
traceHandler.stop(delay);
} catch (InterruptedException e) {}
}
+
+ public void restartFrame(Suspension suspension, DebugStackFrame frame) {
+ suspension.getEvent().prepareUnwindFrame(frame,null) ;
+ suspension.resume();
+ suspension.resume();
+ }
+
+ // Code Uptading stuff
+ public MixinDefinition updateClass(String filePath) {
+ try {
+ //TODO: support inner classes
+ VM vm = webDebugger.vm;
+ StructuralProbe structuralProbe = vm.getStructuralProbe();
+ EconomicSet modules = structuralProbe.getClasses();
+ MixinDefinition oldModule = null;
+ Path newSource = Paths.get(VmSettings.BASE_DIRECTORY).toAbsolutePath().relativize(Path.of(filePath));
+ for(MixinDefinition module : modules ) {
+ if(module.getIdentifier().getString().split(":")[0].equals(newSource.toString())) {
+ oldModule = module;
+ }
+ }
+ MixinDefinition newModule = vm.loadModule(filePath,oldModule);
+ System.out.println(newModule.getName().toString());
+ EconomicMap oldMethods = oldModule.getInstanceDispatchables();
+ oldMethods.putAll(newModule.getInstanceDispatchables());
+ EconomicMap newDisp = newModule.getInstanceDispatchables();
+ //remove slot definition from dispatchables
+ for(ClassFactory module : oldModule.cache) {
+// for (SSymbol key : newDisp.getKeys()){
+// if(newDisp.get(key) instanceof MixinDefinition.SlotDefinition){
+// newDisp.removeKey(key);
+// }
+// }
+ module.dispatchables.putAll(newModule.getInstanceDispatchables());
+ }
+
+ for (Dispatchable disp : oldModule.getInstanceDispatchables().getValues()) {
+ if (disp instanceof SInvokable){
+ SInvokable inv = (SInvokable) disp;
+ inv.setHolder(oldModule);
+ }
+ }
+ oldModule.getSlots().putAll(newModule.getSlots());
+ // Pushing new slots
+ for (MixinDefinition.SlotDefinition sl : oldModule.getSlots().getValues()){
+ for(ClassFactory module : oldModule.cache) {
+ EconomicMap storageLocations =
+ module.getInstanceLayout().getStorageLocations();
+ Iterable oldKeys = storageLocations.getKeys();
+ Map toSubstitute = new HashMap<>();
+ for (MixinDefinition.SlotDefinition oldKey : oldKeys){
+ if(oldKey.getName() == sl.getName()){
+ toSubstitute.put(oldKey,sl);
+ break;
+ }
+ }
+ for (Map.Entry newOld : toSubstitute.entrySet()){
+ StorageLocation location = storageLocations.get(newOld.getKey());
+ storageLocations.removeKey(newOld.getKey());
+ storageLocations.put(newOld.getValue(),location);
+ location.setSlot(newOld.getValue());
+ }
+ }
+ }
+ System.out.println("SUBSTITUTED METHODS IN MODULE");
+
+ DispatchGuard.invalidateAssumption();
+
+ return oldModule;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
}
diff --git a/src/tools/debugger/RuntimeReflectionRegistration.java b/src/tools/debugger/RuntimeReflectionRegistration.java
index d32b04da1..6b7eee568 100644
--- a/src/tools/debugger/RuntimeReflectionRegistration.java
+++ b/src/tools/debugger/RuntimeReflectionRegistration.java
@@ -13,24 +13,9 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import tools.debugger.message.InitializationResponse;
-import tools.debugger.message.InitializeConnection;
+import tools.debugger.message.*;
import tools.debugger.message.Message.IncommingMessage;
import tools.debugger.message.Message.OutgoingMessage;
-import tools.debugger.message.ProgramInfoRequest;
-import tools.debugger.message.ProgramInfoResponse;
-import tools.debugger.message.ScopesRequest;
-import tools.debugger.message.ScopesResponse;
-import tools.debugger.message.SourceMessage;
-import tools.debugger.message.StackTraceRequest;
-import tools.debugger.message.StackTraceResponse;
-import tools.debugger.message.StepMessage;
-import tools.debugger.message.StoppedMessage;
-import tools.debugger.message.SymbolMessage;
-import tools.debugger.message.TraceDataRequest;
-import tools.debugger.message.UpdateBreakpoint;
-import tools.debugger.message.VariablesRequest;
-import tools.debugger.message.VariablesResponse;
import tools.debugger.session.BreakpointInfo;
import tools.debugger.session.LineBreakpoint;
import tools.debugger.session.SectionBreakpoint;
@@ -89,6 +74,8 @@ public void register(final String name, final Class> klass) {
inMsgs.register(VariablesRequest.class);
inMsgs.register(ProgramInfoRequest.class);
inMsgs.register(TraceDataRequest.class);
+ inMsgs.register(UpdateClass.class);
+ inMsgs.register(RestartFrame.class);
ClassGroup bps = new ClassGroup(BreakpointInfo.class, "type", true);
bps.register(LineBreakpoint.class);
diff --git a/src/tools/debugger/frontend/ApplicationThreadTask.java b/src/tools/debugger/frontend/ApplicationThreadTask.java
index 2b16e2045..3396b7e1d 100644
--- a/src/tools/debugger/frontend/ApplicationThreadTask.java
+++ b/src/tools/debugger/frontend/ApplicationThreadTask.java
@@ -7,11 +7,11 @@
* A task that needs to be executed by the application thread while it is in a
* {@link Suspension}.
*/
-abstract class ApplicationThreadTask {
+abstract public class ApplicationThreadTask {
/**
* @return continue waiting on true, resume execution on false.
*/
- abstract boolean execute();
+ protected abstract boolean execute();
static class Resume extends ApplicationThreadTask {
@Override
diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java
index d701cf436..491ca2684 100644
--- a/src/tools/debugger/frontend/Suspension.java
+++ b/src/tools/debugger/frontend/Suspension.java
@@ -132,7 +132,7 @@ public void sendVariables(final long varRef, final FrontendConnector frontend,
frontend.sendVariables(varRef, requestId, this, filter, start, count);
}
- private void submitTask(final ApplicationThreadTask task) {
+ public void submitTask(final ApplicationThreadTask task) {
try {
tasks.put(task);
} catch (InterruptedException e) {
diff --git a/src/tools/debugger/message/RestartFrame.java b/src/tools/debugger/message/RestartFrame.java
new file mode 100644
index 000000000..df845bb91
--- /dev/null
+++ b/src/tools/debugger/message/RestartFrame.java
@@ -0,0 +1,22 @@
+package tools.debugger.message;
+import org.java_websocket.WebSocket;
+import tools.debugger.FrontendConnector;
+import tools.debugger.frontend.Suspension;
+import tools.debugger.message.Message.IncommingMessage;
+public class RestartFrame extends IncommingMessage {
+ private final int frameId;
+
+ public RestartFrame(int currentFrameId) {
+ this.frameId = currentFrameId;
+ }
+
+ @Override
+ public void process(FrontendConnector connector, WebSocket conn) {
+ Suspension suspension= connector.getSuspension(0);
+ int skipCount = suspension.getFrameSkipCount();
+ skipCount = skipCount > 0 ? skipCount - 1 : skipCount;
+ int realId = frameId + skipCount;
+ System.out.print("Restarted Frame Request " + frameId + "After skipping " + realId);
+ connector.restartFrame(suspension,suspension.getStackFrames().get(realId));
+ }
+}
diff --git a/src/tools/debugger/message/StackTraceResponse.java b/src/tools/debugger/message/StackTraceResponse.java
index 0adc25e83..5e5f20fea 100644
--- a/src/tools/debugger/message/StackTraceResponse.java
+++ b/src/tools/debugger/message/StackTraceResponse.java
@@ -74,11 +74,14 @@ private static class StackFrame {
/** An optional number of characters in the range. */
private final int length;
- StackFrame(final long globalId, final String name, final String sourceUri,
+ private final long frameId;
+
+ StackFrame(final long globalId, final long frameId, final String name, final String sourceUri,
final int line, final int column, final int endLine,
final int endColumn, final int length) {
assert TraceData.isWithinJSIntValueRange(globalId);
this.id = globalId;
+ this.frameId = frameId;
this.name = name;
this.sourceUri = sourceUri;
this.line = line;
@@ -170,6 +173,6 @@ private static StackFrame createFrame(final Suspension suspension,
endColumn = 0;
length = 0;
}
- return new StackFrame(id, name, sourceUri, line, column, endLine, endColumn, length);
+ return new StackFrame(id, frameId, name, sourceUri, line, column, endLine, endColumn, length);
}
}
diff --git a/src/tools/debugger/message/UpdateClass.java b/src/tools/debugger/message/UpdateClass.java
new file mode 100644
index 000000000..f38a00ea7
--- /dev/null
+++ b/src/tools/debugger/message/UpdateClass.java
@@ -0,0 +1,83 @@
+package tools.debugger.message;
+
+import com.oracle.truffle.api.debug.DebugStackFrame;
+import com.oracle.truffle.api.frame.Frame;
+import com.oracle.truffle.api.frame.FrameInstance;
+import com.oracle.truffle.api.nodes.RootNode;
+import org.java_websocket.WebSocket;
+import som.compiler.MixinDefinition;
+import som.interpreter.SomLanguage;
+import tools.debugger.FrontendConnector;
+import tools.debugger.frontend.ApplicationThreadTask;
+import tools.debugger.frontend.Suspension;
+import tools.debugger.message.Message.IncommingMessage;
+import tools.debugger.frontend.ApplicationThreadTask;
+
+import java.util.ArrayList;
+
+
+public class UpdateClass extends IncommingMessage {
+ private final String classToRecompile ;
+
+ public UpdateClass(String classToRecompile) {
+ this.classToRecompile = classToRecompile;
+ }
+
+ @Override public void process(FrontendConnector connector, WebSocket conn) {
+ Suspension suspension = connector.getSuspension(0);
+ UpdateClassTask updateTask = new UpdateClassTask(connector,suspension,classToRecompile);
+ suspension.submitTask(updateTask);
+
+ //suspension.resume();
+ //connector.updateClass(classToRecompile);
+ System.out.println("Done Recompilation");
+ System.out.println(classToRecompile);
+ }
+
+ private class UpdateClassTask extends ApplicationThreadTask {
+
+ private final FrontendConnector frontend;
+ private final Suspension suspension;
+ private final String filePath;
+
+ UpdateClassTask(final FrontendConnector frontend, final Suspension suspension, String filePath) {
+ this.frontend = frontend;
+ this.suspension = suspension;
+ this.filePath = filePath;
+
+ }
+
+ @Override
+ public boolean execute() {
+ MixinDefinition updatedModule = frontend.updateClass(filePath);
+ ArrayList frames = suspension.getStackFrames();
+// int a = 1 + 1;
+// System.out.println(a);
+ DebugStackFrame restartFrame = null;
+ for(DebugStackFrame frame : frames){
+ if(frame.getSourceSection().getSource().getURI() == updatedModule.getSourceSection().getSource().getURI()) {
+ restartFrame = frame;
+ break;
+ }
+ }
+ if (restartFrame != null) {
+ // frontend.restartFrame(suspension, restartFrame);
+ }
+ //suspension.resum
+
+ System.out.println(suspension.getEvent().getTopStackFrame().getName());
+
+
+// RootNode node = suspension.getStackFrames().get(2).getRawNode(SomLanguage.class).getRootNode();
+//
+// System.out.println(node.getName());
+// System.out.println(node.getCallTarget().);
+// DebugStackFrame frame = suspension.getStackFrames().get(2);
+// System.out.println(frame.getName());
+// Frame realFrame = frame.getRawFrame(SomLanguage.class, FrameInstance.FrameAccess.READ_ONLY);
+// System.out.println("GOT REAL FRAME");
+//
+ return true;
+ }
+ }
+}