From cdb529c648dee9b3266f6d3f9d8234140f8e3f9a Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 23 Oct 2019 09:35:59 +0200 Subject: [PATCH 001/194] Changes for getting actor mailbox info - add three entries in the trace for the send operation entity. Add a symbol id to record the selector of the message. Add a targetActorId to record the receiver actor of the message. Add a source section corresponding to the origin of the send operation. Update the corresponding usages of this method. - the targetActorId is needed because in the case of a PROMISE_MSG the target of the send operation is a promise, but we need the information of the target actor of the original message. - the source section is already recorded for the dynamic scopes, however, dynamic scopes are created when the message is processed. To show the origin of a message sent in the mailbox, the source section is needed at the point where a message is sent but not yet processed. --- .../interpreter/actors/EventualSendNode.java | 14 +++++++---- src/som/primitives/actors/PromisePrims.java | 8 +++---- src/tools/concurrency/KomposTrace.java | 24 ++++++++++++------- src/tools/concurrency/TracingChannel.java | 2 +- src/tools/debugger/entities/SendOp.java | 7 +++++- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/som/interpreter/actors/EventualSendNode.java b/src/som/interpreter/actors/EventualSendNode.java index 7da8f7ff3a..ec98a34505 100644 --- a/src/som/interpreter/actors/EventualSendNode.java +++ b/src/som/interpreter/actors/EventualSendNode.java @@ -225,7 +225,7 @@ protected void sendDirectMessage(final Object[] args, final Actor owner, if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.ACTOR_MSG, msg.getMessageId(), - target.getId()); + target.getId(), msg.getSelector(), msg.getTarget().getId(), msg.getTargetSourceSection()); } target.send(msg, actorPool); @@ -241,9 +241,15 @@ protected void sendPromiseMessage(final Object[] args, final SPromise rcvr, messageReceiverBreakpoint.executeShouldHalt(), promiseResolverBreakpoint.executeShouldHalt()); + Actor target = null; + if (isFarRefRcvr(args)) { + SFarReference farReference = (SFarReference) args[0]; + target = farReference.getActor(); + } + if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, msg.getMessageId(), - rcvr.getPromiseId()); + rcvr.getPromiseId(), msg.getSelector(), target != null ? target.getId() : -1, msg.getTargetSourceSection()); } registerNode.register(rcvr, msg, rcvr.getOwner()); @@ -300,7 +306,7 @@ public final SPromise toNearRefWithResultPromise(final Object[] args) { if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.ACTOR_MSG, msg.getMessageId(), - current.getId()); + current.getId(), msg.getSelector(), msg.getTarget().getId(), msg.getTargetSourceSection()); } if (VmSettings.SENDER_SIDE_REPLAY) { @@ -351,7 +357,7 @@ public final Object toNearRefWithoutResultPromise(final Object[] args) { if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.ACTOR_MSG, msg.getMessageId(), - current.getId()); + current.getId(), msg.getSelector(), msg.getTarget().getId(), msg.getTargetSourceSection()); } if (VmSettings.SENDER_SIDE_REPLAY) { diff --git a/src/som/primitives/actors/PromisePrims.java b/src/som/primitives/actors/PromisePrims.java index 38c8b264df..7fe1c12db7 100644 --- a/src/som/primitives/actors/PromisePrims.java +++ b/src/som/primitives/actors/PromisePrims.java @@ -186,7 +186,7 @@ protected final SPromise registerWhenResolved(final SPromise rcvr, if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, pcm.getMessageId(), - rcvr.getPromiseId()); + rcvr.getPromiseId(), pcm.getSelector(), rcvr.getOwner().getId(), pcm.getTargetSourceSection()); } registerNode.register(rcvr, pcm, current); @@ -253,7 +253,7 @@ protected final SPromise registerOnError(final SPromise rcvr, if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, msg.getMessageId(), - rcvr.getPromiseId()); + rcvr.getPromiseId(), msg.getSelector(), rcvr.getOwner().getId(), msg.getTargetSourceSection()); } registerNode.register(rcvr, msg, current); @@ -332,9 +332,9 @@ protected final SPromise registerWhenResolvedOrError(final SPromise rcvr, if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, onResolved.getMessageId(), - rcvr.getPromiseId()); + rcvr.getPromiseId(), onResolved.getSelector(), onResolved.getTarget().getId(), onResolved.getTargetSourceSection()); KomposTrace.sendOperation(SendOp.PROMISE_MSG, onError.getMessageId(), - rcvr.getPromiseId()); + rcvr.getPromiseId(), onError.getSelector(), onError.getTarget().getId(), onResolved.getTargetSourceSection()); } synchronized (rcvr) { diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 4157b5bd3f..dfa6c43a3f 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -28,7 +28,7 @@ public static void recordMainActor(final Actor mainActor, KomposTraceBuffer buffer = KomposTraceBuffer.create(0); buffer.recordCurrentActivity(mainActor); buffer.recordMainActor(mainActor, objectSystem); - buffer.recordSendOperation(SendOp.ACTOR_MSG, 0, mainActor.getId(), mainActor); + buffer.recordSendOperation(SendOp.ACTOR_MSG, 0, mainActor.getId(), mainActor, (short) 0, 0, null); buffer.returnBuffer(null); } @@ -84,7 +84,7 @@ public static void promiseResolution(final long promiseId, final Object value) { ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(SendOp.PROMISE_RESOLUTION, 0, promiseId, - t.getActivity()); + t.getActivity(), (short) 0, 0, null); t.resolvedPromises++; } @@ -94,7 +94,7 @@ public static void promiseError(final long promiseId, final Object value) { TracingActivityThread t = (TracingActivityThread) current; ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(SendOp.PROMISE_RESOLUTION, 0, promiseId, - t.getActivity()); + t.getActivity(), (short) 0, 0, null); t.erroredPromises++; } @@ -107,15 +107,15 @@ public static void promiseError(final long promiseId, final Object value) { public static void promiseChained(final long promiseValueId, final long promiseId) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation( - SendOp.PROMISE_RESOLUTION, promiseValueId, promiseId, t.getActivity()); + SendOp.PROMISE_RESOLUTION, promiseValueId, promiseId, t.getActivity(), (short) 0, 0, null); t.resolvedPromises++; } public static void sendOperation(final SendOp op, final long entityId, - final long targetId) { + final long targetId, final SSymbol selector, long targetActorId, SourceSection msgSourceCoordinate) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(op, entityId, targetId, - t.getActivity()); + t.getActivity(), selector.getSymbolId(), targetActorId, msgSourceCoordinate); } public static void receiveOperation(final ReceiveOp op, final long sourceId) { @@ -335,7 +335,7 @@ public void recordReceiveOperation(final ReceiveOp op, final long sourceId, } public void recordSendOperation(final SendOp op, final long entityId, - final long targetId, final Activity current) { + final long targetId, final Activity current, final short symbolId, long targetActorId, SourceSection msgSourceCoordinate) { int requiredSpace = op.getSize(); ensureSufficientSpace(requiredSpace, current); @@ -343,6 +343,12 @@ public void recordSendOperation(final SendOp op, final long entityId, put(op.getId()); putLong(entityId); putLong(targetId); + putLong(targetActorId); + putShort(symbolId); + + if (VmSettings.KOMPOS_TRACING) { + writeSourceSection(msgSourceCoordinate); + } assert position == start + requiredSpace; } @@ -392,8 +398,8 @@ public synchronized void recordReceiveOperation(final ReceiveOp op, @Override public synchronized void recordSendOperation(final SendOp op, - final long entityId, final long targetId, final Activity current) { - super.recordSendOperation(op, entityId, targetId, current); + final long entityId, final long targetId, final Activity current, final short symbol, final long targetActorId, final SourceSection section) { + super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, section); } } } diff --git a/src/tools/concurrency/TracingChannel.java b/src/tools/concurrency/TracingChannel.java index 2a0a21c0eb..6f3a31bf95 100644 --- a/src/tools/concurrency/TracingChannel.java +++ b/src/tools/concurrency/TracingChannel.java @@ -55,7 +55,7 @@ public void write(final Object value, final RecordOneEvent traceWrite) super.write(value, traceWrite); } finally { KomposTrace.sendOperation( - SendOp.CHANNEL_SEND, current.messageId, current.channelId); + SendOp.CHANNEL_SEND, current.messageId, current.channelId, null, 0, null); } } } diff --git a/src/tools/debugger/entities/SendOp.java b/src/tools/debugger/entities/SendOp.java index 89f5577a2c..fa92ea0fa1 100644 --- a/src/tools/debugger/entities/SendOp.java +++ b/src/tools/debugger/entities/SendOp.java @@ -1,5 +1,7 @@ package tools.debugger.entities; +import tools.TraceData; + public enum SendOp { ACTOR_MSG(Marker.ACTOR_MSG_SEND, EntityType.ACT_MSG, EntityType.ACTOR), PROMISE_MSG(Marker.PROMISE_MSG_SEND, EntityType.ACT_MSG, EntityType.PROMISE), @@ -10,6 +12,9 @@ public enum SendOp { private final EntityType entity; private final EntityType target; + private static final int SYMBOL_ID_SIZE = 2; + private static final int RECEIVER_ACTOR_ID_SIZE = 8; + SendOp(final byte id, final EntityType entity, final EntityType target) { this.id = id; this.entity = entity; @@ -29,6 +34,6 @@ public EntityType getTarget() { } public int getSize() { - return 17; + return 17 + RECEIVER_ACTOR_ID_SIZE + SYMBOL_ID_SIZE + TraceData.SOURCE_SECTION_SIZE; } } From f5b8343005d2751a3ae689b21c28ff0eb802a1b3 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 23 Oct 2019 09:40:16 +0200 Subject: [PATCH 002/194] Support for pausing an actor - add static map in in Tracing actors to keep all the actors created in the system. One actor is added to the map every time an actor is created by the createActorFromValue primitive. - add a new incomming message for the request of pausing an actor (PauseActorRequest) - add a method in the WebDebugger that get the actor by its id accessing the map created in TracingActor class - make public the log method of the FrontendConnector to notify by console the actor will pause before processing the next message --- .../primitives/actors/CreateActorPrim.java | 2 ++ src/tools/concurrency/TracingActors.java | 21 ++++++++++------ src/tools/debugger/FrontendConnector.java | 17 ++++++------- .../RuntimeReflectionRegistration.java | 18 ++----------- src/tools/debugger/WebDebugger.java | 6 +++++ .../debugger/message/PauseActorRequest.java | 25 +++++++++++++++++++ 6 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 src/tools/debugger/message/PauseActorRequest.java diff --git a/src/som/primitives/actors/CreateActorPrim.java b/src/som/primitives/actors/CreateActorPrim.java index 9edad9648e..b9bf7a7b29 100644 --- a/src/som/primitives/actors/CreateActorPrim.java +++ b/src/som/primitives/actors/CreateActorPrim.java @@ -57,6 +57,8 @@ public final SFarReference createActor(final VirtualFrame frame, final Object re final SClass actorClass = (SClass) argument; KomposTrace.activityCreation(ActivityType.ACTOR, actor.getId(), actorClass.getName(), sourceSection); + //to keep all the created actors, this information is needed for example when pausing a running actor without specifying a breakpoint + TracingActor.saveActor(actor); } return ref; } diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 50aaff306e..09189d5f56 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -1,12 +1,6 @@ package tools.concurrency; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.WeakHashMap; +import java.util.*; import java.util.concurrent.ForkJoinPool; import java.util.function.BiConsumer; @@ -40,6 +34,11 @@ public static class TracingActor extends Actor { */ protected boolean stepToNextTurn; + /** + * Saves all ids and the instances of the actors created in the system. + */ + private static Map allActors = new HashMap<>(); + public TracingActor(final VM vm) { super(vm); this.activityId = TracingActivityThread.newEntityId(); @@ -142,6 +141,14 @@ public static void handleBreakpointsAndStepping(final EventualMessage msg, public DeserializationBuffer getDeserializationBuffer() { return null; } + + public static void saveActor(Actor actor) { + allActors.put(actor.getId(), actor); + } + + public static Actor getActorById(long actorId){ + return allActors.get(actorId); + } } public static final class ReplayActor extends TracingActor diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 98522f88fb..6c1b05425b 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -24,6 +24,7 @@ import bd.source.SourceCoordinate; import bd.source.TaggedSourceCoordinate; +import som.interpreter.actors.Actor; import som.vm.VmSettings; import som.vmobjects.SSymbol; import tools.Tagging; @@ -41,18 +42,10 @@ import tools.debugger.entities.SendOp; import tools.debugger.entities.SteppingType; import tools.debugger.frontend.Suspension; -import tools.debugger.message.InitializationResponse; -import tools.debugger.message.Message; +import tools.debugger.message.*; import tools.debugger.message.Message.OutgoingMessage; -import tools.debugger.message.ProgramInfoResponse; -import tools.debugger.message.ScopesResponse; -import tools.debugger.message.SourceMessage; import tools.debugger.message.SourceMessage.SourceData; -import tools.debugger.message.StackTraceResponse; -import tools.debugger.message.StoppedMessage; -import tools.debugger.message.SymbolMessage; import tools.debugger.message.VariablesRequest.FilterType; -import tools.debugger.message.VariablesResponse; import tools.debugger.session.Breakpoints; import tools.debugger.session.LineBreakpoint; @@ -320,7 +313,11 @@ public Suspension getSuspensionForGlobalId(final long globalId) { return webDebugger.getSuspension(TraceData.getActivityIdFromGlobalValId(globalId)); } - static void log(final String str) { + public Actor getActorById(final long activityId) { + return webDebugger.getActorById(activityId); + } + + public static void log(final String str) { // Checkstyle: stop System.out.println(str); // Checkstyle: resume diff --git a/src/tools/debugger/RuntimeReflectionRegistration.java b/src/tools/debugger/RuntimeReflectionRegistration.java index d32b04da11..eed952d585 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,7 @@ public void register(final String name, final Class klass) { inMsgs.register(VariablesRequest.class); inMsgs.register(ProgramInfoRequest.class); inMsgs.register(TraceDataRequest.class); + inMsgs.register("pauseActorMessageReceiver", PauseActorRequest.class); ClassGroup bps = new ClassGroup(BreakpointInfo.class, "type", true); bps.register(LineBreakpoint.class); diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index 593e19bf11..3da030237e 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -25,10 +25,12 @@ import bd.source.SourceCoordinate; import som.VM; +import som.interpreter.actors.Actor; import som.vm.Activity; import som.vm.Symbols; import tools.TraceData; import tools.concurrency.TracingActivityThread; +import tools.concurrency.TracingActors; import tools.debugger.frontend.Suspension; import tools.debugger.session.Breakpoints; @@ -178,5 +180,9 @@ public Breakpoints getBreakpoints() { return breakpoints; } + public Actor getActorById(long actorId) { + return TracingActors.TracingActor.getActorById(actorId); + } + private static Gson jsonProcessor = RuntimeReflectionRegistration.createJsonProcessor(); } diff --git a/src/tools/debugger/message/PauseActorRequest.java b/src/tools/debugger/message/PauseActorRequest.java new file mode 100644 index 0000000000..93a3af1cee --- /dev/null +++ b/src/tools/debugger/message/PauseActorRequest.java @@ -0,0 +1,25 @@ +package tools.debugger.message; + +import org.java_websocket.WebSocket; +import som.interpreter.actors.Actor; +import tools.debugger.FrontendConnector; + +public class PauseActorRequest extends Message.IncommingMessage { + private final long actorId; + + public PauseActorRequest() { + actorId = -1; + } + + public PauseActorRequest(long actorId) { + this.actorId = actorId; + } + + @Override + public void process(FrontendConnector connector, WebSocket conn) { + Actor actor = connector.getActorById(this.actorId); + assert actor != null : "Failed to get actor for activityId: " + this.actorId; + actor.setStepToNextTurn(true); + FrontendConnector.log("[DEBUGGER] Actor "+actor.getId() +" will pause before processing the next message."); + } +} From 3b7c9f00c126591c3659632febbbacad63a24642 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 5 Nov 2019 12:40:09 +0100 Subject: [PATCH 003/194] Add PauseActorResponse message - message added to acknowledge the client that the given actor has been paused - add log message that an actor has been resumed --- src/tools/debugger/FrontendConnector.java | 4 ++++ .../debugger/RuntimeReflectionRegistration.java | 1 + src/tools/debugger/message/PauseActorRequest.java | 1 + src/tools/debugger/message/PauseActorResponse.java | 13 +++++++++++++ src/tools/debugger/message/StepMessage.java | 4 ++++ 5 files changed, 23 insertions(+) create mode 100644 src/tools/debugger/message/PauseActorResponse.java diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 6c1b05425b..297efee628 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -301,6 +301,10 @@ public void sendProgramInfo() { send(ProgramInfoResponse.create(webDebugger.vm.getArguments())); } + public void sendPauseActorResponse(long pausedActorId) { + send(PauseActorResponse.create(pausedActorId)); + } + public void registerOrUpdate(final LineBreakpoint bp) { breakpoints.addOrUpdate(bp); } diff --git a/src/tools/debugger/RuntimeReflectionRegistration.java b/src/tools/debugger/RuntimeReflectionRegistration.java index eed952d585..97499db627 100644 --- a/src/tools/debugger/RuntimeReflectionRegistration.java +++ b/src/tools/debugger/RuntimeReflectionRegistration.java @@ -64,6 +64,7 @@ public void register(final String name, final Class klass) { outMsgs.register(ScopesResponse.class); outMsgs.register(VariablesResponse.class); outMsgs.register(ProgramInfoResponse.class); + outMsgs.register("pauseActorResponse", PauseActorResponse.class); ClassGroup inMsgs = new ClassGroup(IncommingMessage.class, "action", true); inMsgs.register(InitializeConnection.class); diff --git a/src/tools/debugger/message/PauseActorRequest.java b/src/tools/debugger/message/PauseActorRequest.java index 93a3af1cee..70788474b6 100644 --- a/src/tools/debugger/message/PauseActorRequest.java +++ b/src/tools/debugger/message/PauseActorRequest.java @@ -21,5 +21,6 @@ public void process(FrontendConnector connector, WebSocket conn) { assert actor != null : "Failed to get actor for activityId: " + this.actorId; actor.setStepToNextTurn(true); FrontendConnector.log("[DEBUGGER] Actor "+actor.getId() +" will pause before processing the next message."); + connector.sendPauseActorResponse(this.actorId); } } diff --git a/src/tools/debugger/message/PauseActorResponse.java b/src/tools/debugger/message/PauseActorResponse.java new file mode 100644 index 0000000000..1786f53f0e --- /dev/null +++ b/src/tools/debugger/message/PauseActorResponse.java @@ -0,0 +1,13 @@ +package tools.debugger.message; + +public class PauseActorResponse extends Message.OutgoingMessage { + private long actorId; + + public PauseActorResponse(long actorId) { + this.actorId = actorId; + } + + public static Message create(long pausedActorId) { + return new PauseActorResponse(pausedActorId); + } +} diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index 55d4e247ef..65a87bd03e 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -26,5 +26,9 @@ public void process(final FrontendConnector connector, final WebSocket conn) { assert susp != null : "Failed to get suspension for activityId: " + activityId; step.process(susp); susp.resume(); + + if (step == SteppingType.RESUME) { + FrontendConnector.log("[DEBUGGER] Resuming actor "+activityId); + } } } From c0b1ee1081762ef90a4b27f96e5e8db364d161fe Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 5 Nov 2019 13:13:30 +0100 Subject: [PATCH 004/194] Add missing ImplThreadCurrentActivity - add missing ImplThreadCurrentActivity when swapping the buffers (forceSwapBuffers method). When the thread is suspended by the debugger, is needed to record the suspended activity in the trace again, in order for the next messages that are send by the actor knows its sender actor, otherwise the sender actor is unknown in the trace. --- src/tools/concurrency/KomposTrace.java | 10 +++++++++- src/tools/concurrency/TracingBackend.java | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index dfa6c43a3f..dc8d9111a1 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -136,6 +136,10 @@ private static TracingActivityThread getThread() { return (TracingActivityThread) current; } + public static void recordSuspendedActivityByDebugger(TracingActivityThread t) { + ((KomposTraceBuffer) t.getBuffer()).recordPausedActivity(t.getActivity()); + } + public static class KomposTraceBuffer extends TraceBuffer { /** @@ -175,6 +179,10 @@ boolean swapStorage(final Activity current) { return true; } + public void recordPausedActivity(final Activity current) { + recordCurrentActivity(current); + } + @TruffleBoundary protected boolean ensureSufficientSpace(final int requiredSpace, final Activity current) { if ((position + requiredSpace) >= VmSettings.BUFFER_SIZE) { @@ -218,7 +226,7 @@ private void recordThreadId() { public void recordCurrentActivity(final Activity current) { - if (current == lastActivity || current == null) { + if (current == null) { return; } diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index 48f33564fe..a2c11c1d4b 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -283,6 +283,7 @@ public static final void forceSwapBuffers() { } else if (t.swapTracingBufferIfThreadSuspendedInDebugger()) { runningThreads -= 1; result[i] = null; + KomposTrace.recordSuspendedActivityByDebugger(t); } else if (isBlockedInJava(t)) { runningThreads -= 1; result[i] = null; From 45cd4ab8d7c14a57ee02cb5b43fbac82aac5ae65 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 11 Nov 2019 10:26:24 +0100 Subject: [PATCH 005/194] Add Debugger label for breakpoint logs - add Debugger label to the breakpoint logs in the WebDebugger --- src/tools/debugger/session/Breakpoints.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index 0010546039..946aa7e8eb 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -60,7 +60,7 @@ public void prepareSteppingAfterNextRootNode(final Thread thread) { public synchronized void addOrUpdate(final LineBreakpoint bId) { Breakpoint bp = truffleBreakpoints.get(bId); if (bp == null) { - WebDebugger.log("LineBreakpoint: " + bId); + WebDebugger.log("[DEBUGGER] LineBreakpoint: " + bId); bp = Breakpoint.newBuilder(bId.getURI()).lineIs(bId.getLine()).build(); debuggerSession.install(bp); truffleBreakpoints.put(bId, bp); @@ -74,8 +74,10 @@ public synchronized void addOrUpdate(final SectionBreakpoint bId) { if (existingBP == null) { existingBP = new BreakpointEnabling(bId); breakpoints.put(loc, existingBP); + WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId); } else { existingBP.setEnabled(bId.isEnabled()); + WebDebugger.log("[DEBUGGER] Enable SectionBreakpoint: " + bId); } } @@ -101,7 +103,7 @@ private Breakpoint saveTruffleBasedBreakpoints(final SectionBreakpoint bId, final Class tag, final SuspendAnchor anchor) { Breakpoint bp = truffleBreakpoints.get(bId); if (bp == null) { - WebDebugger.log("SectionBreakpoint: " + bId); + WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId); bp = Breakpoint.newBuilder(bId.getCoordinate().uri).lineIs(bId.getCoordinate().startLine) .columnIs(bId.getCoordinate().startColumn) .sectionLength(bId.getCoordinate().charLength) From 57e7f231dd0f2505228dec460367c025b8693bfa Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 18 Nov 2019 12:39:03 +0100 Subject: [PATCH 006/194] Update log when updating breakpoints - show in the debugger log if the breakpoint that has been updated is enabled (true) or disabled (false) --- src/tools/debugger/session/Breakpoints.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index 946aa7e8eb..fd7ee05675 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -77,7 +77,7 @@ public synchronized void addOrUpdate(final SectionBreakpoint bId) { WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId); } else { existingBP.setEnabled(bId.isEnabled()); - WebDebugger.log("[DEBUGGER] Enable SectionBreakpoint: " + bId); + WebDebugger.log("[DEBUGGER] Update SectionBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); } } From 94f4654c48092495aaed11e7db86bd5d19b1c371 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 21 Nov 2019 14:00:15 +0100 Subject: [PATCH 007/194] Add message id in the stack trace response - add message id in the stack trace in order to be able to identify the breakpointed message to which the created stack trace corresponds. --- .../debugger/message/StackTraceResponse.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/debugger/message/StackTraceResponse.java b/src/tools/debugger/message/StackTraceResponse.java index 0adc25e83f..789eff0214 100644 --- a/src/tools/debugger/message/StackTraceResponse.java +++ b/src/tools/debugger/message/StackTraceResponse.java @@ -5,7 +5,9 @@ import com.oracle.truffle.api.debug.DebugStackFrame; import com.oracle.truffle.api.source.SourceSection; +import som.interpreter.actors.Actor; import som.interpreter.actors.Actor.ExecutorRootNode; +import som.interpreter.actors.EventualMessage; import som.interpreter.actors.ReceivedRootNode; import tools.TraceData; import tools.debugger.entities.EntityType; @@ -21,6 +23,7 @@ public final class StackTraceResponse extends Response { // but that would make tracking more difficult private final byte[] concurrentEntityScopes; private final long activityId; + private long messageId; /** * Total number of frames available. @@ -29,13 +32,14 @@ public final class StackTraceResponse extends Response { private StackTraceResponse(final long activityId, final StackFrame[] stackFrames, final int totalFrames, - final int requestId, final byte[] concurrentEntityScopes) { + final int requestId, final byte[] concurrentEntityScopes, final long messageId) { super(requestId); assert TraceData.isWithinJSIntValueRange(activityId); this.activityId = activityId; this.stackFrames = stackFrames; this.totalFrames = totalFrames; this.concurrentEntityScopes = concurrentEntityScopes; + this.messageId = messageId; boolean assertsOn = false; assert assertsOn = true; @@ -135,8 +139,18 @@ public static StackTraceResponse create(final int startFrame, final int levels, EntityType[] concEntityScopes = suspension.getCurrentEntityScopes(); + // determine the message id to which this trace corresponds + long messageId = -1; + + Actor actorCurrentMessageIsExecutionOn = EventualMessage.getActorCurrentMessageIsExecutionOn(); + + if (actorCurrentMessageIsExecutionOn.getId() == suspension.getActivity().getId()) { + EventualMessage message = EventualMessage.getCurrentExecutingMessage(); + messageId = message.getMessageId(); + } + return new StackTraceResponse(suspension.activityId, arr, frames.size(), - requestId, EntityType.getIds(concEntityScopes)); + requestId, EntityType.getIds(concEntityScopes), messageId); } private static StackFrame createFrame(final Suspension suspension, From f8e29fc9b5942b7d1bd7a17489f674c2a47b80dd Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 16 Jan 2020 14:03:35 +0100 Subject: [PATCH 008/194] Add asynchronous stack trace implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Clement’s implementation to support asynchronous stack traces. Currently the changes are not possible to merge automatically in github from his branch. That’s the reason they are all in this one commit. From Clement’s notes, the following are the possible configuration settings. The option async_stack_traces_structure has to be enabled for the other ones to change anything. The other 2 settings can be enabled separately or together. -- async_stack_traces_structure: enables the shadow stack entry, allowing to recreate the stack across asynchronous calls. --async_stack_traces_method_cache: enables per method cache to CachedDispatchNode or LexicallyBoundDispatchNode, avoiding to create shadow stack entry if a method is called from a single dispatch node. --async_stack_traces_inline_cache: enables per shadow stack entry creation site cache, avoiding to create repeatedly the same shadow stack entry in loops, the first few times a loop is created. - Add command line argument in build.xml file to raise the error limit to 1000. This was needed to see other errors apart from the ones of the missing generated files in the src_gen folder. - Add a shorter identifier for the arguments of async stack traces in the som file. Add action store true for async args. This way the true value is not needed to be entered by command line. - Declare ResolveNode as an independent class to avoid wrong import generated in ResolvePromiseNodeFactory Originally implemented by Clement. Integrated by Carmen. Co-authored-by: clementbera Co-authored-by: carmen --- build.xml | 1 + core-lib/Actors.ns | 6 +- core-lib/Kernel.ns | 8 + som | 14 + src/som/compiler/MixinDefinition.java | 23 +- src/som/interpreter/Invokable.java | 4 + src/som/interpreter/Method.java | 17 + src/som/interpreter/SArguments.java | 186 ++++++++- src/som/interpreter/SNodeFactory.java | 4 +- .../actors/AbstractPromiseResolutionNode.java | 59 ++- src/som/interpreter/actors/Actor.java | 3 + .../interpreter/actors/ErrorPromiseNode.java | 6 +- .../interpreter/actors/EventualMessage.java | 50 ++- .../interpreter/actors/EventualSendNode.java | 35 +- .../interpreter/actors/ReceivedMessage.java | 54 ++- .../interpreter/actors/ReceivedRootNode.java | 18 +- .../actors/RegisterOnPromiseNode.java | 33 +- src/som/interpreter/actors/ResolveNode.java | 37 ++ .../actors/ResolvePromiseNode.java | 38 +- src/som/interpreter/actors/SPromise.java | 38 +- .../actors/SchedulePromiseHandlerNode.java | 24 +- .../nodes/ExceptionSignalingNode.java | 17 +- .../interpreter/nodes/InstantiationNode.java | 27 +- .../nodes/InternalObjectArrayNode.java | 29 +- .../interpreter/nodes/IsValueCheckNode.java | 2 +- .../interpreter/nodes/MessageSendNode.java | 12 +- .../dispatch/AbstractGenericDispatchNode.java | 13 +- .../nodes/dispatch/BackCacheCallNode.java | 56 +++ .../nodes/dispatch/BlockDispatchNode.java | 5 +- .../nodes/dispatch/CachedDispatchNode.java | 55 ++- .../nodes/dispatch/CachedDnuNode.java | 10 + .../nodes/dispatch/CachedSlotRead.java | 21 +- .../nodes/dispatch/ClassSlotAccessNode.java | 47 ++- .../dispatch/LexicallyBoundDispatchNode.java | 49 ++- .../nodes/nary/EagerBinaryPrimitiveNode.java | 10 +- .../transactions/CachedTxSlotRead.java | 5 +- src/som/primitives/ActivitySpawn.java | 4 +- src/som/primitives/BlockPrims.java | 67 ++-- src/som/primitives/ExceptionsPrims.java | 120 ++++-- src/som/primitives/FilePrims.java | 21 +- src/som/primitives/PathPrims.java | 15 +- src/som/primitives/StringPrims.java | 13 +- src/som/primitives/SystemPrims.java | 130 +++--- .../primitives/actors/CreateActorPrim.java | 4 +- src/som/primitives/actors/PromisePrims.java | 67 ++-- .../arrays/ArraySetAllStrategy.java | 72 ++-- src/som/primitives/arrays/AtPrim.java | 28 +- src/som/primitives/arrays/AtPutPrim.java | 74 ++-- .../processes/ChannelPrimitives.java | 2 +- src/som/vm/ObjectSystem.java | 22 +- src/som/vm/VmSettings.java | 10 + src/som/vmobjects/SFileDescriptor.java | 23 +- src/som/vmobjects/SInvokable.java | 3 +- .../asyncstacktraces/ShadowStackEntry.java | 113 ++++++ .../ShadowStackEntryLoad.java | 132 ++++++ src/tools/asyncstacktraces/StackIterator.java | 378 ++++++++++++++++++ .../frontend/ApplicationThreadStack.java | 49 ++- src/tools/debugger/frontend/RuntimeScope.java | 1 + src/tools/debugger/frontend/Suspension.java | 6 +- .../debugger/message/ScopesResponse.java | 61 +-- .../debugger/message/StackTraceResponse.java | 20 +- src/tools/dym/profiles/Arguments.java | 9 +- .../nodes/MessageSerializationNode.java | 3 +- .../nodes/ObjectSerializationNodes.java | 4 +- 64 files changed, 1965 insertions(+), 502 deletions(-) create mode 100644 src/som/interpreter/actors/ResolveNode.java create mode 100644 src/som/interpreter/nodes/dispatch/BackCacheCallNode.java create mode 100644 src/tools/asyncstacktraces/ShadowStackEntry.java create mode 100644 src/tools/asyncstacktraces/ShadowStackEntryLoad.java create mode 100644 src/tools/asyncstacktraces/StackIterator.java diff --git a/build.xml b/build.xml index 3168d7de9e..a1c5a7cc07 100644 --- a/build.xml +++ b/build.xml @@ -311,6 +311,7 @@ kernel: ${kernel} + diff --git a/core-lib/Actors.ns b/core-lib/Actors.ns index b4c3b9ef70..aae7bfd3db 100644 --- a/core-lib/Actors.ns +++ b/core-lib/Actors.ns @@ -79,8 +79,10 @@ class Actors usingVmMirror: vmMirror usingKernel: kernel = Value ( ) public class Resolver = Value ()( (* Object or Value? *) - public resolve: value = ( vmMirror actorsResolve: self with: value isBPResolver: false isBPResolution: false ) - public error: value = ( vmMirror actorsError: self with: value isBPResolver: false isBPResolution: false ) + (* public resolve: value = ( vmMirror actorsResolve: self with: value isBPResolver: false isBPResolution: false ) + public error: value = ( vmMirror actorsError: self with: value isBPResolver: false isBPResolution: false ) *) + public resolve: value = ( vmMirror actorsResolve: self with: value ) + public error: value = ( vmMirror actorsError: self with: value ) ) class Pair with: promise and: resolver = ( diff --git a/core-lib/Kernel.ns b/core-lib/Kernel.ns index bff84b44a8..fef5469bcd 100644 --- a/core-lib/Kernel.ns +++ b/core-lib/Kernel.ns @@ -26,9 +26,17 @@ class Kernel vmMirror: vmMirror = Object <: Value ( private class Top = ()() public class Thing = Top ()( + (* protected error: msg = ( + vmMirror printNewline: 'ERROR: ' + msg. + vmMirror markTurnErroneous: nil. + vmMirror exit: 1 + ) *) + + (* use the next implementation instead of the previous one to enable printing async stack trace when an error is thrown *) protected error: msg = ( vmMirror printNewline: 'ERROR: ' + msg. vmMirror markTurnErroneous: nil. + vmMirror printStackTrace: nil. vmMirror exit: 1 ) diff --git a/som b/som index 9d305b71fc..bb2ed93311 100755 --- a/som +++ b/som @@ -108,6 +108,13 @@ tools.add_argument('--java-coverage', help='determine Java code coverage and sto tools.add_argument('-kt', '--kompos-tracing', help='enable tracing of actor operations', dest='kompos_tracing', action='store_true', default=False) +tools.add_argument('-asts', '--async_stack_traces_structure', help='enable async stack traces in debugging through a separate structure, default value is false', + dest='async_stack_traces_structure', action='store_true', default=False) +tools.add_argument('-astmc', '--async_stack_traces_method_cache', help='enable async stack traces in debugging through a separate structure and add a per method backpointer cache, default value is false', + dest='async_stack_traces_method_cache', action='store_true', default=False) +tools.add_argument('-astic', '--async_stack_traces_inline_cache', help='enable async stack traces in debugging through a separate structure and add a per send site cache, default value is false', + dest='async_stack_traces_inline_cache', action='store_true', default=False) + parser.add_argument('-o', '--only', help='only compile give methods, comma separated list', dest='only_compile', default=None) parser.add_argument('-A', '--no-assert', help='execute with assertions disabled', @@ -331,6 +338,13 @@ if args.truffle_profile: if args.coverage: SOM_ARGS += ['--coverage', args.coverage] +if args.async_stack_traces_structure: + flags += ['-Dsom.actorAsyncStackTraceStructure=true'] +if args.async_stack_traces_method_cache: + flags += ['-Dsom.actorAsyncStackTraceMethodCache=true'] +if args.async_stack_traces_inline_cache: + flags += ['-Dsom.actorAsyncStackTraceInlineCache=true'] + if args.java_coverage: flags += ['-javaagent:' + BASE_DIR + '/libs/jacoco/lib/jacocoagent.jar=inclbootstrapclasses=true,destfile=' + args.java_coverage] diff --git a/src/som/compiler/MixinDefinition.java b/src/som/compiler/MixinDefinition.java index 539cc4ae7a..160f65cc03 100644 --- a/src/som/compiler/MixinDefinition.java +++ b/src/som/compiler/MixinDefinition.java @@ -66,6 +66,8 @@ import tools.snapshot.nodes.ObjectSerializationNodesFactory.UninitializedObjectSerializationNodeFactory; import tools.snapshot.nodes.PrimitiveSerializationNodesFactory.ClassSerializationNodeFactory; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; /** * Produced by a {@link MixinBuilder}, contains all static information on a @@ -534,16 +536,27 @@ public SClass instantiateModuleClass() { VM.callerNeedsToBeOptimized( "only meant for code loading, which is supposed to be on the slowpath"); CallTarget callTarget = superclassMixinResolution.getCallTarget(); - SClass superClass = (SClass) callTarget.call(Nil.nilObject); - SClass classObject = instantiateClass(Nil.nilObject, superClass); +// SClass superClass = (SClass) callTarget.call(Nil.nilObject); +// SClass classObject = instantiateClass(Nil.nilObject, superClass); + SClass superClass; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // Since this is outside of the main stacks, we create a separate top shadow stack entry + // to deal with async errors. + superClass = + (SClass) callTarget.call(Nil.nilObject, + SArguments.instantiateTopShadowStackEntry(null)); + } else { + superClass = (SClass) callTarget.call(Nil.nilObject, null); + } + SClass classObject = instantiateClass(null, Nil.nilObject, superClass); return classObject; } - public SClass instantiateClass(final SObjectWithClass outer, + public SClass instantiateClass(final VirtualFrame frame, final SObjectWithClass outer, final Object superclassAndMixins) { ClassFactory factory = createClassFactory(superclassAndMixins, false, false, false, UninitializedObjectSerializationNodeFactory.getInstance()); - return ClassInstantiationNode.instantiate(outer, factory, notAValue, + return ClassInstantiationNode.instantiate(frame, outer, factory, notAValue, cannotBeValues); } @@ -753,7 +766,7 @@ public Object invoke(final IndirectCallNode call, final Object[] arguments) { // ok, now it is for sure not initialized yet, instantiate class Object superclassAndMixins = mixinDefinition.getSuperclassAndMixinResolutionInvokable() .getCallTarget().call(rcvr); - SClass clazz = mixinDefinition.instantiateClass(rcvr, superclassAndMixins); + SClass clazz = mixinDefinition.instantiateClass(null, rcvr, superclassAndMixins); rcvr.writeSlot(this, clazz); return clazz; } diff --git a/src/som/interpreter/Invokable.java b/src/som/interpreter/Invokable.java index 726c3388d0..2f8a560e85 100644 --- a/src/som/interpreter/Invokable.java +++ b/src/som/interpreter/Invokable.java @@ -45,6 +45,10 @@ public final boolean isAtomic() { return isAtomic; } + public ExpressionNode getBodyNode() { + return expressionOrSequence; + } + @Override public final Object execute(final VirtualFrame frame) { return expressionOrSequence.executeGeneric(frame); diff --git a/src/som/interpreter/Method.java b/src/som/interpreter/Method.java index 7fc31ddffb..19ea3f8529 100644 --- a/src/som/interpreter/Method.java +++ b/src/som/interpreter/Method.java @@ -33,6 +33,7 @@ import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.SOMNode; import som.vmobjects.SInvokable; +import som.interpreter.nodes.dispatch.BackCacheCallNode; public final class Method extends Invokable { @@ -40,6 +41,7 @@ public final class Method extends Invokable { private final MethodScope methodScope; private final SourceSection[] definition; private final boolean block; + private BackCacheCallNode uniqueCaller; public Method(final String name, final SourceSection sourceSection, final SourceSection[] definition, @@ -77,6 +79,21 @@ public boolean equals(final Object o) { return false; } + public void setNewCaller(final BackCacheCallNode caller) { + if (uniqueCaller == null) { + uniqueCaller = caller; + caller.makeUniqueCaller(); + } else { + uniqueCaller.makeMultipleCaller(); + caller.makeMultipleCaller(); + } + } + + public BackCacheCallNode getUniqueCaller() { + return uniqueCaller; + } + + public SourceSection[] getDefinition() { return definition; } diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index bab650d213..bb16f2e872 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -7,6 +7,17 @@ import som.vm.constants.Classes; import som.vmobjects.SArray; import som.vmobjects.SArray.SImmutableArray; +import java.util.Arrays; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import som.interpreter.nodes.ExpressionNode; +import som.vm.VmSettings; +import som.vmobjects.SBlock; +import tools.asyncstacktraces.ShadowStackEntry; +import tools.asyncstacktraces.ShadowStackEntryLoad; public final class SArguments { @@ -25,37 +36,194 @@ public static Object rcvr(final Frame frame) { return arg(frame, RCVR_IDX); } + public static Object[] convertToArgumentArray(final Object[] args) { + int argLength = args.length; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + argLength++; + } else { + return args; + } + + Object[] array = Arrays.copyOf(args, argLength); + array[argLength - 1] = SArguments.instantiateTopShadowStackEntry(null); + return array; + } + + public static Object[] allocateArgumentsArray(final ExpressionNode[] argumentNodes) { + int argLength = argumentNodes.length; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + argLength++; + } + return new Object[argLength]; + } + /** * Create a new array from an SArguments array that contains only the true * arguments and excludes the receiver. This is used for instance for * #doesNotUnderstand (#dnu) */ public static SImmutableArray getArgumentsWithoutReceiver(final Object[] arguments) { - if (arguments.length == 1) { - return new SImmutableArray(0, Classes.valueArrayClass); - } +// if (arguments.length == 1) { +// return new SImmutableArray(0, Classes.valueArrayClass); +// } +// +// Object[] argsArr = getPlainArgumentWithoutReceiver(arguments); +// return new SImmutableArray(argsArr, Classes.valueArrayClass); - Object[] argsArr = getPlainArgumentWithoutReceiver(arguments); - return new SImmutableArray(argsArr, Classes.valueArrayClass); + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + if (arguments.length == 2) { + assert arguments[1] instanceof ShadowStackEntry; + return new SImmutableArray(0, Classes.valueArrayClass); + } + Object[] argsArr = getPlainArgumentWithoutReceiver(arguments); + return new SImmutableArray(argsArr, Classes.valueArrayClass); + + } else { + if (arguments.length == 1) { + return new SImmutableArray(0, Classes.valueArrayClass); + } + + Object[] argsArr = getPlainArgumentWithoutReceiver(arguments); + return new SImmutableArray(argsArr, Classes.valueArrayClass); + } } + /** + * Create a new array and copy inside the arguments without the receiver. + * Used for FFI calls and DNUs. + */ public static Object[] getPlainArgumentWithoutReceiver(final Object[] arguments) { int rcvrIdx = 0; // the code and magic numbers below are based on the following assumption assert RCVR_IDX == rcvrIdx; assert arguments.length >= 1; // <- that's the receiver - Object[] argsArr = new Object[arguments.length - 1]; +// Object[] argsArr = new Object[arguments.length - 1]; + + int argsSize = arguments.length - 1; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + argsSize--; + } + Object[] argsArr = new Object[argsSize]; System.arraycopy(arguments, 1, argsArr, 0, argsArr.length); return argsArr; } +// public static Object[] getPlainArgumentsWithReceiver(final Object receiver, +// final SArray args, final SizeAndLengthPrim size, final AtPrim at) { +// Object[] result = new Object[(int) (size.executeEvaluated(args) + 1)]; +// result[0] = receiver; +// for (int i = 1; i < result.length; i++) { +// result[i] = at.executeEvaluated(null, args, (long) i); +// } +// return result; +// } + public static Object[] getPlainArgumentsWithReceiver(final Object receiver, - final SArray args, final SizeAndLengthPrim size, final AtPrim at) { - Object[] result = new Object[(int) (size.executeEvaluated(args) + 1)]; + final SArray args, final SizeAndLengthPrim size, final AtPrim at, + final ExpressionNode expression, + final ShadowStackEntryLoad entryLoad, + final VirtualFrame frame) { + int argSize = (int) (size.executeEvaluated(args) + 1); + int defaultArgSize = argSize; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + argSize++; + } + + Object[] result = new Object[argSize]; result[0] = receiver; - for (int i = 1; i < result.length; i++) { + for (int i = 1; i < defaultArgSize; i++) { result[i] = at.executeEvaluated(null, args, (long) i); } + + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + entryLoad.loadShadowStackEntry(result, expression, frame, false); + } return result; } + + public static Object[] getPlainXArgumentsWithReceiver(final ExpressionNode expression, + final ShadowStackEntryLoad entryLoad, + final VirtualFrame frame, + final Object... rcvrAndArgs) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + Object[] arguments = new Object[rcvrAndArgs.length + 1]; + for (int i = 0; i < rcvrAndArgs.length; i++) { + arguments[i] = rcvrAndArgs[i]; + } + entryLoad.loadShadowStackEntry(arguments, expression, frame, false); + return arguments; + } else { + return rcvrAndArgs; + } + } + + public static Object[] getPlainArguments(final Object[] args) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + Object[] newArgs = new Object[args.length + 1]; + for (int i = 0; i < args.length; i++) { + newArgs[i] = args[i]; + } + return newArgs; + } else { + return args; + } + } + + public static Object[] getPromiseCallbackArgumentArray(final SBlock callback) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new Object[] {callback, null, null}; + } else { + return new Object[] {callback, null}; + } + } + + public static void setShadowStackEntryWithCache(final Object[] arguments, + final Node expression, + final ShadowStackEntryLoad entryLoad, + final VirtualFrame frame, + final boolean async) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + entryLoad.loadShadowStackEntry(arguments, expression, frame, async); + } + } + + public static ShadowStackEntry instantiateTopShadowStackEntry(final Node expr) { + return ShadowStackEntry.createTop(expr); + } + + public static ShadowStackEntry instantiateShadowStackEntry(final ShadowStackEntry previous, + final Node expr, final boolean async) { + CompilerAsserts.partialEvaluationConstant(async); + if (async) { + return ShadowStackEntry.createAtAsyncSend(previous, expr); + } else { + return ShadowStackEntry.create(previous, expr); + } + } + + public static ShadowStackEntry getShadowStackEntry(final VirtualFrame frame) { + Object[] args = frame.getArguments(); + return getShadowStackEntry(args); + } + + public static ShadowStackEntry getShadowStackEntry(final Object[] args) { + Object maybeShadowStack = args[args.length - 1]; + if (maybeShadowStack instanceof ShadowStackEntry) { + return (ShadowStackEntry) maybeShadowStack; + } + return null; + } + + public static void setShadowStackEntry(final Object[] args, final ShadowStackEntry entry) { + // assert args[args.length - 1] == null : "Assume shadow stack entry is not already set."; + args[args.length - 1] = entry; + } + + public static int getLengthWithoutShadowStack(final Object[] arguments) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return arguments.length - 1; + } else { + return arguments.length; + } + } } diff --git a/src/som/interpreter/SNodeFactory.java b/src/som/interpreter/SNodeFactory.java index c9ee82e506..6bfed34952 100644 --- a/src/som/interpreter/SNodeFactory.java +++ b/src/som/interpreter/SNodeFactory.java @@ -14,6 +14,7 @@ import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.InternalObjectArrayNode; import som.interpreter.nodes.MessageSendNode; +import som.interpreter.nodes.InternalObjectArrayNode.ArgumentEvaluationNode; import som.interpreter.nodes.OuterObjectReadNodeGen; import som.interpreter.nodes.ResolvingImplicitReceiverSend; import som.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; @@ -59,7 +60,8 @@ public static ExpressionNode createMessageSend(final SSymbol msg, final SomLanguage lang) { if (eventualSend) { return new EventualSendNode(msg, exprs.length, - new InternalObjectArrayNode(exprs).initialize(source), source, sendOperator, lang); + // new InternalObjectArrayNode(exprs).initialize(source), source, sendOperator, lang); + new ArgumentEvaluationNode(exprs).initialize(source), source, sendOperator, lang); } else { return MessageSendNode.createMessageSend(msg, exprs, source, lang.getVM()); } diff --git a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java index f2b5d5b9e5..0c861538d9 100644 --- a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java +++ b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java @@ -25,9 +25,24 @@ import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.NodeChildren; +import som.interpreter.nodes.ExpressionNode; +import som.interpreter.nodes.nary.EagerPrimitiveNode; +import som.interpreter.nodes.nary.EagerlySpecializableNode; +import som.vm.NotYetImplementedException; +import som.vmobjects.SSymbol; + @GenerateWrapper -public abstract class AbstractPromiseResolutionNode extends QuaternaryExpressionNode +//public abstract class AbstractPromiseResolutionNode extends QuaternaryExpressionNode +@NodeChildren({ + @NodeChild(value = "receiver", type = ExpressionNode.class), + @NodeChild(value = "firstArg", type = ExpressionNode.class), + @NodeChild(value = "secondArg", type = ExpressionNode.class), + @NodeChild(value = "thirdArg", type = ExpressionNode.class), + @NodeChild(value = "fourthArg", type = ExpressionNode.class)}) +public abstract class AbstractPromiseResolutionNode extends EagerlySpecializableNode implements WithContext { @CompilationFinal private ForkJoinPool actorPool; @@ -67,8 +82,24 @@ public AbstractPromiseResolutionNode initialize(final SourceSection sourceSectio } public abstract Object executeEvaluated(VirtualFrame frame, - SResolver receiver, Object argument, boolean haltOnResolver, - boolean haltOnResolution); + SResolver receiver, Object argument, Object maybeEntry, + boolean haltOnResolver, boolean haltOnResolution); + + public abstract Object executeEvaluated(VirtualFrame frame, Object receiver, + Object firstArg, Object secondArg, Object thirdArg, Object forth); + + @Override + public final Object doPreEvaluated(final VirtualFrame frame, + final Object[] arguments) { + return executeEvaluated(frame, arguments[0], arguments[1], arguments[2], + arguments[3], arguments[4]); + } + + @Override + public EagerPrimitiveNode wrapInEagerWrapper(final SSymbol selector, + final ExpressionNode[] arguments, final VM vm) { + throw new NotYetImplementedException(); // wasn't needed so far + } @Override public WrapperNode createWrapper(final ProbeNode probe) { @@ -80,8 +111,8 @@ public WrapperNode createWrapper(final ProbeNode probe) { */ @Specialization(guards = {"resolver.getPromise() == result"}) public SResolver selfResolution(final SResolver resolver, - final SPromise result, final boolean haltOnResolver, - final boolean haltOnResolution) { + final SPromise result, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { return resolver; } @@ -90,9 +121,9 @@ public SResolver selfResolution(final SResolver resolver, */ @Specialization(guards = {"resolver.getPromise() != promiseValue"}) public SResolver chainedPromise(final VirtualFrame frame, - final SResolver resolver, final SPromise promiseValue, + final SResolver resolver, final SPromise promiseValue, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { - chainPromise(resolver, promiseValue, haltOnResolver, haltOnResolution); + chainPromise(resolver, promiseValue, maybeEntry, haltOnResolver, haltOnResolution); return resolver; } @@ -101,8 +132,8 @@ protected static boolean notAPromise(final Object result) { } protected void chainPromise(final SResolver resolver, - final SPromise promiseValue, final boolean haltOnResolver, - final boolean haltOnResolution) { + final SPromise promiseValue, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { assert resolver.assertNotCompleted(); SPromise promiseToBeResolved = resolver.getPromise(); if (VmSettings.KOMPOS_TRACING) { @@ -124,7 +155,7 @@ protected void chainPromise(final SResolver resolver, } if (SPromise.isCompleted(state)) { - resolvePromise(state, resolver, promiseValue.getValueUnsync(), + resolvePromise(state, resolver, promiseValue.getValueUnsync(), maybeEntry, haltOnResolution); } else { synchronized (promiseToBeResolved) { // TODO: is this really deadlock free? @@ -150,24 +181,24 @@ protected void chainPromise(final SResolver resolver, } protected void resolvePromise(final Resolution type, - final SResolver resolver, final Object result, + final SResolver resolver, final Object result, final Object maybeEntry, final boolean haltOnResolution) { SPromise promise = resolver.getPromise(); Actor current = EventualMessage.getActorCurrentMessageIsExecutionOn(); - resolve(type, wrapper, promise, result, current, actorPool, haltOnResolution, + resolve(type, wrapper, promise, result, current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, tracePromiseResolution, tracePromiseResolutionEnd); } public static void resolve(final Resolution type, final WrapReferenceNode wrapper, final SPromise promise, - final Object result, final Actor current, final ForkJoinPool actorPool, + final Object result, final Actor current, final ForkJoinPool actorPool, maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { Object wrapped = wrapper.execute(result, promise.owner, current); SResolver.resolveAndTriggerListenersUnsynced(type, result, wrapped, promise, - current, actorPool, haltOnResolution, whenResolvedProfile, tracePromiseResolution2, + current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, tracePromiseResolution2, tracePromiseResolutionEnd2); } } diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index da5cfd1280..64ea0834d5 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -139,6 +139,9 @@ private void doSend(final EventualMessage msg, final ForkJoinPool actorPool) { assert msg.getTarget() == this; + assert msg.args[msg.args.length - 1] != null + || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + if (firstMessage == null) { firstMessage = msg; } else { diff --git a/src/som/interpreter/actors/ErrorPromiseNode.java b/src/som/interpreter/actors/ErrorPromiseNode.java index d5f04c93ca..bdd35019f2 100644 --- a/src/som/interpreter/actors/ErrorPromiseNode.java +++ b/src/som/interpreter/actors/ErrorPromiseNode.java @@ -13,7 +13,7 @@ @GenerateNodeFactory -@Primitive(primitive = "actorsError:with:isBPResolver:isBPResolution:") +@Primitive(primitive = "actorsError:with:entry:isBPResolver:isBPResolution:") public abstract class ErrorPromiseNode extends AbstractPromiseResolutionNode implements Operation { /** @@ -21,14 +21,14 @@ public abstract class ErrorPromiseNode extends AbstractPromiseResolutionNode */ @Specialization(guards = {"notAPromise(result)"}) public SResolver standardError(final VirtualFrame frame, final SResolver resolver, - final Object result, final boolean haltOnResolver, final boolean haltOnResolution) { + final Object result, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { SPromise promise = resolver.getPromise(); if (haltOnResolver || promise.getHaltOnResolver()) { haltNode.executeEvaluated(frame, result); } - resolvePromise(Resolution.ERRONEOUS, resolver, result, haltOnResolution); + resolvePromise(Resolution.ERRONEOUS, resolver, result, maybeEntry, haltOnResolution); return resolver; } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 19d45989dc..5f34382cb9 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -18,6 +18,8 @@ import tools.replay.nodes.RecordEventNodes.RecordOneEvent; import tools.snapshot.SnapshotBackend; import tools.snapshot.SnapshotBuffer; +import som.interpreter.SArguments; +import tools.asyncstacktraces.ShadowStackEntry; public abstract class EventualMessage { @@ -240,7 +242,7 @@ protected static Actor determineTargetAndWrapArguments(final Object[] arguments, : "this should not happen, because we need to redirect messages to the other actor, and normally we just unwrapped this"; assert !(receiver instanceof SPromise); - for (int i = 1; i < arguments.length; i++) { + for (int i = 1; i < SArguments.getLengthWithoutShadowStack(arguments); i++) { arguments[i] = WrapReferenceNode.wrapForUse(target, arguments[i], originalSender, null); } @@ -267,8 +269,8 @@ public PromiseMessage(final Object[] arguments, final Actor originalSender, } } - public abstract void resolve(Object rcvr, Actor target, Actor sendingActor); - + public abstract void resolve(Object rcvr, Actor target, Actor sendingActor, + Object maybeEntry); @Override public final Actor getSender() { assert originalSender != null; @@ -306,20 +308,20 @@ protected AbstractPromiseSendMessage(final SSymbol selector, super(arguments, originalSender, resolver, onReceive, triggerMessageReceiverBreakpoint, triggerPromiseResolverBreakpoint); this.selector = selector; - assert (args[0] instanceof SPromise); - this.originalTarget = (SPromise) args[0]; + assert (args[PROMISE_RCVR_IDX] instanceof SPromise); + this.originalTarget = (SPromise) args[PROMISE_RCVR_IDX]; } @Override - public void resolve(final Object rcvr, final Actor target, final Actor sendingActor) { - determineAndSetTarget(rcvr, target, sendingActor); + public void resolve(final Object rcvr, final Actor target, final Actor sendingActor, final Object maybeEntry) { + determineAndSetTarget(rcvr, target, sendingActor, maybeEntry); } private void determineAndSetTarget(final Object rcvr, final Actor target, - final Actor sendingActor) { + final Actor sendingActor, final Object maybeEntry) { VM.thisMethodNeedsToBeOptimized("not optimized for compilation"); - args[0] = rcvr; + args[PROMISE_RCVR_IDX] = rcvr; Actor finalTarget = determineTargetAndWrapArguments(args, target, sendingActor, originalSender); @@ -329,6 +331,7 @@ private void determineAndSetTarget(final Object rcvr, final Actor target, this.messageId = Math.min(this.messageId, ActorProcessingThread.currentThread().getSnapshotId()); } + // TODO: what do I do with the shadow stack entry here. give it two parents? } @Override @@ -396,14 +399,17 @@ protected AbstractPromiseCallbackMessage(final Actor owner, final SBlock callbac final SResolver resolver, final RootCallTarget onReceive, final boolean triggerMessageReceiverBreakpoint, final boolean triggerPromiseResolverBreakpoint, final SPromise promiseRegisteredOn) { - super(new Object[] {callback, null}, owner, resolver, onReceive, + super(SArguments.getPromiseCallbackArgumentArray(callback), owner, + resolver, onReceive, triggerMessageReceiverBreakpoint, triggerPromiseResolverBreakpoint); this.promise = promiseRegisteredOn; } @Override - public void resolve(final Object rcvr, final Actor target, final Actor sendingActor) { - setPromiseValue(rcvr, sendingActor); + public void resolve(final Object rcvr, final Actor target, final Actor sendingActor, + final Object maybeEntry) { + assert maybeEntry != null || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + setPromiseValue(rcvr, sendingActor, maybeEntry); } /** @@ -412,8 +418,13 @@ public void resolve(final Object rcvr, final Actor target, final Actor sendingAc * * @param resolvingActor - the owner of the value, the promise was resolved to. */ - private void setPromiseValue(final Object value, final Actor resolvingActor) { - args[1] = WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); + private void setPromiseValue(final Object value, final Actor resolvingActor, + final Object maybeEntry) { + args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + assert maybeEntry instanceof ShadowStackEntry; + SArguments.setShadowStackEntry(args, (ShadowStackEntry) maybeEntry); + } if (VmSettings.SNAPSHOTS_ENABLED) { this.messageId = Math.min(this.messageId, ActorProcessingThread.currentThread().getSnapshotId()); @@ -422,7 +433,7 @@ private void setPromiseValue(final Object value, final Actor resolvingActor) { @Override public SSymbol getSelector() { - return ((SBlock) args[0]).getMethod().getSignature(); + return ((SBlock) args[PROMISE_RCVR_IDX]).getMethod().getSignature(); } @Override @@ -471,7 +482,14 @@ public final void execute() { assert onReceive.getRootNode() instanceof ReceivedMessage || onReceive.getRootNode() instanceof ReceivedCallback; - onReceive.call(this); + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + assert args[args.length - 1] instanceof ShadowStackEntry; + ShadowStackEntry ssEntry = (ShadowStackEntry) args[args.length - 1]; + args[args.length - 1] = null; + onReceive.call(this, ssEntry); + } else { + onReceive.call(this); + } } public static Actor getActorCurrentMessageIsExecutionOn() { diff --git a/src/som/interpreter/actors/EventualSendNode.java b/src/som/interpreter/actors/EventualSendNode.java index ec98a34505..1a1d3a9d21 100644 --- a/src/som/interpreter/actors/EventualSendNode.java +++ b/src/som/interpreter/actors/EventualSendNode.java @@ -42,6 +42,8 @@ import tools.debugger.entities.SendOp; import tools.debugger.nodes.AbstractBreakpointNode; import tools.debugger.session.Breakpoints; +import som.interpreter.SArguments; +import som.interpreter.nodes.InternalObjectArrayNode.ArgumentEvaluationNode; import tools.dym.DynamicMetrics; import tools.replay.ReplayRecord; import tools.replay.TraceRecord; @@ -52,11 +54,11 @@ public class EventualSendNode extends ExprWithTagsNode { public static final AtomicLong numPromisesAvoided = DynamicMetrics.createLong("Num.Promises.Avoided"); - @Child protected InternalObjectArrayNode arguments; + @Child protected ArgumentEvaluationNode arguments; @Child protected SendNode send; public EventualSendNode(final SSymbol selector, final int numArgs, - final InternalObjectArrayNode arguments, final SourceSection source, + final ArgumentEvaluationNode arguments, final SourceSection source, final SourceSection sendOperator, final SomLanguage lang) { this.arguments = arguments; this.send = SendNodeGen.create(selector, createArgWrapper(numArgs), @@ -79,6 +81,10 @@ public Object executeGeneric(final VirtualFrame frame) { return send.execute(frame, args); } + public SSymbol getSentSymbol() { + return SOMNode.unwrapIfNecessary(send).getSelector(); + } + public static RootCallTarget createOnReceiveCallTarget(final SSymbol selector, final SourceSection source, final SomLanguage lang) { @@ -204,7 +210,7 @@ protected void sendDirectMessage(final Object[] args, final Actor owner, SFarReference rcvr = (SFarReference) args[0]; Actor target = rcvr.getActor(); - for (int i = 0; i < args.length; i++) { + for (int i = 0; i < SArguments.getLengthWithoutShadowStack(args); i++) { args[i] = wrapArgs[i].execute(args[i], target, owner); } @@ -231,10 +237,10 @@ protected void sendDirectMessage(final Object[] args, final Actor owner, target.send(msg, actorPool); } - protected void sendPromiseMessage(final Object[] args, final SPromise rcvr, - final SResolver resolver, final RegisterWhenResolved registerNode) { - assert rcvr.getOwner() == EventualMessage.getActorCurrentMessageIsExecutionOn() - : "think this should be true because the promise is an Object and owned by this specific actor"; + protected void sendPromiseMessage(final VirtualFrame frame, final Object[] args, + final SPromise rcvr, final SResolver resolver, + final RegisterWhenResolved registerNode) { + assert rcvr.getOwner() == EventualMessage.getActorCurrentMessageIsExecutionOn() : "think this should be true because the promise is an Object and owned by this specific actor"; PromiseSendMessage msg = new PromiseSendMessage(selector, args, rcvr.getOwner(), resolver, onReceive, @@ -252,13 +258,17 @@ protected void sendPromiseMessage(final Object[] args, final SPromise rcvr, rcvr.getPromiseId(), msg.getSelector(), target != null ? target.getId() : -1, msg.getTargetSourceSection()); } - registerNode.register(rcvr, msg, rcvr.getOwner()); + registerNode.register(frame, rcvr, msg, rcvr.getOwner()); } protected RegisterWhenResolved createRegisterNode() { return new RegisterWhenResolved(actorPool); } + public SSymbol getSelector() { + return selector; + } + @Override public String toString() { return "EventSend[" + selector.toString() + "]"; @@ -278,7 +288,8 @@ public final SPromise toFarRefWithResultPromise(final Object[] args) { } @Specialization(guards = {"isResultUsed()", "isPromiseRcvr(args)"}) - public final SPromise toPromiseWithResultPromise(final Object[] args, + public final SPromise toPromiseWithResultPromise(final VirtualFrame frame, + final Object[] args, @Cached("createRegisterNode()") final RegisterWhenResolved registerNode) { SPromise rcvr = (SPromise) args[0]; @@ -287,7 +298,7 @@ public final SPromise toPromiseWithResultPromise(final Object[] args, false, promiseResolutionBreakpoint.executeShouldHalt(), source); SResolver resolver = SPromise.createResolver(promise); - sendPromiseMessage(args, rcvr, resolver, registerNode); + sendPromiseMessage(frame, args, rcvr, resolver, registerNode); return promise; } @@ -334,9 +345,9 @@ public final Object toFarRefWithoutResultPromise(final Object[] args) { } @Specialization(guards = {"!isResultUsed()", "isPromiseRcvr(args)"}) - public final Object toPromiseWithoutResultPromise(final Object[] args, + public final Object toPromiseWithoutResultPromise(final VirtualFrame frame, final Object[] args, @Cached("createRegisterNode()") final RegisterWhenResolved registerNode) { - sendPromiseMessage(args, (SPromise) args[0], null, registerNode); + sendPromiseMessage(frame, args, (SPromise) args[0], null, registerNode); if (VmSettings.DYNAMIC_METRICS) { numPromisesAvoided.getAndIncrement(); diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index f1a76a958e..104c0b1fae 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -13,6 +13,12 @@ import som.interpreter.SomLanguage; import som.interpreter.nodes.MessageSendNode.AbstractMessageSendNode; import som.vmobjects.SSymbol; +import som.interpreter.Invokable; +import som.interpreter.SArguments; +import som.interpreter.nodes.ExpressionNode; +import som.vm.VmSettings; +import som.vmobjects.SInvokable; +import tools.asyncstacktraces.ShadowStackEntry; public class ReceivedMessage extends ReceivedRootNode { @@ -29,14 +35,30 @@ public ReceivedMessage(final AbstractMessageSendNode onReceive, assert onReceive.getSourceSection() != null; } + @Override + public String getName() { + return selector.toString(); + } + @Override protected Object executeBody(final VirtualFrame frame, final EventualMessage msg, final boolean haltOnResolver, final boolean haltOnResolution) { + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive); + } + try { + assert msg.args[msg.args.length - 1] == null + || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; Object result = onReceive.executeEvaluated(frame, msg.args); - resolvePromise(frame, msg.resolver, result, haltOnResolver, haltOnResolution); + resolvePromise(frame, msg.resolver, result, + resolutionEntry, haltOnResolver, haltOnResolution); } catch (SomException exception) { - errorPromise(frame, msg.resolver, exception.getSomObject(), + errorPromise(frame, msg.resolver, exception.getSomObject(), resolutionEntry, haltOnResolver, haltOnResolution); } return null; @@ -81,22 +103,38 @@ private void resolveFuture(final Object result) { public static final class ReceivedCallback extends ReceivedRootNode { @Child protected DirectCallNode onReceive; + private final Invokable onReceiveMethod; - public ReceivedCallback(final RootCallTarget onReceive) { - super(SomLanguage.getLanguage(onReceive.getRootNode()), - onReceive.getRootNode().getSourceSection(), null); - this.onReceive = Truffle.getRuntime().createDirectCallNode(onReceive); + public ReceivedCallback(final SInvokable onReceive) { + super(SomLanguage.getLanguage(onReceive.getInvokable()), + onReceive.getSourceSection(), null); + this.onReceive = Truffle.getRuntime().createDirectCallNode(onReceive.getCallTarget()); + this.onReceiveMethod = onReceive.getInvokable(); + } + + @Override + public String getName() { + return onReceiveMethod.getName(); } @Override protected Object executeBody(final VirtualFrame frame, final EventualMessage msg, final boolean haltOnResolver, final boolean haltOnResolution) { + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode()); + SArguments.setShadowStackEntry(msg.getArgs(), resolutionEntry); + } + try { Object result = onReceive.call(msg.args); - resolvePromise(frame, msg.resolver, result, haltOnResolver, + resolvePromise(frame, msg.resolver, result, resolutionEntry, haltOnResolver, haltOnResolution); } catch (SomException exception) { - errorPromise(frame, msg.resolver, exception.getSomObject(), + errorPromise(frame, msg.resolver, exception.getSomObject(), resolutionEntry, haltOnResolver, haltOnResolution); } return null; diff --git a/src/som/interpreter/actors/ReceivedRootNode.java b/src/som/interpreter/actors/ReceivedRootNode.java index a4a0f48890..f82a05c136 100644 --- a/src/som/interpreter/actors/ReceivedRootNode.java +++ b/src/som/interpreter/actors/ReceivedRootNode.java @@ -115,7 +115,7 @@ public SourceSection getSourceSection() { } protected final void resolvePromise(final VirtualFrame frame, - final SResolver resolver, final Object result, + final SResolver resolver, final Object result, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { // lazy initialization of resolution node if (resolve == null) { @@ -126,8 +126,8 @@ protected final void resolvePromise(final VirtualFrame frame, if (resolver == null) { resolve = insert(new NullResolver()); } else { - resolve = insert( - ResolvePromiseNodeFactory.create(null, null, null, null).initialize(vm)); + resolve = insert( + ResolveNodeGen.create(null, null, null, null, null).initialize(vm)); } resolve.initialize(sourceSection); this.resolve = resolve; @@ -135,11 +135,11 @@ protected final void resolvePromise(final VirtualFrame frame, } // resolve promise - resolve.executeEvaluated(frame, resolver, result, haltOnResolver, haltOnResolution); + resolve.executeEvaluated(frame, resolver, result, maybeEntry, haltOnResolver, haltOnResolution); } protected final void errorPromise(final VirtualFrame frame, - final SResolver resolver, final Object exception, + final SResolver resolver, final Object exception, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { // lazy initialization of resolution node if (error == null) { @@ -151,7 +151,7 @@ protected final void errorPromise(final VirtualFrame frame, error = insert(new NullResolver()); } else { error = insert( - ErrorPromiseNodeFactory.create(null, null, null, null).initialize(vm)); + ErrorPromiseNodeFactory.create(null, null, null, null, null).initialize(vm)); } this.error = error; this.error.initialize(sourceSection); @@ -159,7 +159,7 @@ protected final void errorPromise(final VirtualFrame frame, } // error promise - error.executeEvaluated(frame, resolver, exception, haltOnResolver, haltOnResolution); + error.executeEvaluated(frame, resolver, exception, maybeEntry, haltOnResolver, haltOnResolution); } public MessageSerializationNode getSerializer() { @@ -175,7 +175,7 @@ public static final class NullResolver extends AbstractPromiseResolutionNode { @Override public Object executeEvaluated(final VirtualFrame frame, - final SResolver receiver, final Object argument, + final SResolver receiver, final Object argument, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { assert receiver == null; if (VmSettings.DYNAMIC_METRICS) { @@ -186,7 +186,7 @@ public Object executeEvaluated(final VirtualFrame frame, @Override public Object executeEvaluated(final VirtualFrame frame, final Object rcvr, - final Object firstArg, final Object secondArg, final Object thirdArg) { + final Object firstArg, final Object secondArg, final Object thirdArg, final Object fourthArg) { if (VmSettings.DYNAMIC_METRICS) { numImplicitNullResolutions.getAndIncrement(); } diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 354fa332af..ca9380f138 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -4,13 +4,16 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicLong; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import som.interpreter.actors.EventualMessage.AbstractPromiseSendMessage; import som.interpreter.actors.EventualMessage.PromiseMessage; import som.interpreter.actors.SPromise.SReplayPromise; import som.interpreter.actors.SPromise.STracingPromise; +import som.interpreter.SArguments; import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; import tools.dym.DynamicMetrics; import tools.replay.ReplayRecord; import tools.replay.TraceRecord; @@ -34,7 +37,7 @@ public RegisterWhenResolved(final ForkJoinPool actorPool) { } } - public void register(final SPromise promise, final PromiseMessage msg, + public void register(final VirtualFrame frame, final SPromise promise, final PromiseMessage msg, final Actor current) { Object promiseValue; @@ -75,12 +78,22 @@ public void register(final SPromise promise, final PromiseMessage msg, } if (!promise.isResolvedUnsync()) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // TODO: I think, we need the info about the resolution context from the promise + // we want to know where it was resolved, where the value is coming from + ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( + SArguments.getShadowStackEntry(frame), + getParent().getParent()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; + SArguments.setShadowStackEntry(msg.args, resolutionEntry); + } + if (VmSettings.SENDER_SIDE_REPLAY) { ReplayRecord npr = current.getNextReplayEvent(); assert npr.type == TraceRecord.MESSAGE; msg.messageId = npr.eventNo; } - + if (VmSettings.SENDER_SIDE_TRACING) { // This is whenResolved promiseMsgSend.record(((STracingPromise) promise).version); @@ -118,7 +131,7 @@ public void register(final SPromise promise, final PromiseMessage msg, if (VmSettings.DYNAMIC_METRICS) { numScheduledWhenResolved.incrementAndGet(); } - schedule.execute(promise, msg, current); + schedule.execute(frame, promise, msg, current); } } } @@ -134,7 +147,7 @@ public RegisterOnError(final ForkJoinPool actorPool) { } } - public void register(final SPromise promise, final PromiseMessage msg, + public void register(final VirtualFrame frame, final SPromise promise, final PromiseMessage msg, final Actor current) { Object promiseValue; @@ -158,6 +171,16 @@ public void register(final SPromise promise, final PromiseMessage msg, if (!promise.isErroredUnsync()) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // TODO: I think, we need the info about the resolution context from the promise + // we want to know where it was resolved, where the value is coming from + ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( + SArguments.getShadowStackEntry(frame), + getParent().getParent()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; + SArguments.setShadowStackEntry(msg.args, resolutionEntry); + } + if (VmSettings.SENDER_SIDE_TRACING) { // This is whenResolved promiseMsgSend.record(((STracingPromise) promise).version); @@ -195,7 +218,7 @@ public void register(final SPromise promise, final PromiseMessage msg, if (VmSettings.DYNAMIC_METRICS) { numScheduledOnError.incrementAndGet(); } - schedule.execute(promise, msg, current); + schedule.execute(frame, promise, msg, current); } } } diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java new file mode 100644 index 0000000000..e02d309440 --- /dev/null +++ b/src/som/interpreter/actors/ResolveNode.java @@ -0,0 +1,37 @@ +package som.interpreter.actors; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SomLanguage; + + +public abstract class ResolveNode extends AbstractPromiseResolutionNode { + @CompilerDirectives.CompilationFinal + boolean initialized = false; + + /** + * Normal case, when the promise is resolved with a value that's not a promise. + * Here we need to distinguish the explicit promises to ask directly to the promise + * if a promise resolution breakpoint was set. + */ + @Specialization(guards = {"notAPromise(result)"}) + public SPromise.SResolver normalResolution(final VirtualFrame frame, + final SPromise.SResolver resolver, final Object result, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { + if (!initialized) { + initialized = true; + this.initialize(SomLanguage.getVM(this)); + } + + SPromise promise = resolver.getPromise(); + + if (haltOnResolver || promise.getHaltOnResolver()) { + haltNode.executeEvaluated(frame, result); + } + + resolvePromise(SPromise.Resolution.SUCCESSFUL, resolver, result, maybeEntry, + haltOnResolution || promise.getHaltOnResolution()); + return resolver; + } +} diff --git a/src/som/interpreter/actors/ResolvePromiseNode.java b/src/som/interpreter/actors/ResolvePromiseNode.java index 3b6b1c34c8..96072bd2cc 100644 --- a/src/som/interpreter/actors/ResolvePromiseNode.java +++ b/src/som/interpreter/actors/ResolvePromiseNode.java @@ -1,5 +1,6 @@ package som.interpreter.actors; +import bd.primitives.Primitive; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; @@ -7,33 +8,30 @@ import bd.primitives.Primitive; import bd.tools.nodes.Operation; +import som.interpreter.SArguments; import som.interpreter.actors.SPromise.Resolution; import som.interpreter.actors.SPromise.SResolver; +import som.interpreter.nodes.nary.BinaryExpressionNode; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; import tools.dym.Tags.ComplexPrimitiveOperation; @GenerateNodeFactory -@Primitive(primitive = "actorsResolve:with:isBPResolver:isBPResolution:") -public abstract class ResolvePromiseNode extends AbstractPromiseResolutionNode - implements Operation { - /** - * Normal case, when the promise is resolved with a value that's not a promise. - * Here we need to distinguish the explicit promises to ask directly to the promise - * if a promise resolution breakpoint was set. - */ - @Specialization(guards = {"notAPromise(result)"}) - public SResolver normalResolution(final VirtualFrame frame, - final SResolver resolver, final Object result, - final boolean haltOnResolver, final boolean haltOnResolution) { - SPromise promise = resolver.getPromise(); - - if (haltOnResolver || promise.getHaltOnResolver()) { - haltNode.executeEvaluated(frame, result); - } +@Primitive(primitive = "actorsResolve:with:") +public abstract class ResolvePromiseNode extends BinaryExpressionNode { + @Child protected ResolveNode resolve; + + public ResolvePromiseNode() { + resolve = ResolveNodeGen.create(null, null, null, null, null); + } - resolvePromise(Resolution.SUCCESSFUL, resolver, result, - haltOnResolution || promise.getHaltOnResolution()); - return resolver; + @Specialization + public SResolver normalResolution(final VirtualFrame frame, final SResolver resolver, + final Object result) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame); + assert entry != null || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + return (SResolver) resolve.executeEvaluated(frame, resolver, result, entry, false, false); } @Override diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index 045552c391..3572a7dbb8 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -261,13 +261,13 @@ private void registerMoreOnError(final PromiseMessage msg) { protected final void scheduleCallbacksOnResolution(final Object result, final PromiseMessage msg, final Actor current, - final ForkJoinPool actorPool, final boolean haltOnResolution) { + final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution) { // when a promise is resolved, we need to schedule all the // #whenResolved:/#onError:/... callbacks msgs as well as all eventual send // msgs to the promise assert owner != null; - msg.resolve(result, owner, current); + msg.resolve(result, owner, current, maybeEntry); // if the promise had a haltOnResolution, // the message needs to break on receive @@ -773,7 +773,7 @@ public boolean assertNotCompleted() { @TruffleBoundary protected static void resolveChainedPromisesUnsync(final Resolution type, final SPromise promise, final Object result, final Actor current, - final ForkJoinPool actorPool, final boolean haltOnResolution, + final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final RecordOneEvent record, final RecordOneEvent recordStop) { // TODO: we should change the implementation of chained promises to @@ -787,10 +787,10 @@ protected static void resolveChainedPromisesUnsync(final Resolution type, Object wrapped = WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); resolveAndTriggerListenersUnsynced(type, result, wrapped, - chainedPromise, current, actorPool, + chainedPromise, current, actorPool, maybeEntry, chainedPromise.haltOnResolution, whenResolvedProfile, record, recordStop); resolveMoreChainedPromisesUnsynced(type, promise, result, current, - actorPool, haltOnResolution, whenResolvedProfile, record, recordStop); + actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, record, recordStop); } } @@ -800,7 +800,7 @@ protected static void resolveChainedPromisesUnsync(final Resolution type, @TruffleBoundary private static void resolveMoreChainedPromisesUnsynced(final Resolution type, final SPromise promise, final Object result, final Actor current, - final ForkJoinPool actorPool, final boolean haltOnResolution, + final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final RecordOneEvent record, final RecordOneEvent recordStop) { if (promise.chainedPromiseExt != null) { @@ -810,7 +810,7 @@ private static void resolveMoreChainedPromisesUnsynced(final Resolution type, for (SPromise p : chainedPromiseExt) { Object wrapped = WrapReferenceNode.wrapForUse(p.owner, result, current, null); resolveAndTriggerListenersUnsynced(type, result, wrapped, p, current, - actorPool, haltOnResolution, whenResolvedProfile, record, recordStop); + actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, record, recordStop); } } } @@ -822,7 +822,7 @@ private static void resolveMoreChainedPromisesUnsynced(final Resolution type, */ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, final Object result, final Object wrapped, final SPromise p, final Actor current, - final ForkJoinPool actorPool, final boolean haltOnResolution, + final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { assert !(result instanceof SPromise); @@ -867,13 +867,13 @@ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, } if (type == Resolution.SUCCESSFUL) { - scheduleAllWhenResolvedUnsync(p, result, current, actorPool, haltOnResolution, + scheduleAllWhenResolvedUnsync(p, result, current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile); } else { assert type == Resolution.ERRONEOUS; - scheduleAllOnErrorUnsync(p, result, current, actorPool, haltOnResolution); + scheduleAllOnErrorUnsync(p, result, current, actorPool, maybeEntry, haltOnResolution); } - resolveChainedPromisesUnsync(type, p, result, current, actorPool, haltOnResolution, + resolveChainedPromisesUnsync(type, p, result, current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, tracePromiseResolution2, tracePromiseResolutionEnd2); if (VmSettings.SENDER_SIDE_TRACING) { @@ -886,7 +886,7 @@ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, * Schedule all whenResolved callbacks for the promise. */ protected static void scheduleAllWhenResolvedUnsync(final SPromise promise, - final Object result, final Actor current, final ForkJoinPool actorPool, + final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile) { if (promise.whenResolved != null) { PromiseMessage whenResolved = promise.whenResolved; @@ -900,8 +900,8 @@ protected static void scheduleAllWhenResolvedUnsync(final SPromise promise, } promise.scheduleCallbacksOnResolution(result, - whenResolvedProfile.profile(whenResolved), current, actorPool, haltOnResolution); - scheduleExtensions(promise, whenResolvedExt, result, current, actorPool, + whenResolvedProfile.profile(whenResolved), current, actorPool, maybeEntry, haltOnResolution); + scheduleExtensions(promise, whenResolvedExt, result, current, actorPool, maybeEntry, haltOnResolution); } } @@ -913,12 +913,12 @@ protected static void scheduleAllWhenResolvedUnsync(final SPromise promise, private static void scheduleExtensions(final SPromise promise, final ArrayList extension, final Object result, final Actor current, - final ForkJoinPool actorPool, final boolean haltOnResolution) { + final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution) { if (extension != null) { for (int i = 0; i < extension.size(); i++) { PromiseMessage callbackOrMsg = extension.get(i); promise.scheduleCallbacksOnResolution(result, callbackOrMsg, current, - actorPool, haltOnResolution); + actorPool, maybeEntry, haltOnResolution); } } } @@ -928,7 +928,7 @@ private static void scheduleExtensions(final SPromise promise, */ protected static void scheduleAllOnErrorUnsync(final SPromise promise, final Object result, final Actor current, - final ForkJoinPool actorPool, final boolean haltOnResolution) { + final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution) { if (promise.onError != null) { PromiseMessage onError = promise.onError; ArrayList onErrorExt = promise.onErrorExt; @@ -940,9 +940,9 @@ protected static void scheduleAllOnErrorUnsync(final SPromise promise, numScheduledOnError.addAndGet(1 + count); } - promise.scheduleCallbacksOnResolution(result, onError, current, actorPool, + promise.scheduleCallbacksOnResolution(result, onError, current, actorPool, maybeEntry, haltOnResolution); - scheduleExtensions(promise, onErrorExt, result, current, actorPool, haltOnResolution); + scheduleExtensions(promise, onErrorExt, result, current, actorPool, maybeEntry, haltOnResolution); } } } diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index 2214775407..f97222d8fa 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -16,6 +16,11 @@ import tools.replay.ReplayRecord; import tools.replay.TraceRecord; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; + /** * WARNING: This node needs to be used in a context that makes sure @@ -33,10 +38,10 @@ protected SchedulePromiseHandlerNode(final ForkJoinPool actorPool) { this.actorPool = actorPool; } - public abstract void execute(SPromise promise, PromiseMessage msg, Actor current); + public abstract void execute(VirtualFrame frame, SPromise promise, PromiseMessage msg, Actor current); @Specialization - public final void schedule(final SPromise promise, + public final void schedule(final VirtualFrame frame, final SPromise promise, final PromiseCallbackMessage msg, final Actor current, @Cached("createWrapper()") final WrapReferenceNode wrapper) { assert promise.getOwner() != null; @@ -44,6 +49,16 @@ public final void schedule(final SPromise promise, msg.args[PromiseMessage.PROMISE_VALUE_IDX] = wrapper.execute( promise.getValueUnsync(), msg.originalSender, current); + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // TODO: I think, we need the info about the resolution context from the promise + // we want to know where it was resolved, where the value is coming from + ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( + SArguments.getShadowStackEntry(frame), + getParent().getParent()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; + SArguments.setShadowStackEntry(msg.args, resolutionEntry); + } + if (VmSettings.SENDER_SIDE_REPLAY) { ReplayRecord npr = current.getNextReplayEvent(); assert npr.type == TraceRecord.MESSAGE; @@ -76,6 +91,8 @@ public final void schedule(final SPromise promise, receiver = ((SFarReference) receiver).getValue(); } + // TODO: we already have a shadow stack entry here, Don't think we need to do anything about it + msg.args[PromiseMessage.PROMISE_RCVR_IDX] = receiver; assert !(receiver instanceof SFarReference) @@ -102,7 +119,8 @@ public final void schedule(final SPromise promise, private void wrapArguments(final PromiseSendMessage msg, final Actor finalTarget, final WrapReferenceNode argWrapper) { // TODO: break that out into nodes - for (int i = 1; i < numArgs.profile(msg.args.length); i++) { + for (int i = + 1; i < numArgs.profile(SArguments.getLengthWithoutShadowStack(msg.args)); i++) { msg.args[i] = argWrapper.execute(msg.args[i], finalTarget, msg.originalSender); } } diff --git a/src/som/interpreter/nodes/ExceptionSignalingNode.java b/src/som/interpreter/nodes/ExceptionSignalingNode.java index 927d5321e7..ceedac7be8 100644 --- a/src/som/interpreter/nodes/ExceptionSignalingNode.java +++ b/src/som/interpreter/nodes/ExceptionSignalingNode.java @@ -12,6 +12,7 @@ import som.vmobjects.SClass; import som.vmobjects.SObject; import som.vmobjects.SSymbol; +import com.oracle.truffle.api.frame.VirtualFrame; public abstract class ExceptionSignalingNode extends Node { @@ -44,7 +45,7 @@ public static ExceptionSignalingNode createNode(final Supplier resolver return new ResolveModule(exceptionSelector, factorySelector, sourceSection, resolver); } - public abstract Object signal(Object... args); + public abstract Object signal(VirtualFrame frame, Object... args); private static final class ResolvedModule extends ExceptionSignalingNode { @Child protected ExpressionNode getExceptionClassNode; @@ -63,11 +64,11 @@ private ResolvedModule(final SObject module, final SSymbol exceptionSelector, } @Override - public Object signal(final Object... args) { + public Object signal(VirtualFrame frame, final Object... args) { SClass exceptionClass = - (SClass) ((PreevaluatedExpression) getExceptionClassNode).doPreEvaluated(null, + (SClass) ((PreevaluatedExpression) getExceptionClassNode).doPreEvaluated(frame, new Object[] {module}); - return ((PreevaluatedExpression) signalExceptionNode).doPreEvaluated(null, + return ((PreevaluatedExpression) signalExceptionNode).doPreEvaluated(frame, mergeObjectWithArray(exceptionClass, args)); } @@ -96,12 +97,12 @@ private ResolveModule(final SSymbol exceptionSelector, final SSymbol factorySele } @Override - public Object signal(final Object... args) { + public Object signal(VirtualFrame frame, final Object... args) { CompilerDirectives.transferToInterpreterAndInvalidate(); SObject module = resolver.get(); assert module != null : "Delayed lookup of module failed, still not available"; return replace(new ResolvedModule(module, exceptionSelector, factorySelector, - sourceSection)).signal(args); + sourceSection)).signal(frame, args); } } @@ -121,10 +122,10 @@ private LazyModule(final SSymbol exceptionSelector, final SSymbol factorySelecto } @Override - public Object signal(final Object... args) { + public Object signal(VirtualFrame frame, final Object... args) { CompilerDirectives.transferToInterpreterAndInvalidate(); return replace(new ResolvedModule(module, exceptionSelector, factorySelector, - sourceSection)).signal(args); + sourceSection)).signal(frame, args); } } } diff --git a/src/som/interpreter/nodes/InstantiationNode.java b/src/som/interpreter/nodes/InstantiationNode.java index 7c51435132..260afad20f 100644 --- a/src/som/interpreter/nodes/InstantiationNode.java +++ b/src/som/interpreter/nodes/InstantiationNode.java @@ -12,6 +12,7 @@ import som.vmobjects.SClass; import som.vmobjects.SObjectWithClass; import tools.snapshot.nodes.ObjectSerializationNodesFactory.UninitializedObjectSerializationNodeFactory; +import com.oracle.truffle.api.frame.VirtualFrame; public abstract class InstantiationNode extends Node { @@ -47,19 +48,19 @@ public static SClass instantiateMetaclassClass(final ClassFactory factory, } public static SClass signalExceptionsIfFaultFoundElseReturnClassObject( - final SObjectWithClass outerObj, - final ClassFactory factory, final SClass classObj, - final ExceptionSignalingNode notAValue, final ExceptionSignalingNode cannotBeValue) { + final VirtualFrame frame, final SObjectWithClass outerObj, final ClassFactory factory, + final SClass classObj, final ExceptionSignalingNode notAValue, + final ExceptionSignalingNode cannotBeValue) { factory.initializeClass(classObj); if (factory.isDeclaredAsValue() && factory.isTransferObject()) { // REM: cast is fine here, because we never return anyway - cannotBeValue.signal(classObj); + cannotBeValue.signal(frame, classObj); } if ((factory.isTransferObject() || factory.isDeclaredAsValue()) && !outerObj.isValue()) { - notAValue.signal(classObj); + notAValue.signal(frame, classObj); } return classObj; @@ -71,28 +72,28 @@ public ClassInstantiationNode(final MixinDefinition mixinDefinition) { super(mixinDefinition); } - public abstract SClass execute(SObjectWithClass outerObj, Object superclassAndMixins); + public abstract SClass execute(VirtualFrame frame, SObjectWithClass outerObj, Object superclassAndMixins); @Specialization(guards = {"sameSuperAndMixins(superclassAndMixins, cachedSuperMixins)"}) - public SClass instantiateClass(final SObjectWithClass outerObj, + public SClass instantiateClass(final VirtualFrame frame, final SObjectWithClass outerObj, final Object superclassAndMixins, @Cached("superclassAndMixins") final Object cachedSuperMixins, @Cached("createClassFactory(superclassAndMixins)") final ClassFactory factory) { - return instantiate(outerObj, factory, notAValue, cannotBeValues); + return instantiate(frame, outerObj, factory, notAValue, cannotBeValues); } - public static SClass instantiate(final SObjectWithClass outerObj, + public static SClass instantiate(final VirtualFrame frame, final SObjectWithClass outerObj, final ClassFactory factory, final ExceptionSignalingNode notAValue, final ExceptionSignalingNode cannotBeValues) { SClass classObj = new SClass(outerObj, instantiateMetaclassClass(factory, outerObj)); - return signalExceptionsIfFaultFoundElseReturnClassObject(outerObj, factory, classObj, + return signalExceptionsIfFaultFoundElseReturnClassObject(frame, outerObj, factory, classObj, notAValue, cannotBeValues); } @Specialization(replaces = "instantiateClass") - public SClass instantiateClassWithNewClassFactory(final SObjectWithClass outerObj, + public SClass instantiateClassWithNewClassFactory(final VirtualFrame frame, final SObjectWithClass outerObj, final Object superclassAndMixins) { - return instantiateClass(outerObj, superclassAndMixins, null, + return instantiateClass(frame, outerObj, superclassAndMixins, null, createClassFactory(superclassAndMixins)); } } @@ -127,7 +128,7 @@ private static SClass instantiate(final SObjectWithClass outerObj, final InstantiationNode inst) { SClass classObj = new SClass(outerObj, instantiateMetaclassClass(factory, outerObj), frame); - return signalExceptionsIfFaultFoundElseReturnClassObject(outerObj, factory, classObj, + return signalExceptionsIfFaultFoundElseReturnClassObject(frame, outerObj, factory, classObj, inst.notAValue, inst.cannotBeValues); } diff --git a/src/som/interpreter/nodes/InternalObjectArrayNode.java b/src/som/interpreter/nodes/InternalObjectArrayNode.java index b513c4ca77..88e87790c6 100644 --- a/src/som/interpreter/nodes/InternalObjectArrayNode.java +++ b/src/som/interpreter/nodes/InternalObjectArrayNode.java @@ -6,11 +6,14 @@ import com.oracle.truffle.api.nodes.NodeInfo; import som.interpreter.nodes.nary.ExprWithTagsNode; +import som.interpreter.SArguments; +import tools.asyncstacktraces.ShadowStackEntryLoad; @NodeInfo(cost = NodeCost.NONE) -public final class InternalObjectArrayNode extends ExprWithTagsNode { - @Children private final ExpressionNode[] expressions; +public class InternalObjectArrayNode extends ExprWithTagsNode { + @Children protected final ExpressionNode[] expressions; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); public InternalObjectArrayNode(final ExpressionNode[] expressions) { this.expressions = expressions; @@ -27,7 +30,27 @@ public Object[] executeObjectArray(final VirtualFrame frame) { } @Override - public Object executeGeneric(final VirtualFrame frame) { + public final Object executeGeneric(final VirtualFrame frame) { return executeObjectArray(frame); } + + public static class ArgumentEvaluationNode + extends InternalObjectArrayNode { + + public ArgumentEvaluationNode(final ExpressionNode[] expressions) { + super(expressions); + } + + @Override + @ExplodeLoop + public Object[] executeObjectArray(final VirtualFrame frame) { + Object[] values = SArguments.allocateArgumentsArray(expressions); + for (int i = 0; i < expressions.length; i++) { + values[i] = expressions[i].executeGeneric(frame); + } + SArguments.setShadowStackEntryWithCache(values, this, shadowStackEntryLoad, frame, + true); + return values; + } + } } diff --git a/src/som/interpreter/nodes/IsValueCheckNode.java b/src/som/interpreter/nodes/IsValueCheckNode.java index 49288c099d..786bed7180 100644 --- a/src/som/interpreter/nodes/IsValueCheckNode.java +++ b/src/som/interpreter/nodes/IsValueCheckNode.java @@ -133,7 +133,7 @@ public Object fallback(final Object receiver) { if (allFieldsContainValues) { return rcvr; } - return notAValue.signal(rcvr); + return notAValue.signal(frame, rcvr); } protected static final class FieldTester extends Node { diff --git a/src/som/interpreter/nodes/MessageSendNode.java b/src/som/interpreter/nodes/MessageSendNode.java index 640f0f8aff..1b417229a0 100644 --- a/src/som/interpreter/nodes/MessageSendNode.java +++ b/src/som/interpreter/nodes/MessageSendNode.java @@ -38,7 +38,8 @@ import som.vmobjects.SSymbol; import tools.dym.Tags.VirtualInvoke; import tools.dym.profiles.DispatchProfile; - +import som.interpreter.SArguments; +import tools.asyncstacktraces.ShadowStackEntry; public final class MessageSendNode { @@ -156,12 +157,15 @@ public Object executeGeneric(final VirtualFrame frame) { @ExplodeLoop private Object[] evaluateArguments(final VirtualFrame frame) { - Object[] arguments = new Object[argumentNodes.length]; + Object[] arguments = SArguments.allocateArgumentsArray(argumentNodes); for (int i = 0; i < argumentNodes.length; i++) { arguments[i] = argumentNodes[i].executeGeneric(frame); - assert arguments[i] != null - : "Some expression evaluated to null, which is not supported."; + assert arguments[i] != null : "Some expression evaluated to null, which is not supported."; + assert !(arguments[i] instanceof ShadowStackEntry); } + // We allocate room for the arguments, but it is not set if non + // SArguments.setShadowStackEntryWithCache(arguments, this, shadowStackEntryLoad, frame, + // false); return arguments; } diff --git a/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java b/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java index 69618af937..152392631c 100644 --- a/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java @@ -22,11 +22,13 @@ import som.vmobjects.SArray; import som.vmobjects.SClass; import som.vmobjects.SSymbol; +import tools.asyncstacktraces.ShadowStackEntryLoad; public abstract class AbstractGenericDispatchNode extends AbstractDispatchNode { - @Child protected IndirectCallNode call; - protected final SSymbol selector; + @Child protected IndirectCallNode call; + protected final SSymbol selector; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); public AbstractGenericDispatchNode(final SourceSection source, final SSymbol selector) { @@ -43,6 +45,13 @@ public final Object executeDispatch(final VirtualFrame frame, final Object[] arg SClass rcvrClass = Types.getClassOf(rcvr); Dispatchable method = doLookup(rcvrClass); + // Here we fall back to the slow case since megamorphic sends + // are just not present in benchmarks + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + SArguments.setShadowStackEntryWithCache(arguments, this, + shadowStackEntryLoad, frame, false); + } + if (method != null) { return method.invoke(call, arguments); } else { diff --git a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java new file mode 100644 index 0000000000..3b85c44f22 --- /dev/null +++ b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java @@ -0,0 +1,56 @@ +package som.interpreter.nodes.dispatch; + +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; + +import som.interpreter.Invokable; +import som.interpreter.Method; +import som.interpreter.SArguments; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; +import tools.asyncstacktraces.ShadowStackEntryLoad; + +public interface BackCacheCallNode { + + static void initializeUniqueCaller(final RootCallTarget methodCallTarget, + final BackCacheCallNode node) { + RootNode root = methodCallTarget.getRootNode(); + if (root instanceof Method) { + ((Method) root).setNewCaller(node); + } + } + + static void setShadowStackEntry(final VirtualFrame frame, + final boolean uniqueCaller, final Object[] arguments, + final Node expression, + final ShadowStackEntryLoad shadowStackEntryLoad) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + assert arguments[arguments.length - 1] == null; + assert (frame.getArguments()[frame.getArguments().length + - 1] instanceof ShadowStackEntry); + assert frame.getArguments().length >= 2; + } + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE) { + if (uniqueCaller) { + SArguments.setShadowStackEntry(arguments, SArguments.getShadowStackEntry(frame)); + } else { + SArguments.setShadowStackEntryWithCache(arguments, expression, + shadowStackEntryLoad, frame, false); + } + } else if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + SArguments.setShadowStackEntryWithCache(arguments, expression, + shadowStackEntryLoad, frame, false); + } + assert arguments[arguments.length - 1] != null + || (frame.getArguments()[frame.getArguments().length - 1] == null) + || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + } + + void makeUniqueCaller(); + + void makeMultipleCaller(); + + Invokable getCachedMethod(); +} diff --git a/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java b/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java index 3c3d6be2dc..0c28a2e4d0 100644 --- a/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java @@ -14,6 +14,7 @@ import som.interpreter.Invokable; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; +import som.vm.VmSettings; public abstract class BlockDispatchNode extends Node { @@ -33,7 +34,9 @@ protected static final boolean isSameMethod(final Object[] arguments, protected static final SInvokable getMethod(final Object[] arguments) { SInvokable method = ((SBlock) arguments[0]).getMethod(); - assert method.getNumberOfArguments() == arguments.length; + assert method.getNumberOfArguments() == arguments.length + || (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + && (method.getNumberOfArguments() == arguments.length - 1)); return method; } diff --git a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java index 05c4182b9f..0b4fb1e05c 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java @@ -12,37 +12,84 @@ import som.instrumentation.CountingDirectCallNode; import som.interpreter.Invokable; import som.vm.VmSettings; +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.impl.DefaultCallTarget; +import som.interpreter.Invokable; +import tools.asyncstacktraces.ShadowStackEntryLoad; -public final class CachedDispatchNode extends AbstractDispatchNode { - +public final class CachedDispatchNode extends AbstractDispatchNode implements BackCacheCallNode { + private final Assumption stillUniqueCaller; @Child private DirectCallNode cachedMethod; @Child private AbstractDispatchNode nextInCache; + @CompilationFinal private boolean uniqueCaller; + + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); private final DispatchGuard guard; public CachedDispatchNode(final CallTarget methodCallTarget, - final DispatchGuard guard, final AbstractDispatchNode nextInCache) { + final DispatchGuard guard, final AbstractDispatchNode nextInCache) { + this(methodCallTarget, guard, nextInCache, true); + } + + public CachedDispatchNode(final CallTarget methodCallTarget, + final DispatchGuard guard, final AbstractDispatchNode nextInCache, final boolean defaultUniqueCaller) { super(nextInCache.getSourceSection()); + stillUniqueCaller = Truffle.getRuntime().createAssumption(); this.guard = guard; this.nextInCache = nextInCache; this.cachedMethod = Truffle.getRuntime().createDirectCallNode(methodCallTarget); if (VmSettings.DYNAMIC_METRICS) { this.cachedMethod = new CountingDirectCallNode(this.cachedMethod); } + if (defaultUniqueCaller) { + BackCacheCallNode.initializeUniqueCaller((RootCallTarget) methodCallTarget, this); + } } + public CachedDispatchNode(final CachedDispatchNode node, final boolean uniqueCaller) { + this(node.cachedMethod.getCallTarget(), node.guard, node.nextInCache, false); + this.uniqueCaller = uniqueCaller; + } + + @Override + public void makeUniqueCaller() { + uniqueCaller = true; + } + + @Override + public void makeMultipleCaller() { + uniqueCaller = false; + stillUniqueCaller.invalidate(); + } + + @Override + public Invokable getCachedMethod() { + RootCallTarget ct = (DefaultCallTarget) cachedMethod.getCallTarget(); + return (Invokable) ct.getRootNode(); + } + @Override public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { try { if (guard.entryMatches(arguments[0])) { + stillUniqueCaller.check(); + BackCacheCallNode.setShadowStackEntry(frame, + uniqueCaller, arguments, this, shadowStackEntryLoad); return cachedMethod.call(arguments); } else { return nextInCache.executeDispatch(frame, arguments); } } catch (InvalidAssumptionException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); - return replace(nextInCache).executeDispatch(frame, arguments); + if (stillUniqueCaller.isValid()) { + return replace(nextInCache).executeDispatch(frame, arguments); + } else { + return replace(new CachedDispatchNode(this, false)).executeDispatch(frame, arguments); + } } } diff --git a/src/som/interpreter/nodes/dispatch/CachedDnuNode.java b/src/som/interpreter/nodes/dispatch/CachedDnuNode.java index bc81e129cc..7df02cea66 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDnuNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDnuNode.java @@ -22,6 +22,7 @@ import som.vmobjects.SClass; import som.vmobjects.SInvokable; import som.vmobjects.SSymbol; +import tools.asyncstacktraces.ShadowStackEntryLoad; public final class CachedDnuNode extends AbstractDispatchNode { @@ -32,6 +33,8 @@ public final class CachedDnuNode extends AbstractDispatchNode { private final DispatchGuard guard; private final SSymbol selector; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + public CachedDnuNode(final SClass rcvrClass, final SSymbol selector, final DispatchGuard guard, final VM vm, final AbstractDispatchNode nextInCache) { @@ -47,6 +50,13 @@ public CachedDnuNode(final SClass rcvrClass, final SSymbol selector, public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { boolean match; Object rcvr = arguments[0]; + // Here we fall back to the slow case since DNU sends + // are just too uncommon and we don't want to recreate + // the stack across DNUs + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + SArguments.setShadowStackEntryWithCache(arguments, this, + shadowStackEntryLoad, frame, false); + } try { match = guard.entryMatches(rcvr); } catch (InvalidAssumptionException e) { diff --git a/src/som/interpreter/nodes/dispatch/CachedSlotRead.java b/src/som/interpreter/nodes/dispatch/CachedSlotRead.java index 6c6da5997b..b4fa94de9d 100644 --- a/src/som/interpreter/nodes/dispatch/CachedSlotRead.java +++ b/src/som/interpreter/nodes/dispatch/CachedSlotRead.java @@ -18,6 +18,7 @@ import som.vmobjects.SObject; import tools.dym.Tags.ClassRead; import tools.dym.Tags.FieldRead; +import som.interpreter.SArguments; /** @@ -61,7 +62,7 @@ protected CachedSlotRead() { public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { try { if (guard.entryMatches(arguments[0])) { - return read(guard.cast(arguments[0])); + return read(frame, guard.cast(arguments[0]), SArguments.getShadowStackEntry(frame)); } else { return nextInCache.executeDispatch(frame, arguments); } @@ -71,7 +72,11 @@ public Object executeDispatch(final VirtualFrame frame, final Object[] arguments } } - public abstract Object read(SObject rcvr); + public abstract Object read(VirtualFrame frame, SObject rcvr); + + public Object read(final VirtualFrame frame, final SObject rcvr, final Object maybeEntry) { + return read(frame, rcvr); + } @Override public int lengthOfDispatchChain() { @@ -116,7 +121,7 @@ public UnwrittenSlotRead(final SlotAccess type, final CheckSObject guard, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { return Nil.nilObject; } } @@ -132,7 +137,7 @@ public ObjectSlotRead(final AbstractObjectAccessor accessor, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { return accessor.read(rcvr); } } @@ -159,7 +164,7 @@ public LongSlotReadSetOrUnset(final AbstractPrimitiveAccessor accessor, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { if (accessor.isPrimitiveSet(rcvr, primMarkProfile)) { return accessor.readLong(rcvr); } else { @@ -177,7 +182,7 @@ public LongSlotReadSet(final AbstractPrimitiveAccessor accessor, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { if (accessor.isPrimitiveSet(rcvr, primMarkProfile)) { return accessor.readLong(rcvr); } else { @@ -197,7 +202,7 @@ public DoubleSlotReadSetOrUnset(final AbstractPrimitiveAccessor accessor, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { if (accessor.isPrimitiveSet(rcvr, primMarkProfile)) { return accessor.readDouble(rcvr); } else { @@ -215,7 +220,7 @@ public DoubleSlotReadSet(final AbstractPrimitiveAccessor accessor, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { if (accessor.isPrimitiveSet(rcvr, primMarkProfile)) { return accessor.readDouble(rcvr); } else { diff --git a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java index 88aa2656c8..095644b163 100644 --- a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java +++ b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java @@ -19,6 +19,10 @@ import som.vm.constants.Nil; import som.vmobjects.SClass; import som.vmobjects.SObject; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; /** @@ -57,11 +61,16 @@ public ClassSlotAccessNode(final MixinDefinition mixinDef, final SlotDefinition } @Override - public SClass read(final SObject rcvr) { + public SClass read(final VirtualFrame frame, final SObject rcvr) { + return this.read(frame, rcvr, null); + } + + @Override + public SClass read(final VirtualFrame frame, final SObject rcvr, final Object maybeEntry) { // here we need to synchronize, because this is actually something that // can happen concurrently, and we only want a single instance of the // class object - Object cachedValue = read.read(rcvr); + Object cachedValue = read.read(frame, rcvr); assert cachedValue != null; if (cachedValue != Nil.nilObject) { @@ -83,7 +92,7 @@ public SClass read(final SObject rcvr) { // recheck guard under synchronized, don't want to access object if // layout might have changed, we are going to slow path in that case guard.entryMatches(rcvr); - cachedValue = read.read(rcvr); + cachedValue = read.read(frame, rcvr); } catch (InvalidAssumptionException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); cachedValue = rcvr.readSlot(slotDef); @@ -91,7 +100,7 @@ public SClass read(final SObject rcvr) { // check whether cache is initialized with class object if (cachedValue == Nil.nilObject) { - return instantiateAndWriteUnsynced(rcvr); + return instantiateAndWriteUnsynced(frame, rcvr, maybeEntry); } else { assert cachedValue instanceof SClass; return (SClass) cachedValue; @@ -102,8 +111,9 @@ public SClass read(final SObject rcvr) { /** * Caller needs to hold lock on {@code this}. */ - private SClass instantiateAndWriteUnsynced(final SObject rcvr) { - SClass classObject = instantiateClassObject(rcvr); + private SClass instantiateAndWriteUnsynced(final VirtualFrame frame, final SObject rcvr, + final Object maybeEntry) { + SClass classObject = instantiateClassObject(frame, rcvr, maybeEntry); try { // recheck guard under synchronized, don't want to access object if @@ -127,14 +137,33 @@ private void createResolverCallTargets() { invokable.getCallTarget())); } - private SClass instantiateClassObject(final SObject rcvr) { + private SClass instantiateClassObject(final VirtualFrame frame, final SObject rcvr, + final Object maybeEntry) { if (superclassAndMixinResolver == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); createResolverCallTargets(); } - Object superclassAndMixins = superclassAndMixinResolver.call(new Object[] {rcvr}); - SClass classObject = instantiation.execute(rcvr, superclassAndMixins); + Object superclassAndMixins; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // maybeEntry is set if coming from a cached dispatch node + // Not set if comes from elsewhere (materializer, etc.).. + // But it may not make sense. + ShadowStackEntry actualEntry; + if (maybeEntry != null) { + assert maybeEntry instanceof ShadowStackEntry; + actualEntry = (ShadowStackEntry) maybeEntry; + } else { + actualEntry = SArguments.instantiateTopShadowStackEntry(this); + } + superclassAndMixins = + superclassAndMixinResolver.call( + new Object[] {rcvr, actualEntry}); + } else { + superclassAndMixins = superclassAndMixinResolver.call(new Object[] {rcvr}); + } + + SClass classObject = instantiation.execute(frame, rcvr, superclassAndMixins); return classObject; } } diff --git a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java index 6c29a60e3c..b2572d8646 100644 --- a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java @@ -12,26 +12,69 @@ import som.interpreter.Invokable; import som.vm.VmSettings; +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.impl.DefaultCallTarget; +import som.interpreter.Method; +import tools.asyncstacktraces.ShadowStackEntryLoad; + /** * Private methods are special, they are linked unconditionally to the call site. * Thus, we don't need to check at the dispatch whether they apply or not. */ -public final class LexicallyBoundDispatchNode extends AbstractDispatchNode { +public abstract class LexicallyBoundDispatchNode extends AbstractDispatchNode implements BackCacheCallNode { + + protected final Assumption stillUniqueCaller; + @Child private DirectCallNode cachedMethod; + @CompilationFinal protected boolean uniqueCaller; - @Child private DirectCallNode cachedMethod; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); public LexicallyBoundDispatchNode(final SourceSection source, final CallTarget methodCallTarget) { super(source); + stillUniqueCaller = Truffle.getRuntime().createAssumption(); cachedMethod = Truffle.getRuntime().createDirectCallNode(methodCallTarget); if (VmSettings.DYNAMIC_METRICS) { this.cachedMethod = new CountingDirectCallNode(this.cachedMethod); } + BackCacheCallNode.initializeUniqueCaller((RootCallTarget) methodCallTarget, this); + } + + @Override + public void makeUniqueCaller() { + uniqueCaller = true; + } + + @Override + public void makeMultipleCaller() { + uniqueCaller = false; + stillUniqueCaller.invalidate(); } @Override - public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { + public Method getCachedMethod() { + RootCallTarget ct = (DefaultCallTarget) cachedMethod.getCallTarget(); + return (Method) ct.getRootNode(); + } + + @Override + public abstract Object executeDispatch(VirtualFrame frame, Object[] arguments); + + @Specialization(assumptions = "stillUniqueCaller", guards = "uniqueCaller") + public Object uniqueCallerDispatch(final VirtualFrame frame, final Object[] arguments) { + BackCacheCallNode.setShadowStackEntry(frame, + true, arguments, this, shadowStackEntryLoad); + return cachedMethod.call(arguments); + } + + @Specialization(guards = "!uniqueCaller") + public Object multipleCallerDispatch(final VirtualFrame frame, final Object[] arguments) { + BackCacheCallNode.setShadowStackEntry(frame, + false, arguments, this, shadowStackEntryLoad); return cachedMethod.call(arguments); } diff --git a/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java b/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java index 237912acf2..b9f883e3cd 100644 --- a/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java +++ b/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java @@ -11,6 +11,7 @@ import som.interpreter.nodes.MessageSendNode.GenericMessageSendNode; import som.vm.NotYetImplementedException; import som.vmobjects.SSymbol; +import som.vm.VmSettings; public final class EagerBinaryPrimitiveNode extends EagerPrimitiveNode { @@ -101,8 +102,13 @@ public Object executeEvaluated(final VirtualFrame frame, } catch (UnsupportedSpecializationException e) { TruffleCompiler.transferToInterpreterAndInvalidate( "Eager Primitive with unsupported specialization."); - return makeGenericSend().doPreEvaluated(frame, - new Object[] {receiver, argument}); + Object[] args; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + args = new Object[] {receiver, argument, null}; + } else { + args = new Object[] {receiver, argument}; + } + return makeGenericSend().doPreEvaluated(frame, args); } } diff --git a/src/som/interpreter/transactions/CachedTxSlotRead.java b/src/som/interpreter/transactions/CachedTxSlotRead.java index a08e10b811..7f1e06d747 100644 --- a/src/som/interpreter/transactions/CachedTxSlotRead.java +++ b/src/som/interpreter/transactions/CachedTxSlotRead.java @@ -5,6 +5,7 @@ import som.interpreter.nodes.dispatch.DispatchGuard.CheckSObject; import som.vmobjects.SObject; import som.vmobjects.SObject.SMutableObject; +import com.oracle.truffle.api.frame.VirtualFrame; public final class CachedTxSlotRead extends CachedSlotRead { @@ -19,8 +20,8 @@ public CachedTxSlotRead(final SlotAccess type, } @Override - public Object read(final SObject rcvr) { + public Object read(final VirtualFrame frame, final SObject rcvr) { SMutableObject workingCopy = Transactions.workingCopy((SMutableObject) rcvr); - return read.read(workingCopy); + return read.read(frame, workingCopy); } } diff --git a/src/som/primitives/ActivitySpawn.java b/src/som/primitives/ActivitySpawn.java index ffa61763fe..9415105e84 100644 --- a/src/som/primitives/ActivitySpawn.java +++ b/src/som/primitives/ActivitySpawn.java @@ -176,7 +176,7 @@ public final SomThreadTask spawnThread(final SClass clazz, final SBlock block) { public final Object spawnProcess(final VirtualFrame frame, final SImmutableObject procMod, final SClass procCls, @Cached("createIsValue()") final IsValue isVal) { if (!isVal.executeBoolean(frame, procCls)) { - notAValue.signal(procCls); + notAValue.signal(frame, procCls); } spawnProcess(procCls, traceProcCreation); @@ -268,7 +268,7 @@ public final Object spawnProcess(final VirtualFrame frame, final SImmutableObjec final SClass procCls, final SArray arg, final Object[] argArr, @Cached("createIsValue()") final IsValue isVal) { if (!isVal.executeBoolean(frame, procCls)) { - notAValue.signal(procCls); + notAValue.signal(frame, procCls); } spawnProcess(procCls, argArr, traceProcCreation); diff --git a/src/som/primitives/BlockPrims.java b/src/som/primitives/BlockPrims.java index 5818f25ee9..6ea8aeee6f 100644 --- a/src/som/primitives/BlockPrims.java +++ b/src/som/primitives/BlockPrims.java @@ -33,6 +33,8 @@ import som.vmobjects.SInvokable; import tools.dym.Tags.OpClosureApplication; import tools.dym.profiles.DispatchProfile; +import com.oracle.truffle.api.frame.VirtualFrame; +import tools.asyncstacktraces.ShadowStackEntryLoad; public abstract class BlockPrims { @@ -73,6 +75,8 @@ public abstract static class ValueNonePrim extends UnaryExpressionNode protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + @Override public ExpressionNode initialize(final SourceSection sourceSection, final boolean eagerlyWrapped) { @@ -98,17 +102,20 @@ public final boolean doBoolean(final boolean receiver) { @Specialization( guards = {"cached == receiver.getMethod()", "cached.getNumberOfArguments() == 1"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final SBlock receiver, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { - return call.call(new Object[] {receiver}); + return call.call(SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final SBlock receiver, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, @Cached("create()") final IndirectCallNode call) { - checkArguments(receiver, 1, argumentError); - return receiver.getMethod().invoke(call, new Object[] {receiver}); + checkArguments(frame, receiver, 1, argumentError); + return receiver.getMethod().invoke(call, + SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver)); } @Override @@ -125,11 +132,11 @@ public final void record(final Invokable ivkbl, } } - private static void checkArguments(final SBlock receiver, final int expectedNumArgs, + private static void checkArguments(final VirtualFrame frame, final SBlock receiver, final int expectedNumArgs, final ExceptionSignalingNode argumentError) { int numArgs = receiver.getMethod().getNumberOfArguments(); if (numArgs != expectedNumArgs) { - argumentError.signal(errorMsg(expectedNumArgs, numArgs)); + argumentError.signal(frame, errorMsg(expectedNumArgs, numArgs)); } } @@ -147,6 +154,7 @@ public abstract static class ValueOnePrim extends BinaryExpressionNode implements DispatchProfile, ValuePrimNode { protected @Child ExceptionSignalingNode argumentError; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; @@ -171,17 +179,20 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { @Specialization( guards = {"cached == receiver.getMethod()", "cached.getNumberOfArguments() == 2"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final SBlock receiver, final Object arg, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, final Object arg, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { - return call.call(new Object[] {receiver, arg}); + return call.call(SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver, arg)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final SBlock receiver, final Object arg, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, final Object arg, @Cached("create()") final IndirectCallNode call) { - checkArguments(receiver, 2, argumentError); - return receiver.getMethod().invoke(call, new Object[] {receiver, arg}); + checkArguments(frame, receiver, 2, argumentError); + return receiver.getMethod().invoke(call, + SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver, arg)); } @Override @@ -206,6 +217,8 @@ public abstract static class ValueTwoPrim extends TernaryExpressionNode implements DispatchProfile, ValuePrimNode { protected @Child ExceptionSignalingNode argumentError; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; @@ -230,18 +243,21 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { @Specialization( guards = {"cached == receiver.getMethod()", "cached.getNumberOfArguments() == 3"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final SBlock receiver, final Object arg1, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, final Object arg1, final Object arg2, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { - return call.call(new Object[] {receiver, arg1, arg2}); + return call.call(SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver, arg1, arg2)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final SBlock receiver, final Object arg1, final Object arg2, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, final Object arg1, final Object arg2, @Cached("create()") final IndirectCallNode call) { - checkArguments(receiver, 3, argumentError); - return receiver.getMethod().invoke(call, new Object[] {receiver, arg1, arg2}); + checkArguments(frame, receiver, 3, argumentError); + return receiver.getMethod().invoke(call, + SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver, arg1, arg2)); } @Override @@ -266,9 +282,10 @@ public final void record(final Invokable ivkbl, public abstract static class ValueArgsPrim extends BinaryExpressionNode implements DispatchProfile, ValuePrimNode { - protected @Child SizeAndLengthPrim size = SizeAndLengthPrimFactory.create(null); - protected @Child AtPrim at = AtPrimFactory.create(null, null); + protected @Child SizeAndLengthPrim size = SizeAndLengthPrimFactory.create(null); + protected @Child AtPrim at = AtPrimFactory.create(null, null); protected @Child ExceptionSignalingNode argumentError; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; @@ -298,19 +315,21 @@ protected long getNumArgs(final SArray args) { guards = {"cached == receiver.getMethod()", "numArgs == cached.getNumberOfArguments()"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final SBlock receiver, final SArray args, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, final SArray args, @Cached("getNumArgs(args)") final long numArgs, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { - return call.call(SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at)); + return call.call(SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at, this, + shadowStackEntryLoad, frame)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final SBlock receiver, final SArray args, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, final SArray args, @Cached("create()") final IndirectCallNode call) { - checkArguments(receiver, (int) getNumArgs(args), argumentError); + checkArguments(frame, receiver, (int) getNumArgs(args), argumentError); return receiver.getMethod().invoke( - call, SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at)); + call, SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at, this, + shadowStackEntryLoad, frame)); } @Override diff --git a/src/som/primitives/ExceptionsPrims.java b/src/som/primitives/ExceptionsPrims.java index 1552722742..387b796a0a 100644 --- a/src/som/primitives/ExceptionsPrims.java +++ b/src/som/primitives/ExceptionsPrims.java @@ -19,6 +19,9 @@ import som.vmobjects.SBlock; import som.vmobjects.SClass; import som.vmobjects.SInvokable; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; +import tools.asyncstacktraces.ShadowStackEntryLoad; public abstract class ExceptionsPrims { @@ -29,12 +32,20 @@ public abstract static class ExceptionDoOnPrim extends TernaryExpressionNode { protected static final int INLINE_CACHE_SIZE = VmSettings.DYNAMIC_METRICS ? 100 : 6; + @Child + protected ShadowStackEntryLoad shadowStackEntryLoadBody = + ShadowStackEntryLoad.create(); + + @Child + protected ShadowStackEntryLoad shadowStackEntryLoadException = + ShadowStackEntryLoad.create(); + protected static final IndirectCallNode indirect = - Truffle.getRuntime().createIndirectCallNode(); + Truffle.getRuntime().createIndirectCallNode(); public static final DirectCallNode createCallNode(final SBlock block) { return Truffle.getRuntime().createDirectCallNode( - block.getMethod().getCallTarget()); + block.getMethod().getCallTarget()); } public static final boolean sameBlock(final SBlock block, final SInvokable method) { @@ -42,19 +53,36 @@ public static final boolean sameBlock(final SBlock block, final SInvokable metho } @Specialization(limit = "INLINE_CACHE_SIZE", - guards = {"sameBlock(body, cachedBody)", - "sameBlock(exceptionHandler, cachedExceptionMethod)"}) - public final Object doException(final SBlock body, - final SClass exceptionClass, final SBlock exceptionHandler, - @Cached("body.getMethod()") final SInvokable cachedBody, - @Cached("createCallNode(body)") final DirectCallNode bodyCall, - @Cached("exceptionHandler.getMethod()") final SInvokable cachedExceptionMethod, - @Cached("createCallNode(exceptionHandler)") final DirectCallNode exceptionCall) { + guards = {"sameBlock(body, cachedBody)", + "sameBlock(exceptionHandler, cachedExceptionMethod)"}) + public final Object doException(final VirtualFrame frame, final SBlock body, + final SClass exceptionClass, final SBlock exceptionHandler, + @Cached("body.getMethod()") final SInvokable cachedBody, + @Cached("createCallNode(body)") final DirectCallNode bodyCall, + @Cached("exceptionHandler.getMethod()") final SInvokable cachedExceptionMethod, + @Cached("createCallNode(exceptionHandler)") final DirectCallNode exceptionCall) { try { - return bodyCall.call(new Object[] {body}); + Object[] args; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + args = new Object[]{body, null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadBody, frame, + false); + } else { + args = new Object[]{body}; + } + return bodyCall.call(args); } catch (SomException e) { if (e.getSomObject().getSOMClass().isKindOf(exceptionClass)) { - return exceptionCall.call(new Object[] {exceptionHandler, e.getSomObject()}); + Object[] args; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + args = new Object[]{exceptionHandler, e.getSomObject(), null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadException, + frame, + false); + } else { + args = new Object[]{exceptionHandler, e.getSomObject()}; + } + return exceptionCall.call(args); } else { throw e; } @@ -62,14 +90,30 @@ public final Object doException(final SBlock body, } @Specialization(replaces = "doException") - public final Object doExceptionUncached(final SBlock body, - final SClass exceptionClass, final SBlock exceptionHandler) { + public final Object doExceptionUncached(final VirtualFrame frame, final SBlock body, + final SClass exceptionClass, final SBlock exceptionHandler) { try { - return body.getMethod().invoke(indirect, new Object[] {body}); + Object[] args; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + args = new Object[]{body, null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadBody, frame, + false); + } else { + args = new Object[]{body}; + } + return body.getMethod().invoke(indirect, args); } catch (SomException e) { if (e.getSomObject().getSOMClass().isKindOf(exceptionClass)) { - return exceptionHandler.getMethod().invoke(indirect, - new Object[] {exceptionHandler, e.getSomObject()}); + Object[] args; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + args = new Object[]{exceptionHandler, e.getSomObject(), null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadException, + frame, + false); + } else { + args = new Object[]{exceptionHandler, e.getSomObject()}; + } + return exceptionHandler.getMethod().invoke(indirect, args); } else { throw e; } @@ -88,18 +132,44 @@ public final Object doSignal(final SAbstractObject exceptionObject) { @GenerateNodeFactory @Primitive(primitive = "exceptionDo:ensure:", selector = "ensure:", - receiverType = SBlock.class) + receiverType = SBlock.class) public abstract static class EnsurePrim extends BinaryComplexOperation { - @Child protected BlockDispatchNode dispatchBody = BlockDispatchNodeGen.create(); - @Child protected BlockDispatchNode dispatchHandler = BlockDispatchNodeGen.create(); + @Child + protected BlockDispatchNode dispatchBody = BlockDispatchNodeGen.create(); + @Child + protected BlockDispatchNode dispatchHandler = BlockDispatchNodeGen.create(); + + @Child + protected ShadowStackEntryLoad shadowStackEntryLoadBody = + ShadowStackEntryLoad.create(); + @Child + protected ShadowStackEntryLoad shadowStackEntryLoadHandler = + ShadowStackEntryLoad.create(); @Specialization - public final Object doException(final SBlock body, final SBlock ensureHandler) { - try { - return dispatchBody.executeDispatch(new Object[] {body}); - } finally { - dispatchHandler.executeDispatch(new Object[] {ensureHandler}); + public final Object doException(final VirtualFrame frame, final SBlock body, + final SBlock ensureHandler) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // losing SSEntry info here again + try { + Object[] args = new Object[]{body, null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadBody, frame, + false); + return dispatchBody.executeDispatch(args); + } finally { + Object[] args = new Object[]{ensureHandler, null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadHandler, + frame, + false); + dispatchHandler.executeDispatch(args); + } + } else { + try { + return dispatchBody.executeDispatch(new Object[]{body}); + } finally { + dispatchHandler.executeDispatch(new Object[]{ensureHandler}); + } } } } diff --git a/src/som/primitives/FilePrims.java b/src/som/primitives/FilePrims.java index c8dc07af08..26fc0b8553 100644 --- a/src/som/primitives/FilePrims.java +++ b/src/som/primitives/FilePrims.java @@ -28,6 +28,7 @@ import som.vmobjects.SClass; import som.vmobjects.SFileDescriptor; import som.vmobjects.SSymbol; +import com.oracle.truffle.api.frame.VirtualFrame; public final class FilePrims { @@ -68,8 +69,8 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final Object closeFile(final SFileDescriptor file) { - file.closeFile(ioException); + public final Object closeFile(final VirtualFrame frame, final SFileDescriptor file) { + file.closeFile(frame, ioException); return file; } } @@ -122,18 +123,18 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final Object setModeSymbol(final SFileDescriptor file, final SSymbol mode) { + public final Object setModeSymbol(final VirtualFrame frame, final SFileDescriptor file, final SSymbol mode) { try { file.setMode(mode); } catch (IllegalArgumentException e) { - argumentError.signal(mode.getString()); + argumentError.signal(frame, mode.getString()); } return file; } @Fallback - public final Object setWithUnsupportedValue(final Object file, final Object mode) { - argumentError.signal(errorMsg(mode)); + public final Object setWithUnsupportedValue(final VirtualFrame frame, final Object file, final Object mode) { + argumentError.signal(frame, errorMsg(mode)); return file; } @@ -159,8 +160,8 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final long getFileSize(final SFileDescriptor file) { - return file.getFileSize(ioException); + public final long getFileSize(final VirtualFrame frame, final SFileDescriptor file) { + return file.getFileSize(frame, ioException); } } @@ -216,9 +217,9 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final Object write(final SFileDescriptor file, final long nBytes, + public final Object write(final VirtualFrame frame, final SFileDescriptor file, final long nBytes, final long offset, final SBlock fail) { - file.write((int) nBytes, offset, fail, dispatchHandler, ioException, errorCases); + file.write(frame, (int) nBytes, offset, fail, dispatchHandler, ioException, errorCases); return file; } } diff --git a/src/som/primitives/PathPrims.java b/src/som/primitives/PathPrims.java index 58ff09857d..17a4d87d6c 100644 --- a/src/som/primitives/PathPrims.java +++ b/src/som/primitives/PathPrims.java @@ -34,6 +34,7 @@ import som.vmobjects.SBlock; import som.vmobjects.SObject; import som.vmobjects.SObject.SImmutableObject; +import com.oracle.truffle.api.frame.VirtualFrame; public final class PathPrims { @@ -192,15 +193,14 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - @TruffleBoundary - public final Object lastModified(final String dir) { + public final Object lastModified(final VirtualFrame frame, final String dir) { try { return lastModifiedTime(dir); } catch (FileNotFoundException e) { - fileNotFound.signal(dir, e.getMessage()); + fileNotFound.signal(frame, dir, e.getMessage()); return Nil.nilObject; } catch (IOException e) { - ioException.signal(e.getMessage()); + ioException.signal(frame, e.getMessage()); return Nil.nilObject; } } @@ -250,14 +250,13 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - @TruffleBoundary - public final long getSize(final String dir) { + public final long getSize(final VirtualFrame frame, final String dir) { try { return size(dir); } catch (NoSuchFileException e) { - fileNotFound.signal(dir, e.getMessage()); + fileNotFound.signal(frame, dir, e.getMessage()); } catch (IOException e) { - ioException.signal(e.getMessage()); + ioException.signal(frame, e.getMessage()); } return -1; } diff --git a/src/som/primitives/StringPrims.java b/src/som/primitives/StringPrims.java index 3900b93a65..664594d8c5 100644 --- a/src/som/primitives/StringPrims.java +++ b/src/som/primitives/StringPrims.java @@ -23,6 +23,7 @@ import som.vmobjects.SSymbol; import tools.dym.Tags.ComplexPrimitiveOperation; import tools.dym.Tags.StringAccess; +import com.oracle.truffle.api.frame.VirtualFrame; public class StringPrims { @@ -182,7 +183,7 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final String doString(final SArray chars) { + public final String doString(final VirtualFrame frame, final SArray chars) { VM.thisMethodNeedsToBeOptimized( "Method not yet optimal for compilation, should speculate or use branch profile in the loop"); return doStringWithBoundary(chars); @@ -199,7 +200,7 @@ private String doStringWithBoundary(final SArray chars) { sb.append(((SSymbol) o).getString()); } else { // TODO: there should be a Smalltalk asString message here, I think - argumentError.signal(errorMsg(o)); + argumentError.signal(frame, errorMsg(o)); } } @@ -212,8 +213,8 @@ private static String errorMsg(final Object o) { } @Fallback - public final void doGeneric(final Object obj) { - argumentError.signal(obj); + public final void doGeneric(final VirtualFrame frame, final Object obj) { + argumentError.signal(frame, obj); } } @@ -268,8 +269,8 @@ public final String doUnicodeChar(final long val) { } @Fallback - public final void doGeneric(final Object val) { - argumentError.signal("The value " + val + " is not a valid Unicode code point."); + public final void doGeneric(final VirtualFrame frame, final Object val) { + argumentError.signal(frame, "The value " + val + " is not a valid Unicode code point."); } } diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index fb68789686..a018c5998a 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -71,6 +71,12 @@ import tools.snapshot.SnapshotBuffer; import tools.snapshot.deserialization.DeserializationBuffer; +import java.util.Arrays; +import com.oracle.truffle.api.frame.VirtualFrame; +import tools.asyncstacktraces.ShadowStackEntry; +import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.asyncstacktraces.StackIterator; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; public final class SystemPrims { @@ -95,7 +101,17 @@ public abstract static class TraceStatisticsPrim extends UnarySystemOperation { @Specialization @TruffleBoundary public final Object doSObject(final Object module) { - long[] stats = TracingBackend.getStatistics(); + long[] tracingStats = TracingBackend.getStatistics(); + long[] stats = Arrays.copyOf(tracingStats, tracingStats.length + 5); + stats[tracingStats.length] = ShadowStackEntry.numberOfAllocations; + ShadowStackEntry.numberOfAllocations = 0; + stats[tracingStats.length + 1] = 0; + stats[tracingStats.length + 2] = ShadowStackEntryLoad.cacheHit; + ShadowStackEntryLoad.cacheHit = 0; + stats[tracingStats.length + 3] = ShadowStackEntryLoad.megaMiss; + ShadowStackEntryLoad.megaMiss = 0; + stats[tracingStats.length + 4] = ShadowStackEntryLoad.megaCacheHit; + ShadowStackEntryLoad.megaCacheHit = 0; return new SImmutableArray(stats, Classes.valueArrayClass); } } @@ -131,27 +147,32 @@ public final Object doSObject(final Object module) { } } - public static Object loadModule(final VM vm, final String path, + public static Object loadModule(final VirtualFrame frame, final VM vm, final String path, final ExceptionSignalingNode ioException) { // TODO: a single node for the different exceptions? try { - if (path.endsWith(EXTENSION_EXT)) { - return vm.loadExtensionModule(path); - } else { - MixinDefinition module = vm.loadModule(path); - return module.instantiateModuleClass(); - } + return loadModule(vm, path); } catch (FileNotFoundException e) { - ioException.signal(path, "Could not find module file. " + e.getMessage()); + ioException.signal(frame, path, "Could not find module file. " + e.getMessage()); } catch (NotAFileException e) { - ioException.signal(path, "Path does not seem to be a file. " + e.getMessage()); + ioException.signal(frame, path, "Path does not seem to be a file. " + e.getMessage()); } catch (IOException e) { - ioException.signal(e.getMessage()); + ioException.signal(frame, e.getMessage()); } assert false : "This should never be reached, because exceptions do not return"; return Nil.nilObject; } + @TruffleBoundary + private static Object loadModule(final VM vm, final String path) throws IOException { + if (path.endsWith(EXTENSION_EXT)) { + return vm.loadExtensionModule(path); + } else { + MixinDefinition module = vm.loadModule(path); + return module.instantiateModuleClass(); + } + } + @GenerateNodeFactory @Primitive(primitive = "load:") public abstract static class LoadPrim extends UnarySystemOperation { @@ -166,9 +187,8 @@ public UnarySystemOperation initialize(final VM vm) { } @Specialization - @TruffleBoundary - public final Object doSObject(final String moduleName) { - return loadModule(vm, moduleName, ioException); + public final Object doSObject(final VirtualFrame frame, final String moduleName) { + return loadModule(frame, vm, moduleName, ioException); } } @@ -186,13 +206,12 @@ public BinarySystemOperation initialize(final VM vm) { } @Specialization - @TruffleBoundary - public final Object load(final String filename, final SObjectWithClass moduleObj) { + public final Object load(final VirtualFrame frame, final String filename, final SObjectWithClass moduleObj) { String path = moduleObj.getSOMClass().getMixinDefinition().getSourceSection().getSource() .getPath(); File file = new File(URI.create(path).getPath()); - return loadModule(vm, file.getParent() + File.separator + filename, ioException); + return loadModule(frame, vm, file.getParent() + File.separator + filename, ioException); } } @@ -291,57 +310,52 @@ public final Object doSObject(final Object receiver) { public static void printStackTrace(final int skipDnuFrames, final SourceSection topNode) { ArrayList method = new ArrayList(); ArrayList location = new ArrayList(); - int[] maxLengthMethod = {0}; - boolean[] first = {true}; + int maxLengthMethod = 0; + Output.println("Stack Trace"); - Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { - @Override - public Object visitFrame(final FrameInstance frameInstance) { - RootCallTarget ct = (RootCallTarget) frameInstance.getCallTarget(); - - // TODO: do we need to handle other kinds of root nodes? - if (!(ct.getRootNode() instanceof Invokable)) { - return null; - } - - Invokable m = (Invokable) ct.getRootNode(); - - String id = m.getName(); - method.add(id); - maxLengthMethod[0] = Math.max(maxLengthMethod[0], id.length()); - Node callNode = frameInstance.getCallNode(); - if (callNode != null || first[0]) { - SourceSection nodeSS; - if (first[0]) { - first[0] = false; - nodeSS = topNode; - } else { - nodeSS = callNode.getEncapsulatingSourceSection(); - } - if (nodeSS != null) { - location.add(nodeSS.getSource().getName() - + SourceCoordinate.getLocationQualifier(nodeSS)); - } else { - location.add(""); - } - } else { - location.add(""); - } - - return null; + StackIterator stack = StackIterator.createHaltIterator(); + while (stack.hasNext()) { + StackFrame frame = stack.next(); + if (frame != null) { + method.add(frame.name); + maxLengthMethod = Math.max(maxLengthMethod, frame.name.length()); + // TODO: is frame.section better `callNode.getEncapsulatingSourceSection();` ? + addSourceSection(frame.section, location); } - }); + StringBuilder sb = new StringBuilder(); + for (int i = method.size() - 1; i >= skipDnuFrames; i--) { + sb.append(String.format("\t%1$-" + (maxLengthMethod + 4) + "s", + method.get(i))); + sb.append(location.get(i)); + sb.append('\n'); + } + } + + Output.print(stringStackTraceFrom(method, location, maxLengthMethod, skipDnuFrames)); + } + + private static String stringStackTraceFrom(final ArrayList method, + final ArrayList location, final int maxLengthMethod, final int skipDnuFrames) { StringBuilder sb = new StringBuilder(); for (int i = method.size() - 1; i >= skipDnuFrames; i--) { - sb.append(String.format("\t%1$-" + (maxLengthMethod[0] + 4) + "s", - method.get(i))); + sb.append(String.format("\t%1$-" + (maxLengthMethod + 4) + "s", + method.get(i))); sb.append(location.get(i)); sb.append('\n'); } + return sb.toString(); + } - Output.print(sb.toString()); + private static void addSourceSection(final SourceSection section, + final ArrayList location) { + if (section != null) { + location.add(section.getSource().getName() + + SourceCoordinate.getLocationQualifier(section)); + } else { + location.add(""); + } } } diff --git a/src/som/primitives/actors/CreateActorPrim.java b/src/som/primitives/actors/CreateActorPrim.java index b9bf7a7b29..1ddbbdb273 100644 --- a/src/som/primitives/actors/CreateActorPrim.java +++ b/src/som/primitives/actors/CreateActorPrim.java @@ -64,8 +64,8 @@ public final SFarReference createActor(final VirtualFrame frame, final Object re } @Fallback - public final Object throwNotAValueException(final Object receiver, final Object argument) { - return notAValue.signal(argument); + public final Object throwNotAValueException(final VirtualFrame frame, final Object receiver, final Object argument) { + return notAValue.signal(frame, argument); } @Override diff --git a/src/som/primitives/actors/PromisePrims.java b/src/som/primitives/actors/PromisePrims.java index 7fe1c12db7..3f0445738a 100644 --- a/src/som/primitives/actors/PromisePrims.java +++ b/src/som/primitives/actors/PromisePrims.java @@ -46,6 +46,9 @@ import tools.debugger.entities.SendOp; import tools.debugger.nodes.AbstractBreakpointNode; import tools.debugger.session.Breakpoints; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; +import tools.asyncstacktraces.ShadowStackEntryLoad; public final class PromisePrims { @@ -74,6 +77,8 @@ public abstract static class CreatePromisePairPrim extends UnarySystemOperation @Child protected AbstractBreakpointNode promiseResolverBreakpoint; @Child protected AbstractBreakpointNode promiseResolutionBreakpoint; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + protected static final DirectCallNode create() { Dispatchable disp = SPromise.pairClass.getSOMClass().lookupMessage( withAndFactory, AccessModifier.PUBLIC); @@ -91,7 +96,7 @@ public final CreatePromisePairPrim initialize(final VM vm) { } @Specialization - public final SImmutableObject createPromisePair(final Object nil, + public final SImmutableObject createPromisePair(final VirtualFrame frame, final Object nil, @Cached("create()") final DirectCallNode factory) { SPromise promise = SPromise.createPromise( @@ -100,8 +105,15 @@ public final SImmutableObject createPromisePair(final Object nil, promiseResolutionBreakpoint.executeShouldHalt(), sourceSection); SResolver resolver = SPromise.createResolver(promise); - return (SImmutableObject) factory.call( - new Object[] {SPromise.pairClass, promise, resolver}); + Object[] args; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + args = new Object[] {SPromise.pairClass, promise, resolver, null}; + SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoad, + frame, false); + } else { + args = new Object[] {SPromise.pairClass, promise, resolver}; + } + return (SImmutableObject) factory.call(args); } private static final SSymbol withAndFactory = Symbols.symbolFor("with:and:"); @@ -130,8 +142,7 @@ public int getNumArguments() { // does not require node creation? Might need a generic received node. @TruffleBoundary public static RootCallTarget createReceived(final SBlock callback) { - RootCallTarget target = callback.getMethod().getCallTarget(); - ReceivedCallback node = new ReceivedCallback(target); + ReceivedCallback node = new ReceivedCallback(callback.getMethod()); return node.getCallTarget(); } @@ -157,19 +168,19 @@ public final WhenResolvedPrim initialize(final VM vm) { } @Specialization(guards = "blockMethod == callback.getMethod()", limit = "10") - public final SPromise whenResolved(final SPromise promise, + public final SPromise whenResolved(final VirtualFrame frame, final SPromise promise, final SBlock callback, @Cached("callback.getMethod()") final SInvokable blockMethod, @Cached("createReceived(callback)") final RootCallTarget blockCallTarget) { - return registerWhenResolved(promise, callback, blockCallTarget, registerNode); + return registerWhenResolved(frame, promise, callback, blockCallTarget, registerNode); } @Specialization(replaces = "whenResolved") - public final SPromise whenResolvedUncached(final SPromise promise, final SBlock callback) { - return registerWhenResolved(promise, callback, createReceived(callback), registerNode); + public final SPromise whenResolvedUncached(final VirtualFrame frame, final SPromise promise, final SBlock callback) { + return registerWhenResolved(frame, promise, callback, createReceived(callback), registerNode); } - protected final SPromise registerWhenResolved(final SPromise rcvr, + protected final SPromise registerWhenResolved(final VirtualFrame frame, final SPromise rcvr, final SBlock block, final RootCallTarget blockCallTarget, final RegisterWhenResolved registerNode) { assert block.getMethod().getNumberOfArguments() == 2; @@ -188,7 +199,9 @@ protected final SPromise registerWhenResolved(final SPromise rcvr, KomposTrace.sendOperation(SendOp.PROMISE_MSG, pcm.getMessageId(), rcvr.getPromiseId(), pcm.getSelector(), rcvr.getOwner().getId(), pcm.getTargetSourceSection()); } - registerNode.register(rcvr, pcm, current); + registerNode.register(frame, rcvr, pcm, current); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + || pcm.getArgs()[pcm.getArgs().length - 1] != null; return promise; } @@ -224,19 +237,19 @@ public final OnErrorPrim initialize(final VM vm) { } @Specialization(guards = "blockMethod == callback.getMethod()", limit = "10") - public final SPromise onError(final SPromise promise, + public final SPromise onError(final VirtualFrame frame, final SPromise promise, final SBlock callback, @Cached("callback.getMethod()") final SInvokable blockMethod, @Cached("createReceived(callback)") final RootCallTarget blockCallTarget) { - return registerOnError(promise, callback, blockCallTarget, registerNode); + return registerOnError(frame, promise, callback, blockCallTarget, registerNode); } @Specialization(replaces = "onError") - public final SPromise whenResolvedUncached(final SPromise promise, final SBlock callback) { - return registerOnError(promise, callback, createReceived(callback), registerNode); + public final SPromise whenResolvedUncached(final VirtualFrame frame, final SPromise promise, final SBlock callback) { + return registerOnError(frame, promise, callback, createReceived(callback), registerNode); } - protected final SPromise registerOnError(final SPromise rcvr, + protected final SPromise registerOnError(final VirtualFrame frame, final SPromise rcvr, final SBlock block, final RootCallTarget blockCallTarget, final RegisterOnError registerNode) { assert block.getMethod().getNumberOfArguments() == 2; @@ -255,7 +268,9 @@ protected final SPromise registerOnError(final SPromise rcvr, KomposTrace.sendOperation(SendOp.PROMISE_MSG, msg.getMessageId(), rcvr.getPromiseId(), msg.getSelector(), rcvr.getOwner().getId(), msg.getTargetSourceSection()); } - registerNode.register(rcvr, msg, current); + registerNode.register(frame, rcvr, msg, current); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + || msg.getArgs()[msg.getArgs().length - 1] != null; return promise; } @@ -293,24 +308,24 @@ public final WhenResolvedOnErrorPrim initialize(final VM vm) { @Specialization(guards = {"resolvedMethod == resolved.getMethod()", "errorMethod == error.getMethod()"}) - public final SPromise whenResolvedOnError(final SPromise promise, + public final SPromise whenResolvedOnError(final VirtualFrame frame, final SPromise promise, final SBlock resolved, final SBlock error, @Cached("resolved.getMethod()") final SInvokable resolvedMethod, @Cached("createReceived(resolved)") final RootCallTarget resolvedTarget, @Cached("error.getMethod()") final SInvokable errorMethod, @Cached("createReceived(error)") final RootCallTarget errorTarget) { - return registerWhenResolvedOrError(promise, resolved, error, resolvedTarget, + return registerWhenResolvedOrError(frame, promise, resolved, error, resolvedTarget, errorTarget, registerWhenResolved, registerOnError); } @Specialization(replaces = "whenResolvedOnError") - public final SPromise whenResolvedOnErrorUncached(final SPromise promise, + public final SPromise whenResolvedOnErrorUncached(final VirtualFrame frame, final SPromise promise, final SBlock resolved, final SBlock error) { - return registerWhenResolvedOrError(promise, resolved, error, createReceived(resolved), + return registerWhenResolvedOrError(frame, promise, resolved, error, createReceived(resolved), createReceived(error), registerWhenResolved, registerOnError); } - protected final SPromise registerWhenResolvedOrError(final SPromise rcvr, + protected final SPromise registerWhenResolvedOrError(final VirtualFrame frame, final SPromise rcvr, final SBlock resolved, final SBlock error, final RootCallTarget resolverTarget, final RootCallTarget errorTarget, final RegisterWhenResolved registerWhenResolved, @@ -338,9 +353,13 @@ protected final SPromise registerWhenResolvedOrError(final SPromise rcvr, } synchronized (rcvr) { - registerWhenResolved.register(rcvr, onResolved, current); - registerOnError.register(rcvr, onError, current); + registerWhenResolved.register(frame, rcvr, onResolved, current); + registerOnError.register(frame, rcvr, onError, current); } + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + || onResolved.getArgs()[onResolved.getArgs().length - 1] != null; + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + || onError.getArgs()[onError.getArgs().length - 1] != null; return promise; } diff --git a/src/som/primitives/arrays/ArraySetAllStrategy.java b/src/som/primitives/arrays/ArraySetAllStrategy.java index b576cd7243..61df6c724f 100644 --- a/src/som/primitives/arrays/ArraySetAllStrategy.java +++ b/src/som/primitives/arrays/ArraySetAllStrategy.java @@ -18,24 +18,24 @@ public final class ArraySetAllStrategy { public static void evalBlockForRemaining(final SBlock block, - final long length, final Object[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final Object[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockWithArgForRemaining(final VirtualFrame frame, - final SBlock block, final long length, final Object[] storage, - final BlockDispatchNode blockDispatch, final Object first, final IsValue isValue, - final ExceptionSignalingNode notAValue) { + final SBlock block, final long length, final Object[] storage, + final BlockDispatchNode blockDispatch, final Object first, final IsValue isValue, + final ExceptionSignalingNode notAValue) { if (!isValue.executeBoolean(frame, first)) { - notAValue.signal(Classes.valueArrayClass); + notAValue.signal(frame, Classes.valueArrayClass); } for (int i = SArray.FIRST_IDX + 1; i < length; i++) { Object result = blockDispatch.executeDispatch(new Object[] {block, (long) i + 1}); if (!isValue.executeBoolean(frame, result)) { - notAValue.signal(Classes.valueArrayClass); + notAValue.signal(frame, Classes.valueArrayClass); } else { storage[i] = result; } @@ -43,59 +43,59 @@ public static void evalBlockWithArgForRemaining(final VirtualFrame frame, } public static void evalBlockForRemaining(final SBlock block, - final long length, final long[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final long[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (long) blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockForRemaining(final SBlock block, - final long length, final double[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final double[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (double) blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockForRemaining(final SBlock block, - final long length, final boolean[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final boolean[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (boolean) blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockWithArgForRemaining(final SBlock block, - final long length, final long[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final long[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (long) blockDispatch.executeDispatch( - new Object[] {block, (long) i + 1}); + new Object[] {block, (long) i + 1}); } } public static void evalBlockWithArgForRemaining(final SBlock block, - final long length, final double[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final double[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (double) blockDispatch.executeDispatch( - new Object[] {block, (long) i + 1}); + new Object[] {block, (long) i + 1}); } } public static void evalBlockWithArgForRemaining(final SBlock block, - final long length, final boolean[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final boolean[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (boolean) blockDispatch.executeDispatch( - new Object[] {block, (long) i + 1}); + new Object[] {block, (long) i + 1}); } } @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final long[] storage, final int next) { + final ExpressionNode[] exprs, final long[] storage, final int next) { for (int i = next; i < exprs.length; i++) { try { storage[i] = exprs[i].executeLong(frame); @@ -113,7 +113,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final boolean[] storage, final int next) { + final ExpressionNode[] exprs, final boolean[] storage, final int next) { for (int i = next; i < exprs.length; i++) { try { storage[i] = exprs[i].executeBoolean(frame); @@ -131,7 +131,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final double[] storage, final int next) { + final ExpressionNode[] exprs, final double[] storage, final int next) { for (int i = next; i < exprs.length; i++) { try { storage[i] = exprs[i].executeDouble(frame); @@ -149,7 +149,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final Object[] storage, final int next) { + final ExpressionNode[] exprs, final Object[] storage, final int next) { for (int i = next; i < exprs.length; i++) { storage[i] = exprs[i].executeGeneric(frame); } @@ -158,7 +158,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemainingNils(final VirtualFrame frame, - final ExpressionNode[] exprs, final int next) { + final ExpressionNode[] exprs, final int next) { for (int i = next; i < exprs.length; i++) { Object result = exprs[i].executeGeneric(frame); if (result != Nil.nilObject) { @@ -177,8 +177,8 @@ public static Object evalForRemainingNils(final VirtualFrame frame, } public static Object evaluateFirstDetermineStorageAndEvaluateRest( - final SBlock blockNoArg, final long length, - final BlockDispatchNode blockDispatch) { + final SBlock blockNoArg, final long length, + final BlockDispatchNode blockDispatch) { // TODO: this version does not handle the case that a subsequent value is // not of the expected type... Object result = blockDispatch.executeDispatch(new Object[] {blockNoArg}); @@ -206,9 +206,9 @@ public static Object evaluateFirstDetermineStorageAndEvaluateRest( } public static Object evaluateFirstDetermineStorageAndEvaluateRest(final VirtualFrame frame, - final SBlock blockWithArg, final long length, - final BlockDispatchNode blockDispatch, final IsValue isValue, - final ExceptionSignalingNode notAValue) { + final SBlock blockWithArg, final long length, + final BlockDispatchNode blockDispatch, final IsValue isValue, + final ExceptionSignalingNode notAValue) { // TODO: this version does not handle the case that a subsequent value is // not of the expected type... Object result = blockDispatch.executeDispatch(new Object[] {blockWithArg, (long) 1}); @@ -231,14 +231,14 @@ public static Object evaluateFirstDetermineStorageAndEvaluateRest(final VirtualF } else { Object[] newStorage = new Object[(int) length]; evalBlockWithArgForRemaining(frame, blockWithArg, length, newStorage, blockDispatch, - result, - isValue, notAValue); + result, + isValue, notAValue); return newStorage; } } public static Object evaluateFirstDetermineStorageAndEvaluateRest( - final VirtualFrame frame, final ExpressionNode[] exprs) { + final VirtualFrame frame, final ExpressionNode[] exprs) { Object result = exprs[0].executeGeneric(frame); if (result == Nil.nilObject) { return evalForRemainingNils(frame, exprs, SArray.FIRST_IDX + 1); @@ -260,4 +260,4 @@ public static Object evaluateFirstDetermineStorageAndEvaluateRest( return evalForRemaining(frame, exprs, newStorage, SArray.FIRST_IDX + 1); } } -} +} \ No newline at end of file diff --git a/src/som/primitives/arrays/AtPrim.java b/src/som/primitives/arrays/AtPrim.java index f4b5f7e999..a4bde7bb5e 100644 --- a/src/som/primitives/arrays/AtPrim.java +++ b/src/som/primitives/arrays/AtPrim.java @@ -85,62 +85,62 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { } } - private Object triggerException(final SArray arr, final long idx) { + private Object triggerException(final VirtualFrame frame, final SArray arr, final long idx) { int rcvrIdx = SArguments.RCVR_IDX; assert rcvrIdx == 0; - return indexOutOfBounds.signal(arr, idx); + return indexOutOfBounds.signal(frame, arr, idx); } @Specialization(guards = "receiver.isEmptyType()") - public final Object doEmptySArray(final SArray receiver, final long idx) { + public final Object doEmptySArray(final VirtualFrame frame, final SArray receiver, final long idx) { if (idx < 1 || idx > receiver.getEmptyStorage()) { - return triggerException(receiver, idx); + return triggerException(frame, receiver, idx); } return Nil.nilObject; } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final Object doPartiallyEmptySArray(final SArray receiver, final long idx) { + public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SArray receiver, final long idx) { try { return receiver.getPartiallyEmptyStorage().get(idx - 1); } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, idx); + return triggerException(frame, receiver, idx); } } @Specialization(guards = "receiver.isObjectType()") - public final Object doObjectSArray(final SArray receiver, final long idx) { + public final Object doObjectSArray(final VirtualFrame frame, final SArray receiver, final long idx) { try { return receiver.getObjectStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, idx); + return triggerException(frame, receiver, idx); } } @Specialization(guards = "receiver.isLongType()") - public final long doLongSArray(final SArray receiver, final long idx) { + public final long doLongSArray(final VirtualFrame frame, final SArray receiver, final long idx) { try { return receiver.getLongStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { - return (long) triggerException(receiver, idx); + return (long) triggerException(frame, receiver, idx); } } @Specialization(guards = "receiver.isDoubleType()") - public final double doDoubleSArray(final SArray receiver, final long idx) { + public final double doDoubleSArray(final VirtualFrame frame, final SArray receiver, final long idx) { try { return receiver.getDoubleStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { - return (double) triggerException(receiver, idx); + return (double) triggerException(frame, receiver, idx); } } @Specialization(guards = "receiver.isBooleanType()") - public final boolean doBooleanSArray(final SArray receiver, final long idx) { + public final boolean doBooleanSArray(final VirtualFrame frame, final SArray receiver, final long idx) { try { return receiver.getBooleanStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { - return (boolean) triggerException(receiver, idx); + return (boolean) triggerException(frame, receiver, idx); } } } diff --git a/src/som/primitives/arrays/AtPutPrim.java b/src/som/primitives/arrays/AtPutPrim.java index 92221870c9..f1f0c967ba 100644 --- a/src/som/primitives/arrays/AtPutPrim.java +++ b/src/som/primitives/arrays/AtPutPrim.java @@ -29,7 +29,7 @@ import som.vmobjects.SSymbol; import tools.dym.Tags.ArrayWrite; import tools.dym.Tags.BasicPrimitiveOperation; - +import com.oracle.truffle.api.frame.VirtualFrame; @GenerateNodeFactory @ImportStatic(Nil.class) @@ -108,10 +108,10 @@ protected static final boolean valueNotLongDoubleBoolean(final Object value) { !(value instanceof Boolean); } - private Object triggerException(final SArray arr, final long idx) { + private Object triggerException(final VirtualFrame frame, final SArray arr, final long idx) { int rcvrIdx = SArguments.RCVR_IDX; assert rcvrIdx == 0; - return indexOutOfBounds.signal(arr, idx); + return indexOutOfBounds.signal(frame, arr, idx); } private static void setValue(final long idx, final Object value, @@ -140,41 +140,41 @@ private void setAndPossiblyTransition(final SMutableArray receiver, } @Specialization(guards = {"receiver.isEmptyType()"}) - public final long doEmptySArray(final SMutableArray receiver, final long index, + public final long doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final long value) { try { receiver.transitionFromEmptyToPartiallyEmptyWith(index - 1, value); return value; } catch (IndexOutOfBoundsException e) { - return (long) triggerException(receiver, index); + return (long) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isEmptyType()"}) - public final double doEmptySArray(final SMutableArray receiver, final long index, + public final double doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final double value) { try { receiver.transitionFromEmptyToPartiallyEmptyWith(index - 1, value); return value; } catch (IndexOutOfBoundsException e) { - return (double) triggerException(receiver, index); + return (double) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isEmptyType()"}) - public final boolean doEmptySArray(final SMutableArray receiver, final long index, + public final boolean doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final boolean value) { try { receiver.transitionFromEmptyToPartiallyEmptyWith(index - 1, value); return value; } catch (IndexOutOfBoundsException e) { - return (boolean) triggerException(receiver, index); + return (boolean) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isEmptyType()", "valueIsNotNil(value)", "valueNotLongDoubleBoolean(value)"}) - public final Object doEmptySArray(final SMutableArray receiver, final long index, + public final Object doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { final int idx = (int) index - 1; int size = receiver.getEmptyStorage(); @@ -187,55 +187,55 @@ public final Object doEmptySArray(final SMutableArray receiver, final long index receiver.transitionTo(newStorage); return value; } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isEmptyType()", "valueIsNil(value)"}) - public final Object doEmptySArrayWithNil(final SMutableArray receiver, final long index, + public final Object doEmptySArrayWithNil(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { long idx = index - 1; if (idx < 0 || idx >= receiver.getEmptyStorage()) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } return Nil.nilObject; } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final long doPartiallyEmptySArray(final SMutableArray receiver, final long index, + public final long doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final long value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.LONG); return value; } catch (IndexOutOfBoundsException e) { - return (long) triggerException(receiver, index); + return (long) triggerException(frame, receiver, index); } } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final double doPartiallyEmptySArray(final SMutableArray receiver, final long index, + public final double doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final double value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.DOUBLE); return value; } catch (IndexOutOfBoundsException e) { - return (double) triggerException(receiver, index); + return (double) triggerException(frame, receiver, index); } } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final boolean doPartiallyEmptySArray(final SMutableArray receiver, final long index, + public final boolean doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final boolean value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.BOOLEAN); return value; } catch (IndexOutOfBoundsException e) { - return (boolean) triggerException(receiver, index); + return (boolean) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isPartiallyEmptyType()", "valueIsNil(value)"}) - public final Object doPartiallyEmptySArrayWithNil(final SMutableArray receiver, + public final Object doPartiallyEmptySArrayWithNil(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { long idx = index - 1; PartiallyEmptyArray storage = receiver.getPartiallyEmptyStorage(); @@ -247,45 +247,45 @@ public final Object doPartiallyEmptySArrayWithNil(final SMutableArray receiver, } return value; } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isPartiallyEmptyType()", "valueIsNotNil(value)"}) - public final Object doPartiallyEmptySArray(final SMutableArray receiver, final long index, + public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.OBJECT); return value; } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } @Specialization(guards = "receiver.isObjectType()") - public final Object doObjectSArray(final SMutableArray receiver, final long index, + public final Object doObjectSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { try { receiver.getObjectStorage()[(int) index - 1] = value; return value; } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } @Specialization(guards = "receiver.isLongType()") - public final long doObjectSArray(final SMutableArray receiver, final long index, + public final long doObjectSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final long value) { try { receiver.getLongStorage()[(int) index - 1] = value; return value; } catch (IndexOutOfBoundsException e) { - return (long) triggerException(receiver, index); + return (long) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isLongType()", "valueIsNotLong(value)"}) - public final Object doLongSArray(final SMutableArray receiver, final long index, + public final Object doLongSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { long[] storage = receiver.getLongStorage(); Object[] newStorage = new Object[storage.length]; @@ -296,23 +296,23 @@ public final Object doLongSArray(final SMutableArray receiver, final long index, try { return transitionAndSet(receiver, index, value, newStorage); } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } @Specialization(guards = "receiver.isDoubleType()") - public final double doDoubleSArray(final SMutableArray receiver, final long index, + public final double doDoubleSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final double value) { try { receiver.getDoubleStorage()[(int) index - 1] = value; return value; } catch (IndexOutOfBoundsException e) { - return (double) triggerException(receiver, index); + return (double) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isDoubleType()", "valueIsNotDouble(value)"}) - public final Object doDoubleSArray(final SMutableArray receiver, final long index, + public final Object doDoubleSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { double[] storage = receiver.getDoubleStorage(); Object[] newStorage = new Object[storage.length]; @@ -322,23 +322,23 @@ public final Object doDoubleSArray(final SMutableArray receiver, final long inde try { return transitionAndSet(receiver, index, value, newStorage); } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } @Specialization(guards = "receiver.isBooleanType()") - public final boolean doBooleanSArray(final SMutableArray receiver, final long index, + public final boolean doBooleanSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final boolean value) { try { receiver.getBooleanStorage()[(int) index - 1] = value; return value; } catch (IndexOutOfBoundsException e) { - return (boolean) triggerException(receiver, index); + return (boolean) triggerException(frame, receiver, index); } } @Specialization(guards = {"receiver.isBooleanType()", "valueIsNotBoolean(value)"}) - public final Object doBooleanSArray(final SMutableArray receiver, final long index, + public final Object doBooleanSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, final Object value) { boolean[] storage = receiver.getBooleanStorage(); Object[] newStorage = new Object[storage.length]; @@ -348,7 +348,7 @@ public final Object doBooleanSArray(final SMutableArray receiver, final long ind try { return transitionAndSet(receiver, index, value, newStorage); } catch (IndexOutOfBoundsException e) { - return triggerException(receiver, index); + return triggerException(frame, receiver, index); } } } diff --git a/src/som/primitives/processes/ChannelPrimitives.java b/src/som/primitives/processes/ChannelPrimitives.java index 7899dc238e..aeef74517e 100644 --- a/src/som/primitives/processes/ChannelPrimitives.java +++ b/src/som/primitives/processes/ChannelPrimitives.java @@ -316,7 +316,7 @@ public final WritePrim initialize(final VM vm) { public final Object write(final VirtualFrame frame, final SChannelOutput out, final Object val) { if (!isVal.executeBoolean(frame, val)) { - notAValue.signal(val); + notAValue.signal(frame, val); } try { out.writeAndSuspendReader(val, afterRead.executeShouldHalt(), traceWrite); diff --git a/src/som/vm/ObjectSystem.java b/src/som/vm/ObjectSystem.java index abf9a8ce35..9e52011b9d 100644 --- a/src/som/vm/ObjectSystem.java +++ b/src/som/vm/ObjectSystem.java @@ -64,6 +64,7 @@ import tools.snapshot.nodes.PrimitiveSerializationNodesFactory.SymbolSerializationNodeFactory; import tools.snapshot.nodes.PrimitiveSerializationNodesFactory.TrueSerializationNodeFactory; import tools.snapshot.nodes.SerializerRootNode; +import som.interpreter.SArguments; public final class ObjectSystem { @@ -132,7 +133,7 @@ public SClass loadExtensionModule(final String filename) { ExtensionLoader loader = new ExtensionLoader(filename, compiler.getLanguage()); EconomicMap primitives = loader.getPrimitives(); MixinDefinition mixin = constructPrimitiveMixin(filename, primitives); - return mixin.instantiateClass(Nil.nilObject, Classes.topClass); + return mixin.instantiateClass(null, Nil.nilObject, Classes.topClass); } public MixinDefinition loadModule(final String filename) throws IOException { @@ -209,7 +210,7 @@ null, new MixinDefinitionId(Symbols.VMMIRROR), AccessModifier.PUBLIC, scope, sco true, true, true, null); scope.setMixinDefinition(vmMirrorDef, false); - SClass vmMirrorClass = vmMirrorDef.instantiateClass(Nil.nilObject, + SClass vmMirrorClass = vmMirrorDef.instantiateClass(null, Nil.nilObject, new SClass[] {Classes.topClass, Classes.valueClass}); return vmMirrorClass; } @@ -418,7 +419,7 @@ public SObjectWithoutFields initialize() { setDummyClassFactory(Classes.methodClass, SInvokableSerializationNodeFactory.getInstance()); - SClass kernelClass = kernelModule.instantiateClass(Nil.nilObject, Classes.objectClass); + SClass kernelClass = kernelModule.instantiateClass(null, Nil.nilObject, Classes.objectClass); KernelObj.kernel.setClass(kernelClass); // create and initialize the vmMirror object @@ -527,7 +528,14 @@ public int executeApplication(final SObjectWithoutFields vmMirror, final Actor m mainThreadCompleted = new CompletableFuture<>(); ObjectTransitionSafepoint.INSTANCE.register(); - Object platform = platformModule.instantiateObject(platformClass, vmMirror); + Object platform; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + platform = platformModule.instantiateObject(platformClass, vmMirror, + SArguments.instantiateTopShadowStackEntry(null)); + } else { + platform = platformModule.instantiateObject(platformClass, vmMirror); + } + ObjectTransitionSafepoint.INSTANCE.unregister(); SSymbol start = Symbols.symbolFor("start"); @@ -542,8 +550,10 @@ public int executeApplication(final SObjectWithoutFields vmMirror, final Actor m "ObjectSystem.executeApplication").createSection(1); } + Object[] args = SArguments.convertToArgumentArray(new Object[] {platform}); + DirectMessage msg = new DirectMessage(mainActor, start, - new Object[] {platform}, mainActor, + args, mainActor, null, EventualSendNode.createOnReceiveCallTargetForVMMain( start, 1, source, mainThreadCompleted, compiler.getLanguage())); mainActor.sendInitialStartMessage(msg, vm.getActorPool()); @@ -573,7 +583,7 @@ public Object execute(final String selector) { Symbols.symbolFor(selector), AccessModifier.PUBLIC); try { ObjectTransitionSafepoint.INSTANCE.register(); - return method.invoke(new Object[] {platformClass}); + return method.invoke(SArguments.convertToArgumentArray(new Object[] {platformClass})); } finally { ObjectTransitionSafepoint.INSTANCE.unregister(); } diff --git a/src/som/vm/VmSettings.java b/src/som/vm/VmSettings.java index e855373995..ea2b43664e 100644 --- a/src/som/vm/VmSettings.java +++ b/src/som/vm/VmSettings.java @@ -46,6 +46,10 @@ public class VmSettings implements Settings { public static final boolean SENDER_SIDE_REPLAY; public static final boolean RECEIVER_SIDE_REPLAY; + public static final boolean ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + public static final boolean ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE; + public static final boolean ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE; + public static final String BASE_DIRECTORY; public static final boolean USE_PINNING; @@ -80,6 +84,12 @@ public class VmSettings implements Settings { SENDER_SIDE_REPLAY = REPLAY && !receiverSide; RECEIVER_SIDE_REPLAY = REPLAY && receiverSide; + ACTOR_ASYNC_STACK_TRACE_STRUCTURE = getBool("som.actorAsyncStackTraceStructure", false); + ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE = + getBool("som.actorAsyncStackTraceMethodCache", false); + ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE = + getBool("som.actorAsyncStackTraceInlineCache", false); + TEST_SNAPSHOTS = getBool("som.snapshotTest", false); TEST_SERIALIZE_ALL = getBool("som.actorSnapshotAll", false); SNAPSHOTS_ENABLED = getBool("som.actorSnapshot", false) || TEST_SNAPSHOTS; diff --git a/src/som/vmobjects/SFileDescriptor.java b/src/som/vmobjects/SFileDescriptor.java index 55d4d8d6e3..f939c630a5 100644 --- a/src/som/vmobjects/SFileDescriptor.java +++ b/src/som/vmobjects/SFileDescriptor.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; import som.interpreter.nodes.ExceptionSignalingNode; @@ -65,8 +66,7 @@ private RandomAccessFile open() throws FileNotFoundException { return new RandomAccessFile(f, accessMode.mode); } - @TruffleBoundary - public void closeFile(final ExceptionSignalingNode ioException) { + public void closeFile(final VirtualFrame frame, final ExceptionSignalingNode ioException) { if (raf == null) { return; } @@ -74,7 +74,7 @@ public void closeFile(final ExceptionSignalingNode ioException) { try { closeFile(); } catch (IOException e) { - ioException.signal(e.getMessage()); + ioException.signal(frame, e.getMessage()); } } @@ -133,9 +133,9 @@ private String toString(final IOException e) { return e.toString(); } - public void write(final int nBytes, final long position, final SBlock fail, - final BlockDispatchNode dispatchHandler, final ExceptionSignalingNode ioException, - final BranchProfile errorCases) { + public void write(final VirtualFrame frame, final int nBytes, final long position, + final SBlock fail, final BlockDispatchNode dispatchHandler, + final ExceptionSignalingNode ioException, final BranchProfile errorCases) { if (raf == null) { errorCases.enter(); dispatchHandler.executeDispatch(new Object[] {fail, FILE_IS_CLOSED}); @@ -155,7 +155,7 @@ public void write(final int nBytes, final long position, final SBlock fail, long val = storage[i]; if (val <= Byte.MIN_VALUE && Byte.MAX_VALUE <= val) { errorCases.enter(); - ioException.signal(errorMsg(val)); + ioException.signal(frame, errorMsg(val)); } buff[i] = (byte) val; } @@ -175,17 +175,16 @@ private static String errorMsg(final long val) { @TruffleBoundary private void write(final int nBytes, final long position, final byte[] buff) - throws IOException { + throws IOException { raf.seek(position); raf.write(buff, 0, nBytes); } - @TruffleBoundary - public long getFileSize(final ExceptionSignalingNode ioException) { + public long getFileSize(final VirtualFrame frame, final ExceptionSignalingNode ioException) { try { return length(); } catch (IOException e) { - ioException.signal(e.getMessage()); + ioException.signal(frame, e.getMessage()); } return 0; } @@ -256,4 +255,4 @@ private static String renderValid() { return result; } } -} +} \ No newline at end of file diff --git a/src/som/vmobjects/SInvokable.java b/src/som/vmobjects/SInvokable.java index 7949edd4e5..e34cf359d7 100644 --- a/src/som/vmobjects/SInvokable.java +++ b/src/som/vmobjects/SInvokable.java @@ -48,6 +48,7 @@ import som.vm.Symbols; import som.vm.VmSettings; import som.vm.constants.Classes; +import som.interpreter.nodes.dispatch.LexicallyBoundDispatchNodeGen; public class SInvokable extends SAbstractObject implements Dispatchable { @@ -191,7 +192,7 @@ public final AbstractDispatchNode getDispatchNode(final Object rcvr, // In case it's a private method, it is directly linked and doesn't need guards if (accessModifier == AccessModifier.PRIVATE) { - return new LexicallyBoundDispatchNode(next.getSourceSection(), ct); + return LexicallyBoundDispatchNodeGen.create(next.getSourceSection(), ct); } DispatchGuard guard = DispatchGuard.create(rcvr); diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/asyncstacktraces/ShadowStackEntry.java new file mode 100644 index 0000000000..c39246a08a --- /dev/null +++ b/src/tools/asyncstacktraces/ShadowStackEntry.java @@ -0,0 +1,113 @@ +package tools.asyncstacktraces; + +import com.oracle.truffle.api.instrumentation.InstrumentableNode.WrapperNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.SourceSection; + +import som.interpreter.actors.Actor; +import som.interpreter.actors.Actor.ActorProcessingThread; +import som.interpreter.actors.EventualMessage; +import som.vm.VmSettings; + +public class ShadowStackEntry { + + protected final ShadowStackEntry previous; + protected final Node expression; + + public static long numberOfAllocations; + + public static final boolean ALLOCATION_COUNT = false; + + public Node getExpression() { + return expression; + } + + public ShadowStackEntry getPreviousShadowStackEntry() { + return previous; + } + + public static ShadowStackEntry createTop(final Node expr) { + return new ShadowStackEntry(null, expr); + } + + public static ShadowStackEntry create(final ShadowStackEntry previous, + final Node expr) { + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; + return new ShadowStackEntry(previous, unwrapNodeIfNecessary(expr)); + } + + public static ShadowStackEntry createAtAsyncSend(final ShadowStackEntry previous, + final Node expr) { + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; + return new EntryAtMessageSend(previous, unwrapNodeIfNecessary(expr)); + } + + public static ShadowStackEntry createAtPromiseResolution(final ShadowStackEntry previous, + final Node expr) { + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; + return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr)); + } + + public static Node unwrapNodeIfNecessary(final Node node) { + if (node instanceof WrapperNode) { + return ((WrapperNode) node).getDelegateNode(); + } else { + return node; + } + } + + protected ShadowStackEntry(final ShadowStackEntry previous, final Node expr) { + assert VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + this.previous = previous; + this.expression = expr; + if (ALLOCATION_COUNT) { + numberOfAllocations++; + } + } + + public static Actor getCurrentActorOrNull() { + Thread t = Thread.currentThread(); + if (t instanceof ActorProcessingThread) { + return EventualMessage.getActorCurrentMessageIsExecutionOn(); + } else { + return null; + } + } + + public RootNode getRootNode() { + return expression.getRootNode(); + } + + public SourceSection getSourceSection() { + return expression.getSourceSection(); + } + + public boolean isAsync() { + return false; + } + + public static final class EntryAtMessageSend extends ShadowStackEntry { + + private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { + super(previous, expr); + } + + @Override + public boolean isAsync() { + return true; + } + } + + public static final class EntryForPromiseResolution extends ShadowStackEntry { + private EntryForPromiseResolution(final ShadowStackEntry previous, + final Node expr) { + super(previous, expr); + } + + @Override + public boolean isAsync() { + return true; + } + } +} diff --git a/src/tools/asyncstacktraces/ShadowStackEntryLoad.java b/src/tools/asyncstacktraces/ShadowStackEntryLoad.java new file mode 100644 index 0000000000..e6f2f2650e --- /dev/null +++ b/src/tools/asyncstacktraces/ShadowStackEntryLoad.java @@ -0,0 +1,132 @@ +package tools.asyncstacktraces; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import som.interpreter.SArguments; +import som.vm.VmSettings; + +public abstract class ShadowStackEntryLoad extends Node { + public static final int NUM_SHADOW_STACK_ENTRIES = 6; + + public static final boolean ANALYSIS = false; + public static int cacheHit = 0; + public static int megaCacheHit = 0; + public static int megaMiss = 0; + + public static ShadowStackEntryLoad create() { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new UninitializedShadowStackEntryLoad(); + } else { + return null; + } + } + + public void loadShadowStackEntry(final Object[] arguments, final Node expression, + final VirtualFrame frame, final boolean async) { + ShadowStackEntry prevEntry = SArguments.getShadowStackEntry(frame); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || prevEntry != null; + loadShadowStackEntry(arguments, expression, prevEntry, this, async); + } + + protected abstract void loadShadowStackEntry(Object[] arguments, + Node expression, + ShadowStackEntry prevEntry, + ShadowStackEntryLoad firstShadowStackEntryLoad, + boolean async); + + public abstract int getCurrentCacheSize(); + + protected void setShadowStackEntry(final ShadowStackEntry shadowStackEntry, + final Object[] arguments) { + SArguments.setShadowStackEntry(arguments, shadowStackEntry); + } + + private static final class UninitializedShadowStackEntryLoad extends ShadowStackEntryLoad { + + @Override + protected void loadShadowStackEntry(final Object[] arguments, + final Node expression, + final ShadowStackEntry prevEntry, + final ShadowStackEntryLoad firstShadowStackEntryLoad, + final boolean async) { + if (!VmSettings.ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE) { + setShadowStackEntry( + SArguments.instantiateShadowStackEntry(prevEntry, expression, async), + arguments); + return; + } + ShadowStackEntry newEntry = + SArguments.instantiateShadowStackEntry(prevEntry, expression, async); + ShadowStackEntryLoad newLoad; + if (firstShadowStackEntryLoad.getCurrentCacheSize() > NUM_SHADOW_STACK_ENTRIES) { + newLoad = new GenericShadowStackEntryLoad(); + // firstShadowStackEntryLoad.replace(newLoad); + replace(newLoad); + } else { + newLoad = new CachedShadowStackEntryLoad(prevEntry, newEntry); + replace(newLoad); + } + newLoad.loadShadowStackEntry(arguments, expression, prevEntry, + firstShadowStackEntryLoad, async); + } + + @Override + public int getCurrentCacheSize() { + return 0; + } + + } + + private static final class CachedShadowStackEntryLoad extends ShadowStackEntryLoad { + + @Child protected ShadowStackEntryLoad nextInCache; + protected final ShadowStackEntry expectedShadowStackEntry; + protected final ShadowStackEntry cachedShadowStackEntry; + + CachedShadowStackEntryLoad(final ShadowStackEntry prevEntry, + final ShadowStackEntry newEntry) { + this.expectedShadowStackEntry = prevEntry; + this.cachedShadowStackEntry = newEntry; + nextInCache = new UninitializedShadowStackEntryLoad(); + } + + @Override + public int getCurrentCacheSize() { + return 1 + nextInCache.getCurrentCacheSize(); + } + + @Override + protected void loadShadowStackEntry(final Object[] arguments, + final Node expression, + final ShadowStackEntry prevEntry, final ShadowStackEntryLoad firstShadowStackEntryLoad, + final boolean async) { + if (prevEntry == expectedShadowStackEntry) { + setShadowStackEntry(cachedShadowStackEntry, arguments); + if (ANALYSIS) { + cacheHit++; + } + } else { + nextInCache.loadShadowStackEntry(arguments, expression, prevEntry, + firstShadowStackEntryLoad, async); + } + } + } + + private static final class GenericShadowStackEntryLoad extends ShadowStackEntryLoad { + + @Override + protected void loadShadowStackEntry(final Object[] arguments, + final Node expression, + final ShadowStackEntry prevEntry, final ShadowStackEntryLoad firstShadowStackEntryLoad, + final boolean async) { + setShadowStackEntry(SArguments.instantiateShadowStackEntry(prevEntry, expression, async), + arguments); + } + + @Override + public int getCurrentCacheSize() { + return 0; + } + } +} diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java new file mode 100644 index 0000000000..fb087a662b --- /dev/null +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -0,0 +1,378 @@ +package tools.asyncstacktraces; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.Truffle; +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.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.frame.FrameInstanceVisitor; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.SourceSection; + +import som.interpreter.Invokable; +import som.interpreter.Method; +import som.interpreter.actors.EventualSendNode; +import som.interpreter.nodes.dispatch.BackCacheCallNode; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry.EntryAtMessageSend; +import tools.asyncstacktraces.ShadowStackEntry.EntryForPromiseResolution; +import tools.asyncstacktraces.StackIterator.ShadowStackIterator.HaltShadowStackIterator; +import tools.asyncstacktraces.StackIterator.ShadowStackIterator.SuspensionShadowStackIterator; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; + + +/** + * This iterator traverses the run time stack and all available calling context + * information. + * + *

+ * In special cases, a single stack frame/calling context might be + * represented as multiple stack frames in the iteration. + * We chose to do this to explicitly represent context switches in asynchronous + * control flow, as caused for instance by eventual message sends or promise resolution. + */ + +public abstract class StackIterator implements Iterator { + + @Override + public abstract boolean hasNext(); + + @Override + public abstract StackFrame next(); + + protected StackFrame createStackFrame(final Frame localFrame, final RootNode rootNode, + final String name, final SourceSection location) { + return new StackFrame(name, rootNode, + location, localFrame, false); + } + + public static StackIterator createHaltIterator() { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new HaltShadowStackIterator(); + } else { + return new HaltIterator(); + } + } + + public static StackIterator createSuspensionIterator( + final Iterator localStack) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new SuspensionShadowStackIterator(localStack); + } else { + return new SuspensionIterator(localStack); + } + } + + public static class SuspensionIterator extends StackIterator { + + protected ArrayList frames; + protected int currentIndex = 0; + + public SuspensionIterator(final Iterator localStack) { + assert localStack != null; + while (localStack.hasNext()) { + frames.add(localStack.next()); + } + } + + @Override + public boolean hasNext() { + return currentIndex != frames.size(); + } + + @Override + public StackFrame next() { + DebugStackFrame next = frames.get(currentIndex); + currentIndex++; + return createStackFrame(next.getFrame(), + next.getRootNode(), + next.getRootNode().getName(), + next.getSourceSection()); + } + } + + public static class HaltIterator extends StackIterator { + + protected ArrayList frameInstances; + protected int currentIndex = 0; + + public HaltIterator() { + frameInstances = new ArrayList(); + Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { + @Override + public Object visitFrame(final FrameInstance frameInstance) { + frameInstances.add(frameInstance); + return null; + } + }); + } + + @Override + public boolean hasNext() { + return currentIndex != frameInstances.size(); + } + + @Override + public StackFrame next() { + FrameInstance next = frameInstances.get(currentIndex); + currentIndex++; + RootCallTarget rt = (RootCallTarget) next.getCallTarget(); + if (!(rt.getRootNode() instanceof Invokable)) { + return null; + } + Invokable rootNode = (Invokable) rt.getRootNode(); + SourceSection ss = null; + if (next.getCallNode() != null) { + ss = next.getCallNode().getSourceSection(); + } + return createStackFrame(next.getFrame(FrameAccess.READ_ONLY), + rootNode, + rootNode.getName(), + ss); + } + } + + /** + * + * @author clementbera + * + * By contrast to HaltIterator and Suspension Iterator, the ShadowStackIterator use + * the stack for the first frame only and then rely on shadow stack entry to get the + * following stack entries + */ + public abstract static class ShadowStackIterator extends StackIterator { + private ShadowStackEntry currentSSEntry; + protected boolean first; + private Node currentNode; + private Invokable currentMethod; + + private ShadowStackEntry useAgain; + private Frame useAgainFrame; + + public ShadowStackIterator() { + currentSSEntry = null; + first = true; + } + + @Override + public boolean hasNext() { + return currentSSEntry != null || first || useAgain != null; + } + + protected abstract StackFrameDescription getFirstFrame(); + + @Override + public StackFrame next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE) { + return nextAsyncStackStructureMethodCache(); + } else { + return nextAsyncStackStructure(); + } + } + + protected StackFrame nextAsyncStackStructure() { + + ShadowStackEntry shadow = null; + Frame localFrame = null; + boolean usedAgain = false; + + if (first) { + localFrame = getFirstFrame().getFrame(); + Object[] args = localFrame.getArguments(); + assert args[args.length - 1] instanceof ShadowStackEntry; + currentSSEntry = (ShadowStackEntry) args[args.length - 1]; + first = false; + } else if (useAgain != null) { + shadow = useAgain; + usedAgain = true; + localFrame = useAgainFrame; + useAgain = null; + useAgainFrame = null; + } else { + shadow = currentSSEntry; + if (shadow != null) { + currentSSEntry = shadow.previous; + } + } + return createStackFrame(shadow, localFrame, usedAgain); + } + + protected StackFrame createStackFrame(final ShadowStackEntry shadow, + final Frame localFrame, final boolean usedAgain) { + if (shadow == null) { + return null; + } + if (shadow.expression == null) { + return null; + } + boolean contextTransitionElement; + + String name = shadow.getRootNode().getName(); + SourceSection location; + + if (!usedAgain && (shadow instanceof EntryAtMessageSend + || shadow instanceof EntryForPromiseResolution)) { + contextTransitionElement = true; + location = null; + + if (shadow instanceof EntryAtMessageSend) { + Node sendNode = shadow.expression.getParent(); + if (sendNode instanceof EventualSendNode) { + name = "Send: " + ((EventualSendNode) sendNode).getSentSymbol(); + + } else { + name = "Send: " + name; + } + useAgain = shadow; + useAgainFrame = localFrame; + } else if (shadow instanceof EntryForPromiseResolution) { + name = "Resolved: " + name; + } + } else { + contextTransitionElement = false; + location = shadow.getSourceSection(); + } + + return new StackFrame(name, shadow.getRootNode(), + location, localFrame, contextTransitionElement); + } + + // This version has to skip missing shadow stack entry using method back pointer cache + protected StackFrame nextAsyncStackStructureMethodCache() { + ShadowStackEntry shadow = null; + Frame localFrame = null; + boolean usedAgain = false; + + if (first) { + localFrame = getFirstFrame().getFrame(); + Object[] args = localFrame.getArguments(); + assert args[args.length - 1] instanceof ShadowStackEntry; + currentSSEntry = (ShadowStackEntry) args[args.length - 1]; + currentMethod = (Invokable) getFirstFrame().getRootNode(); + first = false; + } + + if (useAgain != null) { + shadow = useAgain; + usedAgain = true; + localFrame = useAgainFrame; + useAgain = null; + useAgainFrame = null; + } else { + if (shouldUsePreviousShadowStackEntry(currentMethod, + currentSSEntry.getExpression())) { + shadow = currentSSEntry; + currentSSEntry = currentSSEntry.getPreviousShadowStackEntry(); + // null if start frame + if (currentSSEntry != null) { + currentNode = currentSSEntry.getExpression(); + } + } else { + assert currentMethod instanceof Method; + currentNode = (Node) ((Method) currentMethod).getUniqueCaller(); + } + } + + if (shadow != null) { + return createStackFrame(shadow, localFrame, usedAgain); + } else { + return createStackFrame(localFrame, currentNode.getRootNode(), + currentNode.getRootNode().getName(), currentNode.getSourceSection()); + } + } + + public boolean shouldUsePreviousShadowStackEntry(final Invokable currentMethod, + final Node prevExpression) { + if (!(currentMethod instanceof Method)) { + return true; + } + if (prevExpression instanceof BackCacheCallNode) { + BackCacheCallNode ssNode = + (BackCacheCallNode) prevExpression; + return currentMethod == ssNode.getCachedMethod(); + } + return true; + } + + protected static final class StackFrameDescription { + SourceSection sourceSection; + Frame frame; + RootNode rootNode; + + public StackFrameDescription(final SourceSection sourceSection, + final Frame frame, final RootNode rootNode) { + this.sourceSection = sourceSection; + this.frame = frame; + this.rootNode = rootNode; + } + + public SourceSection getSourceSection() { + return sourceSection; + } + + public Frame getFrame() { + return frame; + } + + public RootNode getRootNode() { + return rootNode; + } + } + + public static final class SuspensionShadowStackIterator extends ShadowStackIterator { + private final DebugStackFrame firstFrame; + + public SuspensionShadowStackIterator(final Iterator localStack) { + assert localStack != null; + assert localStack.hasNext(); + firstFrame = localStack.next(); + } + + @Override + protected StackFrameDescription getFirstFrame() { + assert first; + return new StackFrameDescription(firstFrame.getSourceSection(), firstFrame.getFrame(), + firstFrame.getRootNode()); + } + + } + + public static final class HaltShadowStackIterator extends ShadowStackIterator { + private final FrameInstance firstFrame; + + public HaltShadowStackIterator() { + firstFrame = + Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { + @Override + public FrameInstance visitFrame(final FrameInstance frame) { + return frame; + } + }); + } + + @Override + protected StackFrameDescription getFirstFrame() { + assert first; + RootCallTarget rt = (RootCallTarget) firstFrame.getCallTarget(); + assert rt.getRootNode() instanceof Invokable; + Invokable rootNode = (Invokable) rt.getRootNode(); + SourceSection ss = null; + if (firstFrame.getCallNode() != null) { + ss = firstFrame.getCallNode().getSourceSection(); + } + return new StackFrameDescription(ss, + firstFrame.getFrame(FrameAccess.READ_ONLY), + rootNode); + } + } + } +} diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 195084c176..4b06b5f4eb 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -5,7 +5,11 @@ import com.oracle.truffle.api.debug.DebugStackFrame; import com.oracle.truffle.api.debug.SuspendedEvent; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.SourceSection; +import tools.asyncstacktraces.StackIterator; import som.interpreter.LexicalScope.MethodScope; @@ -14,7 +18,7 @@ * Keeps information on the run-time stack of an application thread for * requests from the front-end. Is populated only on demand. */ -class ApplicationThreadStack { +public class ApplicationThreadStack { /** * Track scopes that contain variables as well as objects. @@ -24,9 +28,37 @@ class ApplicationThreadStack { final ArrayList scopesAndObjects; final HashMap scopesAndObjectsSet; - private final ArrayList stackFrames; - private final SuspendedEvent event; - private final Suspension suspension; + private final ArrayList stackFrames; + private final SuspendedEvent event; + private final Suspension suspension; + + public static final class StackFrame { + public final String name; + public final SourceSection section; + + public final Frame frame; + + public final boolean asyncSeparator; + + private final RootNode root; + + public StackFrame(final String name, final RootNode root, final SourceSection section, + final Frame frame, final boolean asyncSeparator) { + this.name = name; + this.root = root; + this.section = section; + this.frame = frame; + this.asyncSeparator = asyncSeparator; + } + + public RootNode getRootNode() { + return root; + } + + public boolean hasFrame() { + return frame != null; + } + } ApplicationThreadStack(final SuspendedEvent event, final Suspension suspension) { this.event = event; @@ -36,10 +68,13 @@ class ApplicationThreadStack { this.suspension = suspension; } - ArrayList get() { + ArrayList get() { if (stackFrames.isEmpty()) { - for (DebugStackFrame frame : event.getStackFrames()) { - stackFrames.add(frame); + StackIterator stack = + StackIterator.createSuspensionIterator(event.getStackFrames().iterator()); + + while (stack.hasNext()) { + stackFrames.add(stack.next()); } assert !stackFrames.isEmpty() : "We expect that there is always at least one stack frame"; diff --git a/src/tools/debugger/frontend/RuntimeScope.java b/src/tools/debugger/frontend/RuntimeScope.java index b4cf184e41..759446d6bb 100644 --- a/src/tools/debugger/frontend/RuntimeScope.java +++ b/src/tools/debugger/frontend/RuntimeScope.java @@ -4,6 +4,7 @@ import som.compiler.Variable; import som.interpreter.LexicalScope.MethodScope; +import com.oracle.truffle.api.frame.Frame; public class RuntimeScope { diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index d701cf4362..d29f76603d 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -23,6 +23,8 @@ import tools.debugger.frontend.ApplicationThreadTask.Resume; import tools.debugger.frontend.ApplicationThreadTask.SendStackTrace; import tools.debugger.message.VariablesRequest.FilterType; +import com.oracle.truffle.api.frame.Frame; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; /** @@ -56,7 +58,7 @@ public synchronized void update(final SuspendedEvent e) { this.stack = new ApplicationThreadStack(e, this); } - public synchronized ArrayList getStackFrames() { + public synchronized ArrayList getStackFrames() { return stack.get(); } @@ -97,7 +99,7 @@ private int getLocalId(final long globalId) { return TraceData.valIdFromGlobal(globalId); } - public synchronized DebugStackFrame getFrame(final long globalId) { + public synchronized StackFrame getFrame(final long globalId) { return stack.get().get(getLocalId(globalId)); } diff --git a/src/tools/debugger/message/ScopesResponse.java b/src/tools/debugger/message/ScopesResponse.java index 7af94e8fb3..f8f32a543c 100644 --- a/src/tools/debugger/message/ScopesResponse.java +++ b/src/tools/debugger/message/ScopesResponse.java @@ -16,15 +16,16 @@ import tools.TraceData; import tools.debugger.frontend.Suspension; import tools.debugger.message.Message.Response; - +import com.oracle.truffle.api.frame.Frame; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; @SuppressWarnings("unused") public final class ScopesResponse extends Response { private final Scope[] scopes; - private final long variablesReference; + private final long variablesReference; private ScopesResponse(final long globalFrameId, final Scope[] scopes, - final int requestId) { + final int requestId) { super(requestId); assert TraceData.isWithinJSIntValueRange(globalFrameId); this.variablesReference = globalFrameId; @@ -32,7 +33,9 @@ private ScopesResponse(final long globalFrameId, final Scope[] scopes, } private static final class Scope { - /** Name of the scope such as 'Arguments', 'Locals'. */ + /** + * Name of the scope such as 'Arguments', 'Locals'. + */ private final String name; /** @@ -41,11 +44,13 @@ private static final class Scope { */ private final long variablesReference; - /** If true, the number of variables in this scope is large or expensive to retrieve. */ + /** + * If true, the number of variables in this scope is large or expensive to retrieve. + */ private final boolean expensive; private Scope(final String name, final long globalVarRef, - final boolean expensive) { + final boolean expensive) { assert TraceData.isWithinJSIntValueRange(globalVarRef); this.name = name; this.variablesReference = globalVarRef; @@ -54,7 +59,7 @@ private Scope(final String name, final long globalVarRef, } private static void addScopes(final ArrayList scopes, - final MethodScope method, final Object rcvr, final Suspension suspension) { + final MethodScope method, final Object rcvr, final Suspension suspension) { MethodScope outer = method.getOuterScopeOrNull(); if (outer != null) { assert rcvr instanceof SBlock; @@ -67,28 +72,30 @@ private static void addScopes(final ArrayList scopes, private static final int SMALL_INITIAL_SIZE = 5; public static ScopesResponse create(final long globalFrameId, final Suspension suspension, - final int requestId) { - DebugStackFrame frame = suspension.getFrame(globalFrameId); + final int requestId) { + StackFrame frame = suspension.getFrame(globalFrameId); ArrayList scopes = new ArrayList<>(SMALL_INITIAL_SIZE); - Frame actualFrame = frame.getFrame(); - - RootNode invokable = frame.getRootNode(); - if (invokable instanceof Method) { - Method m = (Method) invokable; - MethodScope scope = m.getLexicalScope(); - long scopeId = suspension.addScope(actualFrame, scope); - scopes.add(new Scope("Locals", scopeId, false)); - - Object rcvr = SArguments.rcvr(actualFrame); - addScopes(scopes, scope, rcvr, suspension); - } else if (invokable instanceof ReceivedRootNode) { - // NOOP, no scopes here - assert false : "This should not be reached. This scope should never get an id"; - } else { - assert invokable instanceof Primitive : "Got a " + invokable.getClass().getSimpleName() + - " here. Means we need to add support"; + if (frame.hasFrame()) { + Frame actualFrame = frame.frame; + RootNode invokable = frame.getRootNode(); + if (invokable instanceof Method) { + Method m = (Method) invokable; + MethodScope scope = m.getLexicalScope(); + + long scopeId = suspension.addScope(actualFrame, scope); + scopes.add(new Scope("Locals", scopeId, false)); + Object rcvr = SArguments.rcvr(actualFrame); + addScopes(scopes, scope, rcvr, suspension); + } else if (invokable instanceof ReceivedRootNode) { + // NOOP, no scopes here + assert false : "This should not be reached. This scope should never get an id"; + } else { + assert invokable instanceof Primitive : "Got a " + invokable.getClass().getSimpleName() + + + " here. Means we need to add support"; + } } - return new ScopesResponse(globalFrameId, scopes.toArray(new Scope[0]), requestId); + } } diff --git a/src/tools/debugger/message/StackTraceResponse.java b/src/tools/debugger/message/StackTraceResponse.java index 789eff0214..171b8feea1 100644 --- a/src/tools/debugger/message/StackTraceResponse.java +++ b/src/tools/debugger/message/StackTraceResponse.java @@ -2,7 +2,6 @@ import java.util.ArrayList; -import com.oracle.truffle.api.debug.DebugStackFrame; import com.oracle.truffle.api.source.SourceSection; import som.interpreter.actors.Actor; @@ -13,6 +12,7 @@ import tools.debugger.entities.EntityType; import tools.debugger.frontend.Suspension; import tools.debugger.message.Message.Response; +import tools.debugger.frontend.ApplicationThreadStack; @SuppressWarnings("unused") @@ -93,7 +93,7 @@ private static class StackFrame { } } - private static int getNumRootNodesToSkip(final ArrayList frames) { + private static int getNumRootNodesToSkip(final ArrayList frames) { int skip = 0; int size = frames.size(); @@ -112,7 +112,7 @@ private static int getNumRootNodesToSkip(final ArrayList frames public static StackTraceResponse create(final int startFrame, final int levels, final Suspension suspension, final int requestId) { - ArrayList frames = suspension.getStackFrames(); + ArrayList frames = suspension.getStackFrames(); int skipFrames = suspension.getFrameSkipCount(); if (startFrame > skipFrames) { @@ -130,9 +130,11 @@ public static StackTraceResponse create(final int startFrame, final int levels, for (int i = 0; i < numFrames; i += 1) { int frameId = i + skipFrames; - assert !(frames.get( - frameId).getRootNode() instanceof ReceivedRootNode) - : "This should have been skipped in the code above"; + // TODO: remove the below assert once we are satisfied things work. because now we can + // have received root nodes in the stack trace + // assert !(frames.get( + // frameId).getRootNode() instanceof ReceivedRootNode) : "This should have been skipped in the + // code above"; StackFrame f = createFrame(suspension, frameId, frames.get(frameId)); arr[i] = f; } @@ -154,15 +156,15 @@ public static StackTraceResponse create(final int startFrame, final int levels, } private static StackFrame createFrame(final Suspension suspension, - final int frameId, final DebugStackFrame frame) { + final int frameId, final ApplicationThreadStack.StackFrame frame) { long id = suspension.getGlobalId(frameId); - String name = frame.getName(); + String name = frame.name; if (name == null) { name = "vm (internal)"; } - SourceSection ss = frame.getSourceSection(); + SourceSection ss = frame.section; String sourceUri; int line; int column; diff --git a/src/tools/dym/profiles/Arguments.java b/src/tools/dym/profiles/Arguments.java index a1ae60ab5e..a796cce9c2 100644 --- a/src/tools/dym/profiles/Arguments.java +++ b/src/tools/dym/profiles/Arguments.java @@ -8,6 +8,7 @@ import som.interpreter.Types; import som.interpreter.objectstorage.ClassFactory; +import som.vm.VmSettings; public final class Arguments { @@ -19,8 +20,12 @@ public final class Arguments { private final ClassFactory[] argSomTypes; Arguments(final Object[] arguments) { - this.argJavaTypes = getJavaTypes(arguments); - this.argSomTypes = getSomTypes(arguments); + Object[] argsToProfile = arguments; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + argsToProfile = Arrays.copyOf(arguments, arguments.length - 1); + } + this.argJavaTypes = getJavaTypes(argsToProfile); + this.argSomTypes = getSomTypes(argsToProfile); } private static Class[] getJavaTypes(final Object[] args) { diff --git a/src/tools/snapshot/nodes/MessageSerializationNode.java b/src/tools/snapshot/nodes/MessageSerializationNode.java index 4549722359..57d1566719 100644 --- a/src/tools/snapshot/nodes/MessageSerializationNode.java +++ b/src/tools/snapshot/nodes/MessageSerializationNode.java @@ -27,6 +27,7 @@ import tools.snapshot.SnapshotBuffer; import tools.snapshot.deserialization.DeserializationBuffer; import tools.snapshot.deserialization.FixupInformation; +import som.interpreter.SArguments; @GenerateNodeFactory @@ -410,7 +411,7 @@ private PromiseSendMessage deserializeDelivered(final SSymbol selector, final Ac pmf.setMessage(psm); } psm.resolve(value, EventualMessage.getActorCurrentMessageIsExecutionOn(), - finalSender); + finalSender, SArguments.instantiateTopShadowStackEntry(this)); return psm; } diff --git a/src/tools/snapshot/nodes/ObjectSerializationNodes.java b/src/tools/snapshot/nodes/ObjectSerializationNodes.java index eea8f33d0b..e73a8bcf2f 100644 --- a/src/tools/snapshot/nodes/ObjectSerializationNodes.java +++ b/src/tools/snapshot/nodes/ObjectSerializationNodes.java @@ -186,7 +186,7 @@ public void serialize(final SObject so, final SnapshotBuffer sb) { protected final CachedSerializationNode[] getSerializers(final SObject o) { CachedSerializationNode[] nodes = new CachedSerializationNode[fieldCnt]; for (int i = 0; i < fieldCnt; i++) { - Object value = fieldReads[i].read(o); + Object value = fieldReads[i].read(null, o); nodes[i] = CachedSerializationNodeFactory.create(value); } return nodes; @@ -201,7 +201,7 @@ public void doCached(final SObject o, final SnapshotBuffer sb) { } for (int i = 0; i < fieldCnt; i++) { - Object value = fieldReads[i].read(o); + Object value = fieldReads[i].read(null, o); // TODO type profiles could be an optimization (separate profile for each slot) // TODO optimize, maybe it is better to add an integer to the objects (indicating their // offset) rather than using a map. From 30f0d235239dfeebd9ef781a47e0332022dc7326 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 20 Jan 2020 14:40:47 +0100 Subject: [PATCH 009/194] Fix AssertionError for async stack - add a fix for the assertion error according to the arguments received. If the message argument is a promise which is already resolved then the corresponding stack entry should be an EntryForPromiseResolution. If the promise is unresolved then the stack entry corresponds to the EntryAtMessageSend. If the message argument is a block then the stack entry corresponds to the EntryForPromiseResolution created for that frame. - TODO: check IllegalStateException when running the program in debug mode - remove commented code in the Kernel file - reenable assertion when setting the stack entry in SArguments --- core-lib/Kernel.ns | 8 +------- src/som/interpreter/SArguments.java | 2 +- .../actors/RegisterOnPromiseNode.java | 17 ++++++++++++++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/core-lib/Kernel.ns b/core-lib/Kernel.ns index fef5469bcd..b039711552 100644 --- a/core-lib/Kernel.ns +++ b/core-lib/Kernel.ns @@ -26,17 +26,11 @@ class Kernel vmMirror: vmMirror = Object <: Value ( private class Top = ()() public class Thing = Top ()( - (* protected error: msg = ( - vmMirror printNewline: 'ERROR: ' + msg. - vmMirror markTurnErroneous: nil. - vmMirror exit: 1 - ) *) - (* use the next implementation instead of the previous one to enable printing async stack trace when an error is thrown *) protected error: msg = ( vmMirror printNewline: 'ERROR: ' + msg. vmMirror markTurnErroneous: nil. - vmMirror printStackTrace: nil. + vmMirror printStackTrace: nil. (* enables printing the stack trace when an error is thrown *) vmMirror exit: 1 ) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index bb16f2e872..3c04705f60 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -215,7 +215,7 @@ public static ShadowStackEntry getShadowStackEntry(final Object[] args) { } public static void setShadowStackEntry(final Object[] args, final ShadowStackEntry entry) { - // assert args[args.length - 1] == null : "Assume shadow stack entry is not already set."; + assert args[args.length - 1] == null : "Assume shadow stack entry is not already set."; args[args.length - 1] = entry; } diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index ca9380f138..384229dace 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -13,6 +13,7 @@ import som.interpreter.actors.SPromise.STracingPromise; import som.interpreter.SArguments; import som.vm.VmSettings; +import som.vmobjects.SBlock; import tools.asyncstacktraces.ShadowStackEntry; import tools.dym.DynamicMetrics; import tools.replay.ReplayRecord; @@ -85,7 +86,21 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro SArguments.getShadowStackEntry(frame), getParent().getParent()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; - SArguments.setShadowStackEntry(msg.args, resolutionEntry); + + for (Object obj: msg.args) { + if (obj instanceof SPromise) { + if (((SPromise) promise).isCompleted()) { + //if promise is resolved set EntryForPromiseResolution + SArguments.setShadowStackEntry(msg.args, resolutionEntry); + } else { + //if promise is unresolved then the EntryAtMessageSend should be already set + //no entry of type EntryForPromiseResolution should be set because the promise has not been completed + assert msg.args[msg.args.length - 1] != null; + } + } else if (obj instanceof SBlock) { //for whenResolved blocks + SArguments.setShadowStackEntry(msg.args, resolutionEntry); + } + } } if (VmSettings.SENDER_SIDE_REPLAY) { From 9ba51d7784de87490bc13849c17c2688507f00a9 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 21 Jan 2020 14:31:21 +0100 Subject: [PATCH 010/194] Fix in the stack iterator - done TODO related to use the encapsulating source section for a frame of the normal stack (no async), in order to show the correct source section for that frame - update the labels for the output of the async stack --- src/tools/asyncstacktraces/StackIterator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index fb087a662b..053ece34c4 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -129,7 +129,7 @@ public StackFrame next() { Invokable rootNode = (Invokable) rt.getRootNode(); SourceSection ss = null; if (next.getCallNode() != null) { - ss = next.getCallNode().getSourceSection(); + ss = next.getCallNode().getEncapsulatingSourceSection(); } return createStackFrame(next.getFrame(FrameAccess.READ_ONLY), rootNode, @@ -227,10 +227,10 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, if (shadow instanceof EntryAtMessageSend) { Node sendNode = shadow.expression.getParent(); if (sendNode instanceof EventualSendNode) { - name = "Send: " + ((EventualSendNode) sendNode).getSentSymbol(); + name = "Sent: " + ((EventualSendNode) sendNode).getSentSymbol(); } else { - name = "Send: " + name; + name = "Sent: " + name; } useAgain = shadow; useAgainFrame = localFrame; From 8f69a2ccc5a9fd31af4006ce969476d249f9a5c5 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 21 Jan 2020 14:32:53 +0100 Subject: [PATCH 011/194] Update comment in SystemPrims --- src/som/primitives/SystemPrims.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index a018c5998a..15568f124f 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -320,7 +320,8 @@ public static void printStackTrace(final int skipDnuFrames, final SourceSection if (frame != null) { method.add(frame.name); maxLengthMethod = Math.max(maxLengthMethod, frame.name.length()); - // TODO: is frame.section better `callNode.getEncapsulatingSourceSection();` ? + // note: `callNode.getEncapsulatingSourceSection();` is better than frame.section + // because with this one we can get the source section while the other option returns null addSourceSection(frame.section, location); } From fe8efce02dd785704f6bd65bbcbf1f3b21e2183c Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 22 Jan 2020 10:27:26 +0100 Subject: [PATCH 012/194] Minor fixes showing the information of the stack - add label for async stack trace - remove repeated code to print the stack - fix call to VMSettings argument in BackCacheCallNode --- .../nodes/dispatch/BackCacheCallNode.java | 2 +- src/som/primitives/SystemPrims.java | 23 ++++++++++--------- src/tools/asyncstacktraces/StackIterator.java | 17 +++++++++----- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java index 3b85c44f22..7d5411602a 100644 --- a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java +++ b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java @@ -39,7 +39,7 @@ static void setShadowStackEntry(final VirtualFrame frame, SArguments.setShadowStackEntryWithCache(arguments, expression, shadowStackEntryLoad, frame, false); } - } else if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + } else if (VmSettings.ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE) { SArguments.setShadowStackEntryWithCache(arguments, expression, shadowStackEntryLoad, frame, false); } diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index 15568f124f..ae673e512c 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -312,9 +312,17 @@ public static void printStackTrace(final int skipDnuFrames, final SourceSection ArrayList location = new ArrayList(); int maxLengthMethod = 0; - Output.println("Stack Trace"); - StackIterator stack = StackIterator.createHaltIterator(); + + boolean asyncTrace = false; + + if (stack instanceof StackIterator.ShadowStackIterator.HaltShadowStackIterator) { + Output.println("- Async Stack Trace -"); + asyncTrace = true; + } else { + Output.println("- Stack Trace -"); + } + while (stack.hasNext()) { StackFrame frame = stack.next(); if (frame != null) { @@ -324,17 +332,10 @@ public static void printStackTrace(final int skipDnuFrames, final SourceSection // because with this one we can get the source section while the other option returns null addSourceSection(frame.section, location); } - - StringBuilder sb = new StringBuilder(); - for (int i = method.size() - 1; i >= skipDnuFrames; i--) { - sb.append(String.format("\t%1$-" + (maxLengthMethod + 4) + "s", - method.get(i))); - sb.append(location.get(i)); - sb.append('\n'); - } } - Output.print(stringStackTraceFrom(method, location, maxLengthMethod, skipDnuFrames)); + //for async traces hide only 1 frame: Thing>>#error:, because we want to show the last frame although is not async + Output.print(stringStackTraceFrom(method, location, maxLengthMethod, asyncTrace == false ? skipDnuFrames : 1)); } private static String stringStackTraceFrom(final ArrayList method, diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 053ece34c4..f0f12054d3 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -217,29 +217,34 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, boolean contextTransitionElement; String name = shadow.getRootNode().getName(); - SourceSection location; + SourceSection location = shadow.getSourceSection(); if (!usedAgain && (shadow instanceof EntryAtMessageSend || shadow instanceof EntryForPromiseResolution)) { contextTransitionElement = true; - location = null; + location = null; //because the previous frame should correspond to the method name, + // and shows the corresponding location already + String prefix = ""; if (shadow instanceof EntryAtMessageSend) { Node sendNode = shadow.expression.getParent(); + name = ((EventualSendNode) sendNode).getSentSymbol().getString(); + if (sendNode instanceof EventualSendNode) { - name = "Sent: " + ((EventualSendNode) sendNode).getSentSymbol(); + prefix = "at message sent: "; } else { - name = "Sent: " + name; + prefix = "Sent: "; //TODO check if needed } useAgain = shadow; useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { - name = "Resolved: " + name; + prefix = "Resolved: "; } + name = prefix + name; + } else { contextTransitionElement = false; - location = shadow.getSourceSection(); } return new StackFrame(name, shadow.getRootNode(), From d7a00ca12b64dd2bf3d32171c40b5c561a6e74a0 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 22 Jan 2020 16:47:15 +0100 Subject: [PATCH 013/194] Fixing bug in debug mode (WIP) - initialize list for the frames in SuspensionIterator class - minor renaming - TODO: fix problem with the null scopes for the non-async frames --- src/tools/asyncstacktraces/StackIterator.java | 22 ++++++++++--------- .../frontend/ApplicationThreadStack.java | 8 +++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index f0f12054d3..6e00be1e2e 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -76,6 +76,7 @@ public static class SuspensionIterator extends StackIterator { public SuspensionIterator(final Iterator localStack) { assert localStack != null; + frames = new ArrayList(); while (localStack.hasNext()) { frames.add(localStack.next()); } @@ -151,8 +152,7 @@ public abstract static class ShadowStackIterator extends StackIterator { protected boolean first; private Node currentNode; private Invokable currentMethod; - - private ShadowStackEntry useAgain; + private ShadowStackEntry useAgainShadowEntry; private Frame useAgainFrame; public ShadowStackIterator() { @@ -162,7 +162,7 @@ public ShadowStackIterator() { @Override public boolean hasNext() { - return currentSSEntry != null || first || useAgain != null; + return currentSSEntry != null || first || useAgainShadowEntry != null; } protected abstract StackFrameDescription getFirstFrame(); @@ -191,11 +191,11 @@ protected StackFrame nextAsyncStackStructure() { assert args[args.length - 1] instanceof ShadowStackEntry; currentSSEntry = (ShadowStackEntry) args[args.length - 1]; first = false; - } else if (useAgain != null) { - shadow = useAgain; + } else if (useAgainShadowEntry != null) { + shadow = useAgainShadowEntry; usedAgain = true; localFrame = useAgainFrame; - useAgain = null; + useAgainShadowEntry = null; useAgainFrame = null; } else { shadow = currentSSEntry; @@ -219,6 +219,8 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, String name = shadow.getRootNode().getName(); SourceSection location = shadow.getSourceSection(); +// System.out.println(name +" "+shadow.getClass().getName() + " "+location.getStartLine()); + if (!usedAgain && (shadow instanceof EntryAtMessageSend || shadow instanceof EntryForPromiseResolution)) { contextTransitionElement = true; @@ -236,7 +238,7 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, } else { prefix = "Sent: "; //TODO check if needed } - useAgain = shadow; + useAgainShadowEntry = shadow; useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { prefix = "Resolved: "; @@ -266,11 +268,11 @@ protected StackFrame nextAsyncStackStructureMethodCache() { first = false; } - if (useAgain != null) { - shadow = useAgain; + if (useAgainShadowEntry != null) { + shadow = useAgainShadowEntry; usedAgain = true; localFrame = useAgainFrame; - useAgain = null; + useAgainShadowEntry = null; useAgainFrame = null; } else { if (shouldUsePreviousShadowStackEntry(currentMethod, diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 4b06b5f4eb..f0e2aea3ca 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -35,11 +35,8 @@ public class ApplicationThreadStack { public static final class StackFrame { public final String name; public final SourceSection section; - public final Frame frame; - public final boolean asyncSeparator; - private final RootNode root; public StackFrame(final String name, final RootNode root, final SourceSection section, @@ -74,7 +71,10 @@ ArrayList get() { StackIterator.createSuspensionIterator(event.getStackFrames().iterator()); while (stack.hasNext()) { - stackFrames.add(stack.next()); + StackFrame next = stack.next(); + if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values + stackFrames.add(next); + } } assert !stackFrames.isEmpty() : "We expect that there is always at least one stack frame"; From 55afcbcf3e95fb12b34304b664595eda8518619b Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 23 Jan 2020 16:21:50 +0100 Subject: [PATCH 014/194] Changes in the stack iterator - when creating an async frame keep the location, is needed to keep the link of the frame to the program file being debugged - add flag to identify the stack mode in the stack trace response - add top frame to show as first frame in the async stack - renaming variables - add labels for the frame name when the shadow is instance of EntryForPromiseResolution. TODO: check different cases of promise resolution --- src/tools/asyncstacktraces/StackIterator.java | 73 ++++++++++++------- .../frontend/ApplicationThreadStack.java | 16 ++-- .../debugger/message/StackTraceResponse.java | 19 ++++- 3 files changed, 70 insertions(+), 38 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 6e00be1e2e..493ee29007 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -1,9 +1,5 @@ package tools.asyncstacktraces; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.NoSuchElementException; - import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.debug.DebugStackFrame; @@ -14,11 +10,11 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; - import som.interpreter.Invokable; import som.interpreter.Method; import som.interpreter.actors.EventualSendNode; import som.interpreter.nodes.dispatch.BackCacheCallNode; +import som.interpreter.nodes.nary.EagerBinaryPrimitiveNode; import som.vm.VmSettings; import tools.asyncstacktraces.ShadowStackEntry.EntryAtMessageSend; import tools.asyncstacktraces.ShadowStackEntry.EntryForPromiseResolution; @@ -26,6 +22,10 @@ import tools.asyncstacktraces.StackIterator.ShadowStackIterator.SuspensionShadowStackIterator; import tools.debugger.frontend.ApplicationThreadStack.StackFrame; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; + /** * This iterator traverses the run time stack and all available calling context @@ -154,10 +154,12 @@ public abstract static class ShadowStackIterator extends StackIterator { private Invokable currentMethod; private ShadowStackEntry useAgainShadowEntry; private Frame useAgainFrame; + private StackFrame topFrame; public ShadowStackIterator() { currentSSEntry = null; first = true; + topFrame = null; } @Override @@ -180,17 +182,18 @@ public StackFrame next() { } protected StackFrame nextAsyncStackStructure() { - ShadowStackEntry shadow = null; Frame localFrame = null; boolean usedAgain = false; if (first) { - localFrame = getFirstFrame().getFrame(); + StackFrameDescription firstFrame = getFirstFrame(); + localFrame = firstFrame.getFrame(); Object[] args = localFrame.getArguments(); assert args[args.length - 1] instanceof ShadowStackEntry; currentSSEntry = (ShadowStackEntry) args[args.length - 1]; first = false; + } else if (useAgainShadowEntry != null) { shadow = useAgainShadowEntry; usedAgain = true; @@ -206,6 +209,16 @@ protected StackFrame nextAsyncStackStructure() { return createStackFrame(shadow, localFrame, usedAgain); } + public StackFrame getTopFrame() { + if (first) { + StackFrameDescription frameDescription = getFirstFrame(); + + topFrame = new StackFrame(frameDescription.getRootNode().getName(), frameDescription.getRootNode(), + frameDescription.getSourceSection(), frameDescription.getFrame(), false); + } + return topFrame; + } + protected StackFrame createStackFrame(final ShadowStackEntry shadow, final Frame localFrame, final boolean usedAgain) { if (shadow == null) { @@ -219,31 +232,31 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, String name = shadow.getRootNode().getName(); SourceSection location = shadow.getSourceSection(); -// System.out.println(name +" "+shadow.getClass().getName() + " "+location.getStartLine()); - if (!usedAgain && (shadow instanceof EntryAtMessageSend || shadow instanceof EntryForPromiseResolution)) { contextTransitionElement = true; - location = null; //because the previous frame should correspond to the method name, - // and shows the corresponding location already - String prefix = ""; if (shadow instanceof EntryAtMessageSend) { Node sendNode = shadow.expression.getParent(); - name = ((EventualSendNode) sendNode).getSentSymbol().getString(); + String symbol = ((EventualSendNode) sendNode).getSentSymbol().getString(); if (sendNode instanceof EventualSendNode) { - prefix = "at message sent: "; + name = "at message sent: " + symbol; } else { - prefix = "Sent: "; //TODO check if needed + name = "Sent: "; //TODO check if needed } useAgainShadowEntry = shadow; useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { - prefix = "Resolved: "; + if (shadow.expression instanceof EagerBinaryPrimitiveNode) { + EagerBinaryPrimitiveNode node = (EagerBinaryPrimitiveNode)shadow.expression; + name = "resolved before callback: " + node.getOperation(); //this means the promise of this callback was resolved + } else { + + name = "resolved at: "+shadow.expression.getRootNode().getName(); + } } - name = prefix + name; } else { contextTransitionElement = false; @@ -336,28 +349,32 @@ public RootNode getRootNode() { } public static final class SuspensionShadowStackIterator extends ShadowStackIterator { - private final DebugStackFrame firstFrame; + private final DebugStackFrame firstDebugFrame; + private StackFrameDescription firstFrameDescription; public SuspensionShadowStackIterator(final Iterator localStack) { assert localStack != null; assert localStack.hasNext(); - firstFrame = localStack.next(); + firstDebugFrame = localStack.next(); + firstFrameDescription = null; } @Override protected StackFrameDescription getFirstFrame() { assert first; - return new StackFrameDescription(firstFrame.getSourceSection(), firstFrame.getFrame(), - firstFrame.getRootNode()); + if (firstFrameDescription == null) { + firstFrameDescription = new StackFrameDescription(firstDebugFrame.getSourceSection(), firstDebugFrame.getFrame(), + firstDebugFrame.getRootNode()); + } + return firstFrameDescription; } - } public static final class HaltShadowStackIterator extends ShadowStackIterator { - private final FrameInstance firstFrame; + private final FrameInstance firstFrameInstance; public HaltShadowStackIterator() { - firstFrame = + firstFrameInstance = Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { @Override public FrameInstance visitFrame(final FrameInstance frame) { @@ -369,15 +386,15 @@ public FrameInstance visitFrame(final FrameInstance frame) { @Override protected StackFrameDescription getFirstFrame() { assert first; - RootCallTarget rt = (RootCallTarget) firstFrame.getCallTarget(); + RootCallTarget rt = (RootCallTarget) firstFrameInstance.getCallTarget(); assert rt.getRootNode() instanceof Invokable; Invokable rootNode = (Invokable) rt.getRootNode(); SourceSection ss = null; - if (firstFrame.getCallNode() != null) { - ss = firstFrame.getCallNode().getSourceSection(); + if (firstFrameInstance.getCallNode() != null) { + ss = firstFrameInstance.getCallNode().getSourceSection(); } return new StackFrameDescription(ss, - firstFrame.getFrame(FrameAccess.READ_ONLY), + firstFrameInstance.getFrame(FrameAccess.READ_ONLY), rootNode); } } diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index f0e2aea3ca..5d8f8ef570 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -3,9 +3,7 @@ import java.util.ArrayList; import java.util.HashMap; -import com.oracle.truffle.api.debug.DebugStackFrame; import com.oracle.truffle.api.debug.SuspendedEvent; -import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; @@ -36,16 +34,16 @@ public static final class StackFrame { public final String name; public final SourceSection section; public final Frame frame; - public final boolean asyncSeparator; + public final boolean asyncOperation; private final RootNode root; public StackFrame(final String name, final RootNode root, final SourceSection section, - final Frame frame, final boolean asyncSeparator) { + final Frame frame, final boolean asyncOperation) { this.name = name; this.root = root; this.section = section; this.frame = frame; - this.asyncSeparator = asyncSeparator; + this.asyncOperation = asyncOperation; } public RootNode getRootNode() { @@ -70,9 +68,15 @@ ArrayList get() { StackIterator stack = StackIterator.createSuspensionIterator(event.getStackFrames().iterator()); + if (stack instanceof StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) { + StackFrame topFrame = ((StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) stack).getTopFrame(); + //get top frame first + stackFrames.add(topFrame); + } + while (stack.hasNext()) { StackFrame next = stack.next(); - if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values + if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values for null shadows stackFrames.add(next); } } diff --git a/src/tools/debugger/message/StackTraceResponse.java b/src/tools/debugger/message/StackTraceResponse.java index 171b8feea1..4a5ab0f41a 100644 --- a/src/tools/debugger/message/StackTraceResponse.java +++ b/src/tools/debugger/message/StackTraceResponse.java @@ -8,6 +8,7 @@ import som.interpreter.actors.Actor.ExecutorRootNode; import som.interpreter.actors.EventualMessage; import som.interpreter.actors.ReceivedRootNode; +import som.vm.VmSettings; import tools.TraceData; import tools.debugger.entities.EntityType; import tools.debugger.frontend.Suspension; @@ -30,9 +31,11 @@ public final class StackTraceResponse extends Response { */ private final int totalFrames; + private boolean asyncStack; + private StackTraceResponse(final long activityId, final StackFrame[] stackFrames, final int totalFrames, - final int requestId, final byte[] concurrentEntityScopes, final long messageId) { + final int requestId, final byte[] concurrentEntityScopes, final long messageId, final boolean asyncStack) { super(requestId); assert TraceData.isWithinJSIntValueRange(activityId); this.activityId = activityId; @@ -40,6 +43,7 @@ private StackTraceResponse(final long activityId, this.totalFrames = totalFrames; this.concurrentEntityScopes = concurrentEntityScopes; this.messageId = messageId; + this.asyncStack = asyncStack; boolean assertsOn = false; assert assertsOn = true; @@ -78,9 +82,12 @@ private static class StackFrame { /** An optional number of characters in the range. */ private final int length; + /** Indicates if the frame corresponds to an async operation */ + private final boolean async; + StackFrame(final long globalId, final String name, final String sourceUri, final int line, final int column, final int endLine, - final int endColumn, final int length) { + final int endColumn, final int length, final boolean async) { assert TraceData.isWithinJSIntValueRange(globalId); this.id = globalId; this.name = name; @@ -90,6 +97,7 @@ private static class StackFrame { this.endLine = endLine; this.endColumn = endColumn; this.length = length; + this.async = async; } } @@ -152,7 +160,7 @@ public static StackTraceResponse create(final int startFrame, final int levels, } return new StackTraceResponse(suspension.activityId, arr, frames.size(), - requestId, EntityType.getIds(concEntityScopes), messageId); + requestId, EntityType.getIds(concEntityScopes), messageId, VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE); } private static StackFrame createFrame(final Suspension suspension, @@ -186,6 +194,9 @@ private static StackFrame createFrame(final Suspension suspension, endColumn = 0; length = 0; } - return new StackFrame(id, name, sourceUri, line, column, endLine, endColumn, length); + + boolean async = frame.asyncOperation; + + return new StackFrame(id, name, sourceUri, line, column, endLine, endColumn, length, async); } } From 1b767ec832bd62d6040d1419670ea8afe88962c6 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 6 Feb 2020 15:17:18 +0100 Subject: [PATCH 015/194] Minor change in Launcher - TODO: enable assisted debugging for the tracing, at the moment there is an assertion error that needs to be solved. - TODO: solve assertion error in BackCacheCallNode 31. It looks that there is a problem for showing the async stack implementation when there is a loop in the program --- src/som/Launcher.java | 6 +++++- src/tools/asyncstacktraces/StackIterator.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/som/Launcher.java b/src/som/Launcher.java index 037305bb1a..4bc1c917b0 100644 --- a/src/som/Launcher.java +++ b/src/som/Launcher.java @@ -57,7 +57,11 @@ private static void finalizeExecution(final int exitCode) { // Note: Kompos Trace is parsed right after writing it // to produce the list of messages on the erroneous path. // Could be done at the beginning of assisted debugging. - if (VmSettings.KOMPOS_TRACING) { + + //Note2: added VmSettings.ASSISTED_DEBUGGING flag because at the moment the parser + // does not works correctly with this implementation. + // TODO check the assertion error KomposTraceParser 220 + if (VmSettings.KOMPOS_TRACING && VmSettings.ASSISTED_DEBUGGING) { KomposTraceParser tp = new KomposTraceParser(); tp.createStackTraceFile(VmSettings.TRACE_FILE); } diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 493ee29007..e86fd6768e 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -355,7 +355,7 @@ public static final class SuspensionShadowStackIterator extends ShadowStackItera public SuspensionShadowStackIterator(final Iterator localStack) { assert localStack != null; assert localStack.hasNext(); - firstDebugFrame = localStack.next(); + firstDebugFrame = localStack.next(); //only takes the first frame firstFrameDescription = null; } From c08f2c494bea17aa0c086227d3a06bfec9539e1b Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 6 Feb 2020 15:21:50 +0100 Subject: [PATCH 016/194] Add changes for step-end-turn (WIP) - enable haltOnResolver flag on the promise to be able to pause at the end of a turn. TODO: finish --- src/som/interpreter/actors/SPromise.java | 6 +++++- src/tools/debugger/entities/SteppingType.java | 10 +++++++++ src/tools/debugger/frontend/Suspension.java | 21 ++++++++++++------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index 3572a7dbb8..ca8d03fc36 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -107,7 +107,7 @@ public static SPromise createResolved(final Actor owner, final Object value, /** * Trigger breakpoint at the point where the promise is resolved with a value. */ - private final boolean haltOnResolver; + private boolean haltOnResolver; /** * Trigger a breakpoint when executing a resolution callback. @@ -965,4 +965,8 @@ boolean getHaltOnResolution() { public void enableHaltOnResolution() { haltOnResolution = true; } + + public void enableHaltOnResolver() { + haltOnResolver = true; + } } diff --git a/src/tools/debugger/entities/SteppingType.java b/src/tools/debugger/entities/SteppingType.java index 94cbc67594..89f1821486 100644 --- a/src/tools/debugger/entities/SteppingType.java +++ b/src/tools/debugger/entities/SteppingType.java @@ -196,6 +196,16 @@ public void process(final Suspension susp) { susp.getEvent().prepareContinue(); susp.getActivityThread().setSteppingStrategy(this); } + }, + + @SerializedName("stepToEndTurn") + STEP_TO_END_TURN("stepToEndTurn", "Step to End Turn", + Group.ACTOR_STEPPING, "msg-close", null, new ActivityType[] {ActivityType.ACTOR}) { + @Override + public void process(final Suspension susp) { + susp.getEvent().prepareContinue(); + susp.getActivityThread().setSteppingStrategy(this); + } }; public enum Group { diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index d29f76603d..0ad4d02654 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -1,12 +1,7 @@ package tools.debugger.frontend; -import java.util.ArrayList; -import java.util.concurrent.ArrayBlockingQueue; - -import com.oracle.truffle.api.debug.DebugStackFrame; import com.oracle.truffle.api.debug.SuspendedEvent; import com.oracle.truffle.api.frame.Frame; - import som.interpreter.LexicalScope.MethodScope; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage; @@ -20,11 +15,13 @@ import tools.debugger.FrontendConnector; import tools.debugger.entities.EntityType; import tools.debugger.entities.SteppingType; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; import tools.debugger.frontend.ApplicationThreadTask.Resume; import tools.debugger.frontend.ApplicationThreadTask.SendStackTrace; import tools.debugger.message.VariablesRequest.FilterType; -import com.oracle.truffle.api.frame.Frame; -import tools.debugger.frontend.ApplicationThreadStack.StackFrame; + +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; /** @@ -178,6 +175,16 @@ public void suspendWithoutObjectSafepoints() { resolver.getPromise().enableHaltOnResolution(); } } + else if (activityThread.isStepping( + SteppingType.STEP_TO_END_TURN)) { + assert activity instanceof Actor; + EventualMessage turnMessage = EventualMessage.getCurrentExecutingMessage(); + + SResolver resolver = turnMessage.getResolver(); + if (resolver != null) { + resolver.getPromise().enableHaltOnResolver(); + } + } } } catch (InterruptedException e) { /* Just continue waiting */ } } From f3eb8b2e35b8c7caac76fec8777bdf265970e976 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 14 Feb 2020 16:10:23 +0100 Subject: [PATCH 017/194] Changes for the step-end-turn command - extend the suspend method to support the step-end-turn command. The implementation calls the method prepareStepEndTurn added in the the DebuggerSession class of Truffle debug api --- src/tools/debugger/frontend/Suspension.java | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 0ad4d02654..2bba8f5ca3 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -2,6 +2,8 @@ import com.oracle.truffle.api.debug.SuspendedEvent; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; import som.interpreter.LexicalScope.MethodScope; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage; @@ -10,6 +12,7 @@ import som.interpreter.objectstorage.ObjectTransitionSafepoint; import som.primitives.ObjectPrims.HaltPrim; import som.vm.Activity; +import som.vmobjects.SObjectWithClass; import tools.TraceData; import tools.concurrency.TracingActivityThread; import tools.debugger.FrontendConnector; @@ -179,11 +182,24 @@ else if (activityThread.isStepping( SteppingType.STEP_TO_END_TURN)) { assert activity instanceof Actor; EventualMessage turnMessage = EventualMessage.getCurrentExecutingMessage(); + String actorName = ""; + Object[] args = turnMessage.getArgs(); + if (args.length > 0) { + final SObjectWithClass actorObject = (SObjectWithClass) args[0]; + actorName = actorObject.getSOMClass().getName().getString(); + } - SResolver resolver = turnMessage.getResolver(); - if (resolver != null) { - resolver.getPromise().enableHaltOnResolver(); + String turnName = actorName.concat(">>#").concat(turnMessage.getSelector().getString()); + + Node suspendedNode = this.getEvent().getNode(); + ArrayList stackFrames = this.getStackFrames(); + ArrayList rootNodeFrames = new ArrayList<>(); + //get root nodes for the frames in the stack + for (StackFrame frame: stackFrames) { + rootNodeFrames.add(frame.getRootNode()); } + + this.getEvent().getSession().prepareStepEndTurn(Thread.currentThread(), suspendedNode, turnName, rootNodeFrames); } } } catch (InterruptedException e) { /* Just continue waiting */ } From 6b25da290fa69647e5b374827e4adac5897fbf61 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 18 Feb 2020 22:35:00 +0100 Subject: [PATCH 018/194] Add minor validation in step end turn event --- src/tools/debugger/frontend/Suspension.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 2bba8f5ca3..48c67233b4 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -5,6 +5,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import som.interpreter.LexicalScope.MethodScope; +import som.interpreter.Method; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage; import som.interpreter.actors.SPromise.SResolver; @@ -184,12 +185,17 @@ else if (activityThread.isStepping( EventualMessage turnMessage = EventualMessage.getCurrentExecutingMessage(); String actorName = ""; Object[] args = turnMessage.getArgs(); - if (args.length > 0) { + if (args.length > 0 && args[0] instanceof SObjectWithClass) { final SObjectWithClass actorObject = (SObjectWithClass) args[0]; actorName = actorObject.getSOMClass().getName().getString(); } - String turnName = actorName.concat(">>#").concat(turnMessage.getSelector().getString()); + String turnName; + if (actorName.isEmpty()) { + turnName = turnMessage.getSelector().getString(); + } else { + turnName = actorName.concat(">>#").concat(turnMessage.getSelector().getString()); + } Node suspendedNode = this.getEvent().getNode(); ArrayList stackFrames = this.getStackFrames(); From c2a15cf5fb601c9d9272650bf115578468fb3c3f Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 19 Feb 2020 10:04:07 +0100 Subject: [PATCH 019/194] Add comments - comment new entry in EventualMessage for the async stack, because is not needed at the moment. The async stack is work in progress. - add small comment in ResolveNode for flags on the promise resolver --- src/som/interpreter/actors/EventualMessage.java | 3 ++- src/som/interpreter/actors/ResolveNode.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 5f34382cb9..ff67bc0cfd 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; import som.VM; @@ -423,7 +424,7 @@ private void setPromiseValue(final Object value, final Actor resolvingActor, args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { assert maybeEntry instanceof ShadowStackEntry; - SArguments.setShadowStackEntry(args, (ShadowStackEntry) maybeEntry); + // SArguments.setShadowStackEntry(args, (ShadowStackEntry) maybeEntry); } if (VmSettings.SNAPSHOTS_ENABLED) { this.messageId = Math.min(this.messageId, diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java index e02d309440..d5de2932ea 100644 --- a/src/som/interpreter/actors/ResolveNode.java +++ b/src/som/interpreter/actors/ResolveNode.java @@ -26,6 +26,7 @@ public SPromise.SResolver normalResolution(final VirtualFrame frame, SPromise promise = resolver.getPromise(); + //this is needed to suspend on explicit promises (which resolved to a a value different from another promise) if (haltOnResolver || promise.getHaltOnResolver()) { haltNode.executeEvaluated(frame, result); } From 50503dc92bcbebca3f1da54d9e9c89275623a639 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 19 Feb 2020 11:12:41 +0100 Subject: [PATCH 020/194] Update gitmodules file - update configuration of submodule libs/truffle to use the fork that contains the implementation for the command step-end-turn --- .gitmodules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 1e23dd6880..3e6e34a554 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,8 @@ [submodule "libs/truffle"] path = libs/truffle - url = https://github.com/smarr/Truffle.git + url = https://github.com/ctrlpz/truffle.git shallow = false + branch = debugger/step-end-turn [submodule "libs/mx"] path = libs/mx url = https://github.com/smarr/mx.git From f910b6700b8a5857f2025602f6f95d660547002d Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 19 Feb 2020 14:20:03 +0100 Subject: [PATCH 021/194] Update step end turn - add support to step at the end of a turn corresponding to a PromiseCallbackMessage, e.g. when the command is triggered from a node inside a whenResolved block --- src/tools/debugger/frontend/Suspension.java | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 48c67233b4..6515b87069 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -13,6 +13,7 @@ import som.interpreter.objectstorage.ObjectTransitionSafepoint; import som.primitives.ObjectPrims.HaltPrim; import som.vm.Activity; +import som.vmobjects.SBlock; import som.vmobjects.SObjectWithClass; import tools.TraceData; import tools.concurrency.TracingActivityThread; @@ -184,17 +185,24 @@ else if (activityThread.isStepping( assert activity instanceof Actor; EventualMessage turnMessage = EventualMessage.getCurrentExecutingMessage(); String actorName = ""; + String turnName = ""; + Object[] args = turnMessage.getArgs(); - if (args.length > 0 && args[0] instanceof SObjectWithClass) { + if (args.length > 0 && args[0] instanceof SObjectWithClass) { //e.g. PromiseSendMessage, DirectMessage final SObjectWithClass actorObject = (SObjectWithClass) args[0]; actorName = actorObject.getSOMClass().getName().getString(); } + if (args.length > 0 && args[0] instanceof SBlock) { //e.g. PromiseCallbackMessage + SBlock block = (SBlock) args[0]; + turnName = block.getMethod().getInvokable().getName(); + } - String turnName; - if (actorName.isEmpty()) { - turnName = turnMessage.getSelector().getString(); - } else { - turnName = actorName.concat(">>#").concat(turnMessage.getSelector().getString()); + if (turnName.isEmpty()) { + if (actorName.isEmpty()) { + turnName = turnMessage.getSelector().getString(); + } else { + turnName = actorName.concat(">>#").concat(turnMessage.getSelector().getString()); + } } Node suspendedNode = this.getEvent().getNode(); From 7031da406c6112f5d7d88582d2fe278c99c0122b Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 28 Feb 2020 08:51:20 +0100 Subject: [PATCH 022/194] Extend loadModule to accept internal files - add support in load primitive implementation to accept a path that starts with core-lib. This is useful to load runtime system classes declared in the core-lib folder from an IntelliJ project. We use the java classpath to get the absolute path of the classes of the interpreter and then the path to the target class can be configured. - add support in the loadNextTo primitive to find files located in the src of an IntelliJ project based on the absolute path received as reference. This is useful for the tests classes to see their corresponding source classes. --- src/som/primitives/SystemPrims.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index ae673e512c..dffdd73b3b 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -168,7 +168,12 @@ private static Object loadModule(final VM vm, final String path) throws IOExcept if (path.endsWith(EXTENSION_EXT)) { return vm.loadExtensionModule(path); } else { - MixinDefinition module = vm.loadModule(path); + String modulePath = path; + if (path.startsWith("core-lib")) { + String classPath = System.getProperty("java.class.path").split("build")[0]; + modulePath = classPath.concat(path); + } + MixinDefinition module = vm.loadModule(modulePath); return module.instantiateModuleClass(); } } @@ -209,6 +214,11 @@ public BinarySystemOperation initialize(final VM vm) { public final Object load(final VirtualFrame frame, final String filename, final SObjectWithClass moduleObj) { String path = moduleObj.getSOMClass().getMixinDefinition().getSourceSection().getSource() .getPath(); + + if (filename.startsWith("src")) { + path = path.split("test")[0].concat("test"); + } + File file = new File(URI.create(path).getPath()); return loadModule(frame, vm, file.getParent() + File.separator + filename, ioException); From f862fce369ae6d72ec3b7fd36c81bfe68ec32fa7 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 28 Feb 2020 14:24:19 +0100 Subject: [PATCH 023/194] Add small change in loadModule - add change in loadModule to consider the case when the source program is not located directly in the src folder root, but in a child folder, and an import of the core-lib is done in that program --- src/som/primitives/SystemPrims.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index dffdd73b3b..7d84c83ff7 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -219,6 +219,10 @@ public final Object load(final VirtualFrame frame, final String filename, final path = path.split("test")[0].concat("test"); } + if (filename.startsWith("core-lib")) { + return loadModule(frame, vm, filename, ioException); + } + File file = new File(URI.create(path).getPath()); return loadModule(frame, vm, file.getParent() + File.separator + filename, ioException); From 42999947d7a3a49c893bd4e36e36be777f9eb050 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 2 Mar 2020 15:08:57 +0100 Subject: [PATCH 024/194] Changes in the error nodes - add support for the breakpoints in the error nodes, similar as for the resolve nodes. Previous implementation was broken due to the changes of the async stack trace. --- core-lib/Actors.ns | 6 ++-- .../actors/AbstractPromiseResolutionNode.java | 1 - src/som/interpreter/actors/ErrorNode.java | 35 +++++++++++++++++++ .../interpreter/actors/ErrorPromiseNode.java | 31 ++++++++-------- .../interpreter/actors/ReceivedRootNode.java | 4 +-- 5 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 src/som/interpreter/actors/ErrorNode.java diff --git a/core-lib/Actors.ns b/core-lib/Actors.ns index aae7bfd3db..f70b3d0e59 100644 --- a/core-lib/Actors.ns +++ b/core-lib/Actors.ns @@ -79,10 +79,8 @@ class Actors usingVmMirror: vmMirror usingKernel: kernel = Value ( ) public class Resolver = Value ()( (* Object or Value? *) - (* public resolve: value = ( vmMirror actorsResolve: self with: value isBPResolver: false isBPResolution: false ) - public error: value = ( vmMirror actorsError: self with: value isBPResolver: false isBPResolution: false ) *) - public resolve: value = ( vmMirror actorsResolve: self with: value ) - public error: value = ( vmMirror actorsError: self with: value ) + public resolve: value = ( vmMirror actorsResolve: self with: value ) + public error: value = ( vmMirror actorsError: self with: value ) ) class Pair with: promise and: resolver = ( diff --git a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java index 0c861538d9..4e6daa4cf3 100644 --- a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java +++ b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java @@ -35,7 +35,6 @@ @GenerateWrapper -//public abstract class AbstractPromiseResolutionNode extends QuaternaryExpressionNode @NodeChildren({ @NodeChild(value = "receiver", type = ExpressionNode.class), @NodeChild(value = "firstArg", type = ExpressionNode.class), diff --git a/src/som/interpreter/actors/ErrorNode.java b/src/som/interpreter/actors/ErrorNode.java new file mode 100644 index 0000000000..876a5356ee --- /dev/null +++ b/src/som/interpreter/actors/ErrorNode.java @@ -0,0 +1,35 @@ +package som.interpreter.actors; + + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SomLanguage; + +public abstract class ErrorNode extends AbstractPromiseResolutionNode { + @CompilerDirectives.CompilationFinal + boolean initialized = false; + + /** + * Standard error case, when the promise is errored with a value that's not a promise. + */ + @Specialization(guards = {"notAPromise(result)"}) + public SPromise.SResolver standardError(final VirtualFrame frame, + final SPromise.SResolver resolver, final Object result, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { + + if (!initialized) { + initialized = true; + this.initialize(SomLanguage.getVM(this)); + } + + SPromise promise = resolver.getPromise(); + + if (haltOnResolver || promise.getHaltOnResolver()) { + haltNode.executeEvaluated(frame, result); + } + + resolvePromise(SPromise.Resolution.ERRONEOUS, resolver, result, maybeEntry, haltOnResolution); + return resolver; + } +} diff --git a/src/som/interpreter/actors/ErrorPromiseNode.java b/src/som/interpreter/actors/ErrorPromiseNode.java index bdd35019f2..083d14f99f 100644 --- a/src/som/interpreter/actors/ErrorPromiseNode.java +++ b/src/som/interpreter/actors/ErrorPromiseNode.java @@ -7,29 +7,30 @@ import bd.primitives.Primitive; import bd.tools.nodes.Operation; +import som.interpreter.SArguments; import som.interpreter.actors.SPromise.Resolution; import som.interpreter.actors.SPromise.SResolver; +import som.interpreter.nodes.nary.BinaryExpressionNode; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; import tools.dym.Tags.ComplexPrimitiveOperation; @GenerateNodeFactory -@Primitive(primitive = "actorsError:with:entry:isBPResolver:isBPResolution:") -public abstract class ErrorPromiseNode extends AbstractPromiseResolutionNode - implements Operation { - /** - * Standard error case, when the promise is errored with a value that's not a promise. - */ - @Specialization(guards = {"notAPromise(result)"}) - public SResolver standardError(final VirtualFrame frame, final SResolver resolver, - final Object result, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { - SPromise promise = resolver.getPromise(); +@Primitive(primitive = "actorsError:with:") +public abstract class ErrorPromiseNode extends BinaryExpressionNode implements Operation { + @Child protected ErrorNode errorNode; - if (haltOnResolver || promise.getHaltOnResolver()) { - haltNode.executeEvaluated(frame, result); - } + public ErrorPromiseNode() { + errorNode = ErrorNodeGen.create(null, null, null, null, null); + } - resolvePromise(Resolution.ERRONEOUS, resolver, result, maybeEntry, haltOnResolution); - return resolver; + @Specialization + public SResolver standardError(final VirtualFrame frame, final SResolver resolver, + final Object result) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame); + assert entry != null || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + return (SResolver) errorNode.executeEvaluated(frame, resolver, result, entry, false, false); } @Override diff --git a/src/som/interpreter/actors/ReceivedRootNode.java b/src/som/interpreter/actors/ReceivedRootNode.java index f82a05c136..6dd581f542 100644 --- a/src/som/interpreter/actors/ReceivedRootNode.java +++ b/src/som/interpreter/actors/ReceivedRootNode.java @@ -126,7 +126,7 @@ protected final void resolvePromise(final VirtualFrame frame, if (resolver == null) { resolve = insert(new NullResolver()); } else { - resolve = insert( + resolve = insert( ResolveNodeGen.create(null, null, null, null, null).initialize(vm)); } resolve.initialize(sourceSection); @@ -151,7 +151,7 @@ protected final void errorPromise(final VirtualFrame frame, error = insert(new NullResolver()); } else { error = insert( - ErrorPromiseNodeFactory.create(null, null, null, null, null).initialize(vm)); + ErrorNodeGen.create(null, null, null, null, null).initialize(vm)); } this.error = error; this.error.initialize(sourceSection); From 6a68e3f73ed40093a00f04012032bd6c4a74e03f Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 30 Mar 2020 16:34:27 +0200 Subject: [PATCH 025/194] Show id information in SPromise - add promise id in the toString method of SPromise. This is needed to have the id information in the variable response corresponding to a promise. This will be used for the work of interrogative debugging. --- src/som/interpreter/actors/SPromise.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index ca8d03fc36..d52dbc5c4b 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -128,7 +128,7 @@ protected SPromise(final Actor owner, final boolean haltOnResolver, @Override public String toString() { - String r = "Promise[" + owner.toString(); + String r = "Promise[" + getPromiseId() + ", " + owner.toString(); r += ", " + resolutionState.name(); return r + (value == null ? "" : ", " + value.toString()) + "]"; } From b3022ea747da075613fb93333d040b4c8f51234a Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 3 Apr 2020 14:19:56 +0200 Subject: [PATCH 026/194] Add future to avoid assertion error - add future in FrontendConnector.awaitClient method because can happen a race between processing the InitializeConnection (33) message and starting the server in the WebDebugger (176), and then the messageSocket can be null. --- src/tools/debugger/FrontendConnector.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 297efee628..7ca6bdfb08 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -83,6 +83,8 @@ public class FrontendConnector { */ private CompletableFuture clientConnected; + private CompletableFuture messageSocketInitialized; + private final Gson gson; private static final int MESSAGE_PORT = 7977; private static final int TRACE_PORT = 7978; @@ -100,6 +102,7 @@ public FrontendConnector(final Breakpoints breakpoints, this.gson = gson; clientConnected = new CompletableFuture(); + messageSocketInitialized = new CompletableFuture(); try { log("[DEBUGGER] Initialize HTTP and WebSocket Server for Debugger"); @@ -261,6 +264,7 @@ public void awaitClient() { try { messageSocket = clientConnected.get(); assert messageSocket != null; + messageSocketInitialized.complete(messageSocket); traceSocket = traceHandler.getConnection().get(); assert traceSocket != null; @@ -331,10 +335,18 @@ public void completeConnection(final WebSocket conn) { Runtime.getRuntime().addShutdownHook(new Thread(() -> closeAllSockets())); clientConnected.complete(conn); + + //when the server has really started, i.e. the client has connected, then do the send + messageSocketInitialized.thenRun(() -> sendInitResponse()); + } + + private void sendInitResponse() { + log("[DEBUGGER] Message socket initialized "+messageSocketInitialized.isDone()); + send(InitializationResponse.create(EntityType.values(), - ActivityType.values(), PassiveEntityType.values(), - DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), - BreakpointType.values(), SteppingType.values(), Implementation.values())); + ActivityType.values(), PassiveEntityType.values(), + DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), + BreakpointType.values(), SteppingType.values(), Implementation.values())); } private void closeAllSockets() { From b8117ddfe2f7668ce37477b615ca246e0403a35c Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 3 Apr 2020 14:34:06 +0200 Subject: [PATCH 027/194] Change comparison operator in Vector remove - when removing string in a Vector should be use = instead of ==, because == is not in the lookup --- core-lib/Kernel.ns | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-lib/Kernel.ns b/core-lib/Kernel.ns index b039711552..79ce3871eb 100644 --- a/core-lib/Kernel.ns +++ b/core-lib/Kernel.ns @@ -777,7 +777,7 @@ class Kernel vmMirror: vmMirror = Object <: Value ( found:: false. self do: [ :it | - it == object + it = object ifTrue: [ found:: true ] ifFalse: [ newArray at: newLast put: it. From 1c16463aa25e1a458a72928c944e599bb81aec1c Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 9 Apr 2020 21:36:46 +0200 Subject: [PATCH 028/194] Avoid assertion error with ProgramInfoRequest - comment log of message socket initialized --- src/tools/debugger/FrontendConnector.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 7ca6bdfb08..6048f12f16 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -302,7 +302,8 @@ public void sendTracingData() { } public void sendProgramInfo() { - send(ProgramInfoResponse.create(webDebugger.vm.getArguments())); + //when the server has really started, i.e. the client has connected, then do the send + messageSocketInitialized.thenRun(() -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); } public void sendPauseActorResponse(long pausedActorId) { @@ -341,7 +342,7 @@ public void completeConnection(final WebSocket conn) { } private void sendInitResponse() { - log("[DEBUGGER] Message socket initialized "+messageSocketInitialized.isDone()); +// log("[DEBUGGER] Message socket initialized "+messageSocketInitialized.isDone()); send(InitializationResponse.create(EntityType.values(), ActivityType.values(), PassiveEntityType.values(), From d353e7e33d815482080085ce8039c636df2eb2a5 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 23 Apr 2020 09:59:59 +0200 Subject: [PATCH 029/194] Add stack shadow entry for loops - add missing entry for the async stack for the iterating construct doIndexes. This way avoid assertion error in BackCacheCallNode.java 31. --- .../specialized/IntDownToDoMessageNode.java | 23 +++++++++------- .../specialized/IntToByDoMessageNode.java | 26 ++++++++++++------- .../nodes/specialized/IntToDoMessageNode.java | 21 +++++++++------ 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java index 06aa5fea67..cac845bf18 100644 --- a/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java @@ -3,35 +3,40 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import bd.primitives.Primitive; import som.interpreter.nodes.specialized.IntToDoMessageNode.ToDoSplzr; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; +import tools.asyncstacktraces.ShadowStackEntryLoad; @GenerateNodeFactory @Primitive(selector = "downTo:do:", noWrapper = true, disabled = true, specializer = ToDoSplzr.class) public abstract class IntDownToDoMessageNode extends IntToDoMessageNode { + + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + @Override @Specialization(guards = "block.getMethod() == blockMethod") - public final long doIntToDo(final long receiver, - final long limit, final SBlock block, - @Cached("block.getMethod()") final SInvokable blockMethod, - @Cached("create(blockMethod)") final DirectCallNode valueSend) { - return IntToByDoMessageNode.doLoop(valueSend, this, receiver, - limit, -1, block); + public final long doIntToDo(final VirtualFrame frame, final long receiver, + final long limit, final SBlock block, + @Cached("block.getMethod()") final SInvokable blockMethod, + @Cached("create(blockMethod)") final DirectCallNode valueSend) { + return IntToByDoMessageNode.doLoop(frame, valueSend, this, receiver, + limit, -1, block, shadowStackEntryLoad); } @Override @Specialization(guards = "block.getMethod() == blockMethod") - public final long doIntToDo(final long receiver, + public final long doIntToDo(final VirtualFrame frame, final long receiver, final double dLimit, final SBlock block, @Cached("block.getMethod()") final SInvokable blockMethod, @Cached("create(blockMethod)") final DirectCallNode valueSend) { - return IntToByDoMessageNode.doLoop(valueSend, this, receiver, - (long) dLimit, -1, block); + return IntToByDoMessageNode.doLoop(frame, valueSend, this, receiver, + (long) dLimit, -1, block, shadowStackEntryLoad); } } diff --git a/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java index 4a77fd90c3..47a56d786d 100644 --- a/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java @@ -4,16 +4,19 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.Node; import bd.primitives.Primitive; +import som.interpreter.SArguments; import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.nary.QuaternaryExpressionNode; import som.interpreter.objectstorage.ObjectTransitionSafepoint; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; +import tools.asyncstacktraces.ShadowStackEntryLoad; import tools.dym.Tags.LoopNode; @@ -23,6 +26,8 @@ public abstract class IntToByDoMessageNode extends QuaternaryExpressionNode { protected final SInvokable blockMethod; @Child protected DirectCallNode valueSend; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + public IntToByDoMessageNode(final Object[] args) { blockMethod = ((SBlock) args[3]).getMethod(); valueSend = Truffle.getRuntime().createDirectCallNode(blockMethod.getCallTarget()); @@ -38,26 +43,29 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { } @Specialization(guards = "block.getMethod() == blockMethod") - public final long doIntToByDo(final long receiver, + public final long doIntToByDo(final VirtualFrame frame, final long receiver, final long limit, final long step, final SBlock block) { - return doLoop(valueSend, this, receiver, limit, step, block); + return doLoop(frame, valueSend, this, receiver, limit, step, block, shadowStackEntryLoad); } @Specialization(guards = "block.getMethod() == blockMethod") - public final long doIntToByDo(final long receiver, + public final long doIntToByDo(final VirtualFrame frame, final long receiver, final double limit, final long step, final SBlock block) { - return doLoop(valueSend, this, receiver, (long) limit, step, block); + return doLoop(frame, valueSend, this, receiver, (long) limit, step, block, shadowStackEntryLoad); } - public static long doLoop(final DirectCallNode value, - final Node loopNode, final long receiver, final long limit, final long step, - final SBlock block) { + public static long doLoop(final VirtualFrame frame, final DirectCallNode value, + final ExpressionNode loopNode, final long receiver, final long limit, final long step, + final SBlock block, ShadowStackEntryLoad shadowStackEntryLoad) { try { if (receiver <= limit) { - value.call(new Object[] {block, receiver}); + value.call(SArguments.getPlainXArgumentsWithReceiver(loopNode, + shadowStackEntryLoad, frame, block, receiver)); } for (long i = receiver + step; i <= limit; i += step) { - value.call(new Object[] {block, i}); + value.call(SArguments.getPlainXArgumentsWithReceiver(loopNode, + shadowStackEntryLoad, frame, block, i)); + ObjectTransitionSafepoint.INSTANCE.checkAndPerformSafepoint(); } } finally { diff --git a/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java index 7f5d260ff9..4256962685 100644 --- a/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java @@ -5,6 +5,7 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -18,6 +19,7 @@ import som.vmobjects.SBlock; import som.vmobjects.SInvokable; import som.vmobjects.SSymbol; +import tools.asyncstacktraces.ShadowStackEntryLoad; import tools.dym.Tags.LoopNode; @@ -25,6 +27,9 @@ @Primitive(selector = "to:do:", noWrapper = true, disabled = true, specializer = ToDoSplzr.class, inParser = false) public abstract class IntToDoMessageNode extends TernaryExpressionNode { + + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + public static class ToDoSplzr extends Specializer { public ToDoSplzr(final Primitive prim, final NodeFactory fact) { super(prim, fact); @@ -52,20 +57,20 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { } @Specialization(guards = "block.getMethod() == blockMethod") - public long doIntToDo(final long receiver, final long limit, final SBlock block, - @Cached("block.getMethod()") final SInvokable blockMethod, - @Cached("create(blockMethod)") final DirectCallNode valueSend) { - return IntToByDoMessageNode.doLoop(valueSend, this, receiver, - limit, 1, block); + public long doIntToDo(final VirtualFrame frame, final long receiver, final long limit, final SBlock block, + @Cached("block.getMethod()") final SInvokable blockMethod, + @Cached("create(blockMethod)") final DirectCallNode valueSend) { + return IntToByDoMessageNode.doLoop(frame, valueSend, this, receiver, + limit, 1, block, shadowStackEntryLoad); } @Specialization(guards = "block.getMethod() == blockMethod") - public long doIntToDo(final long receiver, final double dLimit, + public long doIntToDo(final VirtualFrame frame, final long receiver, final double dLimit, final SBlock block, @Cached("block.getMethod()") final SInvokable blockMethod, @Cached("create(blockMethod)") final DirectCallNode valueSend) { - return IntToByDoMessageNode.doLoop(valueSend, this, receiver, - (long) dLimit, 1, block); + return IntToByDoMessageNode.doLoop(frame, valueSend, this, receiver, + (long) dLimit, 1, block, shadowStackEntryLoad); } @Override From 76402f5ccc4fc11ecb5ef5fc61ecc1c619755524 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 23 Apr 2020 11:54:00 +0200 Subject: [PATCH 030/194] Minor renaming --- src/tools/asyncstacktraces/StackIterator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index e86fd6768e..e1f1b9e851 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -243,9 +243,10 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, if (sendNode instanceof EventualSendNode) { name = "at message sent: " + symbol; - } else { - name = "Sent: "; //TODO check if needed } +// else { +// name = "Sent: "; //TODO check if needed +// } useAgainShadowEntry = shadow; useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { @@ -254,7 +255,7 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, name = "resolved before callback: " + node.getOperation(); //this means the promise of this callback was resolved } else { - name = "resolved at: "+shadow.expression.getRootNode().getName(); + name = "on callback: "+shadow.expression.getRootNode().getName(); } } From a6eecc3f6038d7a10e3c355418b0db7ae70fd20f Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 4 May 2020 10:13:18 +0200 Subject: [PATCH 031/194] Add intellij config files --- SOMns.iml | 55 +++++++++++++++++++ .../extension/SOMns-ExtensionTests.iml | 33 +++++++++++ core-lib/TestSuite/extension/extension.iml | 14 +++++ 3 files changed, 102 insertions(+) create mode 100644 SOMns.iml create mode 100644 core-lib/TestSuite/extension/SOMns-ExtensionTests.iml create mode 100644 core-lib/TestSuite/extension/extension.iml diff --git a/SOMns.iml b/SOMns.iml new file mode 100644 index 0000000000..50d4e6f507 --- /dev/null +++ b/SOMns.iml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-lib/TestSuite/extension/SOMns-ExtensionTests.iml b/core-lib/TestSuite/extension/SOMns-ExtensionTests.iml new file mode 100644 index 0000000000..276d478b0e --- /dev/null +++ b/core-lib/TestSuite/extension/SOMns-ExtensionTests.iml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-lib/TestSuite/extension/extension.iml b/core-lib/TestSuite/extension/extension.iml new file mode 100644 index 0000000000..6403fde408 --- /dev/null +++ b/core-lib/TestSuite/extension/extension.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file From eb34f29ad229a032f2c35ba23410881ab19fdd6e Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 14 May 2020 15:52:15 +0200 Subject: [PATCH 032/194] Add promise value in the trace - integrating Louise work that extends the send operation entity in the trace with the promise value, for the cases when the promise is resolved with a value or an error. --- src/tools/concurrency/KomposTrace.java | 37 +++++++++++++++++++------ src/tools/debugger/entities/SendOp.java | 6 ++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index dc8d9111a1..309393ef79 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.source.SourceSection; import bd.source.SourceCoordinate; +import som.interpreter.Types; import som.interpreter.actors.Actor; import som.interpreter.nodes.dispatch.Dispatchable; import som.vm.Activity; @@ -28,7 +29,7 @@ public static void recordMainActor(final Actor mainActor, KomposTraceBuffer buffer = KomposTraceBuffer.create(0); buffer.recordCurrentActivity(mainActor); buffer.recordMainActor(mainActor, objectSystem); - buffer.recordSendOperation(SendOp.ACTOR_MSG, 0, mainActor.getId(), mainActor, (short) 0, 0, null); + buffer.recordSendOperation(SendOp.ACTOR_MSG, 0, mainActor.getId(), mainActor, (short) 0, 0, null, null); buffer.returnBuffer(null); } @@ -82,9 +83,12 @@ public static void promiseResolution(final long promiseId, final Object value) { assert current instanceof TracingActivityThread; TracingActivityThread t = (TracingActivityThread) current; + String name = Types.toDebuggerString(value); + byte[] nameBytes = name.getBytes(); + ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(SendOp.PROMISE_RESOLUTION, 0, promiseId, - t.getActivity(), (short) 0, 0, null); + t.getActivity(), (short) 0, 0, null, nameBytes); t.resolvedPromises++; } @@ -92,9 +96,11 @@ public static void promiseError(final long promiseId, final Object value) { Thread current = Thread.currentThread(); assert current instanceof TracingActivityThread; TracingActivityThread t = (TracingActivityThread) current; + String error = Types.toDebuggerString(value); + byte[] errorBytes = error.getBytes(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(SendOp.PROMISE_RESOLUTION, 0, promiseId, - t.getActivity(), (short) 0, 0, null); + t.getActivity(), (short) 0, 0, null, errorBytes); t.erroredPromises++; } @@ -107,7 +113,7 @@ public static void promiseError(final long promiseId, final Object value) { public static void promiseChained(final long promiseValueId, final long promiseId) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation( - SendOp.PROMISE_RESOLUTION, promiseValueId, promiseId, t.getActivity(), (short) 0, 0, null); + SendOp.PROMISE_RESOLUTION, promiseValueId, promiseId, t.getActivity(), (short) 0, 0, null, null); t.resolvedPromises++; } @@ -115,7 +121,7 @@ public static void sendOperation(final SendOp op, final long entityId, final long targetId, final SSymbol selector, long targetActorId, SourceSection msgSourceCoordinate) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(op, entityId, targetId, - t.getActivity(), selector.getSymbolId(), targetActorId, msgSourceCoordinate); + t.getActivity(), selector.getSymbolId(), targetActorId, msgSourceCoordinate, null); } public static void receiveOperation(final ReceiveOp op, final long sourceId) { @@ -343,8 +349,14 @@ public void recordReceiveOperation(final ReceiveOp op, final long sourceId, } public void recordSendOperation(final SendOp op, final long entityId, - final long targetId, final Activity current, final short symbolId, long targetActorId, SourceSection msgSourceCoordinate) { - int requiredSpace = op.getSize(); + final long targetId, final Activity current, final short symbolId, long targetActorId, SourceSection msgSourceCoordinate, byte[] value) { + int requiredSpace; + if (value == null) { + requiredSpace = op.getSize(); + } else { + requiredSpace = op.getSize(value); + } + ensureSufficientSpace(requiredSpace, current); final int start = position; @@ -358,6 +370,13 @@ public void recordSendOperation(final SendOp op, final long entityId, writeSourceSection(msgSourceCoordinate); } + if(value != null) { + putInt(value.length); + for (byte b : value) { + put(b); + } + } + assert position == start + requiredSpace; } @@ -406,8 +425,8 @@ public synchronized void recordReceiveOperation(final ReceiveOp op, @Override public synchronized void recordSendOperation(final SendOp op, - final long entityId, final long targetId, final Activity current, final short symbol, final long targetActorId, final SourceSection section) { - super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, section); + final long entityId, final long targetId, final Activity current, final short symbol, final long targetActorId, final SourceSection section, byte[] value) { + super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, section, value); } } } diff --git a/src/tools/debugger/entities/SendOp.java b/src/tools/debugger/entities/SendOp.java index fa92ea0fa1..3f41623fd7 100644 --- a/src/tools/debugger/entities/SendOp.java +++ b/src/tools/debugger/entities/SendOp.java @@ -14,6 +14,7 @@ public enum SendOp { private static final int SYMBOL_ID_SIZE = 2; private static final int RECEIVER_ACTOR_ID_SIZE = 8; + private static final int PROMISE_VALUE_SIZE = 4; SendOp(final byte id, final EntityType entity, final EntityType target) { this.id = id; @@ -36,4 +37,9 @@ public EntityType getTarget() { public int getSize() { return 17 + RECEIVER_ACTOR_ID_SIZE + SYMBOL_ID_SIZE + TraceData.SOURCE_SECTION_SIZE; } + + //Adds the promise value size and the number of bytes for an integer (4), which is also recorded + public int getSize(byte[] promiseValue) { + return 17 + RECEIVER_ACTOR_ID_SIZE + SYMBOL_ID_SIZE + TraceData.SOURCE_SECTION_SIZE + promiseValue.length + PROMISE_VALUE_SIZE; + } } From 7b5672e0c2f39302562d380cea21c069c3323687 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 17 Jun 2020 12:28:18 +0200 Subject: [PATCH 033/194] Add stack shadow entry for do primitive - add stack shadow entry for do: primitive in arrays --- src/som/primitives/arrays/DoPrim.java | 45 +++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/som/primitives/arrays/DoPrim.java b/src/som/primitives/arrays/DoPrim.java index 07e95b9ce9..4020b90e57 100644 --- a/src/som/primitives/arrays/DoPrim.java +++ b/src/som/primitives/arrays/DoPrim.java @@ -5,6 +5,8 @@ import com.oracle.truffle.api.dsl.Specialization; import bd.primitives.Primitive; +import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.dispatch.BlockDispatchNode; import som.interpreter.nodes.dispatch.BlockDispatchNodeGen; @@ -14,28 +16,31 @@ import som.vmobjects.SArray; import som.vmobjects.SArray.PartiallyEmptyArray; import som.vmobjects.SBlock; +import tools.asyncstacktraces.ShadowStackEntryLoad; @GenerateNodeFactory @Primitive(selector = "do:", receiverType = SArray.class, disabled = true) public abstract class DoPrim extends BinaryComplexOperation { @Child private BlockDispatchNode block = BlockDispatchNodeGen.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); // TODO: tag properly, it is a loop and an access - private void execBlock(final SBlock block, final Object arg) { - this.block.executeDispatch(new Object[] {block, arg}); + private void execBlock(final VirtualFrame frame, final SBlock block, final Object arg) { + this.block.executeDispatch(SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, block, arg)); } @Specialization(guards = "arr.isEmptyType()") - public final SArray doEmptyArray(final SArray arr, final SBlock block) { + public final SArray doEmptyArray(final VirtualFrame frame, final SArray arr, final SBlock block) { int length = arr.getEmptyStorage(); try { if (SArray.FIRST_IDX < length) { - execBlock(block, Nil.nilObject); + execBlock(frame, block, Nil.nilObject); } for (long i = SArray.FIRST_IDX + 1; i < length; i++) { - execBlock(block, Nil.nilObject); + execBlock(frame, block, Nil.nilObject); } } finally { if (CompilerDirectives.inInterpreter()) { @@ -46,15 +51,15 @@ public final SArray doEmptyArray(final SArray arr, final SBlock block) { } @Specialization(guards = "arr.isPartiallyEmptyType()") - public final SArray doPartiallyEmptyArray(final SArray arr, final SBlock block) { + public final SArray doPartiallyEmptyArray(final VirtualFrame frame, final SArray arr, final SBlock block) { PartiallyEmptyArray storage = arr.getPartiallyEmptyStorage(); int length = storage.getLength(); try { if (SArray.FIRST_IDX < length) { - execBlock(block, storage.get(SArray.FIRST_IDX)); + execBlock(frame, block, storage.get(SArray.FIRST_IDX)); } for (long i = SArray.FIRST_IDX + 1; i < length; i++) { - execBlock(block, storage.get(i)); + execBlock(frame, block, storage.get(i)); } } finally { if (CompilerDirectives.inInterpreter()) { @@ -65,15 +70,15 @@ public final SArray doPartiallyEmptyArray(final SArray arr, final SBlock block) } @Specialization(guards = "arr.isObjectType()") - public final SArray doObjectArray(final SArray arr, final SBlock block) { + public final SArray doObjectArray(final VirtualFrame frame, final SArray arr, final SBlock block) { Object[] storage = arr.getObjectStorage(); int length = storage.length; try { if (SArray.FIRST_IDX < length) { - execBlock(block, storage[SArray.FIRST_IDX]); + execBlock(frame, block, storage[SArray.FIRST_IDX]); } for (long i = SArray.FIRST_IDX + 1; i < length; i++) { - execBlock(block, storage[(int) i]); + execBlock(frame, block, storage[(int) i]); } } finally { if (CompilerDirectives.inInterpreter()) { @@ -84,15 +89,15 @@ public final SArray doObjectArray(final SArray arr, final SBlock block) { } @Specialization(guards = "arr.isLongType()") - public final SArray doLongArray(final SArray arr, final SBlock block) { + public final SArray doLongArray(final VirtualFrame frame, final SArray arr, final SBlock block) { long[] storage = arr.getLongStorage(); int length = storage.length; try { if (SArray.FIRST_IDX < length) { - execBlock(block, storage[SArray.FIRST_IDX]); + execBlock(frame, block, storage[SArray.FIRST_IDX]); } for (long i = SArray.FIRST_IDX + 1; i < length; i++) { - execBlock(block, storage[(int) i]); + execBlock(frame, block, storage[(int) i]); } } finally { if (CompilerDirectives.inInterpreter()) { @@ -103,15 +108,15 @@ public final SArray doLongArray(final SArray arr, final SBlock block) { } @Specialization(guards = "arr.isDoubleType()") - public final SArray doDoubleArray(final SArray arr, final SBlock block) { + public final SArray doDoubleArray(final VirtualFrame frame, final SArray arr, final SBlock block) { double[] storage = arr.getDoubleStorage(); int length = storage.length; try { if (SArray.FIRST_IDX < length) { - execBlock(block, storage[SArray.FIRST_IDX]); + execBlock(frame, block, storage[SArray.FIRST_IDX]); } for (long i = SArray.FIRST_IDX + 1; i < length; i++) { - execBlock(block, storage[(int) i]); + execBlock(frame, block, storage[(int) i]); } } finally { if (CompilerDirectives.inInterpreter()) { @@ -122,15 +127,15 @@ public final SArray doDoubleArray(final SArray arr, final SBlock block) { } @Specialization(guards = "arr.isBooleanType()") - public final SArray doBooleanArray(final SArray arr, final SBlock block) { + public final SArray doBooleanArray(final VirtualFrame frame, final SArray arr, final SBlock block) { boolean[] storage = arr.getBooleanStorage(); int length = storage.length; try { if (SArray.FIRST_IDX < length) { - execBlock(block, storage[SArray.FIRST_IDX]); + execBlock(frame, block, storage[SArray.FIRST_IDX]); } for (long i = SArray.FIRST_IDX + 1; i < length; i++) { - execBlock(block, storage[(int) i]); + execBlock(frame, block, storage[(int) i]); } } finally { if (CompilerDirectives.inInterpreter()) { From 3b1db885cc0b47df43bb385d849cdc4b944b276e Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 17 Jun 2020 15:42:21 +0200 Subject: [PATCH 034/194] Add shadow stack entry for timer primitive --- src/som/primitives/TimerPrim.java | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/som/primitives/TimerPrim.java b/src/som/primitives/TimerPrim.java index 4165dce844..21d2f053f0 100644 --- a/src/som/primitives/TimerPrim.java +++ b/src/som/primitives/TimerPrim.java @@ -1,23 +1,14 @@ package som.primitives; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; - +import bd.primitives.Primitive; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; - -import bd.primitives.Primitive; import som.VM; import som.compiler.AccessModifier; +import som.interpreter.SArguments; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage.DirectMessage; import som.interpreter.actors.EventualSendNode; @@ -36,6 +27,11 @@ import tools.replay.nodes.TraceContextNode; import tools.replay.nodes.TraceContextNodeGen; +import java.util.*; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; + @GenerateNodeFactory @Primitive(primitive = "actorDo:after:") @@ -101,8 +97,10 @@ protected final Object perform(final Object target, final Actor targetActor, timer.schedule(new TimerTask() { @Override public void run() { + Object[] args = SArguments.convertToArgumentArray(new Object[] {target}); + ExternalDirectMessage msg = new ExternalDirectMessage(targetActor, - VALUE_SELECTOR, new Object[] {target}, timerActor, null, valueCallTarget, + VALUE_SELECTOR, args, timerActor, null, valueCallTarget, (short) 0, id); targetActor.send(msg, actorPool); } From 360fdb3d78a5df1b03ba59c7da812399ca1a55ea Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 17 Jun 2020 21:08:22 +0200 Subject: [PATCH 035/194] Add shadow stack entry for do indexes prim - add shadow entry for do indexes primitive in arrays --- src/som/primitives/arrays/DoIndexesPrim.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/som/primitives/arrays/DoIndexesPrim.java b/src/som/primitives/arrays/DoIndexesPrim.java index 6bfc66f776..ce9be78273 100644 --- a/src/som/primitives/arrays/DoIndexesPrim.java +++ b/src/som/primitives/arrays/DoIndexesPrim.java @@ -7,6 +7,7 @@ import com.oracle.truffle.api.source.SourceSection; import bd.primitives.Primitive; +import som.interpreter.SArguments; import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.dispatch.BlockDispatchNode; import som.interpreter.nodes.dispatch.BlockDispatchNodeGen; @@ -16,6 +17,7 @@ import som.primitives.SizeAndLengthPrimFactory; import som.vmobjects.SArray; import som.vmobjects.SBlock; +import tools.asyncstacktraces.ShadowStackEntryLoad; @GenerateNodeFactory @@ -23,6 +25,8 @@ public abstract class DoIndexesPrim extends BinaryComplexOperation { @Child protected BlockDispatchNode block = BlockDispatchNodeGen.create(); @Child protected UnaryExpressionNode length; + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + // TODO: tag properly, this is a loop, but without array access @Override @@ -38,23 +42,22 @@ public DoIndexesPrim initialize(final SourceSection sourceSection) { public final SArray doArray(final VirtualFrame frame, final SArray receiver, final SBlock block) { int length = (int) (long) this.length.executeEvaluated(frame, receiver); - loop(block, length); + loop(frame, block, length); return receiver; } - private void loop(final SBlock block, final int length) { + private void loop(final VirtualFrame frame, final SBlock block, final int length) { try { int expectedFirstIdx = 0; // this code is written with this expectation assert SArray.FIRST_IDX == expectedFirstIdx; if (SArray.FIRST_IDX < length) { - this.block.executeDispatch(new Object[] { - // +1 because it is going to the smalltalk level - block, (long) SArray.FIRST_IDX + 1}); + this.block.executeDispatch(SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, block, (long) SArray.FIRST_IDX + 1)); // +1 because it is going to the smalltalk level } for (long i = 1; i < length; i++) { - this.block.executeDispatch(new Object[] { - block, i + 1}); // +1 because it is going to the smalltalk level + this.block.executeDispatch(SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, block, i + 1)); // +1 because it is going to the smalltalk level } } finally { if (CompilerDirectives.inInterpreter()) { From a87b6b276c65c9a99d0bb50ead8d18c8aae70e23 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 18 Jun 2020 11:08:28 +0200 Subject: [PATCH 036/194] Stop actors threads before shutdown - stop actor execution if they are paused to avoid having open threads before system shutdown. This way avoid java.lang.IllegalStateException on com.oracle.truffle.polyglot.PolyglotContextImpl.close(PolyglotContextImpl.java:870). This is needed when the program being debugged has for example a timeout. --- src/som/Launcher.java | 7 +++++++ src/tools/concurrency/TracingActors.java | 23 ++++++++++++++++++++++- src/tools/debugger/WebDebugger.java | 7 +++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/som/Launcher.java b/src/som/Launcher.java index 4bc1c917b0..046331cb09 100644 --- a/src/som/Launcher.java +++ b/src/som/Launcher.java @@ -9,6 +9,8 @@ import som.interpreter.SomLanguage; import som.vm.VmSettings; +import tools.concurrency.TracingActors; +import tools.concurrency.TracingActors.ReplayActor; import tools.concurrency.TracingBackend; import tools.parser.KomposTraceParser; import tools.snapshot.SnapshotBackend; @@ -39,6 +41,11 @@ public static void main(final String[] args) { Value result = context.eval(START); exitCode = result.as(Integer.class); } finally { + if (VmSettings.TRUFFLE_DEBUGGER_ENABLED) { + //Stop execution for all suspended actors if any + TracingActors.TracingActor.stopActorsIfSuspended(); + } + context.eval(SHUTDOWN); context.close(); finalizeExecution(exitCode); diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 09189d5f56..8a7bd40f4c 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -13,6 +13,7 @@ import som.interpreter.actors.SPromise.STracingPromise; import som.vm.VmSettings; import tools.debugger.WebDebugger; +import tools.debugger.frontend.Suspension; import tools.replay.PassiveEntityWithEvents; import tools.replay.ReplayRecord; import tools.replay.TraceParser; @@ -39,6 +40,8 @@ public static class TracingActor extends Actor { */ private static Map allActors = new HashMap<>(); + private static WebDebugger debugger; + public TracingActor(final VM vm) { super(vm); this.activityId = TracingActivityThread.newEntityId(); @@ -47,6 +50,9 @@ public TracingActor(final VM vm) { if (VmSettings.SNAPSHOTS_ENABLED) { snapshotRecord = new SnapshotRecord(); } + if(VmSettings.TRUFFLE_DEBUGGER_ENABLED) { + debugger = vm.getWebDebugger(); + } } protected TracingActor(final VM vm, final long id) { @@ -146,9 +152,24 @@ public static void saveActor(Actor actor) { allActors.put(actor.getId(), actor); } - public static Actor getActorById(long actorId){ + public static Actor getActorById(long actorId) { return allActors.get(actorId); } + + /** + * Stop actor execution if they are paused to avoid open threads before system shutdown + */ + public static void stopActorsIfSuspended() { + for (long actorId: allActors.keySet()) { + if (actorId > 0) { //do not stop Platform actor + Suspension suspension = debugger.getSuspensionByActorId(actorId); + if (suspension != null && suspension.getEvent() != null) { + suspension.getEvent().prepareKill(); + suspension.resume(); + } + } + } + } } public static final class ReplayActor extends TracingActor diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index 3da030237e..1237f357a1 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -142,6 +142,13 @@ private Suspension getSuspension() { return getSuspension(current, activityThread); } + public synchronized Suspension getSuspensionByActorId(final long actorId) { + if (idToSuspension.containsKey(actorId)) { + return idToSuspension.get(actorId); + } + return null; + } + @Override public void onSuspend(final SuspendedEvent e) { Suspension suspension = getSuspension(); From 5f2d364055d489101cdd17e5ec2120204d35bf0f Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 18 Jun 2020 13:23:09 +0200 Subject: [PATCH 037/194] Reuse getSuspension method in WebDebugger --- src/tools/concurrency/TracingActors.java | 2 +- src/tools/debugger/WebDebugger.java | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 8a7bd40f4c..f4dad029ec 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -162,7 +162,7 @@ public static Actor getActorById(long actorId) { public static void stopActorsIfSuspended() { for (long actorId: allActors.keySet()) { if (actorId > 0) { //do not stop Platform actor - Suspension suspension = debugger.getSuspensionByActorId(actorId); + Suspension suspension = debugger.getSuspension(actorId); if (suspension != null && suspension.getEvent() != null) { suspension.getEvent().prepareKill(); suspension.resume(); diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index 1237f357a1..73e524cfe6 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -110,7 +110,7 @@ public void prepareSteppingAfterNextRootNode(final Thread thread) { breakpoints.prepareSteppingAfterNextRootNode(thread); } - Suspension getSuspension(final long activityId) { + public Suspension getSuspension(final long activityId) { return idToSuspension.get(activityId); } @@ -142,13 +142,6 @@ private Suspension getSuspension() { return getSuspension(current, activityThread); } - public synchronized Suspension getSuspensionByActorId(final long actorId) { - if (idToSuspension.containsKey(actorId)) { - return idToSuspension.get(actorId); - } - return null; - } - @Override public void onSuspend(final SuspendedEvent e) { Suspension suspension = getSuspension(); From df91e6d9c7a378fc1af9ee75a48a883ceec9016e Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 18 Jun 2020 15:19:30 +0200 Subject: [PATCH 038/194] Add validation in StepMessage - check that the suspended event is not null --- src/tools/debugger/message/StepMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index 65a87bd03e..ed2cf94702 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -23,7 +23,7 @@ public class StepMessage extends IncommingMessage { @Override public void process(final FrontendConnector connector, final WebSocket conn) { Suspension susp = connector.getSuspension(activityId); - assert susp != null : "Failed to get suspension for activityId: " + activityId; + assert susp != null && susp.getEvent() != null: "Failed to get suspension for activityId: " + activityId; step.process(susp); susp.resume(); From afa9fd120f3055b2af2de9deab0443183aee942b Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 19 Jun 2020 11:09:48 +0200 Subject: [PATCH 039/194] Save Platform actor - add Platform to the list of created actors in TracingActors --- src/som/VM.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/som/VM.java b/src/som/VM.java index bed3d113e5..35e001ad3b 100644 --- a/src/som/VM.java +++ b/src/som/VM.java @@ -50,6 +50,7 @@ import som.vmobjects.SObjectWithClass.SObjectWithoutFields; import som.vmobjects.SSymbol; import tools.concurrency.KomposTrace; +import tools.concurrency.TracingActors; import tools.concurrency.TracingBackend; import tools.debugger.WebDebugger; import tools.debugger.session.Breakpoints; @@ -335,6 +336,7 @@ public void initalize(final SomLanguage lang) throws IOException { } if (VmSettings.KOMPOS_TRACING) { KomposTrace.recordMainActor(mainActor, objectSystem); + TracingActors.TracingActor.saveActor(mainActor); } language = lang; From 6bf9f7dd26e85b113aaf588df3b10461b4511c7a Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 19 Jun 2020 11:40:21 +0200 Subject: [PATCH 040/194] Add ResumeActorResponse message - when an actor is paused in the frontend without breakpoints its mailbox can be empty, and the user could decide to resume it. In that case no suspension exists yet for that actor in the debugger, then the debugger should update the step next turn flag to false and send a message to the frontend to update the actor state to running. --- src/tools/debugger/FrontendConnector.java | 4 ++++ .../RuntimeReflectionRegistration.java | 1 + .../debugger/message/ResumeActorResponse.java | 13 ++++++++++++ src/tools/debugger/message/StepMessage.java | 20 +++++++++++++++---- 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/tools/debugger/message/ResumeActorResponse.java diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 6048f12f16..d79b7e9b87 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -310,6 +310,10 @@ public void sendPauseActorResponse(long pausedActorId) { send(PauseActorResponse.create(pausedActorId)); } + public void sendResumeActorResponse(long actorId) { + send(ResumeActorResponse.create(actorId)); + } + public void registerOrUpdate(final LineBreakpoint bp) { breakpoints.addOrUpdate(bp); } diff --git a/src/tools/debugger/RuntimeReflectionRegistration.java b/src/tools/debugger/RuntimeReflectionRegistration.java index 97499db627..6c7362196e 100644 --- a/src/tools/debugger/RuntimeReflectionRegistration.java +++ b/src/tools/debugger/RuntimeReflectionRegistration.java @@ -65,6 +65,7 @@ public void register(final String name, final Class klass) { outMsgs.register(VariablesResponse.class); outMsgs.register(ProgramInfoResponse.class); outMsgs.register("pauseActorResponse", PauseActorResponse.class); + outMsgs.register("resumeActorResponse", ResumeActorResponse.class); ClassGroup inMsgs = new ClassGroup(IncommingMessage.class, "action", true); inMsgs.register(InitializeConnection.class); diff --git a/src/tools/debugger/message/ResumeActorResponse.java b/src/tools/debugger/message/ResumeActorResponse.java new file mode 100644 index 0000000000..cf21d8c0f1 --- /dev/null +++ b/src/tools/debugger/message/ResumeActorResponse.java @@ -0,0 +1,13 @@ +package tools.debugger.message; + +public class ResumeActorResponse extends Message.OutgoingMessage { + private long actorId; + + public ResumeActorResponse(long actorId) { + this.actorId = actorId; + } + + public static Message create(long runningActorId) { + return new ResumeActorResponse(runningActorId); + } +} diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index ed2cf94702..ba4b01d481 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -2,6 +2,7 @@ import org.java_websocket.WebSocket; +import som.interpreter.actors.Actor; import tools.debugger.FrontendConnector; import tools.debugger.entities.SteppingType; import tools.debugger.frontend.Suspension; @@ -23,12 +24,23 @@ public class StepMessage extends IncommingMessage { @Override public void process(final FrontendConnector connector, final WebSocket conn) { Suspension susp = connector.getSuspension(activityId); - assert susp != null && susp.getEvent() != null: "Failed to get suspension for activityId: " + activityId; - step.process(susp); - susp.resume(); - if (step == SteppingType.RESUME) { + if (susp != null && susp.getEvent() != null) { + step.process(susp); + susp.resume(); + FrontendConnector.log("[DEBUGGER] Executing step "+ step.name +" for actor "+activityId); + } else if(step == SteppingType.RESUME) { + //notify frontend the actor that can be resumed in the GUI because the actor is not suspended, + //this is needed for actors that are paused explicitly in the frontend, and they are not actually suspended yet (mailbox is empty) + Actor actor = connector.getActorById(this.activityId); + assert actor != null : "Failed to get actor for activityId: " + this.activityId; + //reset step next turn flag to false + actor.setStepToNextTurn(false); + //send resume message + connector.sendResumeActorResponse(this.activityId); FrontendConnector.log("[DEBUGGER] Resuming actor "+activityId); + } else { + FrontendConnector.log("[DEBUGGER]: Failed to get suspension for activityId: " + activityId); } } } From 0e7ea392f33aa9d5c7d5c2c131fdfd8cfcac6062 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 19 Jun 2020 12:30:37 +0200 Subject: [PATCH 041/194] Minor fix in log message --- src/tools/debugger/message/StepMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index ba4b01d481..9d39fb50a8 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -28,7 +28,7 @@ public void process(final FrontendConnector connector, final WebSocket conn) { if (susp != null && susp.getEvent() != null) { step.process(susp); susp.resume(); - FrontendConnector.log("[DEBUGGER] Executing step "+ step.name +" for actor "+activityId); + FrontendConnector.log("[DEBUGGER] Executing "+ step.name +" for actor "+activityId); } else if(step == SteppingType.RESUME) { //notify frontend the actor that can be resumed in the GUI because the actor is not suspended, //this is needed for actors that are paused explicitly in the frontend, and they are not actually suspended yet (mailbox is empty) From 97fe1aaaaf232aeacb540f8417cef3b0d7c1ef7a Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 26 Jun 2020 10:43:03 +0200 Subject: [PATCH 042/194] Adjust logs when resuming - send resume message response for the resume command and adjust logs --- src/tools/debugger/message/StepMessage.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index 9d39fb50a8..617a946847 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -28,7 +28,9 @@ public void process(final FrontendConnector connector, final WebSocket conn) { if (susp != null && susp.getEvent() != null) { step.process(susp); susp.resume(); - FrontendConnector.log("[DEBUGGER] Executing "+ step.name +" for actor "+activityId); + if (step != SteppingType.RESUME) { + FrontendConnector.log("[DEBUGGER] Executing "+ step.name +" for actor "+activityId); + } } else if(step == SteppingType.RESUME) { //notify frontend the actor that can be resumed in the GUI because the actor is not suspended, //this is needed for actors that are paused explicitly in the frontend, and they are not actually suspended yet (mailbox is empty) @@ -36,11 +38,18 @@ public void process(final FrontendConnector connector, final WebSocket conn) { assert actor != null : "Failed to get actor for activityId: " + this.activityId; //reset step next turn flag to false actor.setStepToNextTurn(false); + } else { + FrontendConnector.log("[DEBUGGER]: Failed to get suspension for activityId: " + activityId); + } + + sendResumeMessage(connector); + } + + private void sendResumeMessage(FrontendConnector connector) { + if(step == SteppingType.RESUME) { //send resume message connector.sendResumeActorResponse(this.activityId); FrontendConnector.log("[DEBUGGER] Resuming actor "+activityId); - } else { - FrontendConnector.log("[DEBUGGER]: Failed to get suspension for activityId: " + activityId); } } } From 9facd19a4dccf3b42d7e8514abe66a628f961394 Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 27 Jun 2020 22:08:18 +0200 Subject: [PATCH 043/194] Send resume message for return from turn step - send resume message for the actor where the command return from turn to promise resolution was executed. This is needed to update the actors state in the debugger frontend. --- src/tools/debugger/message/StepMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index 617a946847..9e430f4c4e 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -46,7 +46,7 @@ public void process(final FrontendConnector connector, final WebSocket conn) { } private void sendResumeMessage(FrontendConnector connector) { - if(step == SteppingType.RESUME) { + if(step == SteppingType.RESUME || step == SteppingType.RETURN_FROM_TURN_TO_PROMISE_RESOLUTION) { //send resume message connector.sendResumeActorResponse(this.activityId); FrontendConnector.log("[DEBUGGER] Resuming actor "+activityId); From f08bbcd441c3a158bb5f6f37fb0e330c21bd0187 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 30 Jun 2020 15:12:15 +0200 Subject: [PATCH 044/194] Show data flow in async stack - update shadow previous entries when a message sent to a promise is resolved (AbstractPromiseSendMessage class) - add resolution location tag in EntryForPromiseResolution --- src/som/interpreter/SArguments.java | 5 +++ .../interpreter/actors/EventualMessage.java | 21 ++++++--- .../asyncstacktraces/ShadowStackEntry.java | 44 +++++++++++++++---- src/tools/asyncstacktraces/StackIterator.java | 15 ++++--- .../frontend/ApplicationThreadStack.java | 2 + 5 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 3c04705f60..dc6fc9aad3 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -226,4 +226,9 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { return arguments.length; } } + + public static void addEntryForPromiseResolution(ShadowStackEntry.EntryAtMessageSend current, ShadowStackEntry.EntryForPromiseResolution promiseStack) { +// current.setPromiseResolutionEntry(promiseStack); + current.setPrevious(promiseStack); + } } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index ff67bc0cfd..0e61bf41e6 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -4,7 +4,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; import som.VM; @@ -332,7 +331,14 @@ private void determineAndSetTarget(final Object rcvr, final Actor target, this.messageId = Math.min(this.messageId, ActorProcessingThread.currentThread().getSnapshotId()); } - // TODO: what do I do with the shadow stack entry here. give it two parents? + + //save promise resolution entry corresponding to the promise to which the message is sent + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + assert maybeEntry != null && maybeEntry instanceof ShadowStackEntry.EntryForPromiseResolution; + assert args[args.length - 1] instanceof ShadowStackEntry.EntryAtMessageSend; + ShadowStackEntry.EntryAtMessageSend currentStack = (ShadowStackEntry.EntryAtMessageSend) args[args.length - 1]; + SArguments.addEntryForPromiseResolution(currentStack, (ShadowStackEntry.EntryForPromiseResolution)maybeEntry); + } } @Override @@ -422,10 +428,13 @@ public void resolve(final Object rcvr, final Actor target, final Actor sendingAc private void setPromiseValue(final Object value, final Actor resolvingActor, final Object maybeEntry) { args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - assert maybeEntry instanceof ShadowStackEntry; - // SArguments.setShadowStackEntry(args, (ShadowStackEntry) maybeEntry); - } +// if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { +// assert maybeEntry instanceof ShadowStackEntry; +//// SArguments.setShadowStackEntry(args, (ShadowStackEntry) maybeEntry); +// ShadowStackEntry resolutionEntry = +// ShadowStackEntry.createAtPromiseResolution((ShadowStackEntry) maybeEntry,this.onReceive.getRootNode(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_CALLBACK); +// SArguments.setShadowStackEntry(args, resolutionEntry); +// } if (VmSettings.SNAPSHOTS_ENABLED) { this.messageId = Math.min(this.messageId, ActorProcessingThread.currentThread().getSnapshotId()); diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/asyncstacktraces/ShadowStackEntry.java index c39246a08a..fbf00bafc1 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/asyncstacktraces/ShadowStackEntry.java @@ -12,7 +12,7 @@ public class ShadowStackEntry { - protected final ShadowStackEntry previous; + protected ShadowStackEntry previous; protected final Node expression; public static long numberOfAllocations; @@ -44,9 +44,9 @@ public static ShadowStackEntry createAtAsyncSend(final ShadowStackEntry previous } public static ShadowStackEntry createAtPromiseResolution(final ShadowStackEntry previous, - final Node expr) { + final Node expr, final EntryForPromiseResolution.ResolutionLocation resolutionType) { assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; - return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr)); + return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr), resolutionType); } public static Node unwrapNodeIfNecessary(final Node node) { @@ -87,22 +87,50 @@ public boolean isAsync() { return false; } + public void setPrevious(ShadowStackEntry maybeEntry) { + previous = maybeEntry; + } + public static final class EntryAtMessageSend extends ShadowStackEntry { +// EntryForPromiseResolution promiseResolutionEntry; + private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { super(previous, expr); } - @Override - public boolean isAsync() { - return true; - } +// public EntryForPromiseResolution getPromiseResolutionEntry() { +// return promiseResolutionEntry; +// } +// +// public void setPromiseResolutionEntry(EntryForPromiseResolution promiseResolutionEntry) { +// this.promiseResolutionEntry = promiseResolutionEntry; +// } } public static final class EntryForPromiseResolution extends ShadowStackEntry { + public enum ResolutionLocation { + ERROR("on error"), SUCCESSFUL ("on resolution"), + CHAINED("on chain"), ON_CALLBACK("on callback"), + ON_WHEN_RESOLVED("on when resolved"), ON_CALLBACK_ERROR("on callback error"), + ON_RECEIVE_MESSAGE("on async send receiver"), ON_SCHEDULE_PROMISE ("on schedule"); + + private final String value; + + ResolutionLocation(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + ResolutionLocation resolutionLocation; + private EntryForPromiseResolution(final ShadowStackEntry previous, - final Node expr) { + final Node expr, ResolutionLocation resolutionLocation) { super(previous, expr); + this.resolutionLocation = resolutionLocation; } @Override diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index e1f1b9e851..57e02bbe9a 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -206,6 +206,7 @@ protected StackFrame nextAsyncStackStructure() { currentSSEntry = shadow.previous; } } + return createStackFrame(shadow, localFrame, usedAgain); } @@ -241,21 +242,21 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, String symbol = ((EventualSendNode) sendNode).getSentSymbol().getString(); if (sendNode instanceof EventualSendNode) { - name = "at message sent: " + symbol; + name = "at async message: " + symbol; + } else { + name = "EntryAtMessageSend: " + shadow.expression.getRootNode().getName(); } -// else { -// name = "Sent: "; //TODO check if needed -// } useAgainShadowEntry = shadow; useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { + EntryForPromiseResolution.ResolutionLocation resolutionLocation = ((EntryForPromiseResolution) shadow).resolutionLocation; if (shadow.expression instanceof EagerBinaryPrimitiveNode) { EagerBinaryPrimitiveNode node = (EagerBinaryPrimitiveNode)shadow.expression; - name = "resolved before callback: " + node.getOperation(); //this means the promise of this callback was resolved - } else { + name = resolutionLocation.getValue() +": "+node.getOperation(); //this means the promise of this callback was resolved - name = "on callback: "+shadow.expression.getRootNode().getName(); + } else { + name = resolutionLocation.getValue() +": "+shadow.expression.getRootNode().getName(); } } diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 5d8f8ef570..161d590056 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -78,6 +78,8 @@ ArrayList get() { StackFrame next = stack.next(); if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values for null shadows stackFrames.add(next); + } else { +// System.out.println("null frame"); } } assert !stackFrames.isEmpty() From 455137941a117eca878678cb1f3e1723ae8bd15f Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 30 Jun 2020 15:53:20 +0200 Subject: [PATCH 045/194] Show more info for dataflow - add frames corresponding to the promise that has registered callback messages when is resolved (AbstractPromiseCallbackMessage class) - update resolution frames tags --- src/som/interpreter/actors/EventualMessage.java | 14 +++++++------- src/tools/asyncstacktraces/ShadowStackEntry.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 0e61bf41e6..4fb5a39cca 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -428,13 +428,13 @@ public void resolve(final Object rcvr, final Actor target, final Actor sendingAc private void setPromiseValue(final Object value, final Actor resolvingActor, final Object maybeEntry) { args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); -// if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { -// assert maybeEntry instanceof ShadowStackEntry; -//// SArguments.setShadowStackEntry(args, (ShadowStackEntry) maybeEntry); -// ShadowStackEntry resolutionEntry = -// ShadowStackEntry.createAtPromiseResolution((ShadowStackEntry) maybeEntry,this.onReceive.getRootNode(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_CALLBACK); -// SArguments.setShadowStackEntry(args, resolutionEntry); -// } + //save promise resolution entry corresponding to the promise to which this callback is registered + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + assert maybeEntry != null && maybeEntry instanceof ShadowStackEntry; + assert args[args.length - 1] instanceof ShadowStackEntry; + ShadowStackEntry currentStack = (ShadowStackEntry) args[args.length - 1]; + SArguments.addEntryForPromiseResolution(currentStack, (ShadowStackEntry) maybeEntry); + } if (VmSettings.SNAPSHOTS_ENABLED) { this.messageId = Math.min(this.messageId, ActorProcessingThread.currentThread().getSnapshotId()); diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/asyncstacktraces/ShadowStackEntry.java index fbf00bafc1..73d000835c 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/asyncstacktraces/ShadowStackEntry.java @@ -113,7 +113,7 @@ public enum ResolutionLocation { ERROR("on error"), SUCCESSFUL ("on resolution"), CHAINED("on chain"), ON_CALLBACK("on callback"), ON_WHEN_RESOLVED("on when resolved"), ON_CALLBACK_ERROR("on callback error"), - ON_RECEIVE_MESSAGE("on async send receiver"), ON_SCHEDULE_PROMISE ("on schedule"); + ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE ("on schedule"); private final String value; From 7c1015140b4540ba65dfa7224399255515c2faa1 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 30 Jun 2020 15:57:04 +0200 Subject: [PATCH 046/194] Update arguments in method - update arguments and remove commented code --- src/som/interpreter/SArguments.java | 3 +-- src/tools/asyncstacktraces/ShadowStackEntry.java | 10 ---------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index dc6fc9aad3..f03ff82368 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -227,8 +227,7 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } } - public static void addEntryForPromiseResolution(ShadowStackEntry.EntryAtMessageSend current, ShadowStackEntry.EntryForPromiseResolution promiseStack) { -// current.setPromiseResolutionEntry(promiseStack); + public static void addEntryForPromiseResolution(ShadowStackEntry current, ShadowStackEntry promiseStack) { current.setPrevious(promiseStack); } } diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/asyncstacktraces/ShadowStackEntry.java index 73d000835c..71828c703e 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/asyncstacktraces/ShadowStackEntry.java @@ -93,19 +93,9 @@ public void setPrevious(ShadowStackEntry maybeEntry) { public static final class EntryAtMessageSend extends ShadowStackEntry { -// EntryForPromiseResolution promiseResolutionEntry; - private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { super(previous, expr); } - -// public EntryForPromiseResolution getPromiseResolutionEntry() { -// return promiseResolutionEntry; -// } -// -// public void setPromiseResolutionEntry(EntryForPromiseResolution promiseResolutionEntry) { -// this.promiseResolutionEntry = promiseResolutionEntry; -// } } public static final class EntryForPromiseResolution extends ShadowStackEntry { From 1b74e4e11bfac17fe92a3c97979b3b68ea56bb4c Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 30 Jun 2020 16:02:02 +0200 Subject: [PATCH 047/194] Update tags on createAtPromiseResolution calls - add some comments - refactoring in RegisterOnPromiseNode --- .../interpreter/actors/ReceivedMessage.java | 5 +- .../actors/RegisterOnPromiseNode.java | 47 ++++++++++++------- .../actors/SchedulePromiseHandlerNode.java | 4 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index 104c0b1fae..c4d5e52aa0 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -3,7 +3,6 @@ import java.util.concurrent.CompletableFuture; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -48,7 +47,7 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive); + ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_RECEIVE_MESSAGE); } try { @@ -125,7 +124,7 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode()); + ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_CALLBACK); SArguments.setShadowStackEntry(msg.getArgs(), resolutionEntry); } diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 384229dace..6af05ab4ec 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -12,6 +12,7 @@ import som.interpreter.actors.SPromise.SReplayPromise; import som.interpreter.actors.SPromise.STracingPromise; import som.interpreter.SArguments; +import som.interpreter.actors.EventualMessage.PromiseMessage; import som.vm.VmSettings; import som.vmobjects.SBlock; import tools.asyncstacktraces.ShadowStackEntry; @@ -20,6 +21,8 @@ import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; +import java.util.concurrent.ForkJoinPool; + public abstract class RegisterOnPromiseNode { private static final AtomicLong numScheduledWhenResolved = @@ -80,26 +83,36 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro if (!promise.isResolvedUnsync()) { if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - // TODO: I think, we need the info about the resolution context from the promise + // get info about the resolution context from the promise, // we want to know where it was resolved, where the value is coming from - ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( - SArguments.getShadowStackEntry(frame), - getParent().getParent()); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; - for (Object obj: msg.args) { - if (obj instanceof SPromise) { - if (((SPromise) promise).isCompleted()) { - //if promise is resolved set EntryForPromiseResolution - SArguments.setShadowStackEntry(msg.args, resolutionEntry); - } else { - //if promise is unresolved then the EntryAtMessageSend should be already set - //no entry of type EntryForPromiseResolution should be set because the promise has not been completed - assert msg.args[msg.args.length - 1] != null; - } - } else if (obj instanceof SBlock) { //for whenResolved blocks + boolean promiseComplete = (obj instanceof SPromise) && ((SPromise) promise).isCompleted(); +// boolean promiseChained = (obj instanceof SPromise) && !((SPromise) promise).isCompleted(); + if (obj instanceof SBlock || promiseComplete) { + //for whenResolved blocks or if promise is resolved, then create EntryForPromiseResolution + ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( + SArguments.getShadowStackEntry(frame), + getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); + } +// else if (promiseChained) { +// ShadowStackEntry entry = (ShadowStackEntry) msg.args[msg.args.length - 1]; +// assert entry != null && entry instanceof ShadowStackEntry.EntryAtMessageSend; +// ShadowStackEntry shadowStackEntry = SArguments.getShadowStackEntry(frame); +// +//// entry.setPrevious(shadowStackEntry); +// +// System.out.println("-register msg args: "+entry.getSourceSection()); +// System.out.println("shadow: "+shadowStackEntry.getSourceSection()); + +// assert maybeEntry != null && maybeEntry instanceof ShadowStackEntry.EntryForPromiseResolution; +// assert args[args.length - 1] instanceof ShadowStackEntry.EntryAtMessageSend; +// ShadowStackEntry.EntryAtMessageSend current = (ShadowStackEntry.EntryAtMessageSend) args[args.length - 1]; +// SArguments.addEntryForPromiseResolution(current, (ShadowStackEntry.EntryForPromiseResolution) maybeEntry); + +// } } } @@ -191,7 +204,7 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro // we want to know where it was resolved, where the value is coming from ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent()); + getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_CALLBACK_ERROR); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index f97222d8fa..7b4cf6f878 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -50,11 +50,11 @@ public final void schedule(final VirtualFrame frame, final SPromise promise, promise.getValueUnsync(), msg.originalSender, current); if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - // TODO: I think, we need the info about the resolution context from the promise + // Get info about the resolution context from the promise // we want to know where it was resolved, where the value is coming from ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent()); + getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_SCHEDULE_PROMISE); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } From 4ce07e6597602652f6c2212ccaa1242fdb4e3b5a Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 1 Jul 2020 10:52:56 +0200 Subject: [PATCH 048/194] Move to SArguments the stack update - move implementation for saving previous entries corresponding to promise resolution to SArguments class --- src/som/interpreter/SArguments.java | 10 ++++++++-- src/som/interpreter/actors/EventualMessage.java | 16 +++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index f03ff82368..56d610ad0c 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -227,7 +227,13 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } } - public static void addEntryForPromiseResolution(ShadowStackEntry current, ShadowStackEntry promiseStack) { - current.setPrevious(promiseStack); + private static void addEntryForPromiseResolution(ShadowStackEntry currentStack, ShadowStackEntry previousStack) { + currentStack.setPrevious(previousStack); + } + + public static void saveCausalEntryForPromiseInAsyncStack(Object previousPromiseStack, Object currentPromiseStack) { + assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; + assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; + SArguments.addEntryForPromiseResolution((ShadowStackEntry) currentPromiseStack, (ShadowStackEntry) previousPromiseStack); } } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 4fb5a39cca..2ff7f45753 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -334,10 +334,7 @@ private void determineAndSetTarget(final Object rcvr, final Actor target, //save promise resolution entry corresponding to the promise to which the message is sent if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - assert maybeEntry != null && maybeEntry instanceof ShadowStackEntry.EntryForPromiseResolution; - assert args[args.length - 1] instanceof ShadowStackEntry.EntryAtMessageSend; - ShadowStackEntry.EntryAtMessageSend currentStack = (ShadowStackEntry.EntryAtMessageSend) args[args.length - 1]; - SArguments.addEntryForPromiseResolution(currentStack, (ShadowStackEntry.EntryForPromiseResolution)maybeEntry); + SArguments.saveCausalEntryForPromiseInAsyncStack(maybeEntry, args[args.length - 1]); } } @@ -415,7 +412,6 @@ protected AbstractPromiseCallbackMessage(final Actor owner, final SBlock callbac @Override public void resolve(final Object rcvr, final Actor target, final Actor sendingActor, final Object maybeEntry) { - assert maybeEntry != null || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; setPromiseValue(rcvr, sendingActor, maybeEntry); } @@ -427,14 +423,12 @@ public void resolve(final Object rcvr, final Actor target, final Actor sendingAc */ private void setPromiseValue(final Object value, final Actor resolvingActor, final Object maybeEntry) { - args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); - //save promise resolution entry corresponding to the promise to which this callback is registered + args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, alue, resolvingActor, null); + //save promise resolution entry corresponding to the promise to which this callback is registered on if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - assert maybeEntry != null && maybeEntry instanceof ShadowStackEntry; - assert args[args.length - 1] instanceof ShadowStackEntry; - ShadowStackEntry currentStack = (ShadowStackEntry) args[args.length - 1]; - SArguments.addEntryForPromiseResolution(currentStack, (ShadowStackEntry) maybeEntry); + SArguments.saveCausalEntryForPromiseInAsyncStack(maybeEntry, args[args.length - 1]); } + if (VmSettings.SNAPSHOTS_ENABLED) { this.messageId = Math.min(this.messageId, ActorProcessingThread.currentThread().getSnapshotId()); From 3c3e180d6e886eedaca98ffe72e8dc07b68fa567 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 1 Jul 2020 11:41:05 +0200 Subject: [PATCH 049/194] Remove commented code - format code --- src/tools/asyncstacktraces/StackIterator.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 57e02bbe9a..4d827203bd 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -72,7 +72,7 @@ public static StackIterator createSuspensionIterator( public static class SuspensionIterator extends StackIterator { protected ArrayList frames; - protected int currentIndex = 0; + protected int currentIndex = 0; public SuspensionIterator(final Iterator localStack) { assert localStack != null; @@ -101,7 +101,7 @@ public StackFrame next() { public static class HaltIterator extends StackIterator { protected ArrayList frameInstances; - protected int currentIndex = 0; + protected int currentIndex = 0; public HaltIterator() { frameInstances = new ArrayList(); @@ -140,20 +140,19 @@ public StackFrame next() { } /** - * * @author clementbera - * - * By contrast to HaltIterator and Suspension Iterator, the ShadowStackIterator use - * the stack for the first frame only and then rely on shadow stack entry to get the - * following stack entries + *

+ * By contrast to HaltIterator and Suspension Iterator, the ShadowStackIterator use + * the stack for the first frame only and then rely on shadow stack entry to get the + * following stack entries */ public abstract static class ShadowStackIterator extends StackIterator { private ShadowStackEntry currentSSEntry; - protected boolean first; - private Node currentNode; - private Invokable currentMethod; + protected boolean first; + private Node currentNode; + private Invokable currentMethod; private ShadowStackEntry useAgainShadowEntry; - private Frame useAgainFrame; + private Frame useAgainFrame; private StackFrame topFrame; public ShadowStackIterator() { @@ -251,13 +250,7 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { EntryForPromiseResolution.ResolutionLocation resolutionLocation = ((EntryForPromiseResolution) shadow).resolutionLocation; - if (shadow.expression instanceof EagerBinaryPrimitiveNode) { - EagerBinaryPrimitiveNode node = (EagerBinaryPrimitiveNode)shadow.expression; - name = resolutionLocation.getValue() +": "+node.getOperation(); //this means the promise of this callback was resolved - - } else { - name = resolutionLocation.getValue() +": "+shadow.expression.getRootNode().getName(); - } + name = resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName(); } } else { @@ -327,8 +320,8 @@ public boolean shouldUsePreviousShadowStackEntry(final Invokable currentMethod, protected static final class StackFrameDescription { SourceSection sourceSection; - Frame frame; - RootNode rootNode; + Frame frame; + RootNode rootNode; public StackFrameDescription(final SourceSection sourceSection, final Frame frame, final RootNode rootNode) { From 3faab05390dba90337074633cc72d6dc567392d5 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 1 Jul 2020 15:54:30 +0200 Subject: [PATCH 050/194] Minor rename in SArguments --- src/som/interpreter/SArguments.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 56d610ad0c..4d42ed1869 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -227,13 +227,13 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } } - private static void addEntryForPromiseResolution(ShadowStackEntry currentStack, ShadowStackEntry previousStack) { + private static void setEntryForPromiseResolution(ShadowStackEntry currentStack, ShadowStackEntry previousStack) { currentStack.setPrevious(previousStack); } public static void saveCausalEntryForPromiseInAsyncStack(Object previousPromiseStack, Object currentPromiseStack) { assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; - SArguments.addEntryForPromiseResolution((ShadowStackEntry) currentPromiseStack, (ShadowStackEntry) previousPromiseStack); + SArguments.setEntryForPromiseResolution((ShadowStackEntry) currentPromiseStack, (ShadowStackEntry) previousPromiseStack); } } From a32ae73562129d666e695f8efebb41861bd48413 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 2 Jul 2020 15:38:13 +0200 Subject: [PATCH 051/194] Add promise dependencies in promises group (WIP) - add dependencies in the stack to show all resolved promises of a promise group - TODO: check why for some actors all the promises in the group are not shown --- src/som/interpreter/SArguments.java | 61 +++++++++++++++++-- .../interpreter/actors/EventualMessage.java | 12 +++- .../asyncstacktraces/ShadowStackEntry.java | 28 +++++---- 3 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 4d42ed1869..3dce2cc81d 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -7,7 +7,8 @@ import som.vm.constants.Classes; import som.vmobjects.SArray; import som.vmobjects.SArray.SImmutableArray; -import java.util.Arrays; + +import java.util.*; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.frame.VirtualFrame; @@ -227,13 +228,61 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } } - private static void setEntryForPromiseResolution(ShadowStackEntry currentStack, ShadowStackEntry previousStack) { - currentStack.setPrevious(previousStack); - } - + //set the resolution of the promise for the registered callback public static void saveCausalEntryForPromiseInAsyncStack(Object previousPromiseStack, Object currentPromiseStack) { assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; - SArguments.setEntryForPromiseResolution((ShadowStackEntry) currentPromiseStack, (ShadowStackEntry) previousPromiseStack); + ((ShadowStackEntry) currentPromiseStack).setPreviousShadowStackEntry((ShadowStackEntry) previousPromiseStack); + } + + private static Map previousPromiseInGroupByActor = null; + + public static void setEntryForPromiseGroup(Object previousPromiseStack, Object callbackPromiseStack, long actorId) { + if (previousPromiseInGroupByActor != null && previousPromiseInGroupByActor.containsKey(actorId)) { + ShadowStackEntry firstPromise = previousPromiseInGroupByActor.get(actorId).getPreviousShadowStackEntry(); + + //group frames of the previous promise with the frames of the new promise, and then set the grouped stack entries for the callback + ShadowStackEntry groupedFrames = groupFrames(firstPromise, (ShadowStackEntry) previousPromiseStack); + saveCausalEntryForPromiseInAsyncStack(groupedFrames, callbackPromiseStack); + + } else { + saveCausalEntryForPromiseInAsyncStack(previousPromiseStack, callbackPromiseStack); + previousPromiseInGroupByActor = new HashMap<>(); + previousPromiseInGroupByActor.put(actorId, (ShadowStackEntry) callbackPromiseStack); + } + } + + //group non repeated frames + private static ShadowStackEntry groupFrames(ShadowStackEntry firstPromiseStack, ShadowStackEntry secondPromiseStack) { + List listSecond = getAllEntries(secondPromiseStack, new ArrayList<>()); + List listFirst = getAllEntries(firstPromiseStack, new ArrayList<>()); + + ShadowStackEntry group = setNewEntryAtEqualSourceSection(firstPromiseStack, listFirst, listSecond); + + return group; + } + + private static List getAllEntries(ShadowStackEntry stackEntry, List list) { + if (stackEntry == null) { + return list; + } else { + list.add(stackEntry); + getAllEntries(stackEntry.getPreviousShadowStackEntry(), list); + } + return list; + } + + private static ShadowStackEntry setNewEntryAtEqualSourceSection(ShadowStackEntry stackEntryToSet, List listFirst, List listSecond ) { + for (ShadowStackEntry entrySecond: listSecond) { + for (ShadowStackEntry entryFirst: listFirst) { + boolean entryFirstNotNull = entryFirst.getPreviousShadowStackEntry()!= null && entryFirst.getPreviousShadowStackEntry().getExpression()!= null; + boolean entrySecondNotNull = entrySecond.getPreviousShadowStackEntry()!= null && entrySecond.getPreviousShadowStackEntry().getExpression()!= null; + if (entryFirstNotNull && entrySecondNotNull && entrySecond.getPreviousShadowStackEntry().getSourceSection().equals(entryFirst.getPreviousShadowStackEntry().getSourceSection())) { + entrySecond.setPreviousShadowStackEntry(stackEntryToSet); + return listSecond.get(0); //return top entry with the update + } + } + } + return listSecond.get(0);//return top entry } } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 2ff7f45753..8994a014dc 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -51,6 +51,7 @@ public abstract class EventualMessage { protected EventualMessage(final Object[] args, final SResolver resolver, final RootCallTarget onReceive, final boolean haltOnReceive, final boolean haltOnResolver) { + this.args = args; this.resolver = resolver; this.onReceive = onReceive; @@ -398,6 +399,7 @@ public abstract static class AbstractPromiseCallbackMessage extends PromiseMessa * The promise on which this callback is registered on. */ @CompilationFinal protected SPromise promise; + @CompilationFinal protected SBlock callback; protected AbstractPromiseCallbackMessage(final Actor owner, final SBlock callback, final SResolver resolver, final RootCallTarget onReceive, @@ -407,6 +409,7 @@ protected AbstractPromiseCallbackMessage(final Actor owner, final SBlock callbac resolver, onReceive, triggerMessageReceiverBreakpoint, triggerPromiseResolverBreakpoint); this.promise = promiseRegisteredOn; + this.callback = callback; } @Override @@ -426,7 +429,14 @@ private void setPromiseValue(final Object value, final Actor resolvingActor, args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, alue, resolvingActor, null); //save promise resolution entry corresponding to the promise to which this callback is registered on if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - SArguments.saveCausalEntryForPromiseInAsyncStack(maybeEntry, args[args.length - 1]); + boolean promiseGroup = this.callback.getMethod().getInvokable().getName().startsWith("PromiseGroup"); +// System.out.println("owner "+promise.getOwner().getId() + " group "+promiseGroup + " maybe "+((ShadowStackEntry)maybeEntry).getSourceSection() + " callback "+ ((ShadowStackEntry)args[args.length - 1]).getSourceSection()); + + if (promiseGroup) { + SArguments.setEntryForPromiseGroup(maybeEntry, args[args.length - 1], promise.getOwner().getId()); + } else { + SArguments.saveCausalEntryForPromiseInAsyncStack(maybeEntry, args[args.length - 1]); + } } if (VmSettings.SNAPSHOTS_ENABLED) { diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/asyncstacktraces/ShadowStackEntry.java index 71828c703e..8800ce7e56 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/asyncstacktraces/ShadowStackEntry.java @@ -13,7 +13,7 @@ public class ShadowStackEntry { protected ShadowStackEntry previous; - protected final Node expression; + protected final Node expression; public static long numberOfAllocations; @@ -66,14 +66,14 @@ protected ShadowStackEntry(final ShadowStackEntry previous, final Node expr) { } } - public static Actor getCurrentActorOrNull() { - Thread t = Thread.currentThread(); - if (t instanceof ActorProcessingThread) { - return EventualMessage.getActorCurrentMessageIsExecutionOn(); - } else { - return null; - } - } +// public static Actor getCurrentActorOrNull() { +// Thread t = Thread.currentThread(); +// if (t instanceof ActorProcessingThread) { +// return EventualMessage.getActorCurrentMessageIsExecutionOn(); +// } else { +// return null; +// } +// } public RootNode getRootNode() { return expression.getRootNode(); @@ -87,7 +87,7 @@ public boolean isAsync() { return false; } - public void setPrevious(ShadowStackEntry maybeEntry) { + public void setPreviousShadowStackEntry(ShadowStackEntry maybeEntry) { previous = maybeEntry; } @@ -100,10 +100,10 @@ private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { public static final class EntryForPromiseResolution extends ShadowStackEntry { public enum ResolutionLocation { - ERROR("on error"), SUCCESSFUL ("on resolution"), + ERROR("on error"), SUCCESSFUL("on resolution"), CHAINED("on chain"), ON_CALLBACK("on callback"), ON_WHEN_RESOLVED("on when resolved"), ON_CALLBACK_ERROR("on callback error"), - ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE ("on schedule"); + ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE("on schedule"); private final String value; @@ -115,7 +115,8 @@ public String getValue() { return value; } } - ResolutionLocation resolutionLocation; + + public ResolutionLocation resolutionLocation; private EntryForPromiseResolution(final ShadowStackEntry previous, final Node expr, ResolutionLocation resolutionLocation) { @@ -127,5 +128,6 @@ private EntryForPromiseResolution(final ShadowStackEntry previous, public boolean isAsync() { return true; } + } } From 76bedbc025a4816d27031cd3b36b285cc02efee0 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 3 Jul 2020 08:58:43 +0200 Subject: [PATCH 052/194] Minor renaming and comments --- src/som/interpreter/SArguments.java | 15 ++++++++------- src/som/interpreter/actors/EventualMessage.java | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 3dce2cc81d..554b9b2a56 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -228,8 +228,8 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } } - //set the resolution of the promise for the registered callback - public static void saveCausalEntryForPromiseInAsyncStack(Object previousPromiseStack, Object currentPromiseStack) { + //set the resolution of the promise for the registered callback or message sent to a promise + public static void saveCausalEntryForPromise(Object previousPromiseStack, Object currentPromiseStack) { assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; ((ShadowStackEntry) currentPromiseStack).setPreviousShadowStackEntry((ShadowStackEntry) previousPromiseStack); @@ -237,16 +237,16 @@ public static void saveCausalEntryForPromiseInAsyncStack(Object previousPromiseS private static Map previousPromiseInGroupByActor = null; - public static void setEntryForPromiseGroup(Object previousPromiseStack, Object callbackPromiseStack, long actorId) { + public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, Object callbackPromiseStack, long actorId) { if (previousPromiseInGroupByActor != null && previousPromiseInGroupByActor.containsKey(actorId)) { ShadowStackEntry firstPromise = previousPromiseInGroupByActor.get(actorId).getPreviousShadowStackEntry(); //group frames of the previous promise with the frames of the new promise, and then set the grouped stack entries for the callback ShadowStackEntry groupedFrames = groupFrames(firstPromise, (ShadowStackEntry) previousPromiseStack); - saveCausalEntryForPromiseInAsyncStack(groupedFrames, callbackPromiseStack); + saveCausalEntryForPromise(groupedFrames, callbackPromiseStack); } else { - saveCausalEntryForPromiseInAsyncStack(previousPromiseStack, callbackPromiseStack); + saveCausalEntryForPromise(previousPromiseStack, callbackPromiseStack); previousPromiseInGroupByActor = new HashMap<>(); previousPromiseInGroupByActor.put(actorId, (ShadowStackEntry) callbackPromiseStack); } @@ -272,13 +272,14 @@ private static List getAllEntries(ShadowStackEntry stackEntry, return list; } - private static ShadowStackEntry setNewEntryAtEqualSourceSection(ShadowStackEntry stackEntryToSet, List listFirst, List listSecond ) { + //equal source section corresponds to the turn node, from there on the stack frames are the same for both promises stacks + private static ShadowStackEntry setNewEntryAtEqualSourceSection(ShadowStackEntry stackEntryToAdd, List listFirst, List listSecond ) { for (ShadowStackEntry entrySecond: listSecond) { for (ShadowStackEntry entryFirst: listFirst) { boolean entryFirstNotNull = entryFirst.getPreviousShadowStackEntry()!= null && entryFirst.getPreviousShadowStackEntry().getExpression()!= null; boolean entrySecondNotNull = entrySecond.getPreviousShadowStackEntry()!= null && entrySecond.getPreviousShadowStackEntry().getExpression()!= null; if (entryFirstNotNull && entrySecondNotNull && entrySecond.getPreviousShadowStackEntry().getSourceSection().equals(entryFirst.getPreviousShadowStackEntry().getSourceSection())) { - entrySecond.setPreviousShadowStackEntry(stackEntryToSet); + entrySecond.setPreviousShadowStackEntry(stackEntryToAdd); return listSecond.get(0); //return top entry with the update } } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 8994a014dc..25eddf24fc 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -335,7 +335,7 @@ private void determineAndSetTarget(final Object rcvr, final Actor target, //save promise resolution entry corresponding to the promise to which the message is sent if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - SArguments.saveCausalEntryForPromiseInAsyncStack(maybeEntry, args[args.length - 1]); + SArguments.saveCausalEntryForPromise(maybeEntry, args[args.length - 1]); } } @@ -433,9 +433,9 @@ private void setPromiseValue(final Object value, final Actor resolvingActor, // System.out.println("owner "+promise.getOwner().getId() + " group "+promiseGroup + " maybe "+((ShadowStackEntry)maybeEntry).getSourceSection() + " callback "+ ((ShadowStackEntry)args[args.length - 1]).getSourceSection()); if (promiseGroup) { - SArguments.setEntryForPromiseGroup(maybeEntry, args[args.length - 1], promise.getOwner().getId()); + SArguments.saveCausalEntryForPromiseGroup(maybeEntry, args[args.length - 1], promise.getOwner().getId()); } else { - SArguments.saveCausalEntryForPromiseInAsyncStack(maybeEntry, args[args.length - 1]); + SArguments.saveCausalEntryForPromise(maybeEntry, args[args.length - 1]); } } From d5ab428df086734c03e39a3c993eaf11dc5205e5 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 3 Jul 2020 10:32:06 +0200 Subject: [PATCH 053/194] Change label for async msg send frames --- src/tools/asyncstacktraces/StackIterator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 4d827203bd..9c9a9c1198 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -241,7 +241,7 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, String symbol = ((EventualSendNode) sendNode).getSentSymbol().getString(); if (sendNode instanceof EventualSendNode) { - name = "at async message: " + symbol; + name = "on async message send: " + symbol; } else { name = "EntryAtMessageSend: " + shadow.expression.getRootNode().getName(); From 88dd35f19b8fa4c0a450bc49020cf4c650898404 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 6 Jul 2020 11:20:39 +0200 Subject: [PATCH 054/194] Add promise resolution information async stack - add actor id in each shadow entry of the async stack, to be shown as part of the frame information - update tags label - add entry to indicate when a promise has been resolve with a value, with a promise and with an error - TODO: check TruffleBoundary annotations in SPromise - TODO: check promise group dependencies --- .../actors/AbstractPromiseResolutionNode.java | 20 +++++---- src/som/interpreter/actors/ErrorNode.java | 16 ++++++- .../interpreter/actors/EventualMessage.java | 8 +++- .../interpreter/actors/ReceivedMessage.java | 11 ++++- .../actors/RegisterOnPromiseNode.java | 10 +++-- src/som/interpreter/actors/ResolveNode.java | 18 +++++++- src/som/interpreter/actors/SPromise.java | 45 +++++++++++++------ .../actors/SchedulePromiseHandlerNode.java | 5 ++- .../asyncstacktraces/ShadowStackEntry.java | 33 +++++++++----- src/tools/asyncstacktraces/StackIterator.java | 32 +++++++------ .../frontend/ApplicationThreadStack.java | 2 +- 11 files changed, 143 insertions(+), 57 deletions(-) diff --git a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java index 4e6daa4cf3..54747b90ba 100644 --- a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java +++ b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java @@ -4,14 +4,17 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.GenerateWrapper; import com.oracle.truffle.api.instrumentation.ProbeNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.SourceSection; import bd.primitives.nodes.WithContext; import som.VM; +import som.interpreter.SArguments; import som.interpreter.actors.SPromise.Resolution; import som.interpreter.actors.SPromise.SReplayPromise; import som.interpreter.actors.SPromise.SResolver; @@ -19,6 +22,7 @@ import som.interpreter.nodes.nary.QuaternaryExpressionNode; import som.interpreter.nodes.nary.UnaryExpressionNode; import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; import tools.concurrency.KomposTrace; import tools.concurrency.TracingActivityThread; import tools.replay.ReplayRecord; @@ -122,7 +126,7 @@ public SResolver selfResolution(final SResolver resolver, public SResolver chainedPromise(final VirtualFrame frame, final SResolver resolver, final SPromise promiseValue, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { - chainPromise(resolver, promiseValue, maybeEntry, haltOnResolver, haltOnResolution); + chainPromise(frame, resolver, promiseValue, maybeEntry, haltOnResolver, haltOnResolution); return resolver; } @@ -130,7 +134,7 @@ protected static boolean notAPromise(final Object result) { return !(result instanceof SPromise); } - protected void chainPromise(final SResolver resolver, + protected void chainPromise(final VirtualFrame frame, final SResolver resolver, final SPromise promiseValue, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { assert resolver.assertNotCompleted(); @@ -155,7 +159,7 @@ protected void chainPromise(final SResolver resolver, if (SPromise.isCompleted(state)) { resolvePromise(state, resolver, promiseValue.getValueUnsync(), maybeEntry, - haltOnResolution); + haltOnResolution, frame, this); } else { synchronized (promiseToBeResolved) { // TODO: is this really deadlock free? if (haltOnResolution || promiseValue.getHaltOnResolution()) { @@ -181,23 +185,23 @@ protected void chainPromise(final SResolver resolver, protected void resolvePromise(final Resolution type, final SResolver resolver, final Object result, final Object maybeEntry, - final boolean haltOnResolution) { + final boolean haltOnResolution, final VirtualFrame frame, Node expression) { SPromise promise = resolver.getPromise(); Actor current = EventualMessage.getActorCurrentMessageIsExecutionOn(); resolve(type, wrapper, promise, result, current, actorPool, maybeEntry, haltOnResolution, - whenResolvedProfile, tracePromiseResolution, tracePromiseResolutionEnd); + whenResolvedProfile, frame, expression, tracePromiseResolution, tracePromiseResolutionEnd); } public static void resolve(final Resolution type, final WrapReferenceNode wrapper, final SPromise promise, - final Object result, final Actor current, final ForkJoinPool actorPool, maybeEntry, - final boolean haltOnResolution, final ValueProfile whenResolvedProfile, + final Object result, final Actor current, final ForkJoinPool actorPool, Object maybeEntry, + final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final VirtualFrame frame, Node expression, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { Object wrapped = wrapper.execute(result, promise.owner, current); SResolver.resolveAndTriggerListenersUnsynced(type, result, wrapped, promise, - current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, tracePromiseResolution2, + current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, tracePromiseResolution2, tracePromiseResolutionEnd2); } } diff --git a/src/som/interpreter/actors/ErrorNode.java b/src/som/interpreter/actors/ErrorNode.java index 876a5356ee..9c3671bf61 100644 --- a/src/som/interpreter/actors/ErrorNode.java +++ b/src/som/interpreter/actors/ErrorNode.java @@ -4,7 +4,10 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; import som.interpreter.SomLanguage; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; public abstract class ErrorNode extends AbstractPromiseResolutionNode { @CompilerDirectives.CompilationFinal @@ -29,7 +32,18 @@ public SPromise.SResolver standardError(final VirtualFrame frame, haltNode.executeEvaluated(frame, result); } - resolvePromise(SPromise.Resolution.ERRONEOUS, resolver, result, maybeEntry, haltOnResolution); + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ERROR; + location.setArg(", error: "+result.toString()); + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location); + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); + } + + resolvePromise(SPromise.Resolution.ERRONEOUS, resolver, result, resolutionEntry, haltOnResolution, frame, this.getParent()); return resolver; } } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 25eddf24fc..6c26c079da 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -7,6 +7,7 @@ import com.oracle.truffle.api.source.SourceSection; import som.VM; +import som.interpreter.Method; import som.interpreter.actors.Actor.ActorProcessingThread; import som.interpreter.actors.ReceivedMessage.ReceivedCallback; import som.interpreter.actors.SPromise.SResolver; @@ -429,7 +430,12 @@ private void setPromiseValue(final Object value, final Actor resolvingActor, args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, alue, resolvingActor, null); //save promise resolution entry corresponding to the promise to which this callback is registered on if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - boolean promiseGroup = this.callback.getMethod().getInvokable().getName().startsWith("PromiseGroup"); + assert args[args.length - 1] instanceof ShadowStackEntry; + ShadowStackEntry callPromiseStack = (ShadowStackEntry) args[args.length - 1]; + boolean promiseGroup = false; + if (callPromiseStack.getExpression().getParent().getParent() instanceof Method) { + promiseGroup = ((Method)callPromiseStack.getExpression().getParent().getParent()).getName().startsWith("PromiseGroup"); + } // System.out.println("owner "+promise.getOwner().getId() + " group "+promiseGroup + " maybe "+((ShadowStackEntry)maybeEntry).getSourceSection() + " callback "+ ((ShadowStackEntry)args[args.length - 1]).getSourceSection()); if (promiseGroup) { diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index c4d5e52aa0..9a330bbd0c 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -46,8 +46,11 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_RECEIVE_MESSAGE; +// onReceiveLocation.setArg(msg.getTarget().getId() + " sent by actor "+ msg.getSender().getId()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_RECEIVE_MESSAGE); + ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, onReceiveLocation); } try { @@ -123,8 +126,12 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_BLOCK; +// onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_CALLBACK); + ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), onReceiveLocation); + SArguments.setShadowStackEntry(msg.getArgs(), resolutionEntry); } diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 6af05ab4ec..68b1950005 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -89,20 +89,22 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro boolean promiseComplete = (obj instanceof SPromise) && ((SPromise) promise).isCompleted(); // boolean promiseChained = (obj instanceof SPromise) && !((SPromise) promise).isCompleted(); if (obj instanceof SBlock || promiseComplete) { + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED; +// onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); //for whenResolved blocks or if promise is resolved, then create EntryForPromiseResolution ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED); + getParent().getParent(), onReceiveLocation); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); - } // else if (promiseChained) { // ShadowStackEntry entry = (ShadowStackEntry) msg.args[msg.args.length - 1]; // assert entry != null && entry instanceof ShadowStackEntry.EntryAtMessageSend; // ShadowStackEntry shadowStackEntry = SArguments.getShadowStackEntry(frame); // -//// entry.setPrevious(shadowStackEntry); +//// entry.setPreviousShadowStackEntry(shadowStackEntry); // // System.out.println("-register msg args: "+entry.getSourceSection()); // System.out.println("shadow: "+shadowStackEntry.getSourceSection()); @@ -204,7 +206,7 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro // we want to know where it was resolved, where the value is coming from ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_CALLBACK_ERROR); + getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_ERROR); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java index d5de2932ea..44e5353696 100644 --- a/src/som/interpreter/actors/ResolveNode.java +++ b/src/som/interpreter/actors/ResolveNode.java @@ -3,7 +3,10 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import som.interpreter.SArguments; import som.interpreter.SomLanguage; +import som.vm.VmSettings; +import tools.asyncstacktraces.ShadowStackEntry; public abstract class ResolveNode extends AbstractPromiseResolutionNode { @@ -31,8 +34,19 @@ public SPromise.SResolver normalResolution(final VirtualFrame frame, haltNode.executeEvaluated(frame, result); } - resolvePromise(SPromise.Resolution.SUCCESSFUL, resolver, result, maybeEntry, - haltOnResolution || promise.getHaltOnResolution()); + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.SUCCESSFUL; + location.setArg(", value: "+result.toString()); + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location); + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); + } + + resolvePromise(SPromise.Resolution.SUCCESSFUL, resolver, result, resolutionEntry, + haltOnResolution || promise.getHaltOnResolution(), frame, this.getParent()); return resolver; } } diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index d52dbc5c4b..f0bca6475b 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -11,9 +11,13 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.SourceSection; +import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.interpreter.actors.EventualMessage.PromiseMessage; import som.interpreter.objectstorage.ClassFactory; @@ -21,6 +25,7 @@ import som.vm.VmSettings; import som.vmobjects.SClass; import som.vmobjects.SObjectWithClass; +import tools.asyncstacktraces.ShadowStackEntry; import tools.concurrency.KomposTrace; import tools.concurrency.TracingActivityThread; import tools.concurrency.TracingActors.TracingActor; @@ -770,11 +775,11 @@ public boolean assertNotCompleted() { */ // TODO: solve the TODO and then remove the TruffleBoundary, this might even need to go // into a node - @TruffleBoundary +// @TruffleBoundary protected static void resolveChainedPromisesUnsync(final Resolution type, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, - final ValueProfile whenResolvedProfile, final RecordOneEvent record, + final ValueProfile whenResolvedProfile, final VirtualFrame frame, final Node expression, final RecordOneEvent record, final RecordOneEvent recordStop) { // TODO: we should change the implementation of chained promises to // always move all the handlers to the other promise, then we @@ -784,25 +789,39 @@ protected static void resolveChainedPromisesUnsync(final Resolution type, if (promise.chainedPromise != null) { SPromise chainedPromise = promise.chainedPromise; promise.chainedPromise = null; - Object wrapped = - WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); + Object wrapped = WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); + + + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { +// MaterializedFrame context = promise.getContext(); + + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || maybeEntry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.CHAINED; + location.setArg(", promise: "+promise.toString()); + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, expression, location); + + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); + } + resolveAndTriggerListenersUnsynced(type, result, wrapped, - chainedPromise, current, actorPool, maybeEntry, - chainedPromise.haltOnResolution, whenResolvedProfile, record, recordStop); + chainedPromise, current, actorPool, maybeEntry, resolutionEntry, + chainedPromise.haltOnResolution, whenResolvedProfile, frame, expression, record, recordStop); resolveMoreChainedPromisesUnsynced(type, promise, result, current, - actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, record, recordStop); + actorPool, maybeEntry, resolutionEntry, haltOnResolution, whenResolvedProfile, frame, expression, record, recordStop); } } /** * Resolve the other promises that has been chained to the first promise. */ - @TruffleBoundary +// @TruffleBoundary private static void resolveMoreChainedPromisesUnsynced(final Resolution type, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, - final ValueProfile whenResolvedProfile, final RecordOneEvent record, - final RecordOneEvent recordStop) { + final ValueProfile whenResolvedProfile, final VirtualFrame frame, final Node expression, final VirtualFrame frame, final Node expression) { if (promise.chainedPromiseExt != null) { ArrayList chainedPromiseExt = promise.chainedPromiseExt; promise.chainedPromiseExt = null; @@ -810,7 +829,7 @@ private static void resolveMoreChainedPromisesUnsynced(final Resolution type, for (SPromise p : chainedPromiseExt) { Object wrapped = WrapReferenceNode.wrapForUse(p.owner, result, current, null); resolveAndTriggerListenersUnsynced(type, result, wrapped, p, current, - actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, record, recordStop); + actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, record, recordStop); } } } @@ -823,7 +842,7 @@ private static void resolveMoreChainedPromisesUnsynced(final Resolution type, protected static void resolveAndTriggerListenersUnsynced(final Resolution type, final Object result, final Object wrapped, final SPromise p, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, - final ValueProfile whenResolvedProfile, final RecordOneEvent tracePromiseResolution2, + final ValueProfile whenResolvedProfile, final VirtualFrame frame, Node expression, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { assert !(result instanceof SPromise); @@ -874,7 +893,7 @@ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, scheduleAllOnErrorUnsync(p, result, current, actorPool, maybeEntry, haltOnResolution); } resolveChainedPromisesUnsync(type, p, result, current, actorPool, maybeEntry, haltOnResolution, - whenResolvedProfile, tracePromiseResolution2, tracePromiseResolutionEnd2); + whenResolvedProfile, frame, expression, tracePromiseResolution2, tracePromiseResolutionEnd2); if (VmSettings.SENDER_SIDE_TRACING) { tracePromiseResolutionEnd2.record(((STracingPromise) p).version); diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index 7b4cf6f878..b808868c2b 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -52,9 +52,12 @@ public final void schedule(final VirtualFrame frame, final SPromise promise, if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { // Get info about the resolution context from the promise // we want to know where it was resolved, where the value is coming from + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_SCHEDULE_PROMISE; +// onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_SCHEDULE_PROMISE); + getParent().getParent(), onReceiveLocation); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/asyncstacktraces/ShadowStackEntry.java index 8800ce7e56..e37665f0af 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/asyncstacktraces/ShadowStackEntry.java @@ -14,6 +14,7 @@ public class ShadowStackEntry { protected ShadowStackEntry previous; protected final Node expression; + protected final long actorId; public static long numberOfAllocations; @@ -64,16 +65,17 @@ protected ShadowStackEntry(final ShadowStackEntry previous, final Node expr) { if (ALLOCATION_COUNT) { numberOfAllocations++; } + this.actorId = getCurrentActor(); } -// public static Actor getCurrentActorOrNull() { -// Thread t = Thread.currentThread(); -// if (t instanceof ActorProcessingThread) { -// return EventualMessage.getActorCurrentMessageIsExecutionOn(); -// } else { -// return null; -// } -// } + public long getCurrentActor() { + Thread t = Thread.currentThread(); + if (t instanceof ActorProcessingThread) { + return EventualMessage.getActorCurrentMessageIsExecutionOn().getId(); + } else { + return -1l; + } + } public RootNode getRootNode() { return expression.getRootNode(); @@ -100,12 +102,13 @@ private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { public static final class EntryForPromiseResolution extends ShadowStackEntry { public enum ResolutionLocation { - ERROR("on error"), SUCCESSFUL("on resolution"), - CHAINED("on chain"), ON_CALLBACK("on callback"), - ON_WHEN_RESOLVED("on when resolved"), ON_CALLBACK_ERROR("on callback error"), + SUCCESSFUL("resolved with a value"), ERROR("resolved with an error"), + CHAINED("resolved with a promise"), ON_WHEN_RESOLVED_BLOCK("on whenResolved block"), + ON_WHEN_RESOLVED("on whenResolved"), ON_WHEN_RESOLVED_ERROR("on whenResolved error"), ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE("on schedule"); private final String value; + private String arg = ""; ResolutionLocation(String value) { this.value = value; @@ -114,6 +117,14 @@ public enum ResolutionLocation { public String getValue() { return value; } + + public String getArg() { + return arg; + } + + public void setArg(String arg){ + this.arg = arg; + } } public ResolutionLocation resolutionLocation; diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 9c9a9c1198..4edd08bded 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -61,9 +61,9 @@ public static StackIterator createHaltIterator() { } public static StackIterator createSuspensionIterator( - final Iterator localStack) { + final Iterator localStack, long actorId) { if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - return new SuspensionShadowStackIterator(localStack); + return new SuspensionShadowStackIterator(localStack, actorId); } else { return new SuspensionIterator(localStack); } @@ -212,8 +212,8 @@ protected StackFrame nextAsyncStackStructure() { public StackFrame getTopFrame() { if (first) { StackFrameDescription frameDescription = getFirstFrame(); - - topFrame = new StackFrame(frameDescription.getRootNode().getName(), frameDescription.getRootNode(), + String actor = "actor " + frameDescription.getActorId() + ", "; + topFrame = new StackFrame(actor.concat(frameDescription.getRootNode().getName()), frameDescription.getRootNode(), frameDescription.getSourceSection(), frameDescription.getFrame(), false); } return topFrame; @@ -229,7 +229,7 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, } boolean contextTransitionElement; - String name = shadow.getRootNode().getName(); + String name = "actor " + shadow.actorId + ", " + shadow.getRootNode().getName(); SourceSection location = shadow.getSourceSection(); if (!usedAgain && (shadow instanceof EntryAtMessageSend @@ -241,16 +241,14 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, String symbol = ((EventualSendNode) sendNode).getSentSymbol().getString(); if (sendNode instanceof EventualSendNode) { - name = "on async message send: " + symbol; + name = "actor " + shadow.actorId + ", on async message send: " + symbol; - } else { - name = "EntryAtMessageSend: " + shadow.expression.getRootNode().getName(); } useAgainShadowEntry = shadow; useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { EntryForPromiseResolution.ResolutionLocation resolutionLocation = ((EntryForPromiseResolution) shadow).resolutionLocation; - name = resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName(); + name = "actor " + shadow.actorId + ", "+resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName() + " "+resolutionLocation.getArg(); } } else { @@ -322,12 +320,14 @@ protected static final class StackFrameDescription { SourceSection sourceSection; Frame frame; RootNode rootNode; + long actorId; public StackFrameDescription(final SourceSection sourceSection, - final Frame frame, final RootNode rootNode) { + final Frame frame, final RootNode rootNode, long actorId) { this.sourceSection = sourceSection; this.frame = frame; this.rootNode = rootNode; + this.actorId = actorId; } public SourceSection getSourceSection() { @@ -341,17 +341,23 @@ public Frame getFrame() { public RootNode getRootNode() { return rootNode; } + + public long getActorId() { + return actorId; + } } public static final class SuspensionShadowStackIterator extends ShadowStackIterator { private final DebugStackFrame firstDebugFrame; private StackFrameDescription firstFrameDescription; + private long actorId; - public SuspensionShadowStackIterator(final Iterator localStack) { + public SuspensionShadowStackIterator(final Iterator localStack, long actorId) { assert localStack != null; assert localStack.hasNext(); firstDebugFrame = localStack.next(); //only takes the first frame firstFrameDescription = null; + this.actorId = actorId; } @Override @@ -359,7 +365,7 @@ protected StackFrameDescription getFirstFrame() { assert first; if (firstFrameDescription == null) { firstFrameDescription = new StackFrameDescription(firstDebugFrame.getSourceSection(), firstDebugFrame.getFrame(), - firstDebugFrame.getRootNode()); + firstDebugFrame.getRootNode(), this.actorId); } return firstFrameDescription; } @@ -390,7 +396,7 @@ protected StackFrameDescription getFirstFrame() { } return new StackFrameDescription(ss, firstFrameInstance.getFrame(FrameAccess.READ_ONLY), - rootNode); + rootNode, -1); } } } diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 161d590056..a1b4877bbc 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -66,7 +66,7 @@ public boolean hasFrame() { ArrayList get() { if (stackFrames.isEmpty()) { StackIterator stack = - StackIterator.createSuspensionIterator(event.getStackFrames().iterator()); + StackIterator.createSuspensionIterator(event.getStackFrames().iterator(), suspension.getActivity().getId()); if (stack instanceof StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) { StackFrame topFrame = ((StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) stack).getTopFrame(); From b04b7f14e1f30021631091a01fbb0c84178b6121 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 14 Jul 2020 14:49:32 +0200 Subject: [PATCH 055/194] Add frame for explicit resolver - save available frames when creating the async stack frame in StackIterator. this is needed for example to get the first frame when a promise resolver breakpoint has been set for an explicit promise (createPromisePair). --- src/tools/asyncstacktraces/StackIterator.java | 37 +++++++++++++++++-- .../frontend/ApplicationThreadStack.java | 2 - 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 4edd08bded..66eb768920 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -14,7 +14,6 @@ import som.interpreter.Method; import som.interpreter.actors.EventualSendNode; import som.interpreter.nodes.dispatch.BackCacheCallNode; -import som.interpreter.nodes.nary.EagerBinaryPrimitiveNode; import som.vm.VmSettings; import tools.asyncstacktraces.ShadowStackEntry.EntryAtMessageSend; import tools.asyncstacktraces.ShadowStackEntry.EntryForPromiseResolution; @@ -24,6 +23,7 @@ import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; @@ -168,6 +168,8 @@ public boolean hasNext() { protected abstract StackFrameDescription getFirstFrame(); + protected abstract StackFrameDescription getFrameBySource(SourceSection sourceSection); + @Override public StackFrame next() { if (!hasNext()) { @@ -220,7 +222,7 @@ public StackFrame getTopFrame() { } protected StackFrame createStackFrame(final ShadowStackEntry shadow, - final Frame localFrame, final boolean usedAgain) { + Frame localFrame, final boolean usedAgain) { if (shadow == null) { return null; } @@ -248,10 +250,14 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { EntryForPromiseResolution.ResolutionLocation resolutionLocation = ((EntryForPromiseResolution) shadow).resolutionLocation; - name = "actor " + shadow.actorId + ", "+resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName() + " "+resolutionLocation.getArg(); + name = "actor " + shadow.actorId + ", " + resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName() + " " + resolutionLocation.getArg(); } } else { + StackFrameDescription frameByName = getFrameBySource(location); + if (frameByName != null && localFrame == null) { + localFrame = frameByName.frame; + } contextTransitionElement = false; } @@ -351,13 +357,19 @@ public static final class SuspensionShadowStackIterator extends ShadowStackItera private final DebugStackFrame firstDebugFrame; private StackFrameDescription firstFrameDescription; private long actorId; + private List allFrames; public SuspensionShadowStackIterator(final Iterator localStack, long actorId) { assert localStack != null; assert localStack.hasNext(); - firstDebugFrame = localStack.next(); //only takes the first frame + firstDebugFrame = localStack.next(); //first frame firstFrameDescription = null; this.actorId = actorId; + + allFrames = new ArrayList(); + while (localStack.hasNext()) { + allFrames.add(localStack.next()); //save all frames + } } @Override @@ -369,6 +381,18 @@ protected StackFrameDescription getFirstFrame() { } return firstFrameDescription; } + + public StackFrameDescription getFrameBySource(SourceSection sourceSection) { + if (!allFrames.isEmpty()) { + for (DebugStackFrame debugStackFrame : allFrames) { + if (debugStackFrame.getSourceSection() != null && debugStackFrame.getSourceSection().equals(sourceSection)) { + return new StackFrameDescription(debugStackFrame.getSourceSection(), debugStackFrame.getFrame(), + debugStackFrame.getRootNode(), this.actorId); + } + } + } + return null; + } } public static final class HaltShadowStackIterator extends ShadowStackIterator { @@ -398,6 +422,11 @@ protected StackFrameDescription getFirstFrame() { firstFrameInstance.getFrame(FrameAccess.READ_ONLY), rootNode, -1); } + + @Override + protected StackFrameDescription getFrameBySource(SourceSection sourceSection) { + return null; + } } } } diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index a1b4877bbc..331a9d22df 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -78,8 +78,6 @@ ArrayList get() { StackFrame next = stack.next(); if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values for null shadows stackFrames.add(next); - } else { -// System.out.println("null frame"); } } assert !stackFrames.isEmpty() From 355198c90cf044a017fb6504a6e523df0c104ea5 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 14 Jul 2020 14:57:44 +0200 Subject: [PATCH 056/194] Remove unnecessary condition --- src/tools/asyncstacktraces/StackIterator.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 66eb768920..41dd589a2d 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -383,14 +383,13 @@ protected StackFrameDescription getFirstFrame() { } public StackFrameDescription getFrameBySource(SourceSection sourceSection) { - if (!allFrames.isEmpty()) { - for (DebugStackFrame debugStackFrame : allFrames) { - if (debugStackFrame.getSourceSection() != null && debugStackFrame.getSourceSection().equals(sourceSection)) { - return new StackFrameDescription(debugStackFrame.getSourceSection(), debugStackFrame.getFrame(), - debugStackFrame.getRootNode(), this.actorId); - } + for (DebugStackFrame debugStackFrame : allFrames) { + if (debugStackFrame.getSourceSection() != null && debugStackFrame.getSourceSection().equals(sourceSection)) { + return new StackFrameDescription(debugStackFrame.getSourceSection(), debugStackFrame.getFrame(), + debugStackFrame.getRootNode(), this.actorId); } } + return null; } } From 01b3ef8cf24179e1db206f33d306453d23fd860b Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 14 Jul 2020 14:58:20 +0200 Subject: [PATCH 057/194] Fix typo --- src/tools/debugger/frontend/RuntimeScope.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/debugger/frontend/RuntimeScope.java b/src/tools/debugger/frontend/RuntimeScope.java index 759446d6bb..5302227cad 100644 --- a/src/tools/debugger/frontend/RuntimeScope.java +++ b/src/tools/debugger/frontend/RuntimeScope.java @@ -11,10 +11,10 @@ public class RuntimeScope { private final Frame frame; private final MethodScope lexicalScope; - public RuntimeScope(final Frame frame, final MethodScope lexcialScope) { + public RuntimeScope(final Frame frame, final MethodScope lexicalScope) { this.frame = frame; - this.lexicalScope = lexcialScope; - assert frame.getFrameDescriptor() == lexcialScope.getFrameDescriptor(); + this.lexicalScope = lexicalScope; + assert frame.getFrameDescriptor() == lexicalScope.getFrameDescriptor(); } public Variable[] getVariables() { From e91909c1def336d457923e2262a6108a4251a8f5 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 14 Jul 2020 16:02:44 +0200 Subject: [PATCH 058/194] Fix bug when getting the top frame - TODO: think how avoid sequential stepping in message context, developer should not be able to trigger them. --- src/tools/asyncstacktraces/StackIterator.java | 17 +- src/tools/concurrency/TracingActors.java | 2 +- .../frontend/ApplicationThreadStack.java | 173 +++++++++--------- 3 files changed, 102 insertions(+), 90 deletions(-) diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/asyncstacktraces/StackIterator.java index 41dd589a2d..c10caada01 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/asyncstacktraces/StackIterator.java @@ -191,8 +191,11 @@ protected StackFrame nextAsyncStackStructure() { StackFrameDescription firstFrame = getFirstFrame(); localFrame = firstFrame.getFrame(); Object[] args = localFrame.getArguments(); - assert args[args.length - 1] instanceof ShadowStackEntry; - currentSSEntry = (ShadowStackEntry) args[args.length - 1]; + // assert args[args.length - 1] instanceof ShadowStackEntry; + if(args[args.length - 1] instanceof ShadowStackEntry) { + currentSSEntry = (ShadowStackEntry) args[args.length - 1]; + } + first = false; } else if (useAgainShadowEntry != null) { @@ -215,8 +218,16 @@ public StackFrame getTopFrame() { if (first) { StackFrameDescription frameDescription = getFirstFrame(); String actor = "actor " + frameDescription.getActorId() + ", "; - topFrame = new StackFrame(actor.concat(frameDescription.getRootNode().getName()), frameDescription.getRootNode(), + String name; + if (frameDescription.getRootNode().getName() != null) { //case of ExecutorRootNode + String rootNodeName = frameDescription.getRootNode().getName(); + name = actor.concat(rootNodeName); + } else { + name = actor; + } + topFrame = new StackFrame(name, frameDescription.getRootNode(), frameDescription.getSourceSection(), frameDescription.getFrame(), false); + } return topFrame; } diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index f4dad029ec..df54a9a96d 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -163,7 +163,7 @@ public static void stopActorsIfSuspended() { for (long actorId: allActors.keySet()) { if (actorId > 0) { //do not stop Platform actor Suspension suspension = debugger.getSuspension(actorId); - if (suspension != null && suspension.getEvent() != null) { + if (suspension != null && suspension.getEvent() != null && !suspension.getEvent().isDisposed()) { suspension.getEvent().prepareKill(); suspension.resume(); } diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 331a9d22df..1981dd0092 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -18,98 +18,99 @@ */ public class ApplicationThreadStack { - /** - * Track scopes that contain variables as well as objects. - * These have been identified in the debugger, i.e., they got an id for - * direct access. - */ - final ArrayList scopesAndObjects; - final HashMap scopesAndObjectsSet; - - private final ArrayList stackFrames; - private final SuspendedEvent event; - private final Suspension suspension; - - public static final class StackFrame { - public final String name; - public final SourceSection section; - public final Frame frame; - public final boolean asyncOperation; - private final RootNode root; - - public StackFrame(final String name, final RootNode root, final SourceSection section, - final Frame frame, final boolean asyncOperation) { - this.name = name; - this.root = root; - this.section = section; - this.frame = frame; - this.asyncOperation = asyncOperation; + /** + * Track scopes that contain variables as well as objects. + * These have been identified in the debugger, i.e., they got an id for + * direct access. + */ + final ArrayList scopesAndObjects; + final HashMap scopesAndObjectsSet; + + private final ArrayList stackFrames; + private final SuspendedEvent event; + private final Suspension suspension; + + public static final class StackFrame { + public final String name; + public final SourceSection section; + public final Frame frame; + public final boolean asyncOperation; + private final RootNode root; + + public StackFrame(final String name, final RootNode root, final SourceSection section, + final Frame frame, final boolean asyncOperation) { + this.name = name; + this.root = root; + this.section = section; + this.frame = frame; + this.asyncOperation = asyncOperation; + } + + public RootNode getRootNode() { + return root; + } + + public boolean hasFrame() { + return frame != null; + } } - public RootNode getRootNode() { - return root; + ApplicationThreadStack(final SuspendedEvent event, final Suspension suspension) { + this.event = event; + this.stackFrames = new ArrayList<>(); + this.scopesAndObjects = new ArrayList<>(); + this.scopesAndObjectsSet = new HashMap<>(); + this.suspension = suspension; } - public boolean hasFrame() { - return frame != null; + ArrayList get() { + if (stackFrames.isEmpty()) { + StackIterator stack = + StackIterator.createSuspensionIterator(event.getStackFrames().iterator(), suspension.getActivity().getId()); + + if (stack instanceof StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) { + StackFrame topFrame = ((StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) stack).getTopFrame(); + //get top frame first + stackFrames.add(topFrame); + } + + while (stack.hasNext()) { + StackFrame next = stack.next(); + if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values for null shadows + stackFrames.add(next); + } + } + assert !stackFrames.isEmpty() : "We expect that there is always at least one stack frame"; + + } + return stackFrames; } - } - - ApplicationThreadStack(final SuspendedEvent event, final Suspension suspension) { - this.event = event; - this.stackFrames = new ArrayList<>(); - this.scopesAndObjects = new ArrayList<>(); - this.scopesAndObjectsSet = new HashMap<>(); - this.suspension = suspension; - } - - ArrayList get() { - if (stackFrames.isEmpty()) { - StackIterator stack = - StackIterator.createSuspensionIterator(event.getStackFrames().iterator(), suspension.getActivity().getId()); - - if (stack instanceof StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) { - StackFrame topFrame = ((StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) stack).getTopFrame(); - //get top frame first - stackFrames.add(topFrame); - } - - while (stack.hasNext()) { - StackFrame next = stack.next(); - if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values for null shadows - stackFrames.add(next); + + long addScope(final Frame frame, + final MethodScope lexicalScope) { + scopesAndObjects.add(new RuntimeScope(frame, lexicalScope)); + return getLastScopeOrVarId(); + } + + long addObject(final Object obj) { + Long idx = scopesAndObjectsSet.get(obj); + if (idx == null) { + scopesAndObjects.add(obj); + idx = getLastScopeOrVarId(); + scopesAndObjectsSet.put(obj, idx); } - } - assert !stackFrames.isEmpty() - : "We expect that there is always at least one stack frame"; + return idx; } - return stackFrames; - } - - long addScope(final Frame frame, final MethodScope lexicalScope) { - scopesAndObjects.add(new RuntimeScope(frame, lexicalScope)); - return getLastScopeOrVarId(); - } - - long addObject(final Object obj) { - Long idx = scopesAndObjectsSet.get(obj); - if (idx == null) { - scopesAndObjects.add(obj); - idx = getLastScopeOrVarId(); - scopesAndObjectsSet.put(obj, idx); + + Object getScopeOrObject(final int localVarRef) { + // need to subtract 1, because getLastScopeOrVarId uses size + // instead of size - 1 for id, because VS code does not allow 0 as id + return scopesAndObjects.get(localVarRef - 1); + } + + private long getLastScopeOrVarId() { + // using size() means ids start with 1, which seems to be needed + // otherwise, VS code ignores the top frame + return suspension.getGlobalId(scopesAndObjects.size()); } - return idx; - } - - Object getScopeOrObject(final int localVarRef) { - // need to subtract 1, because getLastScopeOrVarId uses size - // instead of size - 1 for id, because VS code does not allow 0 as id - return scopesAndObjects.get(localVarRef - 1); - } - - private long getLastScopeOrVarId() { - // using size() means ids start with 1, which seems to be needed - // otherwise, VS code ignores the top frame - return suspension.getGlobalId(scopesAndObjects.size()); - } } From c5f1c48ed5a866a91ba9a5eb649e26017ef7f8e6 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 16 Jul 2020 22:03:26 +0200 Subject: [PATCH 059/194] Add suspended position in StoppedMessage --- src/tools/debugger/message/StoppedMessage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/debugger/message/StoppedMessage.java b/src/tools/debugger/message/StoppedMessage.java index 4135dc3316..1cf686ce1c 100644 --- a/src/tools/debugger/message/StoppedMessage.java +++ b/src/tools/debugger/message/StoppedMessage.java @@ -45,9 +45,12 @@ public static StoppedMessage create(final Suspension suspension) { reason = Reason.breakpoint; } + String suspendedPosition = suspension.getEvent().getSuspendAnchor().name(); + ActivityType type = suspension.getActivity().getType(); // TODO: look into additional details that can be provided as text - return new StoppedMessage(reason, suspension.activityId, type, ""); + //at the moment pass the suspendedPosition as text + return new StoppedMessage(reason, suspension.activityId, type, suspendedPosition); } } From fb516179eedb4c0ea61a84495091cb3ff07416be Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 23 Jul 2020 10:06:26 +0200 Subject: [PATCH 060/194] Fix map initialization - note for promise group: at the moment the strategy for grouping frames for a promise group will be executed only when the promises are unresolved. In the current timplementation if a promise of the group is resolved the callback is not registered for that promise. See register method in RegisterOnPromiseNode class. --- src/som/interpreter/SArguments.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 554b9b2a56..9ba712e7d0 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -235,7 +235,7 @@ public static void saveCausalEntryForPromise(Object previousPromiseStack, Object ((ShadowStackEntry) currentPromiseStack).setPreviousShadowStackEntry((ShadowStackEntry) previousPromiseStack); } - private static Map previousPromiseInGroupByActor = null; + private static Map previousPromiseInGroupByActor = new HashMap<>(); public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, Object callbackPromiseStack, long actorId) { if (previousPromiseInGroupByActor != null && previousPromiseInGroupByActor.containsKey(actorId)) { @@ -247,7 +247,6 @@ public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, O } else { saveCausalEntryForPromise(previousPromiseStack, callbackPromiseStack); - previousPromiseInGroupByActor = new HashMap<>(); previousPromiseInGroupByActor.put(actorId, (ShadowStackEntry) callbackPromiseStack); } } From 4a5162a331d645ff53f91571ffcc7bbdb1bc5e70 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 23 Jul 2020 10:08:36 +0200 Subject: [PATCH 061/194] Remove commented code --- src/som/interpreter/actors/EventualMessage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 6c26c079da..fff952b6d7 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -436,7 +436,6 @@ private void setPromiseValue(final Object value, final Actor resolvingActor, if (callPromiseStack.getExpression().getParent().getParent() instanceof Method) { promiseGroup = ((Method)callPromiseStack.getExpression().getParent().getParent()).getName().startsWith("PromiseGroup"); } -// System.out.println("owner "+promise.getOwner().getId() + " group "+promiseGroup + " maybe "+((ShadowStackEntry)maybeEntry).getSourceSection() + " callback "+ ((ShadowStackEntry)args[args.length - 1]).getSourceSection()); if (promiseGroup) { SArguments.saveCausalEntryForPromiseGroup(maybeEntry, args[args.length - 1], promise.getOwner().getId()); From 28811acb9b586981dd47503787d440045b1a2baf Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 23 Jul 2020 12:42:07 +0200 Subject: [PATCH 062/194] Remove unnecessary argument - suspendedEvent is already contained in the suspension --- src/tools/debugger/frontend/ApplicationThreadStack.java | 4 ++-- src/tools/debugger/frontend/Suspension.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 1981dd0092..0e3105d0fd 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -55,8 +55,8 @@ public boolean hasFrame() { } } - ApplicationThreadStack(final SuspendedEvent event, final Suspension suspension) { - this.event = event; + ApplicationThreadStack(final Suspension suspension) { + this.event = suspension.getEvent(); this.stackFrames = new ArrayList<>(); this.scopesAndObjects = new ArrayList<>(); this.scopesAndObjectsSet = new HashMap<>(); diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 6515b87069..71c81eb11a 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -57,7 +57,7 @@ public Suspension(final TracingActivityThread activityThread, public synchronized void update(final SuspendedEvent e) { this.suspendedEvent = e; - this.stack = new ApplicationThreadStack(e, this); + this.stack = new ApplicationThreadStack(this); } public synchronized ArrayList getStackFrames() { From 71f41b210e85323b7849404ed1398a4b835666c0 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 24 Jul 2020 15:00:20 +0200 Subject: [PATCH 063/194] Add TruffleBoundary annotation to avoid error - avoid compilation error org.graalvm.compiler.truffle.compiler.nodes.asserts.NeverPartOfCompilationNode$NeverPartOfCompilationException: "do not create a Node from compiled code" --- src/tools/asyncstacktraces/ShadowStackEntryLoad.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/asyncstacktraces/ShadowStackEntryLoad.java b/src/tools/asyncstacktraces/ShadowStackEntryLoad.java index e6f2f2650e..57e950b293 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntryLoad.java +++ b/src/tools/asyncstacktraces/ShadowStackEntryLoad.java @@ -1,5 +1,6 @@ package tools.asyncstacktraces; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -14,6 +15,7 @@ public abstract class ShadowStackEntryLoad extends Node { public static int megaCacheHit = 0; public static int megaMiss = 0; + @CompilerDirectives.TruffleBoundary public static ShadowStackEntryLoad create() { if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { return new UninitializedShadowStackEntryLoad(); @@ -44,6 +46,7 @@ protected void setShadowStackEntry(final ShadowStackEntry shadowStackEntry, private static final class UninitializedShadowStackEntryLoad extends ShadowStackEntryLoad { + @CompilerDirectives.TruffleBoundary @Override protected void loadShadowStackEntry(final Object[] arguments, final Node expression, @@ -84,6 +87,7 @@ private static final class CachedShadowStackEntryLoad extends ShadowStackEntryLo protected final ShadowStackEntry expectedShadowStackEntry; protected final ShadowStackEntry cachedShadowStackEntry; + @CompilerDirectives.TruffleBoundary CachedShadowStackEntryLoad(final ShadowStackEntry prevEntry, final ShadowStackEntry newEntry) { this.expectedShadowStackEntry = prevEntry; From 63288e5266aa06146b557e51d65482cd3f66ee97 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 7 Sep 2020 16:19:11 +0200 Subject: [PATCH 064/194] Add message reception entity - add information on the kompos trace related to the messages received by the actor. This is needed in the frontend to keep the messages of the mailbox in arrival order, which not guaranteed by the send operations alone, e.g. for concurrent eventual messages. --- src/som/interpreter/actors/Actor.java | 9 +++++++ src/tools/concurrency/KomposTrace.java | 23 ++++++++++++----- src/tools/debugger/FrontendConnector.java | 12 ++------- src/tools/debugger/entities/Marker.java | 2 ++ .../debugger/entities/MessageReception.java | 25 +++++++++++++++++++ .../message/InitializationResponse.java | 18 +++++-------- 6 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 src/tools/debugger/entities/MessageReception.java diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 64ea0834d5..633cd23994 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -256,6 +256,15 @@ private void doRunWithObjectSafepoints(final ActorProcessingThread t) { protected void processCurrentMessages(final ActorProcessingThread currentThread, final WebDebugger dbg) { assert size > 0; + //save messages appended in mailbox in the trace before execute them + if (VmSettings.KOMPOS_TRACING) { + KomposTrace.messageReception(firstMessage.getMessageId()); + if (size > 1) { + for (EventualMessage msg : mailboxExtension) { + KomposTrace.messageReception(msg.getMessageId()); + } + } + } if (VmSettings.SNAPSHOTS_ENABLED && !VmSettings.TEST_SNAPSHOTS) { SnapshotBuffer sb = currentThread.getSnapshotBuffer(); diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 309393ef79..6b92847e9f 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -14,12 +14,7 @@ import som.vmobjects.SInvokable; import som.vmobjects.SSymbol; import tools.debugger.PrimitiveCallOrigin; -import tools.debugger.entities.ActivityType; -import tools.debugger.entities.DynamicScopeType; -import tools.debugger.entities.Implementation; -import tools.debugger.entities.PassiveEntityType; -import tools.debugger.entities.ReceiveOp; -import tools.debugger.entities.SendOp; +import tools.debugger.entities.*; public class KomposTrace { @@ -146,6 +141,11 @@ public static void recordSuspendedActivityByDebugger(TracingActivityThread t) { ((KomposTraceBuffer) t.getBuffer()).recordPausedActivity(t.getActivity()); } + public static void messageReception(long messageId) { + TracingActivityThread t = getThread(); + ((KomposTraceBuffer) t.getBuffer()).recordMessageReceived(MessageReception.MESSAGE_RCV, t.getActivity(), messageId); + } + public static class KomposTraceBuffer extends TraceBuffer { /** @@ -380,6 +380,17 @@ public void recordSendOperation(final SendOp op, final long entityId, assert position == start + requiredSpace; } + public void recordMessageReceived(MessageReception mr, final Activity current, final long messageId) { + int requiredSpace = mr.getSize(); + ensureSufficientSpace(requiredSpace, current); + + final int start = position; + put(mr.getId()); + putLong(messageId); + + assert position == start + requiredSpace; + } + public static class SyncedKomposTraceBuffer extends KomposTraceBuffer { protected SyncedKomposTraceBuffer(final long implThreadId) { diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index d79b7e9b87..e692e065c4 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -32,15 +32,7 @@ import tools.concurrency.TracingBackend; import tools.debugger.WebSocketHandler.MessageHandler; import tools.debugger.WebSocketHandler.TraceHandler; -import tools.debugger.entities.ActivityType; -import tools.debugger.entities.BreakpointType; -import tools.debugger.entities.DynamicScopeType; -import tools.debugger.entities.EntityType; -import tools.debugger.entities.Implementation; -import tools.debugger.entities.PassiveEntityType; -import tools.debugger.entities.ReceiveOp; -import tools.debugger.entities.SendOp; -import tools.debugger.entities.SteppingType; +import tools.debugger.entities.*; import tools.debugger.frontend.Suspension; import tools.debugger.message.*; import tools.debugger.message.Message.OutgoingMessage; @@ -351,7 +343,7 @@ private void sendInitResponse() { send(InitializationResponse.create(EntityType.values(), ActivityType.values(), PassiveEntityType.values(), DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), - BreakpointType.values(), SteppingType.values(), Implementation.values())); + BreakpointType.values(), SteppingType.values(), Implementation.values(), MessageReception.values())); } private void closeAllSockets() { diff --git a/src/tools/debugger/entities/Marker.java b/src/tools/debugger/entities/Marker.java index 1191b4e92a..bfd510ed5b 100644 --- a/src/tools/debugger/entities/Marker.java +++ b/src/tools/debugger/entities/Marker.java @@ -34,4 +34,6 @@ public class Marker { public static final byte PROMISE_MSG_SEND = 22; + public static final byte ACTOR_MSG_RECEIVE = 23; + } diff --git a/src/tools/debugger/entities/MessageReception.java b/src/tools/debugger/entities/MessageReception.java new file mode 100644 index 0000000000..ddab06104b --- /dev/null +++ b/src/tools/debugger/entities/MessageReception.java @@ -0,0 +1,25 @@ +package tools.debugger.entities; + +public enum MessageReception { + MESSAGE_RCV(Marker.ACTOR_MSG_RECEIVE, EntityType.ACTOR); + + private final byte id; + private final EntityType source; + + MessageReception(final byte id, final EntityType source) { + this.id = id; + this.source = source; + } + + public byte getId() { + return id; + } + + public EntityType getSource() { + return source; + } + + public int getSize() { + return 9; + } +} diff --git a/src/tools/debugger/message/InitializationResponse.java b/src/tools/debugger/message/InitializationResponse.java index 79ce5eafc7..31a7cfc375 100644 --- a/src/tools/debugger/message/InitializationResponse.java +++ b/src/tools/debugger/message/InitializationResponse.java @@ -2,15 +2,7 @@ import com.oracle.truffle.api.instrumentation.Tag; -import tools.debugger.entities.ActivityType; -import tools.debugger.entities.BreakpointType; -import tools.debugger.entities.DynamicScopeType; -import tools.debugger.entities.EntityType; -import tools.debugger.entities.Implementation; -import tools.debugger.entities.PassiveEntityType; -import tools.debugger.entities.ReceiveOp; -import tools.debugger.entities.SendOp; -import tools.debugger.entities.SteppingType; +import tools.debugger.entities.*; import tools.debugger.message.Message.OutgoingMessage; @@ -214,6 +206,7 @@ private static final class ServerCapabilities { private final ParseData passiveEntityParseData; private final ParseData dynamicScopeParseData; private final ParseData sendReceiveParseData; + private final ParseData actorMessageReceiveData; private final ImplementationData[] implementationData; private final BreakpointData[] breakpointTypes; @@ -227,7 +220,7 @@ private ServerCapabilities(final EntityType[] supportedEntities, final ReceiveOp[] supportedReceiveOps, final BreakpointType[] supportedBreakpoints, final SteppingType[] supportedSteps, - final Implementation[] implData) { + final Implementation[] implData, final MessageReception[] msgReception) { activities = getDefinitions(supportedActivities); passiveEntities = getDefinitions(supportedPassiveEntities); dynamicScopes = getDefinitions(supportedDynamicScopes); @@ -247,6 +240,7 @@ private ServerCapabilities(final EntityType[] supportedEntities, sendReceiveParseData = new ParseData( supportedSendOps[0].getSize(), supportedReceiveOps[0].getSize()); + actorMessageReceiveData = new ParseData(msgReception[0].getSize(), 0); implementationData = getDefinitions(implData); @@ -271,10 +265,10 @@ public static InitializationResponse create(final EntityType[] supportedEntities final SendOp[] supportedSendOps, final ReceiveOp[] supportedReceiveOps, final BreakpointType[] supportedBreakpoints, - final SteppingType[] supportedSteps, final Implementation[] implData) { + final SteppingType[] supportedSteps, final Implementation[] implData, final MessageReception[] msgReception) { return new InitializationResponse(new ServerCapabilities(supportedEntities, supportedActivities, supportedPassiveEntities, supportedDynamicScopes, supportedSendOps, supportedReceiveOps, supportedBreakpoints, - supportedSteps, implData)); + supportedSteps, implData, msgReception)); } } From 01e971217377eff1d51f43e9fbaa93559cd71f31 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 11 Sep 2020 14:31:57 +0200 Subject: [PATCH 065/194] Add future for suspension - add a completable future to await that the suspension is actually done before sending the trace data (swapping the buffers) --- src/tools/concurrency/TracingActivityThread.java | 4 +++- src/tools/debugger/FrontendConnector.java | 3 ++- src/tools/debugger/WebDebugger.java | 11 ++++++++++- src/tools/debugger/frontend/Suspension.java | 5 +++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/tools/concurrency/TracingActivityThread.java b/src/tools/concurrency/TracingActivityThread.java index 2f1463137b..66dff81547 100644 --- a/src/tools/concurrency/TracingActivityThread.java +++ b/src/tools/concurrency/TracingActivityThread.java @@ -1,6 +1,7 @@ package tools.concurrency; import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.atomic.AtomicInteger; @@ -75,8 +76,9 @@ public void swapTracingBufferIfRequestedUnsync() { } } - public synchronized void markThreadAsSuspendedInDebugger() { + public synchronized void markThreadAsSuspendedInDebugger(CompletableFuture suspendedFuture) { suspendedInDebugger = true; + suspendedFuture.complete(suspendedInDebugger); } public synchronized void markThreadAsResumedFromDebugger() { diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index e692e065c4..ad0637a546 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -289,7 +289,8 @@ public void sendStoppedMessage(final Suspension suspension) { public void sendTracingData() { if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { - TracingBackend.forceSwapBuffers(); + this.webDebugger.getSuspendedFuture().thenRun(() -> + TracingBackend.forceSwapBuffers()); } } diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index 73e524cfe6..ac66601cb2 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -4,6 +4,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.Instrument; @@ -45,6 +46,8 @@ public class WebDebugger extends TruffleInstrument implements SuspendedCallback static final String ID = "web-debugger"; + private CompletableFuture suspendedFuture; + public static WebDebugger find(final TruffleLanguage.Env env) { InstrumentInfo instrument = env.getInstruments().get(ID); if (instrument == null) { @@ -147,8 +150,14 @@ public void onSuspend(final SuspendedEvent e) { Suspension suspension = getSuspension(); suspension.update(e); + suspendedFuture = new CompletableFuture<>(); + connector.sendStoppedMessage(suspension); - suspension.suspend(); + suspension.suspend(suspendedFuture); + } + + public CompletableFuture getSuspendedFuture() { + return suspendedFuture; } public static void log(final String str) { diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 71c81eb11a..b43dbb3793 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CompletableFuture; /** @@ -147,12 +148,12 @@ private void submitTask(final ApplicationThreadTask task) { /** * Suspend the current thread, and process tasks from the front-end. */ - public void suspend() { + public void suspend(CompletableFuture suspendedFuture) { // don't participate in safepoints while being suspended ObjectTransitionSafepoint.INSTANCE.unregister(); try { - activityThread.markThreadAsSuspendedInDebugger(); + activityThread.markThreadAsSuspendedInDebugger(suspendedFuture); suspendWithoutObjectSafepoints(); } finally { activityThread.markThreadAsResumedFromDebugger(); From c7c8ff06237be1be0ccd93e66706c50e7e6ed202 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 14 Sep 2020 11:39:01 +0200 Subject: [PATCH 066/194] Change sendTracingData implementation - change the implementation for sending the trace buffers to the frontend. When buffers are available in the buffers queue (TracingBackend.processTraceData()) we save those buffers in the FrontendConnect class. Then when the TraceDataRequest is done by the frontend we need to wait for the web debugger to do the suspension, then the buffers of the current thread are swapped and all saved buffers are sent to the frontend. - this implementation is needed to avoid that the frontend receives incomplete trace buffer information --- src/tools/concurrency/KomposTrace.java | 35 +++++++++- .../concurrency/TracingActivityThread.java | 4 +- src/tools/debugger/FrontendConnector.java | 68 ++++++++++++++----- src/tools/debugger/WebDebugger.java | 4 +- src/tools/debugger/frontend/Suspension.java | 2 +- 5 files changed, 89 insertions(+), 24 deletions(-) diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 6b92847e9f..c01921b71c 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -16,9 +16,28 @@ import tools.debugger.PrimitiveCallOrigin; import tools.debugger.entities.*; +import java.util.*; + public class KomposTrace { + private static Map> buffersByActor = new HashMap<>(); + + public static boolean missingBuffers(long actorSuspendedId) { + List buffers = buffersByActor.get(actorSuspendedId); + Collections.sort(buffers); + + for (int i = 1; i < buffers.size(); i++) { + int previous = buffers.get(i - 1); + int current = buffers.get(i); + if (current != (previous + 1)) { + return true; + } + } + + return false; + } + public static void recordMainActor(final Actor mainActor, final ObjectSystem objectSystem) { KomposTraceBuffer buffer = KomposTraceBuffer.create(0); @@ -243,8 +262,20 @@ public void recordCurrentActivity(final Activity current) { final int start = position; put(Implementation.IMPL_CURRENT_ACTIVITY.getId()); - putLong(current.getId()); - putInt(current.getNextTraceBufferId()); + long actorId = current.getId(); + int bufferId = current.getNextTraceBufferId(); + + putLong(actorId); + putInt(bufferId); + + List bufferList; + if (buffersByActor.containsKey(actorId)) { + bufferList = buffersByActor.get(actorId); + } else { + bufferList = new ArrayList<>(); + } + bufferList.add(bufferId); + buffersByActor.put(actorId, bufferList); assert position == start + Implementation.IMPL_CURRENT_ACTIVITY.getSize(); } diff --git a/src/tools/concurrency/TracingActivityThread.java b/src/tools/concurrency/TracingActivityThread.java index 66dff81547..a9600b12e6 100644 --- a/src/tools/concurrency/TracingActivityThread.java +++ b/src/tools/concurrency/TracingActivityThread.java @@ -76,9 +76,9 @@ public void swapTracingBufferIfRequestedUnsync() { } } - public synchronized void markThreadAsSuspendedInDebugger(CompletableFuture suspendedFuture) { + public synchronized void markThreadAsSuspendedInDebugger(CompletableFuture suspendedFuture) { suspendedInDebugger = true; - suspendedFuture.complete(suspendedInDebugger); + suspendedFuture.complete(this.getActivity().getId()); } public synchronized void markThreadAsResumedFromDebugger() { diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index ad0637a546..fea1e298c9 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -4,10 +4,7 @@ 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.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Function; @@ -29,6 +26,7 @@ import som.vmobjects.SSymbol; import tools.Tagging; import tools.TraceData; +import tools.concurrency.KomposTrace; import tools.concurrency.TracingBackend; import tools.debugger.WebSocketHandler.MessageHandler; import tools.debugger.WebSocketHandler.TraceHandler; @@ -77,6 +75,8 @@ public class FrontendConnector { private CompletableFuture messageSocketInitialized; + private List buffers = new ArrayList<>(); + private final Gson gson; private static final int MESSAGE_PORT = 7977; private static final int TRACE_PORT = 7978; @@ -242,10 +242,6 @@ public void sendSymbols(final ArrayList symbolsToWrite) { send(new SymbolMessage(symbolsToWrite)); } - public void sendTracingData(final ByteBuffer buffer) { - traceSocket.send(buffer); - } - public void awaitClient() { assert VmSettings.TRUFFLE_DEBUGGER_ENABLED; assert clientConnected != null; @@ -287,17 +283,55 @@ public void sendStoppedMessage(final Suspension suspension) { send(StoppedMessage.create(suspension)); } - public void sendTracingData() { - if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { - this.webDebugger.getSuspendedFuture().thenRun(() -> - TracingBackend.forceSwapBuffers()); +// public void sendTracingData() { +// if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { +// this.webDebugger.getSuspendedFuture().thenRun(() -> +// TracingBackend.forceSwapBuffers()); +// } +// } +// +// public void sendTracingData(final ByteBuffer buffer) { +// traceSocket.send(buffer); +// } + + public void sendTracingData(final ByteBuffer buffer) { + System.out.println("-Add buffer"); + if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { + buffers.add(buffer); + } } - } - public void sendProgramInfo() { - //when the server has really started, i.e. the client has connected, then do the send - messageSocketInitialized.thenRun(() -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); - } + private void sendAllBuffers() { + System.out.println("buffers--" + buffers.size()); + for (ByteBuffer buffer : buffers) { + traceSocket.send(buffer); + } + //reset list + buffers = new ArrayList<>(); + } + + public void sendTracingData() { + System.out.println("-Send buffer"); + if (VmSettings.ACTOR_TRACING || VmSettings.KOMPOS_TRACING) { + this.webDebugger.getSuspendedFuture().thenAccept(actorSuspendedId -> + checkBuffersAndSend(actorSuspendedId)); + } + } + + private void checkBuffersAndSend(long actorSuspendedId) { + TracingBackend.forceSwapBuffers(); + //check if there are missing buffers for the actor of the suspension + while (KomposTrace.missingBuffers(actorSuspendedId)) { + TracingBackend.forceSwapBuffers(); + } + + sendAllBuffers(); + } + + public void sendProgramInfo() { + //when the server has really started, i.e. the client has connected, then do the send + messageSocketInitialized.thenRun(() -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); + } public void sendPauseActorResponse(long pausedActorId) { send(PauseActorResponse.create(pausedActorId)); diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index ac66601cb2..c90a5b12f4 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -46,7 +46,7 @@ public class WebDebugger extends TruffleInstrument implements SuspendedCallback static final String ID = "web-debugger"; - private CompletableFuture suspendedFuture; + private CompletableFuture suspendedFuture; public static WebDebugger find(final TruffleLanguage.Env env) { InstrumentInfo instrument = env.getInstruments().get(ID); @@ -156,7 +156,7 @@ public void onSuspend(final SuspendedEvent e) { suspension.suspend(suspendedFuture); } - public CompletableFuture getSuspendedFuture() { + public CompletableFuture getSuspendedFuture() { return suspendedFuture; } diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index b43dbb3793..76b0a057a2 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -148,7 +148,7 @@ private void submitTask(final ApplicationThreadTask task) { /** * Suspend the current thread, and process tasks from the front-end. */ - public void suspend(CompletableFuture suspendedFuture) { + public void suspend(CompletableFuture suspendedFuture) { // don't participate in safepoints while being suspended ObjectTransitionSafepoint.INSTANCE.unregister(); From b9f0bb5553c5695e18918729b50266612607e888 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 14 Sep 2020 13:27:47 +0200 Subject: [PATCH 067/194] Remove prints --- src/tools/debugger/FrontendConnector.java | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index fea1e298c9..23f9464225 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -295,23 +295,12 @@ public void sendStoppedMessage(final Suspension suspension) { // } public void sendTracingData(final ByteBuffer buffer) { - System.out.println("-Add buffer"); if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { buffers.add(buffer); } } - private void sendAllBuffers() { - System.out.println("buffers--" + buffers.size()); - for (ByteBuffer buffer : buffers) { - traceSocket.send(buffer); - } - //reset list - buffers = new ArrayList<>(); - } - public void sendTracingData() { - System.out.println("-Send buffer"); if (VmSettings.ACTOR_TRACING || VmSettings.KOMPOS_TRACING) { this.webDebugger.getSuspendedFuture().thenAccept(actorSuspendedId -> checkBuffersAndSend(actorSuspendedId)); @@ -328,6 +317,15 @@ private void checkBuffersAndSend(long actorSuspendedId) { sendAllBuffers(); } + private void sendAllBuffers() { + for (ByteBuffer buffer : buffers) { + traceSocket.send(buffer); + } + log("[DEBUGGER] Trace buffers sent: "+buffers.size()); + //reset list + buffers = new ArrayList<>(); + } + public void sendProgramInfo() { //when the server has really started, i.e. the client has connected, then do the send messageSocketInitialized.thenRun(() -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); From b0fbfd501d26edaa890d549ea860ac1e85a1ce37 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 17 Sep 2020 16:57:11 +0200 Subject: [PATCH 068/194] Comment log --- src/tools/debugger/FrontendConnector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 23f9464225..bfb2db1690 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -321,7 +321,7 @@ private void sendAllBuffers() { for (ByteBuffer buffer : buffers) { traceSocket.send(buffer); } - log("[DEBUGGER] Trace buffers sent: "+buffers.size()); +// log("[DEBUGGER] Trace buffers sent: "+buffers.size()); //reset list buffers = new ArrayList<>(); } From 26bf162bea61156e8e02d7c365c2228043d9eb09 Mon Sep 17 00:00:00 2001 From: carmen Date: Wed, 30 Sep 2020 20:45:52 +0200 Subject: [PATCH 069/194] Send pending buffers after the suspension - continue sending buffers after the suspension - minor renaming --- src/tools/debugger/FrontendConnector.java | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index bfb2db1690..d5ec1bda49 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -296,32 +296,40 @@ public void sendStoppedMessage(final Suspension suspension) { public void sendTracingData(final ByteBuffer buffer) { if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { - buffers.add(buffer); + buffers.add(buffer); + + if (this.webDebugger.getSuspendedFuture() != null && this.webDebugger.getSuspendedFuture().isDone()) { + //the suspension has been done and there are more actors running, then send new buffers + sendAllBuffers(); + } } } public void sendTracingData() { if (VmSettings.ACTOR_TRACING || VmSettings.KOMPOS_TRACING) { this.webDebugger.getSuspendedFuture().thenAccept(actorSuspendedId -> - checkBuffersAndSend(actorSuspendedId)); + swapBuffersAndSend(actorSuspendedId)); } } - private void checkBuffersAndSend(long actorSuspendedId) { + private void swapBuffersAndSend(long actorSuspendedId) { TracingBackend.forceSwapBuffers(); //check if there are missing buffers for the actor of the suspension while (KomposTrace.missingBuffers(actorSuspendedId)) { TracingBackend.forceSwapBuffers(); } - sendAllBuffers(); + sendAllBuffers(); } private void sendAllBuffers() { for (ByteBuffer buffer : buffers) { - traceSocket.send(buffer); + if (traceSocket.isOpen()) { + traceSocket.send(buffer); +// log("[DEBUGGER] Trace buffers sent: "+buffer); + } } -// log("[DEBUGGER] Trace buffers sent: "+buffers.size()); + //reset list buffers = new ArrayList<>(); } From bbbb957191623749e0ca4c33e5101d99ee3844e9 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 1 Oct 2020 15:50:24 +0200 Subject: [PATCH 070/194] Change implementation to record received msg - record receive messages in the doSend method of the actor, which is valid for running and paused actors, and resolve the tracingActivityThread from the TracingBackend --- src/som/interpreter/actors/Actor.java | 14 +++++--------- src/tools/concurrency/KomposTrace.java | 3 +-- src/tools/concurrency/TracingActors.java | 15 +++++++++++++++ src/tools/concurrency/TracingBackend.java | 12 ++++++++++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 633cd23994..4acc90d064 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -148,6 +148,11 @@ private void doSend(final EventualMessage msg, appendToMailbox(msg); } + //save messages appended in mailbox in the trace when they are received + if (VmSettings.KOMPOS_TRACING) { + TracingActor.saveMessagesReceived(this, firstMessage, mailboxExtension); + } + if (!isExecuting) { isExecuting = true; execute(actorPool); @@ -256,15 +261,6 @@ private void doRunWithObjectSafepoints(final ActorProcessingThread t) { protected void processCurrentMessages(final ActorProcessingThread currentThread, final WebDebugger dbg) { assert size > 0; - //save messages appended in mailbox in the trace before execute them - if (VmSettings.KOMPOS_TRACING) { - KomposTrace.messageReception(firstMessage.getMessageId()); - if (size > 1) { - for (EventualMessage msg : mailboxExtension) { - KomposTrace.messageReception(msg.getMessageId()); - } - } - } if (VmSettings.SNAPSHOTS_ENABLED && !VmSettings.TEST_SNAPSHOTS) { SnapshotBuffer sb = currentThread.getSnapshotBuffer(); diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index c01921b71c..a2ee0d50bf 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -160,8 +160,7 @@ public static void recordSuspendedActivityByDebugger(TracingActivityThread t) { ((KomposTraceBuffer) t.getBuffer()).recordPausedActivity(t.getActivity()); } - public static void messageReception(long messageId) { - TracingActivityThread t = getThread(); + public static void messageReception(long messageId, TracingActivityThread t) { ((KomposTraceBuffer) t.getBuffer()).recordMessageReceived(MessageReception.MESSAGE_RCV, t.getActivity(), messageId); } diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index df54a9a96d..6f4fdac3a5 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -12,6 +12,7 @@ import som.interpreter.actors.EventualMessage.PromiseMessage; import som.interpreter.actors.SPromise.STracingPromise; import som.vm.VmSettings; +import tools.ObjectBuffer; import tools.debugger.WebDebugger; import tools.debugger.frontend.Suspension; import tools.replay.PassiveEntityWithEvents; @@ -60,6 +61,20 @@ protected TracingActor(final VM vm, final long id) { this.activityId = id; } + public static void saveMessagesReceived(Actor actor, EventualMessage firstMessage, ObjectBuffer mailboxExtension) { + TracingActivityThread tracingActivityThread = TracingBackend.getTracingActivityThread(actor.getId()); + if (tracingActivityThread != null) { + KomposTrace.messageReception(firstMessage.getMessageId(), tracingActivityThread); + if (mailboxExtension!= null && mailboxExtension.size() > 1) { + for (EventualMessage msgInMailbox : mailboxExtension) { + KomposTrace.messageReception(msgInMailbox.getMessageId(), tracingActivityThread); + } + } + //forceSwap to ensure that message information is sent, although the actor is paused + TracingBackend.forceSwapBuffers(); + } + } + public final int getActorId() { // TODO: remove after rebasing snapshot PR throw new UnsupportedOperationException("Please remove this call and use getId instead"); diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index a2c11c1d4b..bf90d734aa 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -247,6 +247,18 @@ public static void unregisterThread(final TracingActivityThread t) { } } + public static TracingActivityThread getTracingActivityThread(long actorId) { + synchronized (tracingThreads) { + TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); + for (TracingActivityThread tracingActivityThread: result) { + if (tracingActivityThread.getActivity()!= null && tracingActivityThread.getActivity().getId() == actorId) { + return tracingActivityThread; + } + } + return null; + } + } + public static final void forceSwapBuffers() { assert VmSettings.UNIFORM_TRACING || (VmSettings.TRUFFLE_DEBUGGER_ENABLED); From 3536ca378b8daa175cc25f97aa9e0fd6d3ae849e Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 2 Oct 2020 12:28:09 +0200 Subject: [PATCH 071/194] Remove call to force swap the buffers - the trace should be requested from the frontend --- src/tools/concurrency/TracingActors.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 6f4fdac3a5..3605b5f9cc 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -70,8 +70,6 @@ public static void saveMessagesReceived(Actor actor, EventualMessage firstMessag KomposTrace.messageReception(msgInMailbox.getMessageId(), tracingActivityThread); } } - //forceSwap to ensure that message information is sent, although the actor is paused - TracingBackend.forceSwapBuffers(); } } From 8bcf1397a58b60c9760fac17bc8bfd2f723d5c53 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 2 Oct 2020 14:38:59 +0200 Subject: [PATCH 072/194] Filter empty buffers - do not send empty buffers to the frontend when TracingBackend.forceSwapBuffers method is called --- src/tools/concurrency/TraceBuffer.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/concurrency/TraceBuffer.java b/src/tools/concurrency/TraceBuffer.java index 7fee9fdfc4..df55bb3658 100644 --- a/src/tools/concurrency/TraceBuffer.java +++ b/src/tools/concurrency/TraceBuffer.java @@ -92,6 +92,13 @@ private int nextPutIndex(final int nb) { } public final void returnBuffer(final byte[] nextBuffer) { + //do not swap if buffer is empty + if (VmSettings.KOMPOS_TRACING) { + if (isEmpty()){ + return; + } + } + if (VmSettings.SNAPSHOTS_ENABLED) { TracingBackend.returnBuffer(buffer, position, ActorProcessingThread.currentThread().getSnapshotId()); From ad2a775ce7d699e89656a258ce79134b563dc547 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 2 Oct 2020 16:12:16 +0200 Subject: [PATCH 073/194] Remove suspended future in WebDebugger - future is not really needed, then remove it - adjust sendTracingData methods for the pull based approach --- src/tools/concurrency/TracingBackend.java | 5 +- src/tools/debugger/FrontendConnector.java | 60 ++++----------------- src/tools/debugger/WebDebugger.java | 10 +--- src/tools/debugger/frontend/Suspension.java | 4 +- 4 files changed, 14 insertions(+), 65 deletions(-) diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index bf90d734aa..e0c1b50b3f 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -12,10 +12,7 @@ import java.lang.management.MemoryType; import java.lang.management.MemoryUsage; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index d5ec1bda49..ac90fccd08 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -283,61 +283,21 @@ public void sendStoppedMessage(final Suspension suspension) { send(StoppedMessage.create(suspension)); } -// public void sendTracingData() { -// if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { -// this.webDebugger.getSuspendedFuture().thenRun(() -> -// TracingBackend.forceSwapBuffers()); -// } -// } -// -// public void sendTracingData(final ByteBuffer buffer) { -// traceSocket.send(buffer); -// } - - public void sendTracingData(final ByteBuffer buffer) { - if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { - buffers.add(buffer); - - if (this.webDebugger.getSuspendedFuture() != null && this.webDebugger.getSuspendedFuture().isDone()) { - //the suspension has been done and there are more actors running, then send new buffers - sendAllBuffers(); - } - } - } - - public void sendTracingData() { - if (VmSettings.ACTOR_TRACING || VmSettings.KOMPOS_TRACING) { - this.webDebugger.getSuspendedFuture().thenAccept(actorSuspendedId -> - swapBuffersAndSend(actorSuspendedId)); - } - } - - private void swapBuffersAndSend(long actorSuspendedId) { - TracingBackend.forceSwapBuffers(); - //check if there are missing buffers for the actor of the suspension - while (KomposTrace.missingBuffers(actorSuspendedId)) { - TracingBackend.forceSwapBuffers(); - } - - sendAllBuffers(); + public void sendTracingData() { + if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { + TracingBackend.forceSwapBuffers(); } + } - private void sendAllBuffers() { - for (ByteBuffer buffer : buffers) { - if (traceSocket.isOpen()) { - traceSocket.send(buffer); -// log("[DEBUGGER] Trace buffers sent: "+buffer); - } - } - - //reset list - buffers = new ArrayList<>(); - } + public void sendTracingData(final ByteBuffer buffer) { + log("[DEBUGGER] Trace buffers sent: "+buffer); + traceSocket.send(buffer); + } - public void sendProgramInfo() { + public void sendProgramInfo() { //when the server has really started, i.e. the client has connected, then do the send messageSocketInitialized.thenRun(() -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); - } + } public void sendPauseActorResponse(long pausedActorId) { send(PauseActorResponse.create(pausedActorId)); diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index c90a5b12f4..b185a51903 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -46,8 +46,6 @@ public class WebDebugger extends TruffleInstrument implements SuspendedCallback static final String ID = "web-debugger"; - private CompletableFuture suspendedFuture; - public static WebDebugger find(final TruffleLanguage.Env env) { InstrumentInfo instrument = env.getInstruments().get(ID); if (instrument == null) { @@ -150,14 +148,8 @@ public void onSuspend(final SuspendedEvent e) { Suspension suspension = getSuspension(); suspension.update(e); - suspendedFuture = new CompletableFuture<>(); - connector.sendStoppedMessage(suspension); - suspension.suspend(suspendedFuture); - } - - public CompletableFuture getSuspendedFuture() { - return suspendedFuture; + suspension.suspend(); } public static void log(final String str) { diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 76b0a057a2..2418d773ae 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -148,12 +148,12 @@ private void submitTask(final ApplicationThreadTask task) { /** * Suspend the current thread, and process tasks from the front-end. */ - public void suspend(CompletableFuture suspendedFuture) { + public void suspend() { // don't participate in safepoints while being suspended ObjectTransitionSafepoint.INSTANCE.unregister(); try { - activityThread.markThreadAsSuspendedInDebugger(suspendedFuture); + activityThread.markThreadAsSuspendedInDebugger(); suspendWithoutObjectSafepoints(); } finally { activityThread.markThreadAsResumedFromDebugger(); From 146b95daf46bfd0dad603a5c3a3e4a504e747d68 Mon Sep 17 00:00:00 2001 From: carmen Date: Fri, 2 Oct 2020 21:27:47 +0200 Subject: [PATCH 074/194] Update changes in TracingActivityThread - update test --- src/tools/concurrency/TracingActivityThread.java | 3 +-- tests/java/debugger/JsonTests.java | 12 ++---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/tools/concurrency/TracingActivityThread.java b/src/tools/concurrency/TracingActivityThread.java index a9600b12e6..d476b04523 100644 --- a/src/tools/concurrency/TracingActivityThread.java +++ b/src/tools/concurrency/TracingActivityThread.java @@ -76,9 +76,8 @@ public void swapTracingBufferIfRequestedUnsync() { } } - public synchronized void markThreadAsSuspendedInDebugger(CompletableFuture suspendedFuture) { + public synchronized void markThreadAsSuspendedInDebugger() { suspendedInDebugger = true; - suspendedFuture.complete(this.getActivity().getId()); } public synchronized void markThreadAsResumedFromDebugger() { diff --git a/tests/java/debugger/JsonTests.java b/tests/java/debugger/JsonTests.java index b16e93814f..90cc3f991c 100644 --- a/tests/java/debugger/JsonTests.java +++ b/tests/java/debugger/JsonTests.java @@ -17,15 +17,7 @@ import bd.source.FullSourceCoordinate; import bd.source.SourceCoordinate; import tools.debugger.RuntimeReflectionRegistration; -import tools.debugger.entities.ActivityType; -import tools.debugger.entities.BreakpointType; -import tools.debugger.entities.DynamicScopeType; -import tools.debugger.entities.EntityType; -import tools.debugger.entities.Implementation; -import tools.debugger.entities.PassiveEntityType; -import tools.debugger.entities.ReceiveOp; -import tools.debugger.entities.SendOp; -import tools.debugger.entities.SteppingType; +import tools.debugger.entities.*; import tools.debugger.message.InitializationResponse; import tools.debugger.message.InitializeConnection; import tools.debugger.message.Message.IncommingMessage; @@ -192,7 +184,7 @@ public void initializeResponseSerialize() { String result = gson.toJson(InitializationResponse.create( EntityType.values(), ActivityType.values(), PassiveEntityType.values(), DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), - BreakpointType.values(), SteppingType.values(), Implementation.values()), + BreakpointType.values(), SteppingType.values(), Implementation.values(), MessageReception.values()), OutgoingMessage.class); // This test is only doing a very basic sanity check assertTrue(1000 < result.length()); From 49809f2d67b1b193f4e6b2f88ad7f68e2dc6c3fc Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 3 Oct 2020 08:51:20 +0200 Subject: [PATCH 075/194] Comment log for trace buffers --- src/tools/debugger/FrontendConnector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index ac90fccd08..2431971e1e 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -290,7 +290,7 @@ public void sendTracingData() { } public void sendTracingData(final ByteBuffer buffer) { - log("[DEBUGGER] Trace buffers sent: "+buffer); +// log("[DEBUGGER] Trace buffers sent: "+buffer); traceSocket.send(buffer); } From 83871e8acf26fbf82a39ce5460e155d8c3d62206 Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 3 Oct 2020 15:30:41 +0200 Subject: [PATCH 076/194] Validate recording no repeated messages in mailbox --- src/tools/concurrency/TracingActors.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 3605b5f9cc..ab3ae37285 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -67,7 +67,9 @@ public static void saveMessagesReceived(Actor actor, EventualMessage firstMessag KomposTrace.messageReception(firstMessage.getMessageId(), tracingActivityThread); if (mailboxExtension!= null && mailboxExtension.size() > 1) { for (EventualMessage msgInMailbox : mailboxExtension) { - KomposTrace.messageReception(msgInMailbox.getMessageId(), tracingActivityThread); + if (msgInMailbox.getMessageId() != firstMessage.getMessageId()) { //TODO check why the same message can be added more than once in mailbox + KomposTrace.messageReception(msgInMailbox.getMessageId(), tracingActivityThread); + } } } } From 22ec2332710044749258ff8970a77861197ef22b Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 3 Oct 2020 15:42:01 +0200 Subject: [PATCH 077/194] Fix when recording the message received - record just one message (there is no need to check the entire mailbox, only the message received) --- src/som/interpreter/actors/Actor.java | 4 ++-- src/tools/concurrency/TracingActors.java | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 4acc90d064..751c40f118 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -147,10 +147,10 @@ private void doSend(final EventualMessage msg, } else { appendToMailbox(msg); } - + System.out.println("message received "+msg.getMessageId() + " actor "+getId()); //save messages appended in mailbox in the trace when they are received if (VmSettings.KOMPOS_TRACING) { - TracingActor.saveMessagesReceived(this, firstMessage, mailboxExtension); + TracingActor.saveMessageReceived(this, msg); } if (!isExecuting) { diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index ab3ae37285..0f3697a393 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -61,17 +61,10 @@ protected TracingActor(final VM vm, final long id) { this.activityId = id; } - public static void saveMessagesReceived(Actor actor, EventualMessage firstMessage, ObjectBuffer mailboxExtension) { + public static void saveMessageReceived(Actor actor, EventualMessage message) { TracingActivityThread tracingActivityThread = TracingBackend.getTracingActivityThread(actor.getId()); if (tracingActivityThread != null) { - KomposTrace.messageReception(firstMessage.getMessageId(), tracingActivityThread); - if (mailboxExtension!= null && mailboxExtension.size() > 1) { - for (EventualMessage msgInMailbox : mailboxExtension) { - if (msgInMailbox.getMessageId() != firstMessage.getMessageId()) { //TODO check why the same message can be added more than once in mailbox - KomposTrace.messageReception(msgInMailbox.getMessageId(), tracingActivityThread); - } - } - } + KomposTrace.messageReception(message.getMessageId(), tracingActivityThread); } } From 6bcf1f6b7eb61b4376f4c2abccf96f1f9fed80bd Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 3 Oct 2020 16:24:59 +0200 Subject: [PATCH 078/194] Changes when recording received messages - at method doSend the tracingActivityThread can be null, there we only record the messages received for suspended actors. In method processCurrentMessages, just before processing the messages we can record the messages that are in the mailbox at that moment. --- src/som/interpreter/actors/Actor.java | 13 ++++++++++++- src/tools/concurrency/TracingActors.java | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 751c40f118..49b8304b76 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -148,7 +148,8 @@ private void doSend(final EventualMessage msg, appendToMailbox(msg); } System.out.println("message received "+msg.getMessageId() + " actor "+getId()); - //save messages appended in mailbox in the trace when they are received + //save messages in the trace when they are received + //here we only save messages if the actor is suspended in debugger if (VmSettings.KOMPOS_TRACING) { TracingActor.saveMessageReceived(this, msg); } @@ -261,6 +262,16 @@ private void doRunWithObjectSafepoints(final ActorProcessingThread t) { protected void processCurrentMessages(final ActorProcessingThread currentThread, final WebDebugger dbg) { assert size > 0; + //save messages appended in mailbox in the trace before execute them + if (VmSettings.KOMPOS_TRACING) { + KomposTrace.messageReception(firstMessage.getMessageId(), currentThread); + if (size > 1) { + for (EventualMessage msg : mailboxExtension) { + KomposTrace.messageReception(msg.getMessageId(), currentThread); + } + } + } + if (VmSettings.SNAPSHOTS_ENABLED && !VmSettings.TEST_SNAPSHOTS) { SnapshotBuffer sb = currentThread.getSnapshotBuffer(); diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 0f3697a393..579de89444 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -63,7 +63,7 @@ protected TracingActor(final VM vm, final long id) { public static void saveMessageReceived(Actor actor, EventualMessage message) { TracingActivityThread tracingActivityThread = TracingBackend.getTracingActivityThread(actor.getId()); - if (tracingActivityThread != null) { + if (tracingActivityThread != null && tracingActivityThread.suspendedInDebugger) { //only record new msg for suspended actors KomposTrace.messageReception(message.getMessageId(), tracingActivityThread); } } From 6948691801224e730f38ebb5c606a87175b26b1a Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 5 Oct 2020 13:56:40 +0200 Subject: [PATCH 079/194] Upgrade WebSocket library to version 1.5.1 - add slf4j dependency --- SOMns.iml | 29 ++++++++++++++++-------- som | 1 + src/tools/debugger/WebSocketHandler.java | 2 ++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/SOMns.iml b/SOMns.iml index 50d4e6f507..94c35c2909 100644 --- a/SOMns.iml +++ b/SOMns.iml @@ -19,6 +19,25 @@ + + + + + + + + + + + + + + + + + + + @@ -41,15 +60,5 @@ - - - - - - - - - - \ No newline at end of file diff --git a/som b/som index bb2ed93311..8d8167d2b5 100755 --- a/som +++ b/som @@ -230,6 +230,7 @@ else: classpath = (BASE_DIR + '/build/classes:' + BASE_DIR + '/libs/black-diamonds/build/classes:' + + BASE_DIR + '/libs/Java-WebSocket-1.5.1.jar:' + BASE_DIR + '/libs/somns-deps.jar:' + BASE_DIR + '/libs/affinity.jar:' + BASE_DIR + '/libs/slf4j-api.jar:' diff --git a/src/tools/debugger/WebSocketHandler.java b/src/tools/debugger/WebSocketHandler.java index fdce3d7542..c9595e1e06 100644 --- a/src/tools/debugger/WebSocketHandler.java +++ b/src/tools/debugger/WebSocketHandler.java @@ -66,6 +66,7 @@ public MessageHandler(final int port, final FrontendConnector connector, super(port); this.connector = connector; this.gson = gson; + setConnectionLostTimeout(0); } @Override @@ -87,6 +88,7 @@ public static class TraceHandler extends WebSocketHandler { public TraceHandler(final int port) { super(port); connection = new CompletableFuture<>(); + setConnectionLostTimeout(0); } @Override From 059f8ee66b7ec32ffa79703de3164556fb95e231 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 5 Oct 2020 14:07:07 +0200 Subject: [PATCH 080/194] Remove print --- src/som/interpreter/actors/Actor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 49b8304b76..cd06831285 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -147,7 +147,6 @@ private void doSend(final EventualMessage msg, } else { appendToMailbox(msg); } - System.out.println("message received "+msg.getMessageId() + " actor "+getId()); //save messages in the trace when they are received //here we only save messages if the actor is suspended in debugger if (VmSettings.KOMPOS_TRACING) { From c23e71f5c27a586e620c17f51c497ab0fef89c98 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 6 Oct 2020 12:32:55 +0200 Subject: [PATCH 081/194] Set reuse address to true - declare reuse the same address for the websockets, in order to avoid address already in use exception - move setConnectionLostTiemout to the super constructor - fix version of websocket library in build file --- SOMns.iml | 20 ++++++++++---------- src/tools/debugger/WebSocketHandler.java | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SOMns.iml b/SOMns.iml index 94c35c2909..cc64e22255 100644 --- a/SOMns.iml +++ b/SOMns.iml @@ -19,16 +19,6 @@ - - - - - - - - - - @@ -38,6 +28,16 @@ + + + + + + + + + + diff --git a/src/tools/debugger/WebSocketHandler.java b/src/tools/debugger/WebSocketHandler.java index c9595e1e06..23a83eca24 100644 --- a/src/tools/debugger/WebSocketHandler.java +++ b/src/tools/debugger/WebSocketHandler.java @@ -23,6 +23,8 @@ public abstract class WebSocketHandler extends WebSocketServer { WebSocketHandler(final int port) { super(new InetSocketAddress(port), NUM_THREADS); this.connectionPort = new CompletableFuture<>(); + setReuseAddr(true); + setConnectionLostTimeout(0); } @Override @@ -66,7 +68,6 @@ public MessageHandler(final int port, final FrontendConnector connector, super(port); this.connector = connector; this.gson = gson; - setConnectionLostTimeout(0); } @Override @@ -88,7 +89,6 @@ public static class TraceHandler extends WebSocketHandler { public TraceHandler(final int port) { super(port); connection = new CompletableFuture<>(); - setConnectionLostTimeout(0); } @Override From 2b44948d7ce8ff42c1f3b92ad9720f90542acafd Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 6 Oct 2020 15:27:17 +0200 Subject: [PATCH 082/194] Remove buffer filtering when returning buffer - is needed because otherwise the empty buffers queue in the TracingBackend will be empty eventually, which can cause a blocking state in the interpreter --- src/tools/concurrency/TraceBuffer.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/tools/concurrency/TraceBuffer.java b/src/tools/concurrency/TraceBuffer.java index df55bb3658..7fee9fdfc4 100644 --- a/src/tools/concurrency/TraceBuffer.java +++ b/src/tools/concurrency/TraceBuffer.java @@ -92,13 +92,6 @@ private int nextPutIndex(final int nb) { } public final void returnBuffer(final byte[] nextBuffer) { - //do not swap if buffer is empty - if (VmSettings.KOMPOS_TRACING) { - if (isEmpty()){ - return; - } - } - if (VmSettings.SNAPSHOTS_ENABLED) { TracingBackend.returnBuffer(buffer, position, ActorProcessingThread.currentThread().getSnapshotId()); From 4b793468840cd736c9601ba48666b313c6b52ac2 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 6 Oct 2020 15:41:28 +0200 Subject: [PATCH 083/194] Remove unused code --- src/tools/debugger/FrontendConnector.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 2431971e1e..27db8aebc7 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -26,7 +26,6 @@ import som.vmobjects.SSymbol; import tools.Tagging; import tools.TraceData; -import tools.concurrency.KomposTrace; import tools.concurrency.TracingBackend; import tools.debugger.WebSocketHandler.MessageHandler; import tools.debugger.WebSocketHandler.TraceHandler; @@ -75,8 +74,6 @@ public class FrontendConnector { private CompletableFuture messageSocketInitialized; - private List buffers = new ArrayList<>(); - private final Gson gson; private static final int MESSAGE_PORT = 7977; private static final int TRACE_PORT = 7978; From 78ae0d96db6a41a227f82a8befef4434f28ca6a1 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 6 Oct 2020 20:57:54 +0200 Subject: [PATCH 084/194] Enable connection timeout - move reuse address in message and trace handler classes - remove setConnectionLostTimeout to keep the lost connection detection enabled --- src/tools/debugger/WebSocketHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/debugger/WebSocketHandler.java b/src/tools/debugger/WebSocketHandler.java index 23a83eca24..cd5c801001 100644 --- a/src/tools/debugger/WebSocketHandler.java +++ b/src/tools/debugger/WebSocketHandler.java @@ -23,8 +23,6 @@ public abstract class WebSocketHandler extends WebSocketServer { WebSocketHandler(final int port) { super(new InetSocketAddress(port), NUM_THREADS); this.connectionPort = new CompletableFuture<>(); - setReuseAddr(true); - setConnectionLostTimeout(0); } @Override @@ -66,6 +64,7 @@ public static class MessageHandler extends WebSocketHandler { public MessageHandler(final int port, final FrontendConnector connector, final Gson gson) { super(port); + this.setReuseAddr(true); this.connector = connector; this.gson = gson; } @@ -88,6 +87,7 @@ public static class TraceHandler extends WebSocketHandler { public TraceHandler(final int port) { super(port); + this.setReuseAddr(true); connection = new CompletableFuture<>(); } From adae4c6db4177543d6dacc27a7e94a46c47ce8db Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 8 Oct 2020 16:04:07 +0200 Subject: [PATCH 085/194] Update implementation of the received messages - use getCurrentActor instead of getActivity, we are interested in the actor that is currently being executed in the thread --- src/som/interpreter/actors/Actor.java | 27 ++++++++---- src/tools/concurrency/KomposTrace.java | 50 ++++++++++++++++++++++- src/tools/concurrency/TracingActors.java | 6 +-- src/tools/concurrency/TracingBackend.java | 25 ++++++++++-- 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index cd06831285..0e37e409b6 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -147,6 +147,7 @@ private void doSend(final EventualMessage msg, } else { appendToMailbox(msg); } + System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); //save messages in the trace when they are received //here we only save messages if the actor is suspended in debugger if (VmSettings.KOMPOS_TRACING) { @@ -253,24 +254,36 @@ private void doRunWithObjectSafepoints(final ActorProcessingThread t) { KomposTrace.currentActivity(actor); } - while (getCurrentMessagesOrCompleteExecution()) { - processCurrentMessages(t, dbg); + try { + while (getCurrentMessagesOrCompleteExecution()) { + saveReceivedMessages(t); + processCurrentMessages(t, dbg); + } + } finally { + ObjectTransitionSafepoint.INSTANCE.unregister(); } + + if (VmSettings.ACTOR_TRACING || VmSettings.KOMPOS_TRACING) { + t.swapTracingBufferIfRequestedUnsync(); + } + t.currentlyExecutingActor = null; } - protected void processCurrentMessages(final ActorProcessingThread currentThread, - final WebDebugger dbg) { - assert size > 0; + private void saveReceivedMessages(ActorProcessingThread t) { //save messages appended in mailbox in the trace before execute them if (VmSettings.KOMPOS_TRACING) { - KomposTrace.messageReception(firstMessage.getMessageId(), currentThread); + KomposTrace.actorMessageReception(firstMessage.getMessageId(), t); if (size > 1) { for (EventualMessage msg : mailboxExtension) { - KomposTrace.messageReception(msg.getMessageId(), currentThread); + KomposTrace.actorMessageReception(msg.getMessageId(), t); } } } + } + protected void processCurrentMessages(final ActorProcessingThread currentThread, + final WebDebugger dbg) { + assert size > 0; if (VmSettings.SNAPSHOTS_ENABLED && !VmSettings.TEST_SNAPSHOTS) { SnapshotBuffer sb = currentThread.getSnapshotBuffer(); diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index a2ee0d50bf..35592fbcfd 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -22,6 +22,7 @@ public class KomposTrace { private static Map> buffersByActor = new HashMap<>(); + private static Map> messagesReceivedByActor = new HashMap<>(); public static boolean missingBuffers(long actorSuspendedId) { List buffers = buffersByActor.get(actorSuspendedId); @@ -160,8 +161,43 @@ public static void recordSuspendedActivityByDebugger(TracingActivityThread t) { ((KomposTraceBuffer) t.getBuffer()).recordPausedActivity(t.getActivity()); } - public static void messageReception(long messageId, TracingActivityThread t) { - ((KomposTraceBuffer) t.getBuffer()).recordMessageReceived(MessageReception.MESSAGE_RCV, t.getActivity(), messageId); + public static void actorMessageReception(long messageId, TracingActivityThread t) { +// System.out.println("***** "+((Actor.ActorProcessingThread)t).getCurrentActor() +" activity "+((Actor.ActorProcessingThread)t).getActivity()); + Activity activity = t.getActivity(); + if (activity == null) { + activity = ((Actor.ActorProcessingThread) t).getCurrentActor(); + } + + if (!messageReceivedRecorded(messageId, activity.getId())) { + ((KomposTraceBuffer) t.getBuffer()).recordMessageReceived(MessageReception.MESSAGE_RCV, activity, messageId); + } + } + + /** + * Check the message has not been saved before. + * Messages received can be repeated because we record them at the point where the message is sent and when the messages are processed. + * This is needed because at the point where the message is append in the mailbox the TracingActivityThread may not be available, + * they become available when the actor is about to process the messages. + * + * @param messageId + * @param actorId + * @return + */ + private static boolean messageReceivedRecorded(long messageId, long actorId) { + List messages; + if (!messagesReceivedByActor.containsKey(actorId)) { + messages = new ArrayList<>(); + } else { + messages = messagesReceivedByActor.get(actorId); + } + + if (messages.contains(messageId)) { + return true; + } else { //new message + messages.add(messageId); + messagesReceivedByActor.put(actorId, messages); + } + return false; } public static class KomposTraceBuffer extends TraceBuffer { @@ -245,6 +281,8 @@ private void recordThreadId() { put(Implementation.IMPL_THREAD.getId()); putLong(implThreadId); +// System.out.println("thread "+implThreadId); + assert position == start + Implementation.IMPL_THREAD.getSize(); } @@ -267,6 +305,8 @@ public void recordCurrentActivity(final Activity current) { putLong(actorId); putInt(bufferId); +// System.out.println("recordCurrentActivity "+actorId +" "+bufferId); + List bufferList; if (buffersByActor.containsKey(actorId)) { bufferList = buffersByActor.get(actorId); @@ -418,6 +458,12 @@ public void recordMessageReceived(MessageReception mr, final Activity current, f put(mr.getId()); putLong(messageId); + System.out.println("-message received "+messageId +" actor "+current.getId()); + + if (position != start + requiredSpace ) { + System.out.println(); + } + assert position == start + requiredSpace; } diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 579de89444..fc5b97fa8e 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -12,7 +12,6 @@ import som.interpreter.actors.EventualMessage.PromiseMessage; import som.interpreter.actors.SPromise.STracingPromise; import som.vm.VmSettings; -import tools.ObjectBuffer; import tools.debugger.WebDebugger; import tools.debugger.frontend.Suspension; import tools.replay.PassiveEntityWithEvents; @@ -63,8 +62,9 @@ protected TracingActor(final VM vm, final long id) { public static void saveMessageReceived(Actor actor, EventualMessage message) { TracingActivityThread tracingActivityThread = TracingBackend.getTracingActivityThread(actor.getId()); - if (tracingActivityThread != null && tracingActivityThread.suspendedInDebugger) { //only record new msg for suspended actors - KomposTrace.messageReception(message.getMessageId(), tracingActivityThread); + if (tracingActivityThread != null) { +// System.out.println("saveMessageReceived "+message.getMessageId() + " "+actor.getId()); + KomposTrace.actorMessageReception(message.getMessageId(), tracingActivityThread); } } diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index e0c1b50b3f..17f41bd88f 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -27,6 +27,8 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.sun.management.GarbageCollectionNotificationInfo; +import som.Output; +import som.interpreter.actors.Actor; import som.interpreter.actors.Actor.ActorProcessingThread; import som.vm.VmSettings; import som.vm.constants.Classes; @@ -244,16 +246,31 @@ public static void unregisterThread(final TracingActivityThread t) { } } +// public static TracingActivityThread getTracingActivityThread(long actorId) { +// synchronized (tracingThreads) { +// TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); +// for (TracingActivityThread tracingActivityThread: result) { +// if (tracingActivityThread.getActivity()!= null && tracingActivityThread.getActivity().getId() == actorId) { +// return tracingActivityThread; +// } +// } +// return null; +// } +// } + public static TracingActivityThread getTracingActivityThread(long actorId) { synchronized (tracingThreads) { TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); - for (TracingActivityThread tracingActivityThread: result) { - if (tracingActivityThread.getActivity()!= null && tracingActivityThread.getActivity().getId() == actorId) { - return tracingActivityThread; + for (TracingActivityThread tracingActivityThread : result) { + if ((tracingActivityThread instanceof ActorProcessingThread)) { + Actor currentActor = ((ActorProcessingThread) tracingActivityThread).getCurrentActor(); + if (currentActor != null && currentActor.getId() == actorId) { + return tracingActivityThread; + } } } - return null; } + return null; } public static final void forceSwapBuffers() { From d2281f5863cf9f569f3854724732c2cfc32285be Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 8 Oct 2020 20:37:45 +0200 Subject: [PATCH 086/194] Comment prints --- src/som/interpreter/actors/Actor.java | 2 +- src/tools/concurrency/KomposTrace.java | 2 +- src/tools/debugger/WebSocketHandler.java | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 0e37e409b6..4071c52636 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -147,7 +147,7 @@ private void doSend(final EventualMessage msg, } else { appendToMailbox(msg); } - System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); +// System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); //save messages in the trace when they are received //here we only save messages if the actor is suspended in debugger if (VmSettings.KOMPOS_TRACING) { diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 35592fbcfd..753b85c16b 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -458,7 +458,7 @@ public void recordMessageReceived(MessageReception mr, final Activity current, f put(mr.getId()); putLong(messageId); - System.out.println("-message received "+messageId +" actor "+current.getId()); +// System.out.println("-message received "+messageId +" actor "+current.getId()); if (position != start + requiredSpace ) { System.out.println(); diff --git a/src/tools/debugger/WebSocketHandler.java b/src/tools/debugger/WebSocketHandler.java index cd5c801001..797cfdd95e 100644 --- a/src/tools/debugger/WebSocketHandler.java +++ b/src/tools/debugger/WebSocketHandler.java @@ -65,6 +65,7 @@ public MessageHandler(final int port, final FrontendConnector connector, final Gson gson) { super(port); this.setReuseAddr(true); +// this.setConnectionLostTimeout(0); //uncomment if timeout fails this.connector = connector; this.gson = gson; } @@ -88,6 +89,7 @@ public static class TraceHandler extends WebSocketHandler { public TraceHandler(final int port) { super(port); this.setReuseAddr(true); +// this.setConnectionLostTimeout(0); //uncomment if timeout fails connection = new CompletableFuture<>(); } From 86d1280aad11948b938de59e0198d5e6186999a3 Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 10 Oct 2020 16:51:20 +0200 Subject: [PATCH 087/194] Add log for update line breakpoint --- src/tools/debugger/session/Breakpoints.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index fd7ee05675..47c0785e41 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -64,6 +64,8 @@ public synchronized void addOrUpdate(final LineBreakpoint bId) { bp = Breakpoint.newBuilder(bId.getURI()).lineIs(bId.getLine()).build(); debuggerSession.install(bp); truffleBreakpoints.put(bId, bp); + } else { + WebDebugger.log("[DEBUGGER] Update LineBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); } bp.setEnabled(bId.isEnabled()); } From 0a67bd52f893a23fcc947661789c209e8bd85436 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 12 Oct 2020 21:51:38 +0200 Subject: [PATCH 088/194] Minor fix in log --- src/tools/debugger/session/Breakpoints.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index 47c0785e41..dc0ce4d5a7 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -60,7 +60,7 @@ public void prepareSteppingAfterNextRootNode(final Thread thread) { public synchronized void addOrUpdate(final LineBreakpoint bId) { Breakpoint bp = truffleBreakpoints.get(bId); if (bp == null) { - WebDebugger.log("[DEBUGGER] LineBreakpoint: " + bId); + WebDebugger.log("[DEBUGGER] LineBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); bp = Breakpoint.newBuilder(bId.getURI()).lineIs(bId.getLine()).build(); debuggerSession.install(bp); truffleBreakpoints.put(bId, bp); From bfd19b3ba2a516b3768f6dbe3d0f993620756ab9 Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 12 Oct 2020 21:58:10 +0200 Subject: [PATCH 089/194] Another minor fix in log --- src/tools/debugger/session/Breakpoints.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index dc0ce4d5a7..df15a1910f 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -76,7 +76,7 @@ public synchronized void addOrUpdate(final SectionBreakpoint bId) { if (existingBP == null) { existingBP = new BreakpointEnabling(bId); breakpoints.put(loc, existingBP); - WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId); + WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId +" Enabled: "+bId.isEnabled()); } else { existingBP.setEnabled(bId.isEnabled()); WebDebugger.log("[DEBUGGER] Update SectionBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); From 229a551f54eb31a62dedc52e2c7fbcd84a25bc01 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 13 Oct 2020 13:06:40 +0200 Subject: [PATCH 090/194] Add recordMessageReceived as synchronized - add missing method in SyncedKomposTraceBuffer --- src/tools/concurrency/KomposTrace.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 753b85c16b..fe87ad9f5f 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -515,7 +515,11 @@ public synchronized void recordSendOperation(final SendOp op, final long entityId, final long targetId, final Activity current, final short symbol, final long targetActorId, final SourceSection section, byte[] value) { super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, section, value); } + + @Override + public synchronized void recordMessageReceived(MessageReception mr, final Activity current, final long messageId) { + super.recordMessageReceived(mr, current, messageId); + } } } - } From 685e39aa8950ebff7dfc1ae60ceac9f3d64635ae Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 13 Oct 2020 13:07:45 +0200 Subject: [PATCH 091/194] Remove commented code --- src/som/interpreter/actors/Actor.java | 1 - src/tools/concurrency/TracingBackend.java | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 4071c52636..3a45584197 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -149,7 +149,6 @@ private void doSend(final EventualMessage msg, } // System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); //save messages in the trace when they are received - //here we only save messages if the actor is suspended in debugger if (VmSettings.KOMPOS_TRACING) { TracingActor.saveMessageReceived(this, msg); } diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index 17f41bd88f..9e63db7a20 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -246,18 +246,6 @@ public static void unregisterThread(final TracingActivityThread t) { } } -// public static TracingActivityThread getTracingActivityThread(long actorId) { -// synchronized (tracingThreads) { -// TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); -// for (TracingActivityThread tracingActivityThread: result) { -// if (tracingActivityThread.getActivity()!= null && tracingActivityThread.getActivity().getId() == actorId) { -// return tracingActivityThread; -// } -// } -// return null; -// } -// } - public static TracingActivityThread getTracingActivityThread(long actorId) { synchronized (tracingThreads) { TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); From 1fe46d8c6e157ee6a3c7ae7959a1eef9aff64e70 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 13 Oct 2020 14:28:38 +0200 Subject: [PATCH 092/194] Fix in TraceBuffer - use SyncedKomposTraceBuffer instead of KomposTraceBuffer in order to use the recording methods synchronized. This avoids assertion errors in the recording, because of interleavings of threads. --- src/tools/concurrency/TraceBuffer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/concurrency/TraceBuffer.java b/src/tools/concurrency/TraceBuffer.java index 7fee9fdfc4..6173618a1b 100644 --- a/src/tools/concurrency/TraceBuffer.java +++ b/src/tools/concurrency/TraceBuffer.java @@ -15,8 +15,8 @@ public abstract class TraceBuffer { public static TraceBuffer create(final long threadId) { assert VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING; - if (VmSettings.KOMPOS_TRACING) { - return new KomposTrace.KomposTraceBuffer(threadId); + if (VmSettings.KOMPOS_TRACING || VmSettings.TRUFFLE_DEBUGGER_ENABLED) { + return new KomposTrace.KomposTraceBuffer.SyncedKomposTraceBuffer(threadId); } else { return new UniformTraceBuffer(); } From 55117ab48307c3905058861ef8e23e8db3c946d8 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 13 Oct 2020 14:34:08 +0200 Subject: [PATCH 093/194] Comment unused code - declare recordCurrentActivity as synchronized --- src/tools/concurrency/KomposTrace.java | 55 +++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index fe87ad9f5f..d4b3405da6 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -21,23 +21,23 @@ public class KomposTrace { - private static Map> buffersByActor = new HashMap<>(); private static Map> messagesReceivedByActor = new HashMap<>(); - public static boolean missingBuffers(long actorSuspendedId) { - List buffers = buffersByActor.get(actorSuspendedId); - Collections.sort(buffers); - - for (int i = 1; i < buffers.size(); i++) { - int previous = buffers.get(i - 1); - int current = buffers.get(i); - if (current != (previous + 1)) { - return true; - } - } - - return false; - } +// private static Map> buffersByActor = new HashMap<>(); +// public static boolean missingBuffers(long actorSuspendedId) { +// List buffers = buffersByActor.get(actorSuspendedId); +// Collections.sort(buffers); +// +// for (int i = 1; i < buffers.size(); i++) { +// int previous = buffers.get(i - 1); +// int current = buffers.get(i); +// if (current != (previous + 1)) { +// return true; +// } +// } +// +// return false; +// } public static void recordMainActor(final Actor mainActor, final ObjectSystem objectSystem) { @@ -281,12 +281,10 @@ private void recordThreadId() { put(Implementation.IMPL_THREAD.getId()); putLong(implThreadId); -// System.out.println("thread "+implThreadId); - assert position == start + Implementation.IMPL_THREAD.getSize(); } - public void recordCurrentActivity(final Activity current) { + public synchronized void recordCurrentActivity(final Activity current) { if (current == null) { return; @@ -305,16 +303,19 @@ public void recordCurrentActivity(final Activity current) { putLong(actorId); putInt(bufferId); -// System.out.println("recordCurrentActivity "+actorId +" "+bufferId); - - List bufferList; - if (buffersByActor.containsKey(actorId)) { - bufferList = buffersByActor.get(actorId); - } else { - bufferList = new ArrayList<>(); +// List bufferList; +// if (buffersByActor.containsKey(actorId)) { +// bufferList = buffersByActor.get(actorId); +// } else { +// bufferList = new ArrayList<>(); +// } +// bufferList.add(bufferId); +// buffersByActor.put(actorId, bufferList); + + if (position != (start + Implementation.IMPL_CURRENT_ACTIVITY.getSize())) { + System.out.println(position +" "+(start + Implementation.IMPL_CURRENT_ACTIVITY.getSize())); } - bufferList.add(bufferId); - buffersByActor.put(actorId, bufferList); + assert position == start + Implementation.IMPL_CURRENT_ACTIVITY.getSize(); } From 7abef2aacc66b5c6af8a71b163af70913d9ffc44 Mon Sep 17 00:00:00 2001 From: carmen Date: Tue, 13 Oct 2020 14:35:16 +0200 Subject: [PATCH 094/194] Remove not needed code --- src/tools/concurrency/KomposTrace.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index d4b3405da6..80e91821c9 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -312,11 +312,6 @@ public synchronized void recordCurrentActivity(final Activity current) { // bufferList.add(bufferId); // buffersByActor.put(actorId, bufferList); - if (position != (start + Implementation.IMPL_CURRENT_ACTIVITY.getSize())) { - System.out.println(position +" "+(start + Implementation.IMPL_CURRENT_ACTIVITY.getSize())); - } - - assert position == start + Implementation.IMPL_CURRENT_ACTIVITY.getSize(); } From 67e7e84c1140d8c7c8b0f5d0b046597082b706a0 Mon Sep 17 00:00:00 2001 From: carmen Date: Thu, 15 Oct 2020 14:57:09 +0200 Subject: [PATCH 095/194] Specify the source element for truffle breakpoints - the Root element should be only used for asynchronous before and after. The expression element should not be used for these two breakpoints, it causes an activation of the SimpleCondition when resuming and pauses at the first expression of the method instead of the root node corresponding to the method. --- src/tools/debugger/session/Breakpoints.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index df15a1910f..dabc8af046 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -84,32 +84,32 @@ public synchronized void addOrUpdate(final SectionBreakpoint bId) { } public synchronized void addOrUpdateBeforeExpression(final SectionBreakpoint bId) { - saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.BEFORE); + saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.BEFORE, SourceElement.EXPRESSION); } public synchronized void addOrUpdateAfterExpression(final SectionBreakpoint bId) { - saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.AFTER); + saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.AFTER, SourceElement.EXPRESSION); } public synchronized void addOrUpdateAsyncBefore(final SectionBreakpoint bId) { - Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.BEFORE); + Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.BEFORE, SourceElement.ROOT); bp.setCondition(BreakWhenActivatedByAsyncMessage.INSTANCE); } public synchronized void addOrUpdateAsyncAfter(final SectionBreakpoint bId) { - Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.AFTER); + Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.AFTER, SourceElement.ROOT); bp.setCondition(BreakWhenActivatedByAsyncMessage.INSTANCE); } private Breakpoint saveTruffleBasedBreakpoints(final SectionBreakpoint bId, - final Class tag, final SuspendAnchor anchor) { + final Class tag, final SuspendAnchor anchor, SourceElement sourceElement) { Breakpoint bp = truffleBreakpoints.get(bId); if (bp == null) { WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId); bp = Breakpoint.newBuilder(bId.getCoordinate().uri).lineIs(bId.getCoordinate().startLine) .columnIs(bId.getCoordinate().startColumn) .sectionLength(bId.getCoordinate().charLength) - .sourceElements(SourceElement.EXPRESSION) + .sourceElements(sourceElement) .tag(tag) .suspendAnchor(anchor).build(); debuggerSession.install(bp); From 4c6c121ce539c7e7fe8cbcae20626ec622dad9e6 Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 17 Oct 2020 20:25:19 +0200 Subject: [PATCH 096/194] Revert change - source element expression is needed for async method breakpoints too. The root cause of the problem was in the frontend. --- src/tools/debugger/session/Breakpoints.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/session/Breakpoints.java index dabc8af046..df15a1910f 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/session/Breakpoints.java @@ -84,32 +84,32 @@ public synchronized void addOrUpdate(final SectionBreakpoint bId) { } public synchronized void addOrUpdateBeforeExpression(final SectionBreakpoint bId) { - saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.BEFORE, SourceElement.EXPRESSION); + saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.BEFORE); } public synchronized void addOrUpdateAfterExpression(final SectionBreakpoint bId) { - saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.AFTER, SourceElement.EXPRESSION); + saveTruffleBasedBreakpoints(bId, ExpressionBreakpoint.class, SuspendAnchor.AFTER); } public synchronized void addOrUpdateAsyncBefore(final SectionBreakpoint bId) { - Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.BEFORE, SourceElement.ROOT); + Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.BEFORE); bp.setCondition(BreakWhenActivatedByAsyncMessage.INSTANCE); } public synchronized void addOrUpdateAsyncAfter(final SectionBreakpoint bId) { - Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.AFTER, SourceElement.ROOT); + Breakpoint bp = saveTruffleBasedBreakpoints(bId, RootTag.class, SuspendAnchor.AFTER); bp.setCondition(BreakWhenActivatedByAsyncMessage.INSTANCE); } private Breakpoint saveTruffleBasedBreakpoints(final SectionBreakpoint bId, - final Class tag, final SuspendAnchor anchor, SourceElement sourceElement) { + final Class tag, final SuspendAnchor anchor) { Breakpoint bp = truffleBreakpoints.get(bId); if (bp == null) { WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId); bp = Breakpoint.newBuilder(bId.getCoordinate().uri).lineIs(bId.getCoordinate().startLine) .columnIs(bId.getCoordinate().startColumn) .sectionLength(bId.getCoordinate().charLength) - .sourceElements(sourceElement) + .sourceElements(SourceElement.EXPRESSION) .tag(tag) .suspendAnchor(anchor).build(); debuggerSession.install(bp); From 23e049191562d4b7707d28d9feecd45df86564cc Mon Sep 17 00:00:00 2001 From: carmen Date: Mon, 14 Dec 2020 10:15:27 +0100 Subject: [PATCH 097/194] Refactoring of breakpoints and async stack - rename package of session x breakpoints - move async stack implementation to debugger package --- src/som/VM.java | 2 +- src/som/interpreter/SArguments.java | 4 ++-- .../actors/AbstractPromiseResolutionNode.java | 3 --- src/som/interpreter/actors/ErrorNode.java | 2 +- src/som/interpreter/actors/ErrorPromiseNode.java | 3 +-- src/som/interpreter/actors/EventualMessage.java | 2 +- src/som/interpreter/actors/EventualSendNode.java | 3 +-- src/som/interpreter/actors/ReceivedMessage.java | 2 +- src/som/interpreter/actors/RegisterOnPromiseNode.java | 2 +- src/som/interpreter/actors/ResolveNode.java | 2 +- src/som/interpreter/actors/ResolvePromiseNode.java | 2 +- src/som/interpreter/actors/SPromise.java | 3 +-- .../interpreter/actors/SchedulePromiseHandlerNode.java | 2 +- src/som/interpreter/nodes/InternalObjectArrayNode.java | 2 +- src/som/interpreter/nodes/MessageSendNode.java | 2 +- .../nodes/dispatch/AbstractGenericDispatchNode.java | 2 +- .../interpreter/nodes/dispatch/BackCacheCallNode.java | 4 ++-- .../interpreter/nodes/dispatch/CachedDispatchNode.java | 2 +- src/som/interpreter/nodes/dispatch/CachedDnuNode.java | 2 +- .../nodes/dispatch/ClassSlotAccessNode.java | 2 +- .../nodes/dispatch/LexicallyBoundDispatchNode.java | 2 +- .../nodes/specialized/IntDownToDoMessageNode.java | 2 +- .../nodes/specialized/IntToByDoMessageNode.java | 3 +-- .../nodes/specialized/IntToDoMessageNode.java | 2 +- src/som/primitives/ActivitySpawn.java | 2 +- src/som/primitives/BlockPrims.java | 2 +- src/som/primitives/ExceptionsPrims.java | 2 +- src/som/primitives/SystemPrims.java | 10 +++------- src/som/primitives/actors/PromisePrims.java | 4 ++-- src/som/primitives/arrays/DoIndexesPrim.java | 2 +- src/som/primitives/arrays/DoPrim.java | 2 +- src/som/primitives/processes/ChannelPrimitives.java | 2 +- src/som/primitives/transactions/AtomicPrim.java | 2 +- src/tools/debugger/FrontendConnector.java | 4 ++-- src/tools/debugger/RuntimeReflectionRegistration.java | 6 +++--- src/tools/debugger/WebDebugger.java | 3 +-- .../asyncstacktraces/ShadowStackEntry.java | 3 +-- .../asyncstacktraces/ShadowStackEntryLoad.java | 2 +- .../{ => debugger}/asyncstacktraces/StackIterator.java | 10 +++++----- .../{session => breakpoints}/BreakpointEnabling.java | 2 +- .../{session => breakpoints}/BreakpointInfo.java | 2 +- .../debugger/{session => breakpoints}/Breakpoints.java | 2 +- .../{session => breakpoints}/LineBreakpoint.java | 2 +- .../{session => breakpoints}/SectionBreakpoint.java | 2 +- src/tools/debugger/entities/BreakpointType.java | 4 ++-- .../debugger/frontend/ApplicationThreadStack.java | 2 +- src/tools/debugger/message/InitializeConnection.java | 2 +- src/tools/debugger/message/UpdateBreakpoint.java | 2 +- src/tools/debugger/nodes/BreakpointNode.java | 2 +- tests/java/debugger/JsonTests.java | 6 +++--- 50 files changed, 64 insertions(+), 77 deletions(-) rename src/tools/{ => debugger}/asyncstacktraces/ShadowStackEntry.java (98%) rename src/tools/{ => debugger}/asyncstacktraces/ShadowStackEntryLoad.java (99%) rename src/tools/{ => debugger}/asyncstacktraces/StackIterator.java (97%) rename src/tools/debugger/{session => breakpoints}/BreakpointEnabling.java (97%) rename src/tools/debugger/{session => breakpoints}/BreakpointInfo.java (95%) rename src/tools/debugger/{session => breakpoints}/Breakpoints.java (99%) rename src/tools/debugger/{session => breakpoints}/LineBreakpoint.java (97%) rename src/tools/debugger/{session => breakpoints}/SectionBreakpoint.java (97%) diff --git a/src/som/VM.java b/src/som/VM.java index 35e001ad3b..a43ef8945b 100644 --- a/src/som/VM.java +++ b/src/som/VM.java @@ -53,7 +53,7 @@ import tools.concurrency.TracingActors; import tools.concurrency.TracingBackend; import tools.debugger.WebDebugger; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; import tools.dym.DynamicMetrics; import tools.replay.TraceParser; import tools.snapshot.SnapshotBackend; diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 9ba712e7d0..29bb6a98de 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -17,8 +17,8 @@ import som.interpreter.nodes.ExpressionNode; import som.vm.VmSettings; import som.vmobjects.SBlock; -import tools.asyncstacktraces.ShadowStackEntry; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public final class SArguments { diff --git a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java index 54747b90ba..3d4d1129c5 100644 --- a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java +++ b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java @@ -4,7 +4,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.GenerateWrapper; import com.oracle.truffle.api.instrumentation.ProbeNode; @@ -14,7 +13,6 @@ import bd.primitives.nodes.WithContext; import som.VM; -import som.interpreter.SArguments; import som.interpreter.actors.SPromise.Resolution; import som.interpreter.actors.SPromise.SReplayPromise; import som.interpreter.actors.SPromise.SResolver; @@ -22,7 +20,6 @@ import som.interpreter.nodes.nary.QuaternaryExpressionNode; import som.interpreter.nodes.nary.UnaryExpressionNode; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; import tools.concurrency.KomposTrace; import tools.concurrency.TracingActivityThread; import tools.replay.ReplayRecord; diff --git a/src/som/interpreter/actors/ErrorNode.java b/src/som/interpreter/actors/ErrorNode.java index 9c3671bf61..533c424671 100644 --- a/src/som/interpreter/actors/ErrorNode.java +++ b/src/som/interpreter/actors/ErrorNode.java @@ -7,7 +7,7 @@ import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; public abstract class ErrorNode extends AbstractPromiseResolutionNode { @CompilerDirectives.CompilationFinal diff --git a/src/som/interpreter/actors/ErrorPromiseNode.java b/src/som/interpreter/actors/ErrorPromiseNode.java index 083d14f99f..a9a16b22a8 100644 --- a/src/som/interpreter/actors/ErrorPromiseNode.java +++ b/src/som/interpreter/actors/ErrorPromiseNode.java @@ -8,11 +8,10 @@ import bd.primitives.Primitive; import bd.tools.nodes.Operation; import som.interpreter.SArguments; -import som.interpreter.actors.SPromise.Resolution; import som.interpreter.actors.SPromise.SResolver; import som.interpreter.nodes.nary.BinaryExpressionNode; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.dym.Tags.ComplexPrimitiveOperation; diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index fff952b6d7..2c7071abaa 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -20,7 +20,7 @@ import tools.snapshot.SnapshotBackend; import tools.snapshot.SnapshotBuffer; import som.interpreter.SArguments; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; public abstract class EventualMessage { diff --git a/src/som/interpreter/actors/EventualSendNode.java b/src/som/interpreter/actors/EventualSendNode.java index 1a1d3a9d21..5a4fd4f702 100644 --- a/src/som/interpreter/actors/EventualSendNode.java +++ b/src/som/interpreter/actors/EventualSendNode.java @@ -27,7 +27,6 @@ import som.interpreter.actors.RegisterOnPromiseNode.RegisterWhenResolved; import som.interpreter.actors.SPromise.SResolver; import som.interpreter.nodes.ExpressionNode; -import som.interpreter.nodes.InternalObjectArrayNode; import som.interpreter.nodes.MessageSendNode; import som.interpreter.nodes.MessageSendNode.AbstractMessageSendNode; import som.interpreter.nodes.SOMNode; @@ -41,7 +40,7 @@ import tools.debugger.entities.BreakpointType; import tools.debugger.entities.SendOp; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; import som.interpreter.SArguments; import som.interpreter.nodes.InternalObjectArrayNode.ArgumentEvaluationNode; import tools.dym.DynamicMetrics; diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index 9a330bbd0c..fbaad371fb 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -17,7 +17,7 @@ import som.interpreter.nodes.ExpressionNode; import som.vm.VmSettings; import som.vmobjects.SInvokable; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; public class ReceivedMessage extends ReceivedRootNode { diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 68b1950005..2027ecb913 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -15,7 +15,7 @@ import som.interpreter.actors.EventualMessage.PromiseMessage; import som.vm.VmSettings; import som.vmobjects.SBlock; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.dym.DynamicMetrics; import tools.replay.ReplayRecord; import tools.replay.TraceRecord; diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java index 44e5353696..8ae8a3fdc8 100644 --- a/src/som/interpreter/actors/ResolveNode.java +++ b/src/som/interpreter/actors/ResolveNode.java @@ -6,7 +6,7 @@ import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; public abstract class ResolveNode extends AbstractPromiseResolutionNode { diff --git a/src/som/interpreter/actors/ResolvePromiseNode.java b/src/som/interpreter/actors/ResolvePromiseNode.java index 96072bd2cc..bda18bf53d 100644 --- a/src/som/interpreter/actors/ResolvePromiseNode.java +++ b/src/som/interpreter/actors/ResolvePromiseNode.java @@ -13,7 +13,7 @@ import som.interpreter.actors.SPromise.SResolver; import som.interpreter.nodes.nary.BinaryExpressionNode; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.dym.Tags.ComplexPrimitiveOperation; diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index f0bca6475b..60f20131a4 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -11,7 +11,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ValueProfile; @@ -25,7 +24,7 @@ import som.vm.VmSettings; import som.vmobjects.SClass; import som.vmobjects.SObjectWithClass; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.concurrency.KomposTrace; import tools.concurrency.TracingActivityThread; import tools.concurrency.TracingActors.TracingActor; diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index b808868c2b..61f35d04e8 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -19,7 +19,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import som.interpreter.SArguments; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; /** diff --git a/src/som/interpreter/nodes/InternalObjectArrayNode.java b/src/som/interpreter/nodes/InternalObjectArrayNode.java index 88e87790c6..92f1fa957c 100644 --- a/src/som/interpreter/nodes/InternalObjectArrayNode.java +++ b/src/som/interpreter/nodes/InternalObjectArrayNode.java @@ -7,7 +7,7 @@ import som.interpreter.nodes.nary.ExprWithTagsNode; import som.interpreter.SArguments; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; @NodeInfo(cost = NodeCost.NONE) diff --git a/src/som/interpreter/nodes/MessageSendNode.java b/src/som/interpreter/nodes/MessageSendNode.java index 1b417229a0..3f84c88559 100644 --- a/src/som/interpreter/nodes/MessageSendNode.java +++ b/src/som/interpreter/nodes/MessageSendNode.java @@ -39,7 +39,7 @@ import tools.dym.Tags.VirtualInvoke; import tools.dym.profiles.DispatchProfile; import som.interpreter.SArguments; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; public final class MessageSendNode { diff --git a/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java b/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java index 152392631c..1e9c9f7a6e 100644 --- a/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java @@ -22,7 +22,7 @@ import som.vmobjects.SArray; import som.vmobjects.SClass; import som.vmobjects.SSymbol; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public abstract class AbstractGenericDispatchNode extends AbstractDispatchNode { diff --git a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java index 7d5411602a..76c6082501 100644 --- a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java +++ b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java @@ -9,8 +9,8 @@ import som.interpreter.Method; import som.interpreter.SArguments; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public interface BackCacheCallNode { diff --git a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java index 0b4fb1e05c..80ea4bc3d9 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java @@ -17,7 +17,7 @@ import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.impl.DefaultCallTarget; import som.interpreter.Invokable; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public final class CachedDispatchNode extends AbstractDispatchNode implements BackCacheCallNode { diff --git a/src/som/interpreter/nodes/dispatch/CachedDnuNode.java b/src/som/interpreter/nodes/dispatch/CachedDnuNode.java index 7df02cea66..54a6216688 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDnuNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDnuNode.java @@ -22,7 +22,7 @@ import som.vmobjects.SClass; import som.vmobjects.SInvokable; import som.vmobjects.SSymbol; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public final class CachedDnuNode extends AbstractDispatchNode { diff --git a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java index 095644b163..592cbbefe2 100644 --- a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java +++ b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java @@ -22,7 +22,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import som.interpreter.SArguments; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntry; /** diff --git a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java index b2572d8646..b8e27e279f 100644 --- a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java @@ -18,7 +18,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.impl.DefaultCallTarget; import som.interpreter.Method; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; /** diff --git a/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java index cac845bf18..f288d52f69 100644 --- a/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java @@ -10,7 +10,7 @@ import som.interpreter.nodes.specialized.IntToDoMessageNode.ToDoSplzr; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; @GenerateNodeFactory diff --git a/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java index 47a56d786d..0db42a8531 100644 --- a/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java @@ -7,7 +7,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.Node; import bd.primitives.Primitive; import som.interpreter.SArguments; @@ -16,7 +15,7 @@ import som.interpreter.objectstorage.ObjectTransitionSafepoint; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; import tools.dym.Tags.LoopNode; diff --git a/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java index 4256962685..5fd20bc090 100644 --- a/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java @@ -19,7 +19,7 @@ import som.vmobjects.SBlock; import som.vmobjects.SInvokable; import som.vmobjects.SSymbol; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; import tools.dym.Tags.LoopNode; diff --git a/src/som/primitives/ActivitySpawn.java b/src/som/primitives/ActivitySpawn.java index 9415105e84..dcefd16298 100644 --- a/src/som/primitives/ActivitySpawn.java +++ b/src/som/primitives/ActivitySpawn.java @@ -48,7 +48,7 @@ import tools.debugger.entities.ActivityType; import tools.debugger.entities.BreakpointType; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; diff --git a/src/som/primitives/BlockPrims.java b/src/som/primitives/BlockPrims.java index 6ea8aeee6f..22722c410f 100644 --- a/src/som/primitives/BlockPrims.java +++ b/src/som/primitives/BlockPrims.java @@ -34,7 +34,7 @@ import tools.dym.Tags.OpClosureApplication; import tools.dym.profiles.DispatchProfile; import com.oracle.truffle.api.frame.VirtualFrame; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public abstract class BlockPrims { diff --git a/src/som/primitives/ExceptionsPrims.java b/src/som/primitives/ExceptionsPrims.java index 387b796a0a..e7c60edd61 100644 --- a/src/som/primitives/ExceptionsPrims.java +++ b/src/som/primitives/ExceptionsPrims.java @@ -21,7 +21,7 @@ import som.vmobjects.SInvokable; import com.oracle.truffle.api.frame.VirtualFrame; import som.interpreter.SArguments; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public abstract class ExceptionsPrims { diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index 7d84c83ff7..c2659d0920 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -17,8 +17,6 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameInstance; -import com.oracle.truffle.api.frame.FrameInstanceVisitor; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; @@ -26,7 +24,6 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.SourceSection; import bd.primitives.Primitive; @@ -38,7 +35,6 @@ import som.compiler.MixinDefinition; import som.interop.ValueConversion.ToSomConversion; import som.interop.ValueConversionFactory.ToSomConversionNodeGen; -import som.interpreter.Invokable; import som.interpreter.Types; import som.interpreter.actors.Actor.ActorProcessingThread; import som.interpreter.actors.EventualMessage; @@ -73,9 +69,9 @@ import java.util.Arrays; import com.oracle.truffle.api.frame.VirtualFrame; -import tools.asyncstacktraces.ShadowStackEntry; -import tools.asyncstacktraces.ShadowStackEntryLoad; -import tools.asyncstacktraces.StackIterator; +import tools.debugger.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.StackIterator; import tools.debugger.frontend.ApplicationThreadStack.StackFrame; public final class SystemPrims { diff --git a/src/som/primitives/actors/PromisePrims.java b/src/som/primitives/actors/PromisePrims.java index 3f0445738a..9ee3f0078e 100644 --- a/src/som/primitives/actors/PromisePrims.java +++ b/src/som/primitives/actors/PromisePrims.java @@ -45,10 +45,10 @@ import tools.debugger.entities.BreakpointType; import tools.debugger.entities.SendOp; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; import com.oracle.truffle.api.frame.VirtualFrame; import som.interpreter.SArguments; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public final class PromisePrims { diff --git a/src/som/primitives/arrays/DoIndexesPrim.java b/src/som/primitives/arrays/DoIndexesPrim.java index ce9be78273..4d0b993888 100644 --- a/src/som/primitives/arrays/DoIndexesPrim.java +++ b/src/som/primitives/arrays/DoIndexesPrim.java @@ -17,7 +17,7 @@ import som.primitives.SizeAndLengthPrimFactory; import som.vmobjects.SArray; import som.vmobjects.SBlock; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; @GenerateNodeFactory diff --git a/src/som/primitives/arrays/DoPrim.java b/src/som/primitives/arrays/DoPrim.java index 4020b90e57..6f10efadcb 100644 --- a/src/som/primitives/arrays/DoPrim.java +++ b/src/som/primitives/arrays/DoPrim.java @@ -16,7 +16,7 @@ import som.vmobjects.SArray; import som.vmobjects.SArray.PartiallyEmptyArray; import som.vmobjects.SBlock; -import tools.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; @GenerateNodeFactory diff --git a/src/som/primitives/processes/ChannelPrimitives.java b/src/som/primitives/processes/ChannelPrimitives.java index aeef74517e..75c0ddec44 100644 --- a/src/som/primitives/processes/ChannelPrimitives.java +++ b/src/som/primitives/processes/ChannelPrimitives.java @@ -44,7 +44,7 @@ import tools.debugger.entities.BreakpointType; import tools.debugger.entities.PassiveEntityType; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; import tools.replay.ReplayRecord; import tools.replay.TraceParser; import tools.replay.TraceRecord; diff --git a/src/som/primitives/transactions/AtomicPrim.java b/src/som/primitives/transactions/AtomicPrim.java index aa68c1c9b7..5ed827a8f3 100644 --- a/src/som/primitives/transactions/AtomicPrim.java +++ b/src/som/primitives/transactions/AtomicPrim.java @@ -22,7 +22,7 @@ import tools.debugger.entities.EntityType; import tools.debugger.entities.SteppingType; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 27db8aebc7..dd426dcfe2 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -35,8 +35,8 @@ import tools.debugger.message.Message.OutgoingMessage; import tools.debugger.message.SourceMessage.SourceData; import tools.debugger.message.VariablesRequest.FilterType; -import tools.debugger.session.Breakpoints; -import tools.debugger.session.LineBreakpoint; +import tools.debugger.breakpoints.Breakpoints; +import tools.debugger.breakpoints.LineBreakpoint; /** diff --git a/src/tools/debugger/RuntimeReflectionRegistration.java b/src/tools/debugger/RuntimeReflectionRegistration.java index 6c7362196e..e3882e35fc 100644 --- a/src/tools/debugger/RuntimeReflectionRegistration.java +++ b/src/tools/debugger/RuntimeReflectionRegistration.java @@ -16,9 +16,9 @@ import tools.debugger.message.*; import tools.debugger.message.Message.IncommingMessage; import tools.debugger.message.Message.OutgoingMessage; -import tools.debugger.session.BreakpointInfo; -import tools.debugger.session.LineBreakpoint; -import tools.debugger.session.SectionBreakpoint; +import tools.debugger.breakpoints.BreakpointInfo; +import tools.debugger.breakpoints.LineBreakpoint; +import tools.debugger.breakpoints.SectionBreakpoint; /** diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index b185a51903..c3fdc7ddab 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -4,7 +4,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.concurrent.CompletableFuture; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.Instrument; @@ -33,7 +32,7 @@ import tools.concurrency.TracingActivityThread; import tools.concurrency.TracingActors; import tools.debugger.frontend.Suspension; -import tools.debugger.session.Breakpoints; +import tools.debugger.breakpoints.Breakpoints; /** diff --git a/src/tools/asyncstacktraces/ShadowStackEntry.java b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java similarity index 98% rename from src/tools/asyncstacktraces/ShadowStackEntry.java rename to src/tools/debugger/asyncstacktraces/ShadowStackEntry.java index e37665f0af..96e6d830dc 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java @@ -1,11 +1,10 @@ -package tools.asyncstacktraces; +package tools.debugger.asyncstacktraces; import com.oracle.truffle.api.instrumentation.InstrumentableNode.WrapperNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; -import som.interpreter.actors.Actor; import som.interpreter.actors.Actor.ActorProcessingThread; import som.interpreter.actors.EventualMessage; import som.vm.VmSettings; diff --git a/src/tools/asyncstacktraces/ShadowStackEntryLoad.java b/src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java similarity index 99% rename from src/tools/asyncstacktraces/ShadowStackEntryLoad.java rename to src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java index 57e950b293..dc60a97756 100644 --- a/src/tools/asyncstacktraces/ShadowStackEntryLoad.java +++ b/src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java @@ -1,4 +1,4 @@ -package tools.asyncstacktraces; +package tools.debugger.asyncstacktraces; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; diff --git a/src/tools/asyncstacktraces/StackIterator.java b/src/tools/debugger/asyncstacktraces/StackIterator.java similarity index 97% rename from src/tools/asyncstacktraces/StackIterator.java rename to src/tools/debugger/asyncstacktraces/StackIterator.java index c10caada01..ac91624f96 100644 --- a/src/tools/asyncstacktraces/StackIterator.java +++ b/src/tools/debugger/asyncstacktraces/StackIterator.java @@ -1,4 +1,4 @@ -package tools.asyncstacktraces; +package tools.debugger.asyncstacktraces; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; @@ -15,10 +15,10 @@ import som.interpreter.actors.EventualSendNode; import som.interpreter.nodes.dispatch.BackCacheCallNode; import som.vm.VmSettings; -import tools.asyncstacktraces.ShadowStackEntry.EntryAtMessageSend; -import tools.asyncstacktraces.ShadowStackEntry.EntryForPromiseResolution; -import tools.asyncstacktraces.StackIterator.ShadowStackIterator.HaltShadowStackIterator; -import tools.asyncstacktraces.StackIterator.ShadowStackIterator.SuspensionShadowStackIterator; +import tools.debugger.asyncstacktraces.ShadowStackEntry.EntryAtMessageSend; +import tools.debugger.asyncstacktraces.ShadowStackEntry.EntryForPromiseResolution; +import tools.debugger.asyncstacktraces.StackIterator.ShadowStackIterator.HaltShadowStackIterator; +import tools.debugger.asyncstacktraces.StackIterator.ShadowStackIterator.SuspensionShadowStackIterator; import tools.debugger.frontend.ApplicationThreadStack.StackFrame; import java.util.ArrayList; diff --git a/src/tools/debugger/session/BreakpointEnabling.java b/src/tools/debugger/breakpoints/BreakpointEnabling.java similarity index 97% rename from src/tools/debugger/session/BreakpointEnabling.java rename to src/tools/debugger/breakpoints/BreakpointEnabling.java index cd5d642b22..d663ea0c19 100644 --- a/src/tools/debugger/session/BreakpointEnabling.java +++ b/src/tools/debugger/breakpoints/BreakpointEnabling.java @@ -1,4 +1,4 @@ -package tools.debugger.session; +package tools.debugger.breakpoints; import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.Truffle; diff --git a/src/tools/debugger/session/BreakpointInfo.java b/src/tools/debugger/breakpoints/BreakpointInfo.java similarity index 95% rename from src/tools/debugger/session/BreakpointInfo.java rename to src/tools/debugger/breakpoints/BreakpointInfo.java index deaa0b2a55..b510372ccb 100644 --- a/src/tools/debugger/session/BreakpointInfo.java +++ b/src/tools/debugger/breakpoints/BreakpointInfo.java @@ -1,4 +1,4 @@ -package tools.debugger.session; +package tools.debugger.breakpoints; import com.oracle.truffle.api.debug.Breakpoint; diff --git a/src/tools/debugger/session/Breakpoints.java b/src/tools/debugger/breakpoints/Breakpoints.java similarity index 99% rename from src/tools/debugger/session/Breakpoints.java rename to src/tools/debugger/breakpoints/Breakpoints.java index df15a1910f..f5e0e6fc1f 100644 --- a/src/tools/debugger/session/Breakpoints.java +++ b/src/tools/debugger/breakpoints/Breakpoints.java @@ -1,4 +1,4 @@ -package tools.debugger.session; +package tools.debugger.breakpoints; import java.util.HashMap; import java.util.Map; diff --git a/src/tools/debugger/session/LineBreakpoint.java b/src/tools/debugger/breakpoints/LineBreakpoint.java similarity index 97% rename from src/tools/debugger/session/LineBreakpoint.java rename to src/tools/debugger/breakpoints/LineBreakpoint.java index 09787ea906..3f464b4e0e 100644 --- a/src/tools/debugger/session/LineBreakpoint.java +++ b/src/tools/debugger/breakpoints/LineBreakpoint.java @@ -1,4 +1,4 @@ -package tools.debugger.session; +package tools.debugger.breakpoints; import java.net.URI; import java.util.Objects; diff --git a/src/tools/debugger/session/SectionBreakpoint.java b/src/tools/debugger/breakpoints/SectionBreakpoint.java similarity index 97% rename from src/tools/debugger/session/SectionBreakpoint.java rename to src/tools/debugger/breakpoints/SectionBreakpoint.java index 8952d9f33d..0b0799ace3 100644 --- a/src/tools/debugger/session/SectionBreakpoint.java +++ b/src/tools/debugger/breakpoints/SectionBreakpoint.java @@ -1,4 +1,4 @@ -package tools.debugger.session; +package tools.debugger.breakpoints; import java.util.Objects; diff --git a/src/tools/debugger/entities/BreakpointType.java b/src/tools/debugger/entities/BreakpointType.java index feecdd39f0..00fb54673b 100644 --- a/src/tools/debugger/entities/BreakpointType.java +++ b/src/tools/debugger/entities/BreakpointType.java @@ -16,8 +16,8 @@ import tools.concurrency.Tags.ReleaseLock; import tools.concurrency.Tags.WhenResolved; import tools.concurrency.Tags.WhenResolvedOnError; -import tools.debugger.session.Breakpoints; -import tools.debugger.session.SectionBreakpoint; +import tools.debugger.breakpoints.Breakpoints; +import tools.debugger.breakpoints.SectionBreakpoint; @SuppressWarnings({"unchecked", "rawtypes"}) diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 0e3105d0fd..267e1ca3b4 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -7,7 +7,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; -import tools.asyncstacktraces.StackIterator; +import tools.debugger.asyncstacktraces.StackIterator; import som.interpreter.LexicalScope.MethodScope; diff --git a/src/tools/debugger/message/InitializeConnection.java b/src/tools/debugger/message/InitializeConnection.java index 61ca8b5920..8b9effa95d 100644 --- a/src/tools/debugger/message/InitializeConnection.java +++ b/src/tools/debugger/message/InitializeConnection.java @@ -4,7 +4,7 @@ import tools.debugger.FrontendConnector; import tools.debugger.message.Message.IncommingMessage; -import tools.debugger.session.BreakpointInfo; +import tools.debugger.breakpoints.BreakpointInfo; public class InitializeConnection extends IncommingMessage { diff --git a/src/tools/debugger/message/UpdateBreakpoint.java b/src/tools/debugger/message/UpdateBreakpoint.java index f9d9b47e5b..a70c0fda08 100644 --- a/src/tools/debugger/message/UpdateBreakpoint.java +++ b/src/tools/debugger/message/UpdateBreakpoint.java @@ -4,7 +4,7 @@ import tools.debugger.FrontendConnector; import tools.debugger.message.Message.IncommingMessage; -import tools.debugger.session.BreakpointInfo; +import tools.debugger.breakpoints.BreakpointInfo; public class UpdateBreakpoint extends IncommingMessage { diff --git a/src/tools/debugger/nodes/BreakpointNode.java b/src/tools/debugger/nodes/BreakpointNode.java index 22babb2728..4bec212134 100644 --- a/src/tools/debugger/nodes/BreakpointNode.java +++ b/src/tools/debugger/nodes/BreakpointNode.java @@ -4,7 +4,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; -import tools.debugger.session.BreakpointEnabling; +import tools.debugger.breakpoints.BreakpointEnabling; /** diff --git a/tests/java/debugger/JsonTests.java b/tests/java/debugger/JsonTests.java index 90cc3f991c..a17ec3634b 100644 --- a/tests/java/debugger/JsonTests.java +++ b/tests/java/debugger/JsonTests.java @@ -23,9 +23,9 @@ import tools.debugger.message.Message.IncommingMessage; import tools.debugger.message.Message.OutgoingMessage; import tools.debugger.message.UpdateBreakpoint; -import tools.debugger.session.BreakpointInfo; -import tools.debugger.session.LineBreakpoint; -import tools.debugger.session.SectionBreakpoint; +import tools.debugger.breakpoints.BreakpointInfo; +import tools.debugger.breakpoints.LineBreakpoint; +import tools.debugger.breakpoints.SectionBreakpoint; public class JsonTests { From a1d74c7bf144934ba3b7d3ee0aeb503488ad11ad Mon Sep 17 00:00:00 2001 From: carmen Date: Sat, 29 May 2021 14:11:19 +0200 Subject: [PATCH 098/194] Fix bug when saving the resolution value - old implementation was saving last value, now the value is correct for each promise resolution entry --- src/som/interpreter/actors/ErrorNode.java | 3 +-- .../interpreter/actors/ReceivedMessage.java | 8 +++--- .../actors/RegisterOnPromiseNode.java | 4 +-- src/som/interpreter/actors/ResolveNode.java | 5 ++-- src/som/interpreter/actors/SPromise.java | 3 +-- .../actors/SchedulePromiseHandlerNode.java | 2 +- .../asyncstacktraces/ShadowStackEntry.java | 25 +++++++------------ .../asyncstacktraces/StackIterator.java | 3 ++- 8 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/som/interpreter/actors/ErrorNode.java b/src/som/interpreter/actors/ErrorNode.java index 533c424671..ad936738d7 100644 --- a/src/som/interpreter/actors/ErrorNode.java +++ b/src/som/interpreter/actors/ErrorNode.java @@ -37,9 +37,8 @@ public SPromise.SResolver standardError(final VirtualFrame frame, ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ERROR; - location.setArg(", error: "+result.toString()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location); + ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location, "error: "+result.toString()); SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); } diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index fbaad371fb..ed4ee6b856 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -48,9 +48,9 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_RECEIVE_MESSAGE; -// onReceiveLocation.setArg(msg.getTarget().getId() + " sent by actor "+ msg.getSender().getId()); +// String resolutionValue = (msg.getTarget().getId() + " sent by actor "+ msg.getSender().getId()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, onReceiveLocation); + ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, onReceiveLocation, ""); } try { @@ -128,9 +128,9 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_BLOCK; -// onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); +// String resolutionValue = (msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), onReceiveLocation); + ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), onReceiveLocation, ""); SArguments.setShadowStackEntry(msg.getArgs(), resolutionEntry); } diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 2027ecb913..8c3fa168f3 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -95,7 +95,7 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro //for whenResolved blocks or if promise is resolved, then create EntryForPromiseResolution ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent(), onReceiveLocation); + getParent().getParent(), onReceiveLocation, ""); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } @@ -206,7 +206,7 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro // we want to know where it was resolved, where the value is coming from ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_ERROR); + getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_ERROR, ""); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java index 8ae8a3fdc8..96e95a695e 100644 --- a/src/som/interpreter/actors/ResolveNode.java +++ b/src/som/interpreter/actors/ResolveNode.java @@ -38,10 +38,9 @@ public SPromise.SResolver normalResolution(final VirtualFrame frame, if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.SUCCESSFUL; - location.setArg(", value: "+result.toString()); + final ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.SUCCESSFUL; resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location); + ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location, "value: "+result.toString()); SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); } diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index 60f20131a4..d243cdfe4f 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -798,9 +798,8 @@ protected static void resolveChainedPromisesUnsync(final Resolution type, ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || maybeEntry != null; ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.CHAINED; - location.setArg(", promise: "+promise.toString()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, expression, location); + ShadowStackEntry.createAtPromiseResolution(entry, expression, location, "promise: "+promise.toString()); SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); } diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index 61f35d04e8..f019322a36 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -57,7 +57,7 @@ public final void schedule(final VirtualFrame frame, final SPromise promise, // onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( SArguments.getShadowStackEntry(frame), - getParent().getParent(), onReceiveLocation); + getParent().getParent(), onReceiveLocation, ""); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } diff --git a/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java index 96e6d830dc..82bfb9e4bb 100644 --- a/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java @@ -44,9 +44,9 @@ public static ShadowStackEntry createAtAsyncSend(final ShadowStackEntry previous } public static ShadowStackEntry createAtPromiseResolution(final ShadowStackEntry previous, - final Node expr, final EntryForPromiseResolution.ResolutionLocation resolutionType) { + final Node expr, final EntryForPromiseResolution.ResolutionLocation resolutionType, final String resolutionValue) { assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; - return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr), resolutionType); + return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr), resolutionType, resolutionValue); } public static Node unwrapNodeIfNecessary(final Node node) { @@ -106,32 +106,25 @@ public enum ResolutionLocation { ON_WHEN_RESOLVED("on whenResolved"), ON_WHEN_RESOLVED_ERROR("on whenResolved error"), ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE("on schedule"); - private final String value; - private String arg = ""; + private final String label; - ResolutionLocation(String value) { - this.value = value; + ResolutionLocation(String label) { + this.label = label; } public String getValue() { - return value; - } - - public String getArg() { - return arg; - } - - public void setArg(String arg){ - this.arg = arg; + return label; } } public ResolutionLocation resolutionLocation; + public String resolutionValue; private EntryForPromiseResolution(final ShadowStackEntry previous, - final Node expr, ResolutionLocation resolutionLocation) { + final Node expr, ResolutionLocation resolutionLocation, String resolutionValue) { super(previous, expr); this.resolutionLocation = resolutionLocation; + this.resolutionValue = resolutionValue; } @Override diff --git a/src/tools/debugger/asyncstacktraces/StackIterator.java b/src/tools/debugger/asyncstacktraces/StackIterator.java index ac91624f96..688df99b46 100644 --- a/src/tools/debugger/asyncstacktraces/StackIterator.java +++ b/src/tools/debugger/asyncstacktraces/StackIterator.java @@ -261,7 +261,8 @@ protected StackFrame createStackFrame(final ShadowStackEntry shadow, useAgainFrame = localFrame; } else if (shadow instanceof EntryForPromiseResolution) { EntryForPromiseResolution.ResolutionLocation resolutionLocation = ((EntryForPromiseResolution) shadow).resolutionLocation; - name = "actor " + shadow.actorId + ", " + resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName() + " " + resolutionLocation.getArg(); + String resolutionValue = ((EntryForPromiseResolution) shadow).resolutionValue; + name = "actor " + shadow.actorId + ", " + resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName() + " " + resolutionValue; } } else { From fcd47f79675999046e440f66742e6b296c1b42cd Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 5 Oct 2022 00:27:40 +0100 Subject: [PATCH 099/194] =?UTF-8?q?Update=20truffle=20with=20ctrlpz?= =?UTF-8?q?=E2=80=99=20debugging=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Marr --- libs/truffle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/truffle b/libs/truffle index acb60536e8..c3055fe4e3 160000 --- a/libs/truffle +++ b/libs/truffle @@ -1 +1 @@ -Subproject commit acb60536e81fae64d6409ca07c959bde4e402bd5 +Subproject commit c3055fe4e35b2dc7507558ae735b9303d061979a From 185880cbc3fbe5e84648ebdfda53100771e66838 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 5 Oct 2022 00:28:12 +0100 Subject: [PATCH 100/194] Added Java-WebSocket-1.5.1.jar to Eclipse classpath Signed-off-by: Stefan Marr --- .classpath | 1 + 1 file changed, 1 insertion(+) diff --git a/.classpath b/.classpath index 3de5a861a7..0a09fb80a2 100644 --- a/.classpath +++ b/.classpath @@ -13,6 +13,7 @@ + From dc699001da62ce36fd0283df096f218abf5989e1 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 5 Oct 2022 00:28:57 +0100 Subject: [PATCH 101/194] Fix remaining compilation errors Signed-off-by: Stefan Marr --- src/som/interpreter/actors/Actor.java | 18 +-- .../actors/EagerResolvePromiseNode.java | 8 +- .../interpreter/actors/EventualMessage.java | 46 ++++---- .../actors/ResolvePromiseNode.java | 9 +- src/som/interpreter/actors/SPromise.java | 108 +++++++++++------- .../interpreter/nodes/IsValueCheckNode.java | 4 +- src/som/primitives/StringPrims.java | 7 +- 7 files changed, 114 insertions(+), 86 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 3a45584197..8a02923c57 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -140,15 +140,15 @@ private void doSend(final EventualMessage msg, assert msg.getTarget() == this; assert msg.args[msg.args.length - 1] != null - || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; if (firstMessage == null) { firstMessage = msg; } else { appendToMailbox(msg); } -// System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); - //save messages in the trace when they are received + // System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); + // save messages in the trace when they are received if (VmSettings.KOMPOS_TRACING) { TracingActor.saveMessageReceived(this, msg); } @@ -214,8 +214,7 @@ protected ExecAllMessages(final Actor actor, final VM vm) { @Override public void run() { - assert executorRoot != null - : "Actor system not initalized, call to initializeActorSystem(.) missing?"; + assert executorRoot != null : "Actor system not initalized, call to initializeActorSystem(.) missing?"; executorRoot.call(this); } @@ -262,14 +261,14 @@ private void doRunWithObjectSafepoints(final ActorProcessingThread t) { ObjectTransitionSafepoint.INSTANCE.unregister(); } - if (VmSettings.ACTOR_TRACING || VmSettings.KOMPOS_TRACING) { + if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { t.swapTracingBufferIfRequestedUnsync(); } t.currentlyExecutingActor = null; } - private void saveReceivedMessages(ActorProcessingThread t) { - //save messages appended in mailbox in the trace before execute them + private void saveReceivedMessages(final ActorProcessingThread t) { + // save messages appended in mailbox in the trace before execute them if (VmSettings.KOMPOS_TRACING) { KomposTrace.actorMessageReception(firstMessage.getMessageId(), t); if (size > 1) { @@ -351,7 +350,8 @@ protected void execute(final ForkJoinPool actorPool) { } @Override - public void setStepToNextTurn(final boolean val) {} + public void setStepToNextTurn(final boolean val) { + } public static final class ActorProcessingThreadFactory implements ForkJoinWorkerThreadFactory { diff --git a/src/som/interpreter/actors/EagerResolvePromiseNode.java b/src/som/interpreter/actors/EagerResolvePromiseNode.java index d826b876e7..a3e03ca0a7 100644 --- a/src/som/interpreter/actors/EagerResolvePromiseNode.java +++ b/src/som/interpreter/actors/EagerResolvePromiseNode.java @@ -17,26 +17,26 @@ public abstract class EagerResolvePromiseNode extends BinaryExpressionNode implements WithContext { - @Child protected AbstractPromiseResolutionNode resolve; + @Child protected ResolvePromiseNode resolve; @Override @SuppressWarnings("unchecked") public EagerResolvePromiseNode initialize(final SourceSection sourceSection) { super.initialize(sourceSection); - resolve = ResolvePromiseNodeFactory.create(null, null, null, null); + resolve = ResolvePromiseNodeFactory.create(null, null); resolve.initialize(sourceSection); return this; } @Override public final EagerResolvePromiseNode initialize(final VM vm) { - resolve.initialize(vm); + // resolve.initialize(vm); return this; } @Specialization public SResolver resolve(final VirtualFrame frame, final SResolver resolver, final Object value) { - return (SResolver) resolve.executeEvaluated(frame, resolver, value, false, false); + return resolve.executeEvaluated(frame, resolver, value); } } diff --git a/src/som/interpreter/actors/EventualMessage.java b/src/som/interpreter/actors/EventualMessage.java index 2c7071abaa..1b88aa3f7b 100644 --- a/src/som/interpreter/actors/EventualMessage.java +++ b/src/som/interpreter/actors/EventualMessage.java @@ -8,6 +8,7 @@ import som.VM; import som.interpreter.Method; +import som.interpreter.SArguments; import som.interpreter.actors.Actor.ActorProcessingThread; import som.interpreter.actors.ReceivedMessage.ReceivedCallback; import som.interpreter.actors.SPromise.SResolver; @@ -15,12 +16,11 @@ import som.vmobjects.SBlock; import som.vmobjects.SSymbol; import tools.concurrency.TracingActivityThread; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.parser.KomposTraceParser; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; import tools.snapshot.SnapshotBackend; import tools.snapshot.SnapshotBuffer; -import som.interpreter.SArguments; -import tools.debugger.asyncstacktraces.ShadowStackEntry; public abstract class EventualMessage { @@ -141,8 +141,7 @@ protected AbstractDirectMessage(final Actor target, final SSymbol selector, } assert target != null; - assert !(args[0] instanceof SFarReference) - : "needs to be guaranted by call to this constructor"; + assert !(args[0] instanceof SFarReference) : "needs to be guaranted by call to this constructor"; assert !(args[0] instanceof SPromise); } @@ -163,8 +162,7 @@ protected AbstractDirectMessage(final Actor target, final SSymbol selector, } assert target != null; - assert !(args[0] instanceof SFarReference) - : "needs to be guaranted by call to this constructor"; + assert !(args[0] instanceof SFarReference) : "needs to be guaranted by call to this constructor"; assert !(args[0] instanceof SPromise); } @@ -228,8 +226,7 @@ protected static Actor determineTargetAndWrapArguments(final Object[] arguments, // we need to redirect the message to the owner of that far reference Object receiver = WrapReferenceNode.wrapForUse(target, arguments[0], currentSender, null); - assert !(receiver instanceof SPromise) - : "TODO: handle this case as well?? Is it possible? didn't think about it"; + assert !(receiver instanceof SPromise) : "TODO: handle this case as well?? Is it possible? didn't think about it"; if (receiver instanceof SFarReference) { // now we are about to send a message to a far reference, so, it @@ -240,8 +237,7 @@ protected static Actor determineTargetAndWrapArguments(final Object[] arguments, arguments[0] = receiver; - assert !(receiver instanceof SFarReference) - : "this should not happen, because we need to redirect messages to the other actor, and normally we just unwrapped this"; + assert !(receiver instanceof SFarReference) : "this should not happen, because we need to redirect messages to the other actor, and normally we just unwrapped this"; assert !(receiver instanceof SPromise); for (int i = 1; i < SArguments.getLengthWithoutShadowStack(arguments); i++) { @@ -272,7 +268,8 @@ public PromiseMessage(final Object[] arguments, final Actor originalSender, } public abstract void resolve(Object rcvr, Actor target, Actor sendingActor, - Object maybeEntry); + Object maybeEntry); + @Override public final Actor getSender() { assert originalSender != null; @@ -315,7 +312,8 @@ protected AbstractPromiseSendMessage(final SSymbol selector, } @Override - public void resolve(final Object rcvr, final Actor target, final Actor sendingActor, final Object maybeEntry) { + public void resolve(final Object rcvr, final Actor target, final Actor sendingActor, + final Object maybeEntry) { determineAndSetTarget(rcvr, target, sendingActor, maybeEntry); } @@ -334,7 +332,8 @@ private void determineAndSetTarget(final Object rcvr, final Actor target, ActorProcessingThread.currentThread().getSnapshotId()); } - //save promise resolution entry corresponding to the promise to which the message is sent + // save promise resolution entry corresponding to the promise to which the message is + // sent if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { SArguments.saveCausalEntryForPromise(maybeEntry, args[args.length - 1]); } @@ -400,14 +399,14 @@ public abstract static class AbstractPromiseCallbackMessage extends PromiseMessa * The promise on which this callback is registered on. */ @CompilationFinal protected SPromise promise; - @CompilationFinal protected SBlock callback; + @CompilationFinal protected SBlock callback; protected AbstractPromiseCallbackMessage(final Actor owner, final SBlock callback, final SResolver resolver, final RootCallTarget onReceive, final boolean triggerMessageReceiverBreakpoint, final boolean triggerPromiseResolverBreakpoint, final SPromise promiseRegisteredOn) { super(SArguments.getPromiseCallbackArgumentArray(callback), owner, - resolver, onReceive, + resolver, onReceive, triggerMessageReceiverBreakpoint, triggerPromiseResolverBreakpoint); this.promise = promiseRegisteredOn; this.callback = callback; @@ -415,7 +414,7 @@ protected AbstractPromiseCallbackMessage(final Actor owner, final SBlock callbac @Override public void resolve(final Object rcvr, final Actor target, final Actor sendingActor, - final Object maybeEntry) { + final Object maybeEntry) { setPromiseValue(rcvr, sendingActor, maybeEntry); } @@ -426,19 +425,24 @@ public void resolve(final Object rcvr, final Actor target, final Actor sendingAc * @param resolvingActor - the owner of the value, the promise was resolved to. */ private void setPromiseValue(final Object value, final Actor resolvingActor, - final Object maybeEntry) { - args[PROMISE_VALUE_IDX] = WrapReferenceNode.wrapForUse(originalSender, alue, resolvingActor, null); - //save promise resolution entry corresponding to the promise to which this callback is registered on + final Object maybeEntry) { + args[PROMISE_VALUE_IDX] = + WrapReferenceNode.wrapForUse(originalSender, value, resolvingActor, null); + // save promise resolution entry corresponding to the promise to which this callback is + // registered on if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { assert args[args.length - 1] instanceof ShadowStackEntry; ShadowStackEntry callPromiseStack = (ShadowStackEntry) args[args.length - 1]; boolean promiseGroup = false; if (callPromiseStack.getExpression().getParent().getParent() instanceof Method) { - promiseGroup = ((Method)callPromiseStack.getExpression().getParent().getParent()).getName().startsWith("PromiseGroup"); + promiseGroup = + ((Method) callPromiseStack.getExpression().getParent() + .getParent()).getName().startsWith("PromiseGroup"); } if (promiseGroup) { - SArguments.saveCausalEntryForPromiseGroup(maybeEntry, args[args.length - 1], promise.getOwner().getId()); + SArguments.saveCausalEntryForPromiseGroup(maybeEntry, args[args.length - 1], + promise.getOwner().getId()); } else { SArguments.saveCausalEntryForPromise(maybeEntry, args[args.length - 1]); } diff --git a/src/som/interpreter/actors/ResolvePromiseNode.java b/src/som/interpreter/actors/ResolvePromiseNode.java index bda18bf53d..855c64f695 100644 --- a/src/som/interpreter/actors/ResolvePromiseNode.java +++ b/src/som/interpreter/actors/ResolvePromiseNode.java @@ -1,6 +1,5 @@ package som.interpreter.actors; -import bd.primitives.Primitive; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; @@ -9,7 +8,6 @@ import bd.primitives.Primitive; import bd.tools.nodes.Operation; import som.interpreter.SArguments; -import som.interpreter.actors.SPromise.Resolution; import som.interpreter.actors.SPromise.SResolver; import som.interpreter.nodes.nary.BinaryExpressionNode; import som.vm.VmSettings; @@ -19,16 +17,19 @@ @GenerateNodeFactory @Primitive(primitive = "actorsResolve:with:") -public abstract class ResolvePromiseNode extends BinaryExpressionNode { +public abstract class ResolvePromiseNode extends BinaryExpressionNode implements Operation { @Child protected ResolveNode resolve; public ResolvePromiseNode() { resolve = ResolveNodeGen.create(null, null, null, null, null); } + public abstract SResolver executeEvaluated(VirtualFrame frame, SResolver resolver, + Object result); + @Specialization public SResolver normalResolution(final VirtualFrame frame, final SResolver resolver, - final Object result) { + final Object result) { ShadowStackEntry entry = SArguments.getShadowStackEntry(frame); assert entry != null || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; return (SResolver) resolve.executeEvaluated(frame, resolver, result, entry, false, false); diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index d243cdfe4f..779be4b363 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -24,10 +24,10 @@ import som.vm.VmSettings; import som.vmobjects.SClass; import som.vmobjects.SObjectWithClass; -import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.concurrency.KomposTrace; import tools.concurrency.TracingActivityThread; import tools.concurrency.TracingActors.TracingActor; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.debugger.entities.PassiveEntityType; import tools.dym.DynamicMetrics; import tools.replay.PassiveEntityWithEvents; @@ -317,8 +317,7 @@ public final Resolution getResolutionStateUnsync() { } public final boolean assertNotCompleted() { - assert !isCompleted() - : "Not sure yet what to do with re-resolving of promises? just ignore it? Error?"; + assert !isCompleted() : "Not sure yet what to do with re-resolving of promises? just ignore it? Error?"; assert value == null : "If it isn't resolved yet, it shouldn't have a value"; return true; } @@ -420,7 +419,8 @@ protected SReplayPromise(final Actor owner, final boolean haltOnResolver, @TruffleBoundary public void handleReplayResolution(final boolean haltOnResolution, final Actor resolver, - final Resolution type, final ValueProfile whenResolvedProfile) { + final Resolution type, final ValueProfile whenResolvedProfile, + final Object maybeEntry) { assert !handled; handled = true; @@ -470,7 +470,7 @@ public void handleReplayResolution(final boolean haltOnResolution, final Actor r if (todo != null) { while (!todo.isEmpty()) { PromiseMessage pm = todo.poll(); - pm.resolve(this.value, owner, (Actor) current); + pm.resolve(this.value, owner, (Actor) current, maybeEntry); npr = current.getNextReplayEvent(); assert npr.type == TraceRecord.MESSAGE : "was " + npr.type + " in " @@ -569,13 +569,15 @@ private void tryPerformDelayedResolution() { if (toSend != null) { while (!toSend.isEmpty()) { PromiseMessage pm = toSend.remove(); - pm.resolve(this.value, owner, resolver); + // TODO: can we better than passing null as maybeEntry? + Object maybeEntry = null; + pm.resolve(this.value, owner, resolver, maybeEntry); npr = current.getNextReplayEvent(); assert npr.type == TraceRecord.MESSAGE; pm.setReplayVersion(npr.eventNo); this.scheduleCallbacksOnResolution(this.value, pm, resolver, - SomLanguage.getCurrent().getVM().getActorPool(), + SomLanguage.getCurrent().getVM().getActorPool(), maybeEntry, haltOnResolution); } } @@ -609,11 +611,13 @@ private void sendDelayedMessages() { if (delayedMessages != null) { Activity current = TracingActivityThread.currentThread().getActivity(); for (Entry> e : delayedMessages.entrySet()) { + // TODO: can we do better than maybeEntry == null? + Object maybeEntry = null; PromiseMessage pm = e.getKey(); LinkedList events = e.getValue(); current.getReplayEventBuffer().addAll(0, events); this.scheduleCallbacksOnResolution(value, pm, (Actor) current, - SomLanguage.getCurrent().getVM().getActorPool(), haltOnResolution); + SomLanguage.getCurrent().getVM().getActorPool(), maybeEntry, haltOnResolution); } } } @@ -681,11 +685,13 @@ private void resolveChainedPromisesReplay(final Resolution type, if (replayChainedPromises != null) { while (!replayChainedPromises.isEmpty()) { SReplayPromise rp = replayChainedPromises.remove(); + // TODO: can we do better than maybeEntry == null? + Object maybeEntry = null; Object wrapped = WrapReferenceNode.wrapForUse(rp.owner, value, resolver, null); SResolver.resolveAndTriggerListenersUnsynced(type, value, wrapped, rp, resolver, - SomLanguage.getCurrent().getVM().getActorPool(), haltOnResolution, - whenResolvedProfile, null, null); + SomLanguage.getCurrent().getVM().getActorPool(), maybeEntry, haltOnResolution, + whenResolvedProfile, null, null, null, null); } } } @@ -774,11 +780,12 @@ public boolean assertNotCompleted() { */ // TODO: solve the TODO and then remove the TruffleBoundary, this might even need to go // into a node -// @TruffleBoundary + // @TruffleBoundary protected static void resolveChainedPromisesUnsync(final Resolution type, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, - final ValueProfile whenResolvedProfile, final VirtualFrame frame, final Node expression, final RecordOneEvent record, + final ValueProfile whenResolvedProfile, final VirtualFrame frame, + final Node expression, final RecordOneEvent record, final RecordOneEvent recordStop) { // TODO: we should change the implementation of chained promises to // always move all the handlers to the other promise, then we @@ -788,38 +795,44 @@ protected static void resolveChainedPromisesUnsync(final Resolution type, if (promise.chainedPromise != null) { SPromise chainedPromise = promise.chainedPromise; promise.chainedPromise = null; - Object wrapped = WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); - + Object wrapped = + WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); ShadowStackEntry resolutionEntry = null; - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { -// MaterializedFrame context = promise.getContext(); - - ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || maybeEntry != null; - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.CHAINED; - resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, expression, location, "promise: "+promise.toString()); - - SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); - } + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // MaterializedFrame context = promise.getContext(); + + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || maybeEntry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.CHAINED; + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, expression, location, + "promise: " + promise.toString()); + + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); + } resolveAndTriggerListenersUnsynced(type, result, wrapped, - chainedPromise, current, actorPool, maybeEntry, resolutionEntry, - chainedPromise.haltOnResolution, whenResolvedProfile, frame, expression, record, recordStop); + chainedPromise, current, actorPool, resolutionEntry, + chainedPromise.haltOnResolution, whenResolvedProfile, frame, expression, record, + recordStop); resolveMoreChainedPromisesUnsynced(type, promise, result, current, - actorPool, maybeEntry, resolutionEntry, haltOnResolution, whenResolvedProfile, frame, expression, record, recordStop); + actorPool, resolutionEntry, haltOnResolution, whenResolvedProfile, + frame, expression, record, recordStop); } } /** * Resolve the other promises that has been chained to the first promise. */ -// @TruffleBoundary + // @TruffleBoundary private static void resolveMoreChainedPromisesUnsynced(final Resolution type, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, - final ValueProfile whenResolvedProfile, final VirtualFrame frame, final Node expression, final VirtualFrame frame, final Node expression) { + final ValueProfile whenResolvedProfile, final VirtualFrame frame, + final Node expression, final RecordOneEvent record, + final RecordOneEvent recordStop) { if (promise.chainedPromiseExt != null) { ArrayList chainedPromiseExt = promise.chainedPromiseExt; promise.chainedPromiseExt = null; @@ -827,7 +840,8 @@ private static void resolveMoreChainedPromisesUnsynced(final Resolution type, for (SPromise p : chainedPromiseExt) { Object wrapped = WrapReferenceNode.wrapForUse(p.owner, result, current, null); resolveAndTriggerListenersUnsynced(type, result, wrapped, p, current, - actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, record, recordStop); + actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, + record, recordStop); } } } @@ -840,7 +854,8 @@ private static void resolveMoreChainedPromisesUnsynced(final Resolution type, protected static void resolveAndTriggerListenersUnsynced(final Resolution type, final Object result, final Object wrapped, final SPromise p, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, - final ValueProfile whenResolvedProfile, final VirtualFrame frame, Node expression, final RecordOneEvent tracePromiseResolution2, + final ValueProfile whenResolvedProfile, final VirtualFrame frame, + final Node expression, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { assert !(result instanceof SPromise); @@ -875,7 +890,7 @@ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, if (VmSettings.SENDER_SIDE_REPLAY) { ((SReplayPromise) p).handleReplayResolution(haltOnResolution, current, type, - whenResolvedProfile); + whenResolvedProfile, maybeEntry); } } @@ -884,14 +899,18 @@ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, } if (type == Resolution.SUCCESSFUL) { - scheduleAllWhenResolvedUnsync(p, result, current, actorPool, maybeEntry, haltOnResolution, + scheduleAllWhenResolvedUnsync(p, result, current, actorPool, maybeEntry, + haltOnResolution, whenResolvedProfile); } else { assert type == Resolution.ERRONEOUS; - scheduleAllOnErrorUnsync(p, result, current, actorPool, maybeEntry, haltOnResolution); + scheduleAllOnErrorUnsync(p, result, current, actorPool, maybeEntry, + haltOnResolution); } - resolveChainedPromisesUnsync(type, p, result, current, actorPool, maybeEntry, haltOnResolution, - whenResolvedProfile, frame, expression, tracePromiseResolution2, tracePromiseResolutionEnd2); + resolveChainedPromisesUnsync(type, p, result, current, actorPool, maybeEntry, + haltOnResolution, + whenResolvedProfile, frame, expression, tracePromiseResolution2, + tracePromiseResolutionEnd2); if (VmSettings.SENDER_SIDE_TRACING) { tracePromiseResolutionEnd2.record(((STracingPromise) p).version); @@ -903,7 +922,8 @@ protected static void resolveAndTriggerListenersUnsynced(final Resolution type, * Schedule all whenResolved callbacks for the promise. */ protected static void scheduleAllWhenResolvedUnsync(final SPromise promise, - final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, + final Object result, final Actor current, final ForkJoinPool actorPool, + final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile) { if (promise.whenResolved != null) { PromiseMessage whenResolved = promise.whenResolved; @@ -917,7 +937,8 @@ protected static void scheduleAllWhenResolvedUnsync(final SPromise promise, } promise.scheduleCallbacksOnResolution(result, - whenResolvedProfile.profile(whenResolved), current, actorPool, maybeEntry, haltOnResolution); + whenResolvedProfile.profile(whenResolved), current, actorPool, maybeEntry, + haltOnResolution); scheduleExtensions(promise, whenResolvedExt, result, current, actorPool, maybeEntry, haltOnResolution); } @@ -930,7 +951,8 @@ protected static void scheduleAllWhenResolvedUnsync(final SPromise promise, private static void scheduleExtensions(final SPromise promise, final ArrayList extension, final Object result, final Actor current, - final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution) { + final ForkJoinPool actorPool, final Object maybeEntry, + final boolean haltOnResolution) { if (extension != null) { for (int i = 0; i < extension.size(); i++) { PromiseMessage callbackOrMsg = extension.get(i); @@ -945,7 +967,8 @@ private static void scheduleExtensions(final SPromise promise, */ protected static void scheduleAllOnErrorUnsync(final SPromise promise, final Object result, final Actor current, - final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution) { + final ForkJoinPool actorPool, final Object maybeEntry, + final boolean haltOnResolution) { if (promise.onError != null) { PromiseMessage onError = promise.onError; ArrayList onErrorExt = promise.onErrorExt; @@ -959,7 +982,8 @@ protected static void scheduleAllOnErrorUnsync(final SPromise promise, promise.scheduleCallbacksOnResolution(result, onError, current, actorPool, maybeEntry, haltOnResolution); - scheduleExtensions(promise, onErrorExt, result, current, actorPool, maybeEntry, haltOnResolution); + scheduleExtensions(promise, onErrorExt, result, current, actorPool, maybeEntry, + haltOnResolution); } } } diff --git a/src/som/interpreter/nodes/IsValueCheckNode.java b/src/som/interpreter/nodes/IsValueCheckNode.java index 786bed7180..fdf0aea05e 100644 --- a/src/som/interpreter/nodes/IsValueCheckNode.java +++ b/src/som/interpreter/nodes/IsValueCheckNode.java @@ -122,12 +122,12 @@ public Object allFieldsAreValues(final VirtualFrame frame, final SImmutableObjec if (cachedTester.allFieldsContainValues(rcvr)) { return rcvr; } else { - return notAValue.signal(rcvr); + return notAValue.signal(frame, rcvr); } } @Specialization - public Object fallback(final Object receiver) { + public Object fallback(final VirtualFrame frame, final Object receiver) { SImmutableObject rcvr = (SImmutableObject) receiver; boolean allFieldsContainValues = allFieldsContainValues(rcvr); if (allFieldsContainValues) { diff --git a/src/som/primitives/StringPrims.java b/src/som/primitives/StringPrims.java index 664594d8c5..fbc038f18b 100644 --- a/src/som/primitives/StringPrims.java +++ b/src/som/primitives/StringPrims.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.source.SourceSection; @@ -23,7 +24,6 @@ import som.vmobjects.SSymbol; import tools.dym.Tags.ComplexPrimitiveOperation; import tools.dym.Tags.StringAccess; -import com.oracle.truffle.api.frame.VirtualFrame; public class StringPrims { @@ -186,11 +186,10 @@ public ExpressionNode initialize(final SourceSection sourceSection, public final String doString(final VirtualFrame frame, final SArray chars) { VM.thisMethodNeedsToBeOptimized( "Method not yet optimal for compilation, should speculate or use branch profile in the loop"); - return doStringWithBoundary(chars); + return doStringWithBoundary(frame, chars); } - @TruffleBoundary - private String doStringWithBoundary(final SArray chars) { + private String doStringWithBoundary(final VirtualFrame frame, final SArray chars) { Object[] storage = chars.getObjectStorage(); StringBuilder sb = new StringBuilder(storage.length); for (Object o : storage) { From 5143456d65518d71c413a22075e1078fb89e8f3e Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 5 Oct 2022 00:48:23 +0100 Subject: [PATCH 102/194] =?UTF-8?q?Formatting=20settings=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Marr --- .settings/org.eclipse.jdt.core.prefs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 8556c967c0..098fc97fae 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -44,7 +44,7 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assertion_message=16 +org.eclipse.jdt.core.formatter.alignment_for_assertion_message=0 org.eclipse.jdt.core.formatter.alignment_for_assignment=16 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 From 60e428786e78e5906d135fa605a34ac02dfce817 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 5 Oct 2022 00:51:00 +0100 Subject: [PATCH 103/194] Eclipse format Signed-off-by: Stefan Marr --- src/som/Launcher.java | 4 +- src/som/VM.java | 6 +- src/som/compiler/MixinDefinition.java | 9 +- src/som/compiler/Variable.java | 3 +- src/som/interpreter/LexicalScope.java | 9 +- src/som/interpreter/Method.java | 4 +- src/som/interpreter/SArguments.java | 121 +-- src/som/interpreter/SNodeFactory.java | 5 +- .../actors/AbstractPromiseResolutionNode.java | 42 +- src/som/interpreter/actors/Actor.java | 3 +- src/som/interpreter/actors/ErrorNode.java | 72 +- .../interpreter/actors/ErrorPromiseNode.java | 3 +- .../interpreter/actors/EventualSendNode.java | 26 +- .../interpreter/actors/ReceivedMessage.java | 23 +- .../interpreter/actors/ReceivedRootNode.java | 13 +- .../actors/RegisterOnPromiseNode.java | 76 +- src/som/interpreter/actors/ResolveNode.java | 76 +- .../actors/SchedulePromiseHandlerNode.java | 25 +- .../interpreter/actors/TransferObject.java | 3 +- .../interpreter/nodes/InstantiationNode.java | 18 +- .../nodes/InternalObjectArrayNode.java | 7 +- .../interpreter/nodes/MessageSendNode.java | 1 + src/som/interpreter/nodes/SOMNode.java | 3 +- .../dispatch/AbstractGenericDispatchNode.java | 2 +- .../nodes/dispatch/BackCacheCallNode.java | 69 +- .../nodes/dispatch/BlockDispatchNode.java | 2 +- .../nodes/dispatch/CachedDispatchNode.java | 44 +- .../nodes/dispatch/CachedDnuNode.java | 2 +- .../nodes/dispatch/ClassSlotAccessNode.java | 8 +- .../dispatch/LexicallyBoundDispatchNode.java | 7 +- .../nodes/literals/ArrayLiteralNode.java | 3 +- .../nodes/nary/EagerBinaryPrimitiveNode.java | 10 +- .../nodes/nary/EagerTernaryPrimitiveNode.java | 6 +- .../nodes/nary/EagerUnaryPrimitiveNode.java | 3 +- .../specialized/IntDownToDoMessageNode.java | 6 +- .../specialized/IntToByDoMessageNode.java | 11 +- .../nodes/specialized/IntToDoMessageNode.java | 7 +- .../objectstorage/StorageAccessor.java | 10 +- .../objectstorage/StorageLocation.java | 3 +- src/som/primitives/BlockPrims.java | 61 +- src/som/primitives/ExceptionsPrims.java | 92 ++- src/som/primitives/FilePrims.java | 9 +- src/som/primitives/SystemPrims.java | 25 +- .../primitives/actors/CreateActorPrim.java | 6 +- src/som/primitives/actors/PromisePrims.java | 43 +- .../arrays/ArraySetAllStrategy.java | 68 +- src/som/primitives/arrays/AtPrim.java | 18 +- src/som/primitives/arrays/AtPutPrim.java | 52 +- src/som/primitives/arrays/CopyPrim.java | 18 +- src/som/primitives/arrays/DoIndexesPrim.java | 12 +- src/som/primitives/arrays/DoPrim.java | 22 +- src/som/primitives/threading/TaskThreads.java | 3 +- src/som/vm/ExtensionLoader.java | 3 +- src/som/vm/ObjectSystem.java | 5 +- src/som/vm/Primitives.java | 5 +- src/som/vm/VmSettings.java | 6 +- src/som/vmobjects/SClass.java | 3 +- src/som/vmobjects/SFileDescriptor.java | 8 +- src/tools/concurrency/KomposTrace.java | 95 ++- src/tools/concurrency/TracingActors.java | 18 +- src/tools/concurrency/TracingBackend.java | 3 +- src/tools/debugger/FrontendConnector.java | 18 +- src/tools/debugger/WebSocketHandler.java | 7 +- .../asyncstacktraces/ShadowStackEntry.java | 207 ++--- .../ShadowStackEntryLoad.java | 211 ++--- .../asyncstacktraces/StackIterator.java | 720 +++++++++--------- .../debugger/breakpoints/Breakpoints.java | 10 +- src/tools/debugger/entities/Marker.java | 2 +- .../debugger/entities/MessageReception.java | 32 +- src/tools/debugger/entities/SendOp.java | 11 +- src/tools/debugger/entities/SteppingType.java | 2 +- .../frontend/ApplicationThreadStack.java | 175 ++--- src/tools/debugger/frontend/Suspension.java | 27 +- .../message/InitializationResponse.java | 3 +- .../debugger/message/PauseActorRequest.java | 32 +- .../debugger/message/PauseActorResponse.java | 14 +- .../debugger/message/ResumeActorResponse.java | 14 +- .../debugger/message/ScopesResponse.java | 15 +- .../debugger/message/StackTraceResponse.java | 20 +- src/tools/debugger/message/StepMessage.java | 23 +- .../debugger/message/StoppedMessage.java | 2 +- src/tools/dym/DynamicMetrics.java | 6 +- .../dym/nodes/OperationProfilingNode.java | 3 +- tests/java/debugger/JsonTests.java | 3 +- 84 files changed, 1512 insertions(+), 1365 deletions(-) diff --git a/src/som/Launcher.java b/src/som/Launcher.java index 046331cb09..66654c0081 100644 --- a/src/som/Launcher.java +++ b/src/som/Launcher.java @@ -42,7 +42,7 @@ public static void main(final String[] args) { exitCode = result.as(Integer.class); } finally { if (VmSettings.TRUFFLE_DEBUGGER_ENABLED) { - //Stop execution for all suspended actors if any + // Stop execution for all suspended actors if any TracingActors.TracingActor.stopActorsIfSuspended(); } @@ -65,7 +65,7 @@ private static void finalizeExecution(final int exitCode) { // to produce the list of messages on the erroneous path. // Could be done at the beginning of assisted debugging. - //Note2: added VmSettings.ASSISTED_DEBUGGING flag because at the moment the parser + // Note2: added VmSettings.ASSISTED_DEBUGGING flag because at the moment the parser // does not works correctly with this implementation. // TODO check the assertion error KomposTraceParser 220 if (VmSettings.KOMPOS_TRACING && VmSettings.ASSISTED_DEBUGGING) { diff --git a/src/som/VM.java b/src/som/VM.java index a43ef8945b..55a303389c 100644 --- a/src/som/VM.java +++ b/src/som/VM.java @@ -379,8 +379,7 @@ public void setupInstruments(final Env env) { } if (VmSettings.TRUFFLE_DEBUGGER_ENABLED) { - assert options.webDebuggerEnabled - : "If debugging is enabled, we currently expect the web debugger to be used."; + assert options.webDebuggerEnabled : "If debugging is enabled, we currently expect the web debugger to be used."; Debugger debugger = Debugger.find(env); webDebugger = WebDebugger.find(env); @@ -407,8 +406,7 @@ public void setupInstruments(final Env env) { } if (VmSettings.TRACK_SNAPSHOT_ENTITIES) { - assert !options.siCandidateIdentifierEnabled - : "Currently, CandidateIdentifer and Snapshots are not compatible"; + assert !options.siCandidateIdentifierEnabled : "Currently, CandidateIdentifer and Snapshots are not compatible"; structuralProbe = SnapshotBackend.getProbe(); } } diff --git a/src/som/compiler/MixinDefinition.java b/src/som/compiler/MixinDefinition.java index 160f65cc03..44c4d63025 100644 --- a/src/som/compiler/MixinDefinition.java +++ b/src/som/compiler/MixinDefinition.java @@ -69,6 +69,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import som.interpreter.SArguments; + /** * Produced by a {@link MixinBuilder}, contains all static information on a * mixin that is in the source. Is used to instantiate a {@link ClassFactory} @@ -536,15 +537,15 @@ public SClass instantiateModuleClass() { VM.callerNeedsToBeOptimized( "only meant for code loading, which is supposed to be on the slowpath"); CallTarget callTarget = superclassMixinResolution.getCallTarget(); -// SClass superClass = (SClass) callTarget.call(Nil.nilObject); -// SClass classObject = instantiateClass(Nil.nilObject, superClass); + // SClass superClass = (SClass) callTarget.call(Nil.nilObject); + // SClass classObject = instantiateClass(Nil.nilObject, superClass); SClass superClass; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { // Since this is outside of the main stacks, we create a separate top shadow stack entry // to deal with async errors. superClass = - (SClass) callTarget.call(Nil.nilObject, - SArguments.instantiateTopShadowStackEntry(null)); + (SClass) callTarget.call(Nil.nilObject, + SArguments.instantiateTopShadowStackEntry(null)); } else { superClass = (SClass) callTarget.call(Nil.nilObject, null); } diff --git a/src/som/compiler/Variable.java b/src/som/compiler/Variable.java index 06000fe7ae..335bee4b03 100644 --- a/src/som/compiler/Variable.java +++ b/src/som/compiler/Variable.java @@ -90,8 +90,7 @@ public boolean equals(final Object o) { return true; } assert source == null || !source.equals( - var.source) - : "Why are there multiple objects for this source section? might need to fix comparison above"; + var.source) : "Why are there multiple objects for this source section? might need to fix comparison above"; return false; } diff --git a/src/som/interpreter/LexicalScope.java b/src/som/interpreter/LexicalScope.java index b1e9bfef5b..23cfdb7275 100644 --- a/src/som/interpreter/LexicalScope.java +++ b/src/som/interpreter/LexicalScope.java @@ -434,8 +434,7 @@ public String toString() { @Override public MixinScope getMixinScope() { - assert outerScope != null - : "Should not be possible, because we do not support top-level methods"; + assert outerScope != null : "Should not be possible, because we do not support top-level methods"; return outerScope.getMixinScope(); } @@ -460,15 +459,13 @@ public MethodScope getOuterMethod() { @Override public boolean lookupSlotOrClass(final SSymbol selector, final List results) { - assert outerScope != null - : "Should not be possible, because we do not support top-level methods, except for superclass resolution"; + assert outerScope != null : "Should not be possible, because we do not support top-level methods, except for superclass resolution"; // this traversal concerns only the enclosing objects, not the activations return outerScope.lookupSlotOrClass(selector, results); } public MethodScope getEmbeddedScope(final SourceSection source) { - assert embeddedScopes != null - : "Something is wrong, trying to get embedded scope for leaf method, except for superclass resolution"; + assert embeddedScopes != null : "Something is wrong, trying to get embedded scope for leaf method, except for superclass resolution"; for (MethodScope s : embeddedScopes) { if (s.method.getSourceSection().equals(source)) { return s; diff --git a/src/som/interpreter/Method.java b/src/som/interpreter/Method.java index 19ea3f8529..46aeaff232 100644 --- a/src/som/interpreter/Method.java +++ b/src/som/interpreter/Method.java @@ -74,8 +74,7 @@ public boolean equals(final Object o) { } assert !getSourceSection().equals( - m.getSourceSection()) - : "If that triggers, something with the source sections is wrong."; + m.getSourceSection()) : "If that triggers, something with the source sections is wrong."; return false; } @@ -93,7 +92,6 @@ public BackCacheCallNode getUniqueCaller() { return uniqueCaller; } - public SourceSection[] getDefinition() { return definition; } diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 29bb6a98de..5600d020f0 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -64,12 +64,12 @@ public static Object[] allocateArgumentsArray(final ExpressionNode[] argumentNod * #doesNotUnderstand (#dnu) */ public static SImmutableArray getArgumentsWithoutReceiver(final Object[] arguments) { -// if (arguments.length == 1) { -// return new SImmutableArray(0, Classes.valueArrayClass); -// } -// -// Object[] argsArr = getPlainArgumentWithoutReceiver(arguments); -// return new SImmutableArray(argsArr, Classes.valueArrayClass); + // if (arguments.length == 1) { + // return new SImmutableArray(0, Classes.valueArrayClass); + // } + // + // Object[] argsArr = getPlainArgumentWithoutReceiver(arguments); + // return new SImmutableArray(argsArr, Classes.valueArrayClass); if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { if (arguments.length == 2) { @@ -97,7 +97,7 @@ public static Object[] getPlainArgumentWithoutReceiver(final Object[] arguments) int rcvrIdx = 0; // the code and magic numbers below are based on the following assumption assert RCVR_IDX == rcvrIdx; assert arguments.length >= 1; // <- that's the receiver -// Object[] argsArr = new Object[arguments.length - 1]; + // Object[] argsArr = new Object[arguments.length - 1]; int argsSize = arguments.length - 1; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { @@ -109,21 +109,21 @@ public static Object[] getPlainArgumentWithoutReceiver(final Object[] arguments) return argsArr; } -// public static Object[] getPlainArgumentsWithReceiver(final Object receiver, -// final SArray args, final SizeAndLengthPrim size, final AtPrim at) { -// Object[] result = new Object[(int) (size.executeEvaluated(args) + 1)]; -// result[0] = receiver; -// for (int i = 1; i < result.length; i++) { -// result[i] = at.executeEvaluated(null, args, (long) i); -// } -// return result; -// } + // public static Object[] getPlainArgumentsWithReceiver(final Object receiver, + // final SArray args, final SizeAndLengthPrim size, final AtPrim at) { + // Object[] result = new Object[(int) (size.executeEvaluated(args) + 1)]; + // result[0] = receiver; + // for (int i = 1; i < result.length; i++) { + // result[i] = at.executeEvaluated(null, args, (long) i); + // } + // return result; + // } public static Object[] getPlainArgumentsWithReceiver(final Object receiver, - final SArray args, final SizeAndLengthPrim size, final AtPrim at, - final ExpressionNode expression, - final ShadowStackEntryLoad entryLoad, - final VirtualFrame frame) { + final SArray args, final SizeAndLengthPrim size, final AtPrim at, + final ExpressionNode expression, + final ShadowStackEntryLoad entryLoad, + final VirtualFrame frame) { int argSize = (int) (size.executeEvaluated(args) + 1); int defaultArgSize = argSize; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { @@ -143,9 +143,9 @@ public static Object[] getPlainArgumentsWithReceiver(final Object receiver, } public static Object[] getPlainXArgumentsWithReceiver(final ExpressionNode expression, - final ShadowStackEntryLoad entryLoad, - final VirtualFrame frame, - final Object... rcvrAndArgs) { + final ShadowStackEntryLoad entryLoad, + final VirtualFrame frame, + final Object... rcvrAndArgs) { if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { Object[] arguments = new Object[rcvrAndArgs.length + 1]; for (int i = 0; i < rcvrAndArgs.length; i++) { @@ -179,10 +179,10 @@ public static Object[] getPromiseCallbackArgumentArray(final SBlock callback) { } public static void setShadowStackEntryWithCache(final Object[] arguments, - final Node expression, - final ShadowStackEntryLoad entryLoad, - final VirtualFrame frame, - final boolean async) { + final Node expression, + final ShadowStackEntryLoad entryLoad, + final VirtualFrame frame, + final boolean async) { if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { entryLoad.loadShadowStackEntry(arguments, expression, frame, async); } @@ -193,7 +193,7 @@ public static ShadowStackEntry instantiateTopShadowStackEntry(final Node expr) { } public static ShadowStackEntry instantiateShadowStackEntry(final ShadowStackEntry previous, - final Node expr, final boolean async) { + final Node expr, final boolean async) { CompilerAsserts.partialEvaluationConstant(async); if (async) { return ShadowStackEntry.createAtAsyncSend(previous, expr); @@ -228,21 +228,28 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } } - //set the resolution of the promise for the registered callback or message sent to a promise - public static void saveCausalEntryForPromise(Object previousPromiseStack, Object currentPromiseStack) { - assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; - assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; - ((ShadowStackEntry) currentPromiseStack).setPreviousShadowStackEntry((ShadowStackEntry) previousPromiseStack); + // set the resolution of the promise for the registered callback or message sent to a promise + public static void saveCausalEntryForPromise(Object previousPromiseStack, + Object currentPromiseStack) { + assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; + assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; + ((ShadowStackEntry) currentPromiseStack).setPreviousShadowStackEntry( + (ShadowStackEntry) previousPromiseStack); } private static Map previousPromiseInGroupByActor = new HashMap<>(); - public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, Object callbackPromiseStack, long actorId) { - if (previousPromiseInGroupByActor != null && previousPromiseInGroupByActor.containsKey(actorId)) { - ShadowStackEntry firstPromise = previousPromiseInGroupByActor.get(actorId).getPreviousShadowStackEntry(); - - //group frames of the previous promise with the frames of the new promise, and then set the grouped stack entries for the callback - ShadowStackEntry groupedFrames = groupFrames(firstPromise, (ShadowStackEntry) previousPromiseStack); + public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, + Object callbackPromiseStack, long actorId) { + if (previousPromiseInGroupByActor != null + && previousPromiseInGroupByActor.containsKey(actorId)) { + ShadowStackEntry firstPromise = + previousPromiseInGroupByActor.get(actorId).getPreviousShadowStackEntry(); + + // group frames of the previous promise with the frames of the new promise, and then set + // the grouped stack entries for the callback + ShadowStackEntry groupedFrames = + groupFrames(firstPromise, (ShadowStackEntry) previousPromiseStack); saveCausalEntryForPromise(groupedFrames, callbackPromiseStack); } else { @@ -251,17 +258,20 @@ public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, O } } - //group non repeated frames - private static ShadowStackEntry groupFrames(ShadowStackEntry firstPromiseStack, ShadowStackEntry secondPromiseStack) { + // group non repeated frames + private static ShadowStackEntry groupFrames(ShadowStackEntry firstPromiseStack, + ShadowStackEntry secondPromiseStack) { List listSecond = getAllEntries(secondPromiseStack, new ArrayList<>()); List listFirst = getAllEntries(firstPromiseStack, new ArrayList<>()); - ShadowStackEntry group = setNewEntryAtEqualSourceSection(firstPromiseStack, listFirst, listSecond); + ShadowStackEntry group = + setNewEntryAtEqualSourceSection(firstPromiseStack, listFirst, listSecond); return group; } - private static List getAllEntries(ShadowStackEntry stackEntry, List list) { + private static List getAllEntries(ShadowStackEntry stackEntry, + List list) { if (stackEntry == null) { return list; } else { @@ -271,18 +281,25 @@ private static List getAllEntries(ShadowStackEntry stackEntry, return list; } - //equal source section corresponds to the turn node, from there on the stack frames are the same for both promises stacks - private static ShadowStackEntry setNewEntryAtEqualSourceSection(ShadowStackEntry stackEntryToAdd, List listFirst, List listSecond ) { - for (ShadowStackEntry entrySecond: listSecond) { - for (ShadowStackEntry entryFirst: listFirst) { - boolean entryFirstNotNull = entryFirst.getPreviousShadowStackEntry()!= null && entryFirst.getPreviousShadowStackEntry().getExpression()!= null; - boolean entrySecondNotNull = entrySecond.getPreviousShadowStackEntry()!= null && entrySecond.getPreviousShadowStackEntry().getExpression()!= null; - if (entryFirstNotNull && entrySecondNotNull && entrySecond.getPreviousShadowStackEntry().getSourceSection().equals(entryFirst.getPreviousShadowStackEntry().getSourceSection())) { + // equal source section corresponds to the turn node, from there on the stack frames are the + // same for both promises stacks + private static ShadowStackEntry setNewEntryAtEqualSourceSection( + ShadowStackEntry stackEntryToAdd, List listFirst, + List listSecond) { + for (ShadowStackEntry entrySecond : listSecond) { + for (ShadowStackEntry entryFirst : listFirst) { + boolean entryFirstNotNull = entryFirst.getPreviousShadowStackEntry() != null + && entryFirst.getPreviousShadowStackEntry().getExpression() != null; + boolean entrySecondNotNull = entrySecond.getPreviousShadowStackEntry() != null + && entrySecond.getPreviousShadowStackEntry().getExpression() != null; + if (entryFirstNotNull && entrySecondNotNull + && entrySecond.getPreviousShadowStackEntry().getSourceSection().equals( + entryFirst.getPreviousShadowStackEntry().getSourceSection())) { entrySecond.setPreviousShadowStackEntry(stackEntryToAdd); - return listSecond.get(0); //return top entry with the update + return listSecond.get(0); // return top entry with the update } } } - return listSecond.get(0);//return top entry + return listSecond.get(0);// return top entry } } diff --git a/src/som/interpreter/SNodeFactory.java b/src/som/interpreter/SNodeFactory.java index 6bfed34952..1ac835ca3a 100644 --- a/src/som/interpreter/SNodeFactory.java +++ b/src/som/interpreter/SNodeFactory.java @@ -60,8 +60,9 @@ public static ExpressionNode createMessageSend(final SSymbol msg, final SomLanguage lang) { if (eventualSend) { return new EventualSendNode(msg, exprs.length, - // new InternalObjectArrayNode(exprs).initialize(source), source, sendOperator, lang); - new ArgumentEvaluationNode(exprs).initialize(source), source, sendOperator, lang); + // new InternalObjectArrayNode(exprs).initialize(source), source, sendOperator, + // lang); + new ArgumentEvaluationNode(exprs).initialize(source), source, sendOperator, lang); } else { return MessageSendNode.createMessageSend(msg, exprs, source, lang.getVM()); } diff --git a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java index 3d4d1129c5..c334d41575 100644 --- a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java +++ b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java @@ -37,11 +37,11 @@ @GenerateWrapper @NodeChildren({ - @NodeChild(value = "receiver", type = ExpressionNode.class), - @NodeChild(value = "firstArg", type = ExpressionNode.class), - @NodeChild(value = "secondArg", type = ExpressionNode.class), - @NodeChild(value = "thirdArg", type = ExpressionNode.class), - @NodeChild(value = "fourthArg", type = ExpressionNode.class)}) + @NodeChild(value = "receiver", type = ExpressionNode.class), + @NodeChild(value = "firstArg", type = ExpressionNode.class), + @NodeChild(value = "secondArg", type = ExpressionNode.class), + @NodeChild(value = "thirdArg", type = ExpressionNode.class), + @NodeChild(value = "fourthArg", type = ExpressionNode.class)}) public abstract class AbstractPromiseResolutionNode extends EagerlySpecializableNode implements WithContext { @CompilationFinal private ForkJoinPool actorPool; @@ -82,22 +82,22 @@ public AbstractPromiseResolutionNode initialize(final SourceSection sourceSectio } public abstract Object executeEvaluated(VirtualFrame frame, - SResolver receiver, Object argument, Object maybeEntry, - boolean haltOnResolver, boolean haltOnResolution); + SResolver receiver, Object argument, Object maybeEntry, + boolean haltOnResolver, boolean haltOnResolution); public abstract Object executeEvaluated(VirtualFrame frame, Object receiver, - Object firstArg, Object secondArg, Object thirdArg, Object forth); + Object firstArg, Object secondArg, Object thirdArg, Object forth); @Override public final Object doPreEvaluated(final VirtualFrame frame, - final Object[] arguments) { + final Object[] arguments) { return executeEvaluated(frame, arguments[0], arguments[1], arguments[2], - arguments[3], arguments[4]); + arguments[3], arguments[4]); } @Override public EagerPrimitiveNode wrapInEagerWrapper(final SSymbol selector, - final ExpressionNode[] arguments, final VM vm) { + final ExpressionNode[] arguments, final VM vm) { throw new NotYetImplementedException(); // wasn't needed so far } @@ -111,8 +111,8 @@ public WrapperNode createWrapper(final ProbeNode probe) { */ @Specialization(guards = {"resolver.getPromise() == result"}) public SResolver selfResolution(final SResolver resolver, - final SPromise result, final Object maybeEntry, - final boolean haltOnResolver, final boolean haltOnResolution) { + final SPromise result, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { return resolver; } @@ -132,8 +132,8 @@ protected static boolean notAPromise(final Object result) { } protected void chainPromise(final VirtualFrame frame, final SResolver resolver, - final SPromise promiseValue, final Object maybeEntry, - final boolean haltOnResolver, final boolean haltOnResolution) { + final SPromise promiseValue, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { assert resolver.assertNotCompleted(); SPromise promiseToBeResolved = resolver.getPromise(); if (VmSettings.KOMPOS_TRACING) { @@ -187,18 +187,22 @@ protected void resolvePromise(final Resolution type, Actor current = EventualMessage.getActorCurrentMessageIsExecutionOn(); resolve(type, wrapper, promise, result, current, actorPool, maybeEntry, haltOnResolution, - whenResolvedProfile, frame, expression, tracePromiseResolution, tracePromiseResolutionEnd); + whenResolvedProfile, frame, expression, tracePromiseResolution, + tracePromiseResolutionEnd); } public static void resolve(final Resolution type, final WrapReferenceNode wrapper, final SPromise promise, - final Object result, final Actor current, final ForkJoinPool actorPool, Object maybeEntry, - final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final VirtualFrame frame, Node expression, + final Object result, final Actor current, final ForkJoinPool actorPool, + Object maybeEntry, + final boolean haltOnResolution, final ValueProfile whenResolvedProfile, + final VirtualFrame frame, Node expression, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { Object wrapped = wrapper.execute(result, promise.owner, current); SResolver.resolveAndTriggerListenersUnsynced(type, result, wrapped, promise, - current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, tracePromiseResolution2, + current, actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, + expression, tracePromiseResolution2, tracePromiseResolutionEnd2); } } diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 8a02923c57..23584ec8a2 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -350,8 +350,7 @@ protected void execute(final ForkJoinPool actorPool) { } @Override - public void setStepToNextTurn(final boolean val) { - } + public void setStepToNextTurn(final boolean val) {} public static final class ActorProcessingThreadFactory implements ForkJoinWorkerThreadFactory { diff --git a/src/som/interpreter/actors/ErrorNode.java b/src/som/interpreter/actors/ErrorNode.java index ad936738d7..2910792e82 100644 --- a/src/som/interpreter/actors/ErrorNode.java +++ b/src/som/interpreter/actors/ErrorNode.java @@ -1,6 +1,5 @@ package som.interpreter.actors; - import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; @@ -9,40 +8,43 @@ import som.vm.VmSettings; import tools.debugger.asyncstacktraces.ShadowStackEntry; + public abstract class ErrorNode extends AbstractPromiseResolutionNode { - @CompilerDirectives.CompilationFinal - boolean initialized = false; - - /** - * Standard error case, when the promise is errored with a value that's not a promise. - */ - @Specialization(guards = {"notAPromise(result)"}) - public SPromise.SResolver standardError(final VirtualFrame frame, - final SPromise.SResolver resolver, final Object result, final Object maybeEntry, - final boolean haltOnResolver, final boolean haltOnResolution) { - - if (!initialized) { - initialized = true; - this.initialize(SomLanguage.getVM(this)); - } - - SPromise promise = resolver.getPromise(); - - if (haltOnResolver || promise.getHaltOnResolver()) { - haltNode.executeEvaluated(frame, result); - } - - ShadowStackEntry resolutionEntry = null; - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ERROR; - resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location, "error: "+result.toString()); - SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); - } - - resolvePromise(SPromise.Resolution.ERRONEOUS, resolver, result, resolutionEntry, haltOnResolution, frame, this.getParent()); - return resolver; + @CompilerDirectives.CompilationFinal boolean initialized = false; + + /** + * Standard error case, when the promise is errored with a value that's not a promise. + */ + @Specialization(guards = {"notAPromise(result)"}) + public SPromise.SResolver standardError(final VirtualFrame frame, + final SPromise.SResolver resolver, final Object result, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { + + if (!initialized) { + initialized = true; + this.initialize(SomLanguage.getVM(this)); + } + + SPromise promise = resolver.getPromise(); + + if (haltOnResolver || promise.getHaltOnResolver()) { + haltNode.executeEvaluated(frame, result); + } + + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ERROR; + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location, + "error: " + result.toString()); + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); } + + resolvePromise(SPromise.Resolution.ERRONEOUS, resolver, result, resolutionEntry, + haltOnResolution, frame, this.getParent()); + return resolver; + } } diff --git a/src/som/interpreter/actors/ErrorPromiseNode.java b/src/som/interpreter/actors/ErrorPromiseNode.java index a9a16b22a8..f14b70fbba 100644 --- a/src/som/interpreter/actors/ErrorPromiseNode.java +++ b/src/som/interpreter/actors/ErrorPromiseNode.java @@ -29,7 +29,8 @@ public SResolver standardError(final VirtualFrame frame, final SResolver resolve final Object result) { ShadowStackEntry entry = SArguments.getShadowStackEntry(frame); assert entry != null || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; - return (SResolver) errorNode.executeEvaluated(frame, resolver, result, entry, false, false); + return (SResolver) errorNode.executeEvaluated(frame, resolver, result, entry, false, + false); } @Override diff --git a/src/som/interpreter/actors/EventualSendNode.java b/src/som/interpreter/actors/EventualSendNode.java index 5a4fd4f702..1abc49255b 100644 --- a/src/som/interpreter/actors/EventualSendNode.java +++ b/src/som/interpreter/actors/EventualSendNode.java @@ -54,7 +54,7 @@ public class EventualSendNode extends ExprWithTagsNode { DynamicMetrics.createLong("Num.Promises.Avoided"); @Child protected ArgumentEvaluationNode arguments; - @Child protected SendNode send; + @Child protected SendNode send; public EventualSendNode(final SSymbol selector, final int numArgs, final ArgumentEvaluationNode arguments, final SourceSection source, @@ -213,8 +213,7 @@ protected void sendDirectMessage(final Object[] args, final Actor owner, args[i] = wrapArgs[i].execute(args[i], target, owner); } - assert !(args[0] instanceof SFarReference) - : "This should not happen for this specialization, but it is handled in determineTargetAndWrapArguments(.)"; + assert !(args[0] instanceof SFarReference) : "This should not happen for this specialization, but it is handled in determineTargetAndWrapArguments(.)"; assert !(args[0] instanceof SPromise) : "Should not happen either, but just to be sure"; DirectMessage msg = new DirectMessage(target, selector, args, @@ -230,15 +229,16 @@ protected void sendDirectMessage(final Object[] args, final Actor owner, if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.ACTOR_MSG, msg.getMessageId(), - target.getId(), msg.getSelector(), msg.getTarget().getId(), msg.getTargetSourceSection()); + target.getId(), msg.getSelector(), msg.getTarget().getId(), + msg.getTargetSourceSection()); } target.send(msg, actorPool); } protected void sendPromiseMessage(final VirtualFrame frame, final Object[] args, - final SPromise rcvr, final SResolver resolver, - final RegisterWhenResolved registerNode) { + final SPromise rcvr, final SResolver resolver, + final RegisterWhenResolved registerNode) { assert rcvr.getOwner() == EventualMessage.getActorCurrentMessageIsExecutionOn() : "think this should be true because the promise is an Object and owned by this specific actor"; PromiseSendMessage msg = new PromiseSendMessage(selector, args, @@ -254,7 +254,8 @@ protected void sendPromiseMessage(final VirtualFrame frame, final Object[] args, if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, msg.getMessageId(), - rcvr.getPromiseId(), msg.getSelector(), target != null ? target.getId() : -1, msg.getTargetSourceSection()); + rcvr.getPromiseId(), msg.getSelector(), target != null ? target.getId() : -1, + msg.getTargetSourceSection()); } registerNode.register(frame, rcvr, msg, rcvr.getOwner()); @@ -288,7 +289,7 @@ public final SPromise toFarRefWithResultPromise(final Object[] args) { @Specialization(guards = {"isResultUsed()", "isPromiseRcvr(args)"}) public final SPromise toPromiseWithResultPromise(final VirtualFrame frame, - final Object[] args, + final Object[] args, @Cached("createRegisterNode()") final RegisterWhenResolved registerNode) { SPromise rcvr = (SPromise) args[0]; @@ -316,7 +317,8 @@ public final SPromise toNearRefWithResultPromise(final Object[] args) { if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.ACTOR_MSG, msg.getMessageId(), - current.getId(), msg.getSelector(), msg.getTarget().getId(), msg.getTargetSourceSection()); + current.getId(), msg.getSelector(), msg.getTarget().getId(), + msg.getTargetSourceSection()); } if (VmSettings.SENDER_SIDE_REPLAY) { @@ -344,7 +346,8 @@ public final Object toFarRefWithoutResultPromise(final Object[] args) { } @Specialization(guards = {"!isResultUsed()", "isPromiseRcvr(args)"}) - public final Object toPromiseWithoutResultPromise(final VirtualFrame frame, final Object[] args, + public final Object toPromiseWithoutResultPromise(final VirtualFrame frame, + final Object[] args, @Cached("createRegisterNode()") final RegisterWhenResolved registerNode) { sendPromiseMessage(frame, args, (SPromise) args[0], null, registerNode); @@ -367,7 +370,8 @@ public final Object toNearRefWithoutResultPromise(final Object[] args) { if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.ACTOR_MSG, msg.getMessageId(), - current.getId(), msg.getSelector(), msg.getTarget().getId(), msg.getTargetSourceSection()); + current.getId(), msg.getSelector(), msg.getTarget().getId(), + msg.getTargetSourceSection()); } if (VmSettings.SENDER_SIDE_REPLAY) { diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index ed4ee6b856..66e9b3f6cf 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -47,18 +47,21 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_RECEIVE_MESSAGE; -// String resolutionValue = (msg.getTarget().getId() + " sent by actor "+ msg.getSender().getId()); + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_RECEIVE_MESSAGE; + // String resolutionValue = (msg.getTarget().getId() + " sent by actor "+ + // msg.getSender().getId()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, onReceiveLocation, ""); + ShadowStackEntry.createAtPromiseResolution(entry, (ExpressionNode) onReceive, + onReceiveLocation, ""); } try { assert msg.args[msg.args.length - 1] == null - || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; Object result = onReceive.executeEvaluated(frame, msg.args); resolvePromise(frame, msg.resolver, result, - resolutionEntry, haltOnResolver, haltOnResolution); + resolutionEntry, haltOnResolver, haltOnResolution); } catch (SomException exception) { errorPromise(frame, msg.resolver, exception.getSomObject(), resolutionEntry, haltOnResolver, haltOnResolution); @@ -109,7 +112,7 @@ public static final class ReceivedCallback extends ReceivedRootNode { public ReceivedCallback(final SInvokable onReceive) { super(SomLanguage.getLanguage(onReceive.getInvokable()), - onReceive.getSourceSection(), null); + onReceive.getSourceSection(), null); this.onReceive = Truffle.getRuntime().createDirectCallNode(onReceive.getCallTarget()); this.onReceiveMethod = onReceive.getInvokable(); } @@ -127,10 +130,12 @@ protected Object executeBody(final VirtualFrame frame, final EventualMessage msg ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_BLOCK; -// String resolutionValue = (msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_BLOCK; + // String resolutionValue = (msg.getTarget().getId() + " send by actor "+ + // msg.getSender().getId()); resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), onReceiveLocation, ""); + ShadowStackEntry.createAtPromiseResolution(entry, onReceiveMethod.getBodyNode(), + onReceiveLocation, ""); SArguments.setShadowStackEntry(msg.getArgs(), resolutionEntry); } diff --git a/src/som/interpreter/actors/ReceivedRootNode.java b/src/som/interpreter/actors/ReceivedRootNode.java index 6dd581f542..b3f6ca1f34 100644 --- a/src/som/interpreter/actors/ReceivedRootNode.java +++ b/src/som/interpreter/actors/ReceivedRootNode.java @@ -127,7 +127,7 @@ protected final void resolvePromise(final VirtualFrame frame, resolve = insert(new NullResolver()); } else { resolve = insert( - ResolveNodeGen.create(null, null, null, null, null).initialize(vm)); + ResolveNodeGen.create(null, null, null, null, null).initialize(vm)); } resolve.initialize(sourceSection); this.resolve = resolve; @@ -135,7 +135,8 @@ protected final void resolvePromise(final VirtualFrame frame, } // resolve promise - resolve.executeEvaluated(frame, resolver, result, maybeEntry, haltOnResolver, haltOnResolution); + resolve.executeEvaluated(frame, resolver, result, maybeEntry, haltOnResolver, + haltOnResolution); } protected final void errorPromise(final VirtualFrame frame, @@ -151,7 +152,7 @@ protected final void errorPromise(final VirtualFrame frame, error = insert(new NullResolver()); } else { error = insert( - ErrorNodeGen.create(null, null, null, null, null).initialize(vm)); + ErrorNodeGen.create(null, null, null, null, null).initialize(vm)); } this.error = error; this.error.initialize(sourceSection); @@ -159,7 +160,8 @@ protected final void errorPromise(final VirtualFrame frame, } // error promise - error.executeEvaluated(frame, resolver, exception, maybeEntry, haltOnResolver, haltOnResolution); + error.executeEvaluated(frame, resolver, exception, maybeEntry, haltOnResolver, + haltOnResolution); } public MessageSerializationNode getSerializer() { @@ -186,7 +188,8 @@ public Object executeEvaluated(final VirtualFrame frame, @Override public Object executeEvaluated(final VirtualFrame frame, final Object rcvr, - final Object firstArg, final Object secondArg, final Object thirdArg, final Object fourthArg) { + final Object firstArg, final Object secondArg, final Object thirdArg, + final Object fourthArg) { if (VmSettings.DYNAMIC_METRICS) { numImplicitNullResolutions.getAndIncrement(); } diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 8c3fa168f3..9afe43c43f 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -41,7 +41,8 @@ public RegisterWhenResolved(final ForkJoinPool actorPool) { } } - public void register(final VirtualFrame frame, final SPromise promise, final PromiseMessage msg, + public void register(final VirtualFrame frame, final SPromise promise, + final PromiseMessage msg, final Actor current) { Object promiseValue; @@ -85,45 +86,53 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { // get info about the resolution context from the promise, // we want to know where it was resolved, where the value is coming from - for (Object obj: msg.args) { - boolean promiseComplete = (obj instanceof SPromise) && ((SPromise) promise).isCompleted(); -// boolean promiseChained = (obj instanceof SPromise) && !((SPromise) promise).isCompleted(); + for (Object obj : msg.args) { + boolean promiseComplete = + (obj instanceof SPromise) && ((SPromise) promise).isCompleted(); + // boolean promiseChained = (obj instanceof SPromise) && !((SPromise) + // promise).isCompleted(); if (obj instanceof SBlock || promiseComplete) { ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED; -// onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); - //for whenResolved blocks or if promise is resolved, then create EntryForPromiseResolution + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED; + // onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ + // msg.getSender().getId()); + // for whenResolved blocks or if promise is resolved, then create + // EntryForPromiseResolution ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( - SArguments.getShadowStackEntry(frame), - getParent().getParent(), onReceiveLocation, ""); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; + SArguments.getShadowStackEntry(frame), + getParent().getParent(), onReceiveLocation, ""); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } -// else if (promiseChained) { -// ShadowStackEntry entry = (ShadowStackEntry) msg.args[msg.args.length - 1]; -// assert entry != null && entry instanceof ShadowStackEntry.EntryAtMessageSend; -// ShadowStackEntry shadowStackEntry = SArguments.getShadowStackEntry(frame); -// -//// entry.setPreviousShadowStackEntry(shadowStackEntry); -// -// System.out.println("-register msg args: "+entry.getSourceSection()); -// System.out.println("shadow: "+shadowStackEntry.getSourceSection()); - -// assert maybeEntry != null && maybeEntry instanceof ShadowStackEntry.EntryForPromiseResolution; -// assert args[args.length - 1] instanceof ShadowStackEntry.EntryAtMessageSend; -// ShadowStackEntry.EntryAtMessageSend current = (ShadowStackEntry.EntryAtMessageSend) args[args.length - 1]; -// SArguments.addEntryForPromiseResolution(current, (ShadowStackEntry.EntryForPromiseResolution) maybeEntry); - -// } + // else if (promiseChained) { + // ShadowStackEntry entry = (ShadowStackEntry) msg.args[msg.args.length - 1]; + // assert entry != null && entry instanceof ShadowStackEntry.EntryAtMessageSend; + // ShadowStackEntry shadowStackEntry = SArguments.getShadowStackEntry(frame); + // + //// entry.setPreviousShadowStackEntry(shadowStackEntry); + // + // System.out.println("-register msg args: "+entry.getSourceSection()); + // System.out.println("shadow: "+shadowStackEntry.getSourceSection()); + + // assert maybeEntry != null && maybeEntry instanceof + // ShadowStackEntry.EntryForPromiseResolution; + // assert args[args.length - 1] instanceof ShadowStackEntry.EntryAtMessageSend; + // ShadowStackEntry.EntryAtMessageSend current = + // (ShadowStackEntry.EntryAtMessageSend) args[args.length - 1]; + // SArguments.addEntryForPromiseResolution(current, + // (ShadowStackEntry.EntryForPromiseResolution) maybeEntry); + + // } } } - + if (VmSettings.SENDER_SIDE_REPLAY) { ReplayRecord npr = current.getNextReplayEvent(); assert npr.type == TraceRecord.MESSAGE; msg.messageId = npr.eventNo; } - + if (VmSettings.SENDER_SIDE_TRACING) { // This is whenResolved promiseMsgSend.record(((STracingPromise) promise).version); @@ -177,7 +186,8 @@ public RegisterOnError(final ForkJoinPool actorPool) { } } - public void register(final VirtualFrame frame, final SPromise promise, final PromiseMessage msg, + public void register(final VirtualFrame frame, final SPromise promise, + final PromiseMessage msg, final Actor current) { Object promiseValue; @@ -205,12 +215,14 @@ public void register(final VirtualFrame frame, final SPromise promise, final Pro // TODO: I think, we need the info about the resolution context from the promise // we want to know where it was resolved, where the value is coming from ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( - SArguments.getShadowStackEntry(frame), - getParent().getParent(), ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_ERROR, ""); + SArguments.getShadowStackEntry(frame), + getParent().getParent(), + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_WHEN_RESOLVED_ERROR, + ""); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } - + if (VmSettings.SENDER_SIDE_TRACING) { // This is whenResolved promiseMsgSend.record(((STracingPromise) promise).version); diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java index 96e95a695e..cf2828b460 100644 --- a/src/som/interpreter/actors/ResolveNode.java +++ b/src/som/interpreter/actors/ResolveNode.java @@ -10,42 +10,44 @@ public abstract class ResolveNode extends AbstractPromiseResolutionNode { - @CompilerDirectives.CompilationFinal - boolean initialized = false; - - /** - * Normal case, when the promise is resolved with a value that's not a promise. - * Here we need to distinguish the explicit promises to ask directly to the promise - * if a promise resolution breakpoint was set. - */ - @Specialization(guards = {"notAPromise(result)"}) - public SPromise.SResolver normalResolution(final VirtualFrame frame, - final SPromise.SResolver resolver, final Object result, final Object maybeEntry, - final boolean haltOnResolver, final boolean haltOnResolution) { - if (!initialized) { - initialized = true; - this.initialize(SomLanguage.getVM(this)); - } - - SPromise promise = resolver.getPromise(); - - //this is needed to suspend on explicit promises (which resolved to a a value different from another promise) - if (haltOnResolver || promise.getHaltOnResolver()) { - haltNode.executeEvaluated(frame, result); - } - - ShadowStackEntry resolutionEntry = null; - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; - final ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.SUCCESSFUL; - resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location, "value: "+result.toString()); - SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); - } - - resolvePromise(SPromise.Resolution.SUCCESSFUL, resolver, result, resolutionEntry, - haltOnResolution || promise.getHaltOnResolution(), frame, this.getParent()); - return resolver; + @CompilerDirectives.CompilationFinal boolean initialized = false; + + /** + * Normal case, when the promise is resolved with a value that's not a promise. + * Here we need to distinguish the explicit promises to ask directly to the promise + * if a promise resolution breakpoint was set. + */ + @Specialization(guards = {"notAPromise(result)"}) + public SPromise.SResolver normalResolution(final VirtualFrame frame, + final SPromise.SResolver resolver, final Object result, final Object maybeEntry, + final boolean haltOnResolver, final boolean haltOnResolution) { + if (!initialized) { + initialized = true; + this.initialize(SomLanguage.getVM(this)); } + + SPromise promise = resolver.getPromise(); + + // this is needed to suspend on explicit promises (which resolved to a a value different + // from another promise) + if (haltOnResolver || promise.getHaltOnResolver()) { + haltNode.executeEvaluated(frame, result); + } + + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || entry != null; + final ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.SUCCESSFUL; + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, this.getParent(), location, + "value: " + result.toString()); + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); + } + + resolvePromise(SPromise.Resolution.SUCCESSFUL, resolver, result, resolutionEntry, + haltOnResolution || promise.getHaltOnResolution(), frame, this.getParent()); + return resolver; + } } diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index f019322a36..1561552394 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -38,7 +38,8 @@ protected SchedulePromiseHandlerNode(final ForkJoinPool actorPool) { this.actorPool = actorPool; } - public abstract void execute(VirtualFrame frame, SPromise promise, PromiseMessage msg, Actor current); + public abstract void execute(VirtualFrame frame, SPromise promise, PromiseMessage msg, + Actor current); @Specialization public final void schedule(final VirtualFrame frame, final SPromise promise, @@ -53,15 +54,16 @@ public final void schedule(final VirtualFrame frame, final SPromise promise, // Get info about the resolution context from the promise // we want to know where it was resolved, where the value is coming from ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation onReceiveLocation = - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_SCHEDULE_PROMISE; -// onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ msg.getSender().getId()); + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.ON_SCHEDULE_PROMISE; + // onReceiveLocation.setArg(msg.getTarget().getId() + " send by actor "+ + // msg.getSender().getId()); ShadowStackEntry resolutionEntry = ShadowStackEntry.createAtPromiseResolution( - SArguments.getShadowStackEntry(frame), - getParent().getParent(), onReceiveLocation, ""); + SArguments.getShadowStackEntry(frame), + getParent().getParent(), onReceiveLocation, ""); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || resolutionEntry != null; SArguments.setShadowStackEntry(msg.args, resolutionEntry); } - + if (VmSettings.SENDER_SIDE_REPLAY) { ReplayRecord npr = current.getNextReplayEvent(); assert npr.type == TraceRecord.MESSAGE; @@ -83,8 +85,7 @@ public final void schedule(final SPromise promise, Object receiver = rcvrWrapper.execute(promise.getValueUnsync(), finalTarget, current); - assert !(receiver instanceof SPromise) - : "TODO: handle this case as well?? Is it possible? didn't think about it"; + assert !(receiver instanceof SPromise) : "TODO: handle this case as well?? Is it possible? didn't think about it"; // TODO: might want to handle that in a specialization if (receiver instanceof SFarReference) { @@ -94,12 +95,12 @@ public final void schedule(final SPromise promise, receiver = ((SFarReference) receiver).getValue(); } - // TODO: we already have a shadow stack entry here, Don't think we need to do anything about it + // TODO: we already have a shadow stack entry here, Don't think we need to do anything + // about it msg.args[PromiseMessage.PROMISE_RCVR_IDX] = receiver; - assert !(receiver instanceof SFarReference) - : "this should not happen, because we need to redirect messages to the other actor, and normally we just unwrapped this"; + assert !(receiver instanceof SFarReference) : "this should not happen, because we need to redirect messages to the other actor, and normally we just unwrapped this"; assert !(receiver instanceof SPromise); wrapArguments(msg, finalTarget, argWrapper); @@ -123,7 +124,7 @@ private void wrapArguments(final PromiseSendMessage msg, final Actor finalTarget final WrapReferenceNode argWrapper) { // TODO: break that out into nodes for (int i = - 1; i < numArgs.profile(SArguments.getLengthWithoutShadowStack(msg.args)); i++) { + 1; i < numArgs.profile(SArguments.getLengthWithoutShadowStack(msg.args)); i++) { msg.args[i] = argWrapper.execute(msg.args[i], finalTarget, msg.originalSender); } } diff --git a/src/som/interpreter/actors/TransferObject.java b/src/som/interpreter/actors/TransferObject.java index 92d247eb0d..6d52cf9aaf 100644 --- a/src/som/interpreter/actors/TransferObject.java +++ b/src/som/interpreter/actors/TransferObject.java @@ -50,8 +50,7 @@ public static SObject transfer(final SObject obj, final Actor origin, final Actor target, final Map transferedObjects) { assert obj.getSOMClass() - .isTransferObject() - : "only TransferObjects should be handled here"; + .isTransferObject() : "only TransferObjects should be handled here"; assert !obj.isValue() : "TransferObjects can't be Values"; ObjectLayout layout = obj.getObjectLayout(); diff --git a/src/som/interpreter/nodes/InstantiationNode.java b/src/som/interpreter/nodes/InstantiationNode.java index 260afad20f..3209db9595 100644 --- a/src/som/interpreter/nodes/InstantiationNode.java +++ b/src/som/interpreter/nodes/InstantiationNode.java @@ -48,9 +48,9 @@ public static SClass instantiateMetaclassClass(final ClassFactory factory, } public static SClass signalExceptionsIfFaultFoundElseReturnClassObject( - final VirtualFrame frame, final SObjectWithClass outerObj, final ClassFactory factory, - final SClass classObj, final ExceptionSignalingNode notAValue, - final ExceptionSignalingNode cannotBeValue) { + final VirtualFrame frame, final SObjectWithClass outerObj, final ClassFactory factory, + final SClass classObj, final ExceptionSignalingNode notAValue, + final ExceptionSignalingNode cannotBeValue) { factory.initializeClass(classObj); if (factory.isDeclaredAsValue() && factory.isTransferObject()) { @@ -72,7 +72,8 @@ public ClassInstantiationNode(final MixinDefinition mixinDefinition) { super(mixinDefinition); } - public abstract SClass execute(VirtualFrame frame, SObjectWithClass outerObj, Object superclassAndMixins); + public abstract SClass execute(VirtualFrame frame, SObjectWithClass outerObj, + Object superclassAndMixins); @Specialization(guards = {"sameSuperAndMixins(superclassAndMixins, cachedSuperMixins)"}) public SClass instantiateClass(final VirtualFrame frame, final SObjectWithClass outerObj, @@ -86,12 +87,14 @@ public static SClass instantiate(final VirtualFrame frame, final SObjectWithClas final ClassFactory factory, final ExceptionSignalingNode notAValue, final ExceptionSignalingNode cannotBeValues) { SClass classObj = new SClass(outerObj, instantiateMetaclassClass(factory, outerObj)); - return signalExceptionsIfFaultFoundElseReturnClassObject(frame, outerObj, factory, classObj, + return signalExceptionsIfFaultFoundElseReturnClassObject(frame, outerObj, factory, + classObj, notAValue, cannotBeValues); } @Specialization(replaces = "instantiateClass") - public SClass instantiateClassWithNewClassFactory(final VirtualFrame frame, final SObjectWithClass outerObj, + public SClass instantiateClassWithNewClassFactory(final VirtualFrame frame, + final SObjectWithClass outerObj, final Object superclassAndMixins) { return instantiateClass(frame, outerObj, superclassAndMixins, null, createClassFactory(superclassAndMixins)); @@ -128,7 +131,8 @@ private static SClass instantiate(final SObjectWithClass outerObj, final InstantiationNode inst) { SClass classObj = new SClass(outerObj, instantiateMetaclassClass(factory, outerObj), frame); - return signalExceptionsIfFaultFoundElseReturnClassObject(frame, outerObj, factory, classObj, + return signalExceptionsIfFaultFoundElseReturnClassObject(frame, outerObj, factory, + classObj, inst.notAValue, inst.cannotBeValues); } diff --git a/src/som/interpreter/nodes/InternalObjectArrayNode.java b/src/som/interpreter/nodes/InternalObjectArrayNode.java index 92f1fa957c..647bd74f41 100644 --- a/src/som/interpreter/nodes/InternalObjectArrayNode.java +++ b/src/som/interpreter/nodes/InternalObjectArrayNode.java @@ -13,7 +13,8 @@ @NodeInfo(cost = NodeCost.NONE) public class InternalObjectArrayNode extends ExprWithTagsNode { @Children protected final ExpressionNode[] expressions; - @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = + ShadowStackEntryLoad.create(); public InternalObjectArrayNode(final ExpressionNode[] expressions) { this.expressions = expressions; @@ -35,7 +36,7 @@ public final Object executeGeneric(final VirtualFrame frame) { } public static class ArgumentEvaluationNode - extends InternalObjectArrayNode { + extends InternalObjectArrayNode { public ArgumentEvaluationNode(final ExpressionNode[] expressions) { super(expressions); @@ -49,7 +50,7 @@ public Object[] executeObjectArray(final VirtualFrame frame) { values[i] = expressions[i].executeGeneric(frame); } SArguments.setShadowStackEntryWithCache(values, this, shadowStackEntryLoad, frame, - true); + true); return values; } } diff --git a/src/som/interpreter/nodes/MessageSendNode.java b/src/som/interpreter/nodes/MessageSendNode.java index 3f84c88559..5970eea07e 100644 --- a/src/som/interpreter/nodes/MessageSendNode.java +++ b/src/som/interpreter/nodes/MessageSendNode.java @@ -41,6 +41,7 @@ import som.interpreter.SArguments; import tools.debugger.asyncstacktraces.ShadowStackEntry; + public final class MessageSendNode { public static ExpressionNode createMessageSend(final SSymbol selector, diff --git a/src/som/interpreter/nodes/SOMNode.java b/src/som/interpreter/nodes/SOMNode.java index 93547e8aca..f057bcc361 100644 --- a/src/som/interpreter/nodes/SOMNode.java +++ b/src/som/interpreter/nodes/SOMNode.java @@ -126,8 +126,7 @@ public static T unwrapIfNecessary(final T node) { } public static Node getParentIgnoringWrapper(final Node node) { - assert !(node instanceof WrapperNode) - : "A correct usage will not see nodes that are wrappers. This is to detect bugs"; + assert !(node instanceof WrapperNode) : "A correct usage will not see nodes that are wrappers. This is to detect bugs"; Node parent = node.getParent(); if (parent instanceof WrapperNode) { diff --git a/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java b/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java index 1e9c9f7a6e..97a34a4f51 100644 --- a/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/AbstractGenericDispatchNode.java @@ -49,7 +49,7 @@ public final Object executeDispatch(final VirtualFrame frame, final Object[] arg // are just not present in benchmarks if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { SArguments.setShadowStackEntryWithCache(arguments, this, - shadowStackEntryLoad, frame, false); + shadowStackEntryLoad, frame, false); } if (method != null) { diff --git a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java index 76c6082501..627234d5b1 100644 --- a/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java +++ b/src/som/interpreter/nodes/dispatch/BackCacheCallNode.java @@ -12,45 +12,46 @@ import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; + public interface BackCacheCallNode { - static void initializeUniqueCaller(final RootCallTarget methodCallTarget, - final BackCacheCallNode node) { - RootNode root = methodCallTarget.getRootNode(); - if (root instanceof Method) { - ((Method) root).setNewCaller(node); - } + static void initializeUniqueCaller(final RootCallTarget methodCallTarget, + final BackCacheCallNode node) { + RootNode root = methodCallTarget.getRootNode(); + if (root instanceof Method) { + ((Method) root).setNewCaller(node); } - - static void setShadowStackEntry(final VirtualFrame frame, - final boolean uniqueCaller, final Object[] arguments, - final Node expression, - final ShadowStackEntryLoad shadowStackEntryLoad) { - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - assert arguments[arguments.length - 1] == null; - assert (frame.getArguments()[frame.getArguments().length - - 1] instanceof ShadowStackEntry); - assert frame.getArguments().length >= 2; - } - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE) { - if (uniqueCaller) { - SArguments.setShadowStackEntry(arguments, SArguments.getShadowStackEntry(frame)); - } else { - SArguments.setShadowStackEntryWithCache(arguments, expression, - shadowStackEntryLoad, frame, false); - } - } else if (VmSettings.ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE) { - SArguments.setShadowStackEntryWithCache(arguments, expression, - shadowStackEntryLoad, frame, false); - } - assert arguments[arguments.length - 1] != null - || (frame.getArguments()[frame.getArguments().length - 1] == null) - || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + } + + static void setShadowStackEntry(final VirtualFrame frame, + final boolean uniqueCaller, final Object[] arguments, + final Node expression, + final ShadowStackEntryLoad shadowStackEntryLoad) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + assert arguments[arguments.length - 1] == null; + assert (frame.getArguments()[frame.getArguments().length + - 1] instanceof ShadowStackEntry); + assert frame.getArguments().length >= 2; + } + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE) { + if (uniqueCaller) { + SArguments.setShadowStackEntry(arguments, SArguments.getShadowStackEntry(frame)); + } else { + SArguments.setShadowStackEntryWithCache(arguments, expression, + shadowStackEntryLoad, frame, false); + } + } else if (VmSettings.ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE) { + SArguments.setShadowStackEntryWithCache(arguments, expression, + shadowStackEntryLoad, frame, false); } + assert arguments[arguments.length - 1] != null + || (frame.getArguments()[frame.getArguments().length - 1] == null) + || !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + } - void makeUniqueCaller(); + void makeUniqueCaller(); - void makeMultipleCaller(); + void makeMultipleCaller(); - Invokable getCachedMethod(); + Invokable getCachedMethod(); } diff --git a/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java b/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java index 0c28a2e4d0..ee779f4ce8 100644 --- a/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java @@ -35,7 +35,7 @@ protected static final boolean isSameMethod(final Object[] arguments, protected static final SInvokable getMethod(final Object[] arguments) { SInvokable method = ((SBlock) arguments[0]).getMethod(); assert method.getNumberOfArguments() == arguments.length - || (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE + || (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE && (method.getNumberOfArguments() == arguments.length - 1)); return method; } diff --git a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java index 80ea4bc3d9..f24ab89440 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java @@ -20,7 +20,8 @@ import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; -public final class CachedDispatchNode extends AbstractDispatchNode implements BackCacheCallNode { +public final class CachedDispatchNode extends AbstractDispatchNode + implements BackCacheCallNode { private final Assumption stillUniqueCaller; @Child private DirectCallNode cachedMethod; @Child private AbstractDispatchNode nextInCache; @@ -31,12 +32,13 @@ public final class CachedDispatchNode extends AbstractDispatchNode implements Ba private final DispatchGuard guard; public CachedDispatchNode(final CallTarget methodCallTarget, - final DispatchGuard guard, final AbstractDispatchNode nextInCache) { + final DispatchGuard guard, final AbstractDispatchNode nextInCache) { this(methodCallTarget, guard, nextInCache, true); } public CachedDispatchNode(final CallTarget methodCallTarget, - final DispatchGuard guard, final AbstractDispatchNode nextInCache, final boolean defaultUniqueCaller) { + final DispatchGuard guard, final AbstractDispatchNode nextInCache, + final boolean defaultUniqueCaller) { super(nextInCache.getSourceSection()); stillUniqueCaller = Truffle.getRuntime().createAssumption(); this.guard = guard; @@ -51,26 +53,26 @@ public CachedDispatchNode(final CallTarget methodCallTarget, } public CachedDispatchNode(final CachedDispatchNode node, final boolean uniqueCaller) { - this(node.cachedMethod.getCallTarget(), node.guard, node.nextInCache, false); - this.uniqueCaller = uniqueCaller; - } + this(node.cachedMethod.getCallTarget(), node.guard, node.nextInCache, false); + this.uniqueCaller = uniqueCaller; + } - @Override - public void makeUniqueCaller() { - uniqueCaller = true; - } + @Override + public void makeUniqueCaller() { + uniqueCaller = true; + } - @Override - public void makeMultipleCaller() { - uniqueCaller = false; - stillUniqueCaller.invalidate(); - } + @Override + public void makeMultipleCaller() { + uniqueCaller = false; + stillUniqueCaller.invalidate(); + } - @Override - public Invokable getCachedMethod() { - RootCallTarget ct = (DefaultCallTarget) cachedMethod.getCallTarget(); - return (Invokable) ct.getRootNode(); - } + @Override + public Invokable getCachedMethod() { + RootCallTarget ct = (DefaultCallTarget) cachedMethod.getCallTarget(); + return (Invokable) ct.getRootNode(); + } @Override public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) { @@ -78,7 +80,7 @@ public Object executeDispatch(final VirtualFrame frame, final Object[] arguments if (guard.entryMatches(arguments[0])) { stillUniqueCaller.check(); BackCacheCallNode.setShadowStackEntry(frame, - uniqueCaller, arguments, this, shadowStackEntryLoad); + uniqueCaller, arguments, this, shadowStackEntryLoad); return cachedMethod.call(arguments); } else { return nextInCache.executeDispatch(frame, arguments); diff --git a/src/som/interpreter/nodes/dispatch/CachedDnuNode.java b/src/som/interpreter/nodes/dispatch/CachedDnuNode.java index 54a6216688..bb8a0d421f 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDnuNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDnuNode.java @@ -55,7 +55,7 @@ public Object executeDispatch(final VirtualFrame frame, final Object[] arguments // the stack across DNUs if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { SArguments.setShadowStackEntryWithCache(arguments, this, - shadowStackEntryLoad, frame, false); + shadowStackEntryLoad, frame, false); } try { match = guard.entryMatches(rcvr); diff --git a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java index 592cbbefe2..7879b22ed4 100644 --- a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java +++ b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java @@ -112,7 +112,7 @@ public SClass read(final VirtualFrame frame, final SObject rcvr, final Object ma * Caller needs to hold lock on {@code this}. */ private SClass instantiateAndWriteUnsynced(final VirtualFrame frame, final SObject rcvr, - final Object maybeEntry) { + final Object maybeEntry) { SClass classObject = instantiateClassObject(frame, rcvr, maybeEntry); try { @@ -138,7 +138,7 @@ private void createResolverCallTargets() { } private SClass instantiateClassObject(final VirtualFrame frame, final SObject rcvr, - final Object maybeEntry) { + final Object maybeEntry) { if (superclassAndMixinResolver == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); createResolverCallTargets(); @@ -157,8 +157,8 @@ private SClass instantiateClassObject(final VirtualFrame frame, final SObject rc actualEntry = SArguments.instantiateTopShadowStackEntry(this); } superclassAndMixins = - superclassAndMixinResolver.call( - new Object[] {rcvr, actualEntry}); + superclassAndMixinResolver.call( + new Object[] {rcvr, actualEntry}); } else { superclassAndMixins = superclassAndMixinResolver.call(new Object[] {rcvr}); } diff --git a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java index b8e27e279f..64e1da22be 100644 --- a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java @@ -25,7 +25,8 @@ * Private methods are special, they are linked unconditionally to the call site. * Thus, we don't need to check at the dispatch whether they apply or not. */ -public abstract class LexicallyBoundDispatchNode extends AbstractDispatchNode implements BackCacheCallNode { +public abstract class LexicallyBoundDispatchNode extends AbstractDispatchNode + implements BackCacheCallNode { protected final Assumption stillUniqueCaller; @Child private DirectCallNode cachedMethod; @@ -67,14 +68,14 @@ public Method getCachedMethod() { @Specialization(assumptions = "stillUniqueCaller", guards = "uniqueCaller") public Object uniqueCallerDispatch(final VirtualFrame frame, final Object[] arguments) { BackCacheCallNode.setShadowStackEntry(frame, - true, arguments, this, shadowStackEntryLoad); + true, arguments, this, shadowStackEntryLoad); return cachedMethod.call(arguments); } @Specialization(guards = "!uniqueCaller") public Object multipleCallerDispatch(final VirtualFrame frame, final Object[] arguments) { BackCacheCallNode.setShadowStackEntry(frame, - false, arguments, this, shadowStackEntryLoad); + false, arguments, this, shadowStackEntryLoad); return cachedMethod.call(arguments); } diff --git a/src/som/interpreter/nodes/literals/ArrayLiteralNode.java b/src/som/interpreter/nodes/literals/ArrayLiteralNode.java index 12b1b45b3b..671cd775f7 100644 --- a/src/som/interpreter/nodes/literals/ArrayLiteralNode.java +++ b/src/som/interpreter/nodes/literals/ArrayLiteralNode.java @@ -78,8 +78,7 @@ private void specialize(final SMutableArray storage) { } else if (storage.isLongType()) { node = new Longs(expressions); } else { - assert storage.isObjectType() - : "Partially empty is not supported yet. Should be simple to add."; + assert storage.isObjectType() : "Partially empty is not supported yet. Should be simple to add."; node = new Objects(expressions); } replace(node.initialize(sourceSection)); diff --git a/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java b/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java index b9f883e3cd..be5ee3e3da 100644 --- a/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java +++ b/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java @@ -35,10 +35,9 @@ protected EagerlySpecializableNode getPrimitive() { @Override public boolean hasTag(final Class tag) { - assert !(primitive instanceof WrapperNode) - : "primitive can't be WrapperNodes to avoid double wrapping. It is: " - + primitive.getClass().getSimpleName() + " and contains a " - + ((WrapperNode) primitive).getDelegateNode().getClass().getSimpleName(); + assert !(primitive instanceof WrapperNode) : "primitive can't be WrapperNodes to avoid double wrapping. It is: " + + primitive.getClass().getSimpleName() + " and contains a " + + ((WrapperNode) primitive).getDelegateNode().getClass().getSimpleName(); return primitive.hasTagIgnoringEagerness(tag); } @@ -136,8 +135,7 @@ protected void onReplace(final Node newNode, final CharSequence reason) { if (newNode instanceof ExprWithTagsNode) { ((ExprWithTagsNode) newNode).tagMark = primitive.tagMark; } else if (newNode instanceof WrapperNode) { - assert ((WrapperNode) newNode).getDelegateNode() == this - : "Wrapping should not also do specialization or other changes, I think"; + assert ((WrapperNode) newNode).getDelegateNode() == this : "Wrapping should not also do specialization or other changes, I think"; } else { throw new NotYetImplementedException(); } diff --git a/src/som/interpreter/nodes/nary/EagerTernaryPrimitiveNode.java b/src/som/interpreter/nodes/nary/EagerTernaryPrimitiveNode.java index dd9e30cbea..add68d695e 100644 --- a/src/som/interpreter/nodes/nary/EagerTernaryPrimitiveNode.java +++ b/src/som/interpreter/nodes/nary/EagerTernaryPrimitiveNode.java @@ -38,8 +38,7 @@ protected EagerlySpecializableNode getPrimitive() { @Override public boolean hasTag(final Class tag) { - assert !(primitive instanceof WrapperNode) - : "Eager primitives are expected to point directly to primitive nodes, and do not have wrapper nodes. I think, we wanted the wrapper nodes to be strictly around the eager wrappers."; + assert !(primitive instanceof WrapperNode) : "Eager primitives are expected to point directly to primitive nodes, and do not have wrapper nodes. I think, we wanted the wrapper nodes to be strictly around the eager wrappers."; return primitive.hasTagIgnoringEagerness(tag); } @@ -133,8 +132,7 @@ protected void onReplace(final Node newNode, final CharSequence reason) { if (newNode instanceof ExprWithTagsNode) { ((ExprWithTagsNode) newNode).tagMark = primitive.tagMark; } else if (newNode instanceof WrapperNode) { - assert ((WrapperNode) newNode).getDelegateNode() == this - : "Wrapping should not also do specialization or other changes, I think"; + assert ((WrapperNode) newNode).getDelegateNode() == this : "Wrapping should not also do specialization or other changes, I think"; } else { throw new NotYetImplementedException(); } diff --git a/src/som/interpreter/nodes/nary/EagerUnaryPrimitiveNode.java b/src/som/interpreter/nodes/nary/EagerUnaryPrimitiveNode.java index 6bf7507282..a4f51b5721 100644 --- a/src/som/interpreter/nodes/nary/EagerUnaryPrimitiveNode.java +++ b/src/som/interpreter/nodes/nary/EagerUnaryPrimitiveNode.java @@ -122,8 +122,7 @@ protected void onReplace(final Node newNode, final CharSequence reason) { if (newNode instanceof ExprWithTagsNode) { ((ExprWithTagsNode) newNode).tagMark = primitive.tagMark; } else if (newNode instanceof WrapperNode) { - assert ((WrapperNode) newNode).getDelegateNode() == this - : "Wrapping should not also do specialization or other changes, I think"; + assert ((WrapperNode) newNode).getDelegateNode() == this : "Wrapping should not also do specialization or other changes, I think"; } else { throw new NotYetImplementedException(); } diff --git a/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java index f288d52f69..a48614bc3b 100644 --- a/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntDownToDoMessageNode.java @@ -23,9 +23,9 @@ public abstract class IntDownToDoMessageNode extends IntToDoMessageNode { @Override @Specialization(guards = "block.getMethod() == blockMethod") public final long doIntToDo(final VirtualFrame frame, final long receiver, - final long limit, final SBlock block, - @Cached("block.getMethod()") final SInvokable blockMethod, - @Cached("create(blockMethod)") final DirectCallNode valueSend) { + final long limit, final SBlock block, + @Cached("block.getMethod()") final SInvokable blockMethod, + @Cached("create(blockMethod)") final DirectCallNode valueSend) { return IntToByDoMessageNode.doLoop(frame, valueSend, this, receiver, limit, -1, block, shadowStackEntryLoad); } diff --git a/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java index 0db42a8531..0907551ccf 100644 --- a/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntToByDoMessageNode.java @@ -50,20 +50,21 @@ public final long doIntToByDo(final VirtualFrame frame, final long receiver, @Specialization(guards = "block.getMethod() == blockMethod") public final long doIntToByDo(final VirtualFrame frame, final long receiver, final double limit, final long step, final SBlock block) { - return doLoop(frame, valueSend, this, receiver, (long) limit, step, block, shadowStackEntryLoad); + return doLoop(frame, valueSend, this, receiver, (long) limit, step, block, + shadowStackEntryLoad); } public static long doLoop(final VirtualFrame frame, final DirectCallNode value, - final ExpressionNode loopNode, final long receiver, final long limit, final long step, - final SBlock block, ShadowStackEntryLoad shadowStackEntryLoad) { + final ExpressionNode loopNode, final long receiver, final long limit, final long step, + final SBlock block, ShadowStackEntryLoad shadowStackEntryLoad) { try { if (receiver <= limit) { value.call(SArguments.getPlainXArgumentsWithReceiver(loopNode, - shadowStackEntryLoad, frame, block, receiver)); + shadowStackEntryLoad, frame, block, receiver)); } for (long i = receiver + step; i <= limit; i += step) { value.call(SArguments.getPlainXArgumentsWithReceiver(loopNode, - shadowStackEntryLoad, frame, block, i)); + shadowStackEntryLoad, frame, block, i)); ObjectTransitionSafepoint.INSTANCE.checkAndPerformSafepoint(); } diff --git a/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java b/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java index 5fd20bc090..edf3114380 100644 --- a/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java +++ b/src/som/interpreter/nodes/specialized/IntToDoMessageNode.java @@ -57,9 +57,10 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { } @Specialization(guards = "block.getMethod() == blockMethod") - public long doIntToDo(final VirtualFrame frame, final long receiver, final long limit, final SBlock block, - @Cached("block.getMethod()") final SInvokable blockMethod, - @Cached("create(blockMethod)") final DirectCallNode valueSend) { + public long doIntToDo(final VirtualFrame frame, final long receiver, final long limit, + final SBlock block, + @Cached("block.getMethod()") final SInvokable blockMethod, + @Cached("create(blockMethod)") final DirectCallNode valueSend) { return IntToByDoMessageNode.doLoop(frame, valueSend, this, receiver, limit, 1, block, shadowStackEntryLoad); } diff --git a/src/som/interpreter/objectstorage/StorageAccessor.java b/src/som/interpreter/objectstorage/StorageAccessor.java index e23d88c9a2..a368aac250 100644 --- a/src/som/interpreter/objectstorage/StorageAccessor.java +++ b/src/som/interpreter/objectstorage/StorageAccessor.java @@ -59,18 +59,16 @@ private static long getFieldOffset(final String fieldName) { } public static AbstractObjectAccessor getObjectAccessor(final int idx) { - assert idx < MAX_OBJECT_FIELDS - : "Got a object slot allocated that goes beyond the currently supported. idx: " - + idx; + assert idx < MAX_OBJECT_FIELDS : "Got a object slot allocated that goes beyond the currently supported. idx: " + + idx; AbstractObjectAccessor result = objAccessors[idx]; assert result != null : "Object accessors not yet initialized?"; return result; } public static AbstractPrimitiveAccessor getPrimitiveAccessor(final int idx) { - assert idx < MAX_OBJECT_FIELDS - : "Got a primitive slot allocated that goes beyond the currently supported. idx: " - + idx; + assert idx < MAX_OBJECT_FIELDS : "Got a primitive slot allocated that goes beyond the currently supported. idx: " + + idx; AbstractPrimitiveAccessor result = primAccessors[idx]; assert result != null : "Primitive accessors not yet initialized?"; return result; diff --git a/src/som/interpreter/objectstorage/StorageLocation.java b/src/som/interpreter/objectstorage/StorageLocation.java index a933cddf07..6c2ecb8822 100644 --- a/src/som/interpreter/objectstorage/StorageLocation.java +++ b/src/som/interpreter/objectstorage/StorageLocation.java @@ -208,8 +208,7 @@ public void write(final SObject obj, final Object value) { @Override public boolean isSet(final SObject obj) { assert read( - obj) != null - : "null is not a valid value for an object slot, it needs to be initialized with nil."; + obj) != null : "null is not a valid value for an object slot, it needs to be initialized with nil."; return true; } diff --git a/src/som/primitives/BlockPrims.java b/src/som/primitives/BlockPrims.java index 22722c410f..8f0a82623f 100644 --- a/src/som/primitives/BlockPrims.java +++ b/src/som/primitives/BlockPrims.java @@ -106,7 +106,7 @@ public final Object doCachedBlock(final VirtualFrame frame, final SBlock receive @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { return call.call(SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, receiver)); + shadowStackEntryLoad, frame, receiver)); } @Specialization(replaces = "doCachedBlock") @@ -114,8 +114,8 @@ public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, @Cached("create()") final IndirectCallNode call) { checkArguments(frame, receiver, 1, argumentError); return receiver.getMethod().invoke(call, - SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, receiver)); + SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver)); } @Override @@ -132,7 +132,8 @@ public final void record(final Invokable ivkbl, } } - private static void checkArguments(final VirtualFrame frame, final SBlock receiver, final int expectedNumArgs, + private static void checkArguments(final VirtualFrame frame, final SBlock receiver, + final int expectedNumArgs, final ExceptionSignalingNode argumentError) { int numArgs = receiver.getMethod().getNumberOfArguments(); if (numArgs != expectedNumArgs) { @@ -154,7 +155,8 @@ public abstract static class ValueOnePrim extends BinaryExpressionNode implements DispatchProfile, ValuePrimNode { protected @Child ExceptionSignalingNode argumentError; - @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = + ShadowStackEntryLoad.create(); protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; @@ -179,20 +181,22 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { @Specialization( guards = {"cached == receiver.getMethod()", "cached.getNumberOfArguments() == 2"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, final Object arg, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, + final Object arg, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { return call.call(SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, receiver, arg)); + shadowStackEntryLoad, frame, receiver, arg)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, final Object arg, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, + final Object arg, @Cached("create()") final IndirectCallNode call) { checkArguments(frame, receiver, 2, argumentError); return receiver.getMethod().invoke(call, - SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, receiver, arg)); + SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver, arg)); } @Override @@ -217,8 +221,8 @@ public abstract static class ValueTwoPrim extends TernaryExpressionNode implements DispatchProfile, ValuePrimNode { protected @Child ExceptionSignalingNode argumentError; - @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); - + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = + ShadowStackEntryLoad.create(); protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; @@ -243,21 +247,23 @@ protected boolean hasTagIgnoringEagerness(final Class tag) { @Specialization( guards = {"cached == receiver.getMethod()", "cached.getNumberOfArguments() == 3"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, final Object arg1, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, + final Object arg1, final Object arg2, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { return call.call(SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, receiver, arg1, arg2)); + shadowStackEntryLoad, frame, receiver, arg1, arg2)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, final Object arg1, final Object arg2, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, + final Object arg1, final Object arg2, @Cached("create()") final IndirectCallNode call) { checkArguments(frame, receiver, 3, argumentError); return receiver.getMethod().invoke(call, - SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, receiver, arg1, arg2)); + SArguments.getPlainXArgumentsWithReceiver(this, + shadowStackEntryLoad, frame, receiver, arg1, arg2)); } @Override @@ -282,10 +288,13 @@ public final void record(final Invokable ivkbl, public abstract static class ValueArgsPrim extends BinaryExpressionNode implements DispatchProfile, ValuePrimNode { - protected @Child SizeAndLengthPrim size = SizeAndLengthPrimFactory.create(null); - protected @Child AtPrim at = AtPrimFactory.create(null, null); + protected @Child SizeAndLengthPrim size = + SizeAndLengthPrimFactory.create(null); + protected @Child AtPrim at = + AtPrimFactory.create(null, null); protected @Child ExceptionSignalingNode argumentError; - @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoad = + ShadowStackEntryLoad.create(); protected final HashMap targets = VmSettings.DYNAMIC_METRICS ? new HashMap<>() : null; @@ -315,21 +324,23 @@ protected long getNumArgs(final SArray args) { guards = {"cached == receiver.getMethod()", "numArgs == cached.getNumberOfArguments()"}, limit = "CHAIN_LENGTH") - public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, final SArray args, + public final Object doCachedBlock(final VirtualFrame frame, final SBlock receiver, + final SArray args, @Cached("getNumArgs(args)") final long numArgs, @Cached("createDirectCallNode(receiver, getThis())") final DirectCallNode call, @Cached("receiver.getMethod()") final SInvokable cached) { return call.call(SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at, this, - shadowStackEntryLoad, frame)); + shadowStackEntryLoad, frame)); } @Specialization(replaces = "doCachedBlock") - public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, final SArray args, + public final Object doGeneric(final VirtualFrame frame, final SBlock receiver, + final SArray args, @Cached("create()") final IndirectCallNode call) { checkArguments(frame, receiver, (int) getNumArgs(args), argumentError); return receiver.getMethod().invoke( - call, SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at, this, - shadowStackEntryLoad, frame)); + call, SArguments.getPlainArgumentsWithReceiver(receiver, args, size, at, this, + shadowStackEntryLoad, frame)); } @Override diff --git a/src/som/primitives/ExceptionsPrims.java b/src/som/primitives/ExceptionsPrims.java index e7c60edd61..fab2659e56 100644 --- a/src/som/primitives/ExceptionsPrims.java +++ b/src/som/primitives/ExceptionsPrims.java @@ -32,20 +32,18 @@ public abstract static class ExceptionDoOnPrim extends TernaryExpressionNode { protected static final int INLINE_CACHE_SIZE = VmSettings.DYNAMIC_METRICS ? 100 : 6; - @Child - protected ShadowStackEntryLoad shadowStackEntryLoadBody = - ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoadBody = + ShadowStackEntryLoad.create(); - @Child - protected ShadowStackEntryLoad shadowStackEntryLoadException = - ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoadException = + ShadowStackEntryLoad.create(); protected static final IndirectCallNode indirect = - Truffle.getRuntime().createIndirectCallNode(); + Truffle.getRuntime().createIndirectCallNode(); public static final DirectCallNode createCallNode(final SBlock block) { return Truffle.getRuntime().createDirectCallNode( - block.getMethod().getCallTarget()); + block.getMethod().getCallTarget()); } public static final boolean sameBlock(final SBlock block, final SInvokable method) { @@ -53,34 +51,34 @@ public static final boolean sameBlock(final SBlock block, final SInvokable metho } @Specialization(limit = "INLINE_CACHE_SIZE", - guards = {"sameBlock(body, cachedBody)", - "sameBlock(exceptionHandler, cachedExceptionMethod)"}) + guards = {"sameBlock(body, cachedBody)", + "sameBlock(exceptionHandler, cachedExceptionMethod)"}) public final Object doException(final VirtualFrame frame, final SBlock body, - final SClass exceptionClass, final SBlock exceptionHandler, - @Cached("body.getMethod()") final SInvokable cachedBody, - @Cached("createCallNode(body)") final DirectCallNode bodyCall, - @Cached("exceptionHandler.getMethod()") final SInvokable cachedExceptionMethod, - @Cached("createCallNode(exceptionHandler)") final DirectCallNode exceptionCall) { + final SClass exceptionClass, final SBlock exceptionHandler, + @Cached("body.getMethod()") final SInvokable cachedBody, + @Cached("createCallNode(body)") final DirectCallNode bodyCall, + @Cached("exceptionHandler.getMethod()") final SInvokable cachedExceptionMethod, + @Cached("createCallNode(exceptionHandler)") final DirectCallNode exceptionCall) { try { Object[] args; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - args = new Object[]{body, null}; + args = new Object[] {body, null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadBody, frame, - false); + false); } else { - args = new Object[]{body}; + args = new Object[] {body}; } return bodyCall.call(args); } catch (SomException e) { if (e.getSomObject().getSOMClass().isKindOf(exceptionClass)) { Object[] args; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - args = new Object[]{exceptionHandler, e.getSomObject(), null}; + args = new Object[] {exceptionHandler, e.getSomObject(), null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadException, - frame, - false); + frame, + false); } else { - args = new Object[]{exceptionHandler, e.getSomObject()}; + args = new Object[] {exceptionHandler, e.getSomObject()}; } return exceptionCall.call(args); } else { @@ -91,27 +89,27 @@ public final Object doException(final VirtualFrame frame, final SBlock body, @Specialization(replaces = "doException") public final Object doExceptionUncached(final VirtualFrame frame, final SBlock body, - final SClass exceptionClass, final SBlock exceptionHandler) { + final SClass exceptionClass, final SBlock exceptionHandler) { try { Object[] args; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - args = new Object[]{body, null}; + args = new Object[] {body, null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadBody, frame, - false); + false); } else { - args = new Object[]{body}; + args = new Object[] {body}; } return body.getMethod().invoke(indirect, args); } catch (SomException e) { if (e.getSomObject().getSOMClass().isKindOf(exceptionClass)) { Object[] args; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - args = new Object[]{exceptionHandler, e.getSomObject(), null}; + args = new Object[] {exceptionHandler, e.getSomObject(), null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadException, - frame, - false); + frame, + false); } else { - args = new Object[]{exceptionHandler, e.getSomObject()}; + args = new Object[] {exceptionHandler, e.getSomObject()}; } return exceptionHandler.getMethod().invoke(indirect, args); } else { @@ -132,43 +130,39 @@ public final Object doSignal(final SAbstractObject exceptionObject) { @GenerateNodeFactory @Primitive(primitive = "exceptionDo:ensure:", selector = "ensure:", - receiverType = SBlock.class) + receiverType = SBlock.class) public abstract static class EnsurePrim extends BinaryComplexOperation { - @Child - protected BlockDispatchNode dispatchBody = BlockDispatchNodeGen.create(); - @Child - protected BlockDispatchNode dispatchHandler = BlockDispatchNodeGen.create(); + @Child protected BlockDispatchNode dispatchBody = BlockDispatchNodeGen.create(); + @Child protected BlockDispatchNode dispatchHandler = BlockDispatchNodeGen.create(); - @Child - protected ShadowStackEntryLoad shadowStackEntryLoadBody = - ShadowStackEntryLoad.create(); - @Child - protected ShadowStackEntryLoad shadowStackEntryLoadHandler = - ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoadBody = + ShadowStackEntryLoad.create(); + @Child protected ShadowStackEntryLoad shadowStackEntryLoadHandler = + ShadowStackEntryLoad.create(); @Specialization public final Object doException(final VirtualFrame frame, final SBlock body, - final SBlock ensureHandler) { + final SBlock ensureHandler) { if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { // losing SSEntry info here again try { - Object[] args = new Object[]{body, null}; + Object[] args = new Object[] {body, null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadBody, frame, - false); + false); return dispatchBody.executeDispatch(args); } finally { - Object[] args = new Object[]{ensureHandler, null}; + Object[] args = new Object[] {ensureHandler, null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoadHandler, - frame, - false); + frame, + false); dispatchHandler.executeDispatch(args); } } else { try { - return dispatchBody.executeDispatch(new Object[]{body}); + return dispatchBody.executeDispatch(new Object[] {body}); } finally { - dispatchHandler.executeDispatch(new Object[]{ensureHandler}); + dispatchHandler.executeDispatch(new Object[] {ensureHandler}); } } } diff --git a/src/som/primitives/FilePrims.java b/src/som/primitives/FilePrims.java index 26fc0b8553..e6b21b8fc4 100644 --- a/src/som/primitives/FilePrims.java +++ b/src/som/primitives/FilePrims.java @@ -123,7 +123,8 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final Object setModeSymbol(final VirtualFrame frame, final SFileDescriptor file, final SSymbol mode) { + public final Object setModeSymbol(final VirtualFrame frame, final SFileDescriptor file, + final SSymbol mode) { try { file.setMode(mode); } catch (IllegalArgumentException e) { @@ -133,7 +134,8 @@ public final Object setModeSymbol(final VirtualFrame frame, final SFileDescripto } @Fallback - public final Object setWithUnsupportedValue(final VirtualFrame frame, final Object file, final Object mode) { + public final Object setWithUnsupportedValue(final VirtualFrame frame, final Object file, + final Object mode) { argumentError.signal(frame, errorMsg(mode)); return file; } @@ -217,7 +219,8 @@ public ExpressionNode initialize(final SourceSection sourceSection, } @Specialization - public final Object write(final VirtualFrame frame, final SFileDescriptor file, final long nBytes, + public final Object write(final VirtualFrame frame, final SFileDescriptor file, + final long nBytes, final long offset, final SBlock fail) { file.write(frame, (int) nBytes, offset, fail, dispatchHandler, ioException, errorCases); return file; diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index c2659d0920..38d70a066f 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -74,6 +74,7 @@ import tools.debugger.asyncstacktraces.StackIterator; import tools.debugger.frontend.ApplicationThreadStack.StackFrame; + public final class SystemPrims { /** File extension for SOMns extensions with Java code. */ @@ -147,7 +148,7 @@ public static Object loadModule(final VirtualFrame frame, final VM vm, final Str final ExceptionSignalingNode ioException) { // TODO: a single node for the different exceptions? try { - return loadModule(vm, path); + return loadModule(vm, path); } catch (FileNotFoundException e) { ioException.signal(frame, path, "Could not find module file. " + e.getMessage()); } catch (NotAFileException e) { @@ -207,7 +208,8 @@ public BinarySystemOperation initialize(final VM vm) { } @Specialization - public final Object load(final VirtualFrame frame, final String filename, final SObjectWithClass moduleObj) { + public final Object load(final VirtualFrame frame, final String filename, + final SObjectWithClass moduleObj) { String path = moduleObj.getSOMClass().getMixinDefinition().getSourceSection().getSource() .getPath(); @@ -338,22 +340,25 @@ public static void printStackTrace(final int skipDnuFrames, final SourceSection if (frame != null) { method.add(frame.name); maxLengthMethod = Math.max(maxLengthMethod, frame.name.length()); - // note: `callNode.getEncapsulatingSourceSection();` is better than frame.section - // because with this one we can get the source section while the other option returns null + // note: `callNode.getEncapsulatingSourceSection();` is better than frame.section + // because with this one we can get the source section while the other option returns + // null addSourceSection(frame.section, location); } } - //for async traces hide only 1 frame: Thing>>#error:, because we want to show the last frame although is not async - Output.print(stringStackTraceFrom(method, location, maxLengthMethod, asyncTrace == false ? skipDnuFrames : 1)); + // for async traces hide only 1 frame: Thing>>#error:, because we want to show the last + // frame although is not async + Output.print(stringStackTraceFrom(method, location, maxLengthMethod, + asyncTrace == false ? skipDnuFrames : 1)); } private static String stringStackTraceFrom(final ArrayList method, - final ArrayList location, final int maxLengthMethod, final int skipDnuFrames) { + final ArrayList location, final int maxLengthMethod, final int skipDnuFrames) { StringBuilder sb = new StringBuilder(); for (int i = method.size() - 1; i >= skipDnuFrames; i--) { sb.append(String.format("\t%1$-" + (maxLengthMethod + 4) + "s", - method.get(i))); + method.get(i))); sb.append(location.get(i)); sb.append('\n'); } @@ -361,10 +366,10 @@ private static String stringStackTraceFrom(final ArrayList method, } private static void addSourceSection(final SourceSection section, - final ArrayList location) { + final ArrayList location) { if (section != null) { location.add(section.getSource().getName() - + SourceCoordinate.getLocationQualifier(section)); + + SourceCoordinate.getLocationQualifier(section)); } else { location.add(""); } diff --git a/src/som/primitives/actors/CreateActorPrim.java b/src/som/primitives/actors/CreateActorPrim.java index 1ddbbdb273..fb0a4c7c1b 100644 --- a/src/som/primitives/actors/CreateActorPrim.java +++ b/src/som/primitives/actors/CreateActorPrim.java @@ -57,14 +57,16 @@ public final SFarReference createActor(final VirtualFrame frame, final Object re final SClass actorClass = (SClass) argument; KomposTrace.activityCreation(ActivityType.ACTOR, actor.getId(), actorClass.getName(), sourceSection); - //to keep all the created actors, this information is needed for example when pausing a running actor without specifying a breakpoint + // to keep all the created actors, this information is needed for example when pausing a + // running actor without specifying a breakpoint TracingActor.saveActor(actor); } return ref; } @Fallback - public final Object throwNotAValueException(final VirtualFrame frame, final Object receiver, final Object argument) { + public final Object throwNotAValueException(final VirtualFrame frame, final Object receiver, + final Object argument) { return notAValue.signal(frame, argument); } diff --git a/src/som/primitives/actors/PromisePrims.java b/src/som/primitives/actors/PromisePrims.java index 9ee3f0078e..1cdc1c88a0 100644 --- a/src/som/primitives/actors/PromisePrims.java +++ b/src/som/primitives/actors/PromisePrims.java @@ -109,7 +109,7 @@ public final SImmutableObject createPromisePair(final VirtualFrame frame, final if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { args = new Object[] {SPromise.pairClass, promise, resolver, null}; SArguments.setShadowStackEntryWithCache(args, this, shadowStackEntryLoad, - frame, false); + frame, false); } else { args = new Object[] {SPromise.pairClass, promise, resolver}; } @@ -176,11 +176,14 @@ public final SPromise whenResolved(final VirtualFrame frame, final SPromise prom } @Specialization(replaces = "whenResolved") - public final SPromise whenResolvedUncached(final VirtualFrame frame, final SPromise promise, final SBlock callback) { - return registerWhenResolved(frame, promise, callback, createReceived(callback), registerNode); + public final SPromise whenResolvedUncached(final VirtualFrame frame, + final SPromise promise, final SBlock callback) { + return registerWhenResolved(frame, promise, callback, createReceived(callback), + registerNode); } - protected final SPromise registerWhenResolved(final VirtualFrame frame, final SPromise rcvr, + protected final SPromise registerWhenResolved(final VirtualFrame frame, + final SPromise rcvr, final SBlock block, final RootCallTarget blockCallTarget, final RegisterWhenResolved registerNode) { assert block.getMethod().getNumberOfArguments() == 2; @@ -197,11 +200,12 @@ protected final SPromise registerWhenResolved(final VirtualFrame frame, final SP if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, pcm.getMessageId(), - rcvr.getPromiseId(), pcm.getSelector(), rcvr.getOwner().getId(), pcm.getTargetSourceSection()); + rcvr.getPromiseId(), pcm.getSelector(), rcvr.getOwner().getId(), + pcm.getTargetSourceSection()); } registerNode.register(frame, rcvr, pcm, current); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE - || pcm.getArgs()[pcm.getArgs().length - 1] != null; + || pcm.getArgs()[pcm.getArgs().length - 1] != null; return promise; } @@ -245,7 +249,8 @@ public final SPromise onError(final VirtualFrame frame, final SPromise promise, } @Specialization(replaces = "onError") - public final SPromise whenResolvedUncached(final VirtualFrame frame, final SPromise promise, final SBlock callback) { + public final SPromise whenResolvedUncached(final VirtualFrame frame, + final SPromise promise, final SBlock callback) { return registerOnError(frame, promise, callback, createReceived(callback), registerNode); } @@ -266,11 +271,12 @@ protected final SPromise registerOnError(final VirtualFrame frame, final SPromis if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, msg.getMessageId(), - rcvr.getPromiseId(), msg.getSelector(), rcvr.getOwner().getId(), msg.getTargetSourceSection()); + rcvr.getPromiseId(), msg.getSelector(), rcvr.getOwner().getId(), + msg.getTargetSourceSection()); } registerNode.register(frame, rcvr, msg, current); assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE - || msg.getArgs()[msg.getArgs().length - 1] != null; + || msg.getArgs()[msg.getArgs().length - 1] != null; return promise; } @@ -319,13 +325,16 @@ public final SPromise whenResolvedOnError(final VirtualFrame frame, final SPromi } @Specialization(replaces = "whenResolvedOnError") - public final SPromise whenResolvedOnErrorUncached(final VirtualFrame frame, final SPromise promise, + public final SPromise whenResolvedOnErrorUncached(final VirtualFrame frame, + final SPromise promise, final SBlock resolved, final SBlock error) { - return registerWhenResolvedOrError(frame, promise, resolved, error, createReceived(resolved), + return registerWhenResolvedOrError(frame, promise, resolved, error, + createReceived(resolved), createReceived(error), registerWhenResolved, registerOnError); } - protected final SPromise registerWhenResolvedOrError(final VirtualFrame frame, final SPromise rcvr, + protected final SPromise registerWhenResolvedOrError(final VirtualFrame frame, + final SPromise rcvr, final SBlock resolved, final SBlock error, final RootCallTarget resolverTarget, final RootCallTarget errorTarget, final RegisterWhenResolved registerWhenResolved, @@ -347,9 +356,11 @@ protected final SPromise registerWhenResolvedOrError(final VirtualFrame frame, f if (VmSettings.KOMPOS_TRACING) { KomposTrace.sendOperation(SendOp.PROMISE_MSG, onResolved.getMessageId(), - rcvr.getPromiseId(), onResolved.getSelector(), onResolved.getTarget().getId(), onResolved.getTargetSourceSection()); + rcvr.getPromiseId(), onResolved.getSelector(), onResolved.getTarget().getId(), + onResolved.getTargetSourceSection()); KomposTrace.sendOperation(SendOp.PROMISE_MSG, onError.getMessageId(), - rcvr.getPromiseId(), onError.getSelector(), onError.getTarget().getId(), onResolved.getTargetSourceSection()); + rcvr.getPromiseId(), onError.getSelector(), onError.getTarget().getId(), + onResolved.getTargetSourceSection()); } synchronized (rcvr) { @@ -357,9 +368,9 @@ protected final SPromise registerWhenResolvedOrError(final VirtualFrame frame, f registerOnError.register(frame, rcvr, onError, current); } assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE - || onResolved.getArgs()[onResolved.getArgs().length - 1] != null; + || onResolved.getArgs()[onResolved.getArgs().length - 1] != null; assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE - || onError.getArgs()[onError.getArgs().length - 1] != null; + || onError.getArgs()[onError.getArgs().length - 1] != null; return promise; } diff --git a/src/som/primitives/arrays/ArraySetAllStrategy.java b/src/som/primitives/arrays/ArraySetAllStrategy.java index 61df6c724f..6091a510c7 100644 --- a/src/som/primitives/arrays/ArraySetAllStrategy.java +++ b/src/som/primitives/arrays/ArraySetAllStrategy.java @@ -18,17 +18,17 @@ public final class ArraySetAllStrategy { public static void evalBlockForRemaining(final SBlock block, - final long length, final Object[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final Object[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockWithArgForRemaining(final VirtualFrame frame, - final SBlock block, final long length, final Object[] storage, - final BlockDispatchNode blockDispatch, final Object first, final IsValue isValue, - final ExceptionSignalingNode notAValue) { + final SBlock block, final long length, final Object[] storage, + final BlockDispatchNode blockDispatch, final Object first, final IsValue isValue, + final ExceptionSignalingNode notAValue) { if (!isValue.executeBoolean(frame, first)) { notAValue.signal(frame, Classes.valueArrayClass); } @@ -43,59 +43,59 @@ public static void evalBlockWithArgForRemaining(final VirtualFrame frame, } public static void evalBlockForRemaining(final SBlock block, - final long length, final long[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final long[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (long) blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockForRemaining(final SBlock block, - final long length, final double[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final double[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (double) blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockForRemaining(final SBlock block, - final long length, final boolean[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final boolean[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (boolean) blockDispatch.executeDispatch(new Object[] {block}); } } public static void evalBlockWithArgForRemaining(final SBlock block, - final long length, final long[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final long[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (long) blockDispatch.executeDispatch( - new Object[] {block, (long) i + 1}); + new Object[] {block, (long) i + 1}); } } public static void evalBlockWithArgForRemaining(final SBlock block, - final long length, final double[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final double[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (double) blockDispatch.executeDispatch( - new Object[] {block, (long) i + 1}); + new Object[] {block, (long) i + 1}); } } public static void evalBlockWithArgForRemaining(final SBlock block, - final long length, final boolean[] storage, - final BlockDispatchNode blockDispatch) { + final long length, final boolean[] storage, + final BlockDispatchNode blockDispatch) { for (int i = SArray.FIRST_IDX + 1; i < length; i++) { storage[i] = (boolean) blockDispatch.executeDispatch( - new Object[] {block, (long) i + 1}); + new Object[] {block, (long) i + 1}); } } @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final long[] storage, final int next) { + final ExpressionNode[] exprs, final long[] storage, final int next) { for (int i = next; i < exprs.length; i++) { try { storage[i] = exprs[i].executeLong(frame); @@ -113,7 +113,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final boolean[] storage, final int next) { + final ExpressionNode[] exprs, final boolean[] storage, final int next) { for (int i = next; i < exprs.length; i++) { try { storage[i] = exprs[i].executeBoolean(frame); @@ -131,7 +131,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final double[] storage, final int next) { + final ExpressionNode[] exprs, final double[] storage, final int next) { for (int i = next; i < exprs.length; i++) { try { storage[i] = exprs[i].executeDouble(frame); @@ -149,7 +149,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemaining(final VirtualFrame frame, - final ExpressionNode[] exprs, final Object[] storage, final int next) { + final ExpressionNode[] exprs, final Object[] storage, final int next) { for (int i = next; i < exprs.length; i++) { storage[i] = exprs[i].executeGeneric(frame); } @@ -158,7 +158,7 @@ public static Object evalForRemaining(final VirtualFrame frame, @ExplodeLoop public static Object evalForRemainingNils(final VirtualFrame frame, - final ExpressionNode[] exprs, final int next) { + final ExpressionNode[] exprs, final int next) { for (int i = next; i < exprs.length; i++) { Object result = exprs[i].executeGeneric(frame); if (result != Nil.nilObject) { @@ -177,8 +177,8 @@ public static Object evalForRemainingNils(final VirtualFrame frame, } public static Object evaluateFirstDetermineStorageAndEvaluateRest( - final SBlock blockNoArg, final long length, - final BlockDispatchNode blockDispatch) { + final SBlock blockNoArg, final long length, + final BlockDispatchNode blockDispatch) { // TODO: this version does not handle the case that a subsequent value is // not of the expected type... Object result = blockDispatch.executeDispatch(new Object[] {blockNoArg}); @@ -206,9 +206,9 @@ public static Object evaluateFirstDetermineStorageAndEvaluateRest( } public static Object evaluateFirstDetermineStorageAndEvaluateRest(final VirtualFrame frame, - final SBlock blockWithArg, final long length, - final BlockDispatchNode blockDispatch, final IsValue isValue, - final ExceptionSignalingNode notAValue) { + final SBlock blockWithArg, final long length, + final BlockDispatchNode blockDispatch, final IsValue isValue, + final ExceptionSignalingNode notAValue) { // TODO: this version does not handle the case that a subsequent value is // not of the expected type... Object result = blockDispatch.executeDispatch(new Object[] {blockWithArg, (long) 1}); @@ -231,14 +231,14 @@ public static Object evaluateFirstDetermineStorageAndEvaluateRest(final VirtualF } else { Object[] newStorage = new Object[(int) length]; evalBlockWithArgForRemaining(frame, blockWithArg, length, newStorage, blockDispatch, - result, - isValue, notAValue); + result, + isValue, notAValue); return newStorage; } } public static Object evaluateFirstDetermineStorageAndEvaluateRest( - final VirtualFrame frame, final ExpressionNode[] exprs) { + final VirtualFrame frame, final ExpressionNode[] exprs) { Object result = exprs[0].executeGeneric(frame); if (result == Nil.nilObject) { return evalForRemainingNils(frame, exprs, SArray.FIRST_IDX + 1); @@ -260,4 +260,4 @@ public static Object evaluateFirstDetermineStorageAndEvaluateRest( return evalForRemaining(frame, exprs, newStorage, SArray.FIRST_IDX + 1); } } -} \ No newline at end of file +} diff --git a/src/som/primitives/arrays/AtPrim.java b/src/som/primitives/arrays/AtPrim.java index a4bde7bb5e..65fa66d281 100644 --- a/src/som/primitives/arrays/AtPrim.java +++ b/src/som/primitives/arrays/AtPrim.java @@ -92,7 +92,8 @@ private Object triggerException(final VirtualFrame frame, final SArray arr, fina } @Specialization(guards = "receiver.isEmptyType()") - public final Object doEmptySArray(final VirtualFrame frame, final SArray receiver, final long idx) { + public final Object doEmptySArray(final VirtualFrame frame, final SArray receiver, + final long idx) { if (idx < 1 || idx > receiver.getEmptyStorage()) { return triggerException(frame, receiver, idx); } @@ -100,7 +101,8 @@ public final Object doEmptySArray(final VirtualFrame frame, final SArray receive } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SArray receiver, final long idx) { + public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SArray receiver, + final long idx) { try { return receiver.getPartiallyEmptyStorage().get(idx - 1); } catch (IndexOutOfBoundsException e) { @@ -109,7 +111,8 @@ public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SArra } @Specialization(guards = "receiver.isObjectType()") - public final Object doObjectSArray(final VirtualFrame frame, final SArray receiver, final long idx) { + public final Object doObjectSArray(final VirtualFrame frame, final SArray receiver, + final long idx) { try { return receiver.getObjectStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { @@ -118,7 +121,8 @@ public final Object doObjectSArray(final VirtualFrame frame, final SArray receiv } @Specialization(guards = "receiver.isLongType()") - public final long doLongSArray(final VirtualFrame frame, final SArray receiver, final long idx) { + public final long doLongSArray(final VirtualFrame frame, final SArray receiver, + final long idx) { try { return receiver.getLongStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { @@ -127,7 +131,8 @@ public final long doLongSArray(final VirtualFrame frame, final SArray receiver, } @Specialization(guards = "receiver.isDoubleType()") - public final double doDoubleSArray(final VirtualFrame frame, final SArray receiver, final long idx) { + public final double doDoubleSArray(final VirtualFrame frame, final SArray receiver, + final long idx) { try { return receiver.getDoubleStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { @@ -136,7 +141,8 @@ public final double doDoubleSArray(final VirtualFrame frame, final SArray receiv } @Specialization(guards = "receiver.isBooleanType()") - public final boolean doBooleanSArray(final VirtualFrame frame, final SArray receiver, final long idx) { + public final boolean doBooleanSArray(final VirtualFrame frame, final SArray receiver, + final long idx) { try { return receiver.getBooleanStorage()[(int) idx - 1]; } catch (IndexOutOfBoundsException e) { diff --git a/src/som/primitives/arrays/AtPutPrim.java b/src/som/primitives/arrays/AtPutPrim.java index f1f0c967ba..70795edb8a 100644 --- a/src/som/primitives/arrays/AtPutPrim.java +++ b/src/som/primitives/arrays/AtPutPrim.java @@ -31,6 +31,7 @@ import tools.dym.Tags.BasicPrimitiveOperation; import com.oracle.truffle.api.frame.VirtualFrame; + @GenerateNodeFactory @ImportStatic(Nil.class) @Primitive(primitive = "array:at:put:", selector = "at:put:", @@ -140,7 +141,8 @@ private void setAndPossiblyTransition(final SMutableArray receiver, } @Specialization(guards = {"receiver.isEmptyType()"}) - public final long doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final long doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final long value) { try { receiver.transitionFromEmptyToPartiallyEmptyWith(index - 1, value); @@ -151,7 +153,8 @@ public final long doEmptySArray(final VirtualFrame frame, final SMutableArray re } @Specialization(guards = {"receiver.isEmptyType()"}) - public final double doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final double doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final double value) { try { receiver.transitionFromEmptyToPartiallyEmptyWith(index - 1, value); @@ -162,7 +165,8 @@ public final double doEmptySArray(final VirtualFrame frame, final SMutableArray } @Specialization(guards = {"receiver.isEmptyType()"}) - public final boolean doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final boolean doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final boolean value) { try { receiver.transitionFromEmptyToPartiallyEmptyWith(index - 1, value); @@ -174,7 +178,8 @@ public final boolean doEmptySArray(final VirtualFrame frame, final SMutableArray @Specialization(guards = {"receiver.isEmptyType()", "valueIsNotNil(value)", "valueNotLongDoubleBoolean(value)"}) - public final Object doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doEmptySArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final Object value) { final int idx = (int) index - 1; int size = receiver.getEmptyStorage(); @@ -192,7 +197,8 @@ public final Object doEmptySArray(final VirtualFrame frame, final SMutableArray } @Specialization(guards = {"receiver.isEmptyType()", "valueIsNil(value)"}) - public final Object doEmptySArrayWithNil(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doEmptySArrayWithNil(final VirtualFrame frame, + final SMutableArray receiver, final long index, final Object value) { long idx = index - 1; if (idx < 0 || idx >= receiver.getEmptyStorage()) { @@ -202,7 +208,8 @@ public final Object doEmptySArrayWithNil(final VirtualFrame frame, final SMutabl } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final long doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final long doPartiallyEmptySArray(final VirtualFrame frame, + final SMutableArray receiver, final long index, final long value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.LONG); @@ -213,7 +220,8 @@ public final long doPartiallyEmptySArray(final VirtualFrame frame, final SMutabl } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final double doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final double doPartiallyEmptySArray(final VirtualFrame frame, + final SMutableArray receiver, final long index, final double value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.DOUBLE); @@ -224,7 +232,8 @@ public final double doPartiallyEmptySArray(final VirtualFrame frame, final SMuta } @Specialization(guards = "receiver.isPartiallyEmptyType()") - public final boolean doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final boolean doPartiallyEmptySArray(final VirtualFrame frame, + final SMutableArray receiver, final long index, final boolean value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.BOOLEAN); @@ -235,7 +244,8 @@ public final boolean doPartiallyEmptySArray(final VirtualFrame frame, final SMut } @Specialization(guards = {"receiver.isPartiallyEmptyType()", "valueIsNil(value)"}) - public final Object doPartiallyEmptySArrayWithNil(final VirtualFrame frame, final SMutableArray receiver, + public final Object doPartiallyEmptySArrayWithNil(final VirtualFrame frame, + final SMutableArray receiver, final long index, final Object value) { long idx = index - 1; PartiallyEmptyArray storage = receiver.getPartiallyEmptyStorage(); @@ -252,7 +262,8 @@ public final Object doPartiallyEmptySArrayWithNil(final VirtualFrame frame, fina } @Specialization(guards = {"receiver.isPartiallyEmptyType()", "valueIsNotNil(value)"}) - public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doPartiallyEmptySArray(final VirtualFrame frame, + final SMutableArray receiver, final long index, final Object value) { try { setAndPossiblyTransition(receiver, index, value, PartiallyEmptyArray.Type.OBJECT); @@ -263,7 +274,8 @@ public final Object doPartiallyEmptySArray(final VirtualFrame frame, final SMuta } @Specialization(guards = "receiver.isObjectType()") - public final Object doObjectSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doObjectSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final Object value) { try { receiver.getObjectStorage()[(int) index - 1] = value; @@ -274,7 +286,8 @@ public final Object doObjectSArray(final VirtualFrame frame, final SMutableArray } @Specialization(guards = "receiver.isLongType()") - public final long doObjectSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final long doObjectSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final long value) { try { receiver.getLongStorage()[(int) index - 1] = value; @@ -285,7 +298,8 @@ public final long doObjectSArray(final VirtualFrame frame, final SMutableArray r } @Specialization(guards = {"receiver.isLongType()", "valueIsNotLong(value)"}) - public final Object doLongSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doLongSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final Object value) { long[] storage = receiver.getLongStorage(); Object[] newStorage = new Object[storage.length]; @@ -301,7 +315,8 @@ public final Object doLongSArray(final VirtualFrame frame, final SMutableArray r } @Specialization(guards = "receiver.isDoubleType()") - public final double doDoubleSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final double doDoubleSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final double value) { try { receiver.getDoubleStorage()[(int) index - 1] = value; @@ -312,7 +327,8 @@ public final double doDoubleSArray(final VirtualFrame frame, final SMutableArray } @Specialization(guards = {"receiver.isDoubleType()", "valueIsNotDouble(value)"}) - public final Object doDoubleSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doDoubleSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final Object value) { double[] storage = receiver.getDoubleStorage(); Object[] newStorage = new Object[storage.length]; @@ -327,7 +343,8 @@ public final Object doDoubleSArray(final VirtualFrame frame, final SMutableArray } @Specialization(guards = "receiver.isBooleanType()") - public final boolean doBooleanSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final boolean doBooleanSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final boolean value) { try { receiver.getBooleanStorage()[(int) index - 1] = value; @@ -338,7 +355,8 @@ public final boolean doBooleanSArray(final VirtualFrame frame, final SMutableArr } @Specialization(guards = {"receiver.isBooleanType()", "valueIsNotBoolean(value)"}) - public final Object doBooleanSArray(final VirtualFrame frame, final SMutableArray receiver, final long index, + public final Object doBooleanSArray(final VirtualFrame frame, final SMutableArray receiver, + final long index, final Object value) { boolean[] storage = receiver.getBooleanStorage(); Object[] newStorage = new Object[storage.length]; diff --git a/src/som/primitives/arrays/CopyPrim.java b/src/som/primitives/arrays/CopyPrim.java index 3e02a2a2d3..f0146af2d8 100644 --- a/src/som/primitives/arrays/CopyPrim.java +++ b/src/som/primitives/arrays/CopyPrim.java @@ -16,16 +16,14 @@ public abstract class CopyPrim extends UnaryExpressionNode { @Specialization(guards = "receiver.isEmptyType()") public final SMutableArray doEmptyArray(final SMutableArray receiver) { assert !receiver.getSOMClass() - .isTransferObject() - : "Not yet supported, need to instantiate another class"; + .isTransferObject() : "Not yet supported, need to instantiate another class"; return new SMutableArray(receiver.getEmptyStorage(), receiver.getSOMClass()); } @Specialization(guards = "receiver.isPartiallyEmptyType()") public final SMutableArray doPartiallyEmptyArray(final SMutableArray receiver) { assert !receiver.getSOMClass() - .isTransferObject() - : "Not yet supported, need to instantiate another class"; + .isTransferObject() : "Not yet supported, need to instantiate another class"; return new SMutableArray(receiver.getPartiallyEmptyStorage().copy(), receiver.getSOMClass()); } @@ -33,8 +31,7 @@ public final SMutableArray doPartiallyEmptyArray(final SMutableArray receiver) { @Specialization(guards = "receiver.isObjectType()") public final SMutableArray doObjectArray(final SMutableArray receiver) { assert !receiver.getSOMClass() - .isTransferObject() - : "Not yet supported, need to instantiate another class"; + .isTransferObject() : "Not yet supported, need to instantiate another class"; return new SMutableArray(receiver.getObjectStorage().clone(), receiver.getSOMClass()); } @@ -42,8 +39,7 @@ public final SMutableArray doObjectArray(final SMutableArray receiver) { @Specialization(guards = "receiver.isLongType()") public final SMutableArray doLongArray(final SMutableArray receiver) { assert !receiver.getSOMClass() - .isTransferObject() - : "Not yet supported, need to instantiate another class"; + .isTransferObject() : "Not yet supported, need to instantiate another class"; return new SMutableArray(receiver.getLongStorage().clone(), receiver.getSOMClass()); } @@ -51,8 +47,7 @@ public final SMutableArray doLongArray(final SMutableArray receiver) { @Specialization(guards = "receiver.isDoubleType()") public final SMutableArray doDoubleArray(final SMutableArray receiver) { assert !receiver.getSOMClass() - .isTransferObject() - : "Not yet supported, need to instantiate another class"; + .isTransferObject() : "Not yet supported, need to instantiate another class"; return new SMutableArray(receiver.getDoubleStorage().clone(), receiver.getSOMClass()); } @@ -60,8 +55,7 @@ public final SMutableArray doDoubleArray(final SMutableArray receiver) { @Specialization(guards = "receiver.isBooleanType()") public final SMutableArray doBooleanArray(final SMutableArray receiver) { assert !receiver.getSOMClass() - .isTransferObject() - : "Not yet supported, need to instantiate another class"; + .isTransferObject() : "Not yet supported, need to instantiate another class"; return new SMutableArray(receiver.getBooleanStorage().clone(), receiver.getSOMClass()); } diff --git a/src/som/primitives/arrays/DoIndexesPrim.java b/src/som/primitives/arrays/DoIndexesPrim.java index 4d0b993888..8763a470df 100644 --- a/src/som/primitives/arrays/DoIndexesPrim.java +++ b/src/som/primitives/arrays/DoIndexesPrim.java @@ -23,8 +23,8 @@ @GenerateNodeFactory @Primitive(selector = "doIndexes:", receiverType = SArray.class, disabled = true) public abstract class DoIndexesPrim extends BinaryComplexOperation { - @Child protected BlockDispatchNode block = BlockDispatchNodeGen.create(); - @Child protected UnaryExpressionNode length; + @Child protected BlockDispatchNode block = BlockDispatchNodeGen.create(); + @Child protected UnaryExpressionNode length; @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); // TODO: tag properly, this is a loop, but without array access @@ -53,11 +53,15 @@ private void loop(final VirtualFrame frame, final SBlock block, final int length if (SArray.FIRST_IDX < length) { this.block.executeDispatch(SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, block, (long) SArray.FIRST_IDX + 1)); // +1 because it is going to the smalltalk level + shadowStackEntryLoad, frame, block, (long) SArray.FIRST_IDX + 1)); // +1 because it + // is going to + // the smalltalk + // level } for (long i = 1; i < length; i++) { this.block.executeDispatch(SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, block, i + 1)); // +1 because it is going to the smalltalk level + shadowStackEntryLoad, frame, block, i + 1)); // +1 because it is going to the + // smalltalk level } } finally { if (CompilerDirectives.inInterpreter()) { diff --git a/src/som/primitives/arrays/DoPrim.java b/src/som/primitives/arrays/DoPrim.java index 6f10efadcb..33cabf0e24 100644 --- a/src/som/primitives/arrays/DoPrim.java +++ b/src/som/primitives/arrays/DoPrim.java @@ -22,18 +22,19 @@ @GenerateNodeFactory @Primitive(selector = "do:", receiverType = SArray.class, disabled = true) public abstract class DoPrim extends BinaryComplexOperation { - @Child private BlockDispatchNode block = BlockDispatchNodeGen.create(); + @Child private BlockDispatchNode block = BlockDispatchNodeGen.create(); @Child protected ShadowStackEntryLoad shadowStackEntryLoad = ShadowStackEntryLoad.create(); // TODO: tag properly, it is a loop and an access private void execBlock(final VirtualFrame frame, final SBlock block, final Object arg) { this.block.executeDispatch(SArguments.getPlainXArgumentsWithReceiver(this, - shadowStackEntryLoad, frame, block, arg)); + shadowStackEntryLoad, frame, block, arg)); } @Specialization(guards = "arr.isEmptyType()") - public final SArray doEmptyArray(final VirtualFrame frame, final SArray arr, final SBlock block) { + public final SArray doEmptyArray(final VirtualFrame frame, final SArray arr, + final SBlock block) { int length = arr.getEmptyStorage(); try { if (SArray.FIRST_IDX < length) { @@ -51,7 +52,8 @@ public final SArray doEmptyArray(final VirtualFrame frame, final SArray arr, fin } @Specialization(guards = "arr.isPartiallyEmptyType()") - public final SArray doPartiallyEmptyArray(final VirtualFrame frame, final SArray arr, final SBlock block) { + public final SArray doPartiallyEmptyArray(final VirtualFrame frame, final SArray arr, + final SBlock block) { PartiallyEmptyArray storage = arr.getPartiallyEmptyStorage(); int length = storage.getLength(); try { @@ -70,7 +72,8 @@ public final SArray doPartiallyEmptyArray(final VirtualFrame frame, final SArray } @Specialization(guards = "arr.isObjectType()") - public final SArray doObjectArray(final VirtualFrame frame, final SArray arr, final SBlock block) { + public final SArray doObjectArray(final VirtualFrame frame, final SArray arr, + final SBlock block) { Object[] storage = arr.getObjectStorage(); int length = storage.length; try { @@ -89,7 +92,8 @@ public final SArray doObjectArray(final VirtualFrame frame, final SArray arr, fi } @Specialization(guards = "arr.isLongType()") - public final SArray doLongArray(final VirtualFrame frame, final SArray arr, final SBlock block) { + public final SArray doLongArray(final VirtualFrame frame, final SArray arr, + final SBlock block) { long[] storage = arr.getLongStorage(); int length = storage.length; try { @@ -108,7 +112,8 @@ public final SArray doLongArray(final VirtualFrame frame, final SArray arr, fina } @Specialization(guards = "arr.isDoubleType()") - public final SArray doDoubleArray(final VirtualFrame frame, final SArray arr, final SBlock block) { + public final SArray doDoubleArray(final VirtualFrame frame, final SArray arr, + final SBlock block) { double[] storage = arr.getDoubleStorage(); int length = storage.length; try { @@ -127,7 +132,8 @@ public final SArray doDoubleArray(final VirtualFrame frame, final SArray arr, fi } @Specialization(guards = "arr.isBooleanType()") - public final SArray doBooleanArray(final VirtualFrame frame, final SArray arr, final SBlock block) { + public final SArray doBooleanArray(final VirtualFrame frame, final SArray arr, + final SBlock block) { boolean[] storage = arr.getBooleanStorage(); int length = storage.length; try { diff --git a/src/som/primitives/threading/TaskThreads.java b/src/som/primitives/threading/TaskThreads.java index af4e859c83..3b01ca2b94 100644 --- a/src/som/primitives/threading/TaskThreads.java +++ b/src/som/primitives/threading/TaskThreads.java @@ -39,8 +39,7 @@ public abstract static class SomTaskOrThread extends RecursiveTask public SomTaskOrThread(final Object[] argArray, final boolean stopOnRoot) { this.argArray = argArray; this.stopOnRoot = stopOnRoot; - assert argArray[0] instanceof SBlock - : "First argument of a block needs to be the block object"; + assert argArray[0] instanceof SBlock : "First argument of a block needs to be the block object"; } public final SInvokable getMethod() { diff --git a/src/som/vm/ExtensionLoader.java b/src/som/vm/ExtensionLoader.java index d493110210..78e23aea5b 100644 --- a/src/som/vm/ExtensionLoader.java +++ b/src/som/vm/ExtensionLoader.java @@ -110,8 +110,7 @@ protected void registerPrimitive( private SInvokable constructPrimitive(final SSymbol signature, final Specializer specializer, final SomLanguage lang) { CompilerAsserts.neverPartOfCompilation("This is only executed during bootstrapping."); - assert signature.getNumberOfSignatureArguments() >= 1 - : "Primitives should have at least a receiver"; + assert signature.getNumberOfSignatureArguments() >= 1 : "Primitives should have at least a receiver"; // ignore the implicit vmMirror argument final int numArgs = signature.getNumberOfSignatureArguments(); diff --git a/src/som/vm/ObjectSystem.java b/src/som/vm/ObjectSystem.java index 9e52011b9d..cf5e7aa771 100644 --- a/src/som/vm/ObjectSystem.java +++ b/src/som/vm/ObjectSystem.java @@ -419,7 +419,8 @@ public SObjectWithoutFields initialize() { setDummyClassFactory(Classes.methodClass, SInvokableSerializationNodeFactory.getInstance()); - SClass kernelClass = kernelModule.instantiateClass(null, Nil.nilObject, Classes.objectClass); + SClass kernelClass = + kernelModule.instantiateClass(null, Nil.nilObject, Classes.objectClass); KernelObj.kernel.setClass(kernelClass); // create and initialize the vmMirror object @@ -531,7 +532,7 @@ public int executeApplication(final SObjectWithoutFields vmMirror, final Actor m Object platform; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { platform = platformModule.instantiateObject(platformClass, vmMirror, - SArguments.instantiateTopShadowStackEntry(null)); + SArguments.instantiateTopShadowStackEntry(null)); } else { platform = platformModule.instantiateObject(platformClass, vmMirror); } diff --git a/src/som/vm/Primitives.java b/src/som/vm/Primitives.java index 20f475b352..72f6c0fdff 100644 --- a/src/som/vm/Primitives.java +++ b/src/som/vm/Primitives.java @@ -125,9 +125,8 @@ public Primitives(final SomLanguage lang) { private static SInvokable constructVmMirrorPrimitive(final SSymbol signature, final Specializer specializer, final SomLanguage lang) { CompilerAsserts.neverPartOfCompilation("This is only executed during bootstrapping."); - assert signature.getNumberOfSignatureArguments() > 1 - : "Primitives should have the vmMirror as receiver, " - + "and then at least one object they are applied to"; + assert signature.getNumberOfSignatureArguments() > 1 : "Primitives should have the vmMirror as receiver, " + + "and then at least one object they are applied to"; // ignore the implicit vmMirror argument final int numArgs = signature.getNumberOfSignatureArguments() - 1; diff --git a/src/som/vm/VmSettings.java b/src/som/vm/VmSettings.java index ea2b43664e..840099c5cf 100644 --- a/src/som/vm/VmSettings.java +++ b/src/som/vm/VmSettings.java @@ -86,10 +86,10 @@ public class VmSettings implements Settings { ACTOR_ASYNC_STACK_TRACE_STRUCTURE = getBool("som.actorAsyncStackTraceStructure", false); ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE = - getBool("som.actorAsyncStackTraceMethodCache", false); + getBool("som.actorAsyncStackTraceMethodCache", false); ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE = - getBool("som.actorAsyncStackTraceInlineCache", false); - + getBool("som.actorAsyncStackTraceInlineCache", false); + TEST_SNAPSHOTS = getBool("som.snapshotTest", false); TEST_SERIALIZE_ALL = getBool("som.actorSnapshotAll", false); SNAPSHOTS_ENABLED = getBool("som.actorSnapshot", false) || TEST_SNAPSHOTS; diff --git a/src/som/vmobjects/SClass.java b/src/som/vmobjects/SClass.java index 787209c6ff..fa2e3c4b0d 100644 --- a/src/som/vmobjects/SClass.java +++ b/src/som/vmobjects/SClass.java @@ -328,8 +328,7 @@ public Dispatchable lookupPrivate(final SSymbol selector, */ public Dispatchable lookupMessage(final SSymbol selector, final AccessModifier hasAtLeast) { - assert hasAtLeast.ordinal() >= AccessModifier.PROTECTED.ordinal() - : "Access modifier should be protected or public"; + assert hasAtLeast.ordinal() >= AccessModifier.PROTECTED.ordinal() : "Access modifier should be protected or public"; VM.callerNeedsToBeOptimized("should never be called on fast path"); Dispatchable disp = dispatchables.get(selector); diff --git a/src/som/vmobjects/SFileDescriptor.java b/src/som/vmobjects/SFileDescriptor.java index f939c630a5..3ecfe5b0ff 100644 --- a/src/som/vmobjects/SFileDescriptor.java +++ b/src/som/vmobjects/SFileDescriptor.java @@ -134,8 +134,8 @@ private String toString(final IOException e) { } public void write(final VirtualFrame frame, final int nBytes, final long position, - final SBlock fail, final BlockDispatchNode dispatchHandler, - final ExceptionSignalingNode ioException, final BranchProfile errorCases) { + final SBlock fail, final BlockDispatchNode dispatchHandler, + final ExceptionSignalingNode ioException, final BranchProfile errorCases) { if (raf == null) { errorCases.enter(); dispatchHandler.executeDispatch(new Object[] {fail, FILE_IS_CLOSED}); @@ -175,7 +175,7 @@ private static String errorMsg(final long val) { @TruffleBoundary private void write(final int nBytes, final long position, final byte[] buff) - throws IOException { + throws IOException { raf.seek(position); raf.write(buff, 0, nBytes); } @@ -255,4 +255,4 @@ private static String renderValid() { return result; } } -} \ No newline at end of file +} diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 80e91821c9..303648f531 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -23,28 +23,29 @@ public class KomposTrace { private static Map> messagesReceivedByActor = new HashMap<>(); -// private static Map> buffersByActor = new HashMap<>(); -// public static boolean missingBuffers(long actorSuspendedId) { -// List buffers = buffersByActor.get(actorSuspendedId); -// Collections.sort(buffers); -// -// for (int i = 1; i < buffers.size(); i++) { -// int previous = buffers.get(i - 1); -// int current = buffers.get(i); -// if (current != (previous + 1)) { -// return true; -// } -// } -// -// return false; -// } + // private static Map> buffersByActor = new HashMap<>(); + // public static boolean missingBuffers(long actorSuspendedId) { + // List buffers = buffersByActor.get(actorSuspendedId); + // Collections.sort(buffers); + // + // for (int i = 1; i < buffers.size(); i++) { + // int previous = buffers.get(i - 1); + // int current = buffers.get(i); + // if (current != (previous + 1)) { + // return true; + // } + // } + // + // return false; + // } public static void recordMainActor(final Actor mainActor, final ObjectSystem objectSystem) { KomposTraceBuffer buffer = KomposTraceBuffer.create(0); buffer.recordCurrentActivity(mainActor); buffer.recordMainActor(mainActor, objectSystem); - buffer.recordSendOperation(SendOp.ACTOR_MSG, 0, mainActor.getId(), mainActor, (short) 0, 0, null, null); + buffer.recordSendOperation(SendOp.ACTOR_MSG, 0, mainActor.getId(), mainActor, (short) 0, 0, + null, null); buffer.returnBuffer(null); } @@ -128,12 +129,14 @@ public static void promiseError(final long promiseId, final Object value) { public static void promiseChained(final long promiseValueId, final long promiseId) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation( - SendOp.PROMISE_RESOLUTION, promiseValueId, promiseId, t.getActivity(), (short) 0, 0, null, null); + SendOp.PROMISE_RESOLUTION, promiseValueId, promiseId, t.getActivity(), (short) 0, 0, + null, null); t.resolvedPromises++; } public static void sendOperation(final SendOp op, final long entityId, - final long targetId, final SSymbol selector, long targetActorId, SourceSection msgSourceCoordinate) { + final long targetId, final SSymbol selector, long targetActorId, + SourceSection msgSourceCoordinate) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(op, entityId, targetId, t.getActivity(), selector.getSymbolId(), targetActorId, msgSourceCoordinate, null); @@ -162,21 +165,25 @@ public static void recordSuspendedActivityByDebugger(TracingActivityThread t) { } public static void actorMessageReception(long messageId, TracingActivityThread t) { -// System.out.println("***** "+((Actor.ActorProcessingThread)t).getCurrentActor() +" activity "+((Actor.ActorProcessingThread)t).getActivity()); + // System.out.println("***** "+((Actor.ActorProcessingThread)t).getCurrentActor() +" + // activity "+((Actor.ActorProcessingThread)t).getActivity()); Activity activity = t.getActivity(); if (activity == null) { activity = ((Actor.ActorProcessingThread) t).getCurrentActor(); } if (!messageReceivedRecorded(messageId, activity.getId())) { - ((KomposTraceBuffer) t.getBuffer()).recordMessageReceived(MessageReception.MESSAGE_RCV, activity, messageId); + ((KomposTraceBuffer) t.getBuffer()).recordMessageReceived(MessageReception.MESSAGE_RCV, + activity, messageId); } } /** * Check the message has not been saved before. - * Messages received can be repeated because we record them at the point where the message is sent and when the messages are processed. - * This is needed because at the point where the message is append in the mailbox the TracingActivityThread may not be available, + * Messages received can be repeated because we record them at the point where the message is + * sent and when the messages are processed. + * This is needed because at the point where the message is append in the mailbox the + * TracingActivityThread may not be available, * they become available when the actor is about to process the messages. * * @param messageId @@ -193,7 +200,7 @@ private static boolean messageReceivedRecorded(long messageId, long actorId) { if (messages.contains(messageId)) { return true; - } else { //new message + } else { // new message messages.add(messageId); messagesReceivedByActor.put(actorId, messages); } @@ -303,14 +310,14 @@ public synchronized void recordCurrentActivity(final Activity current) { putLong(actorId); putInt(bufferId); -// List bufferList; -// if (buffersByActor.containsKey(actorId)) { -// bufferList = buffersByActor.get(actorId); -// } else { -// bufferList = new ArrayList<>(); -// } -// bufferList.add(bufferId); -// buffersByActor.put(actorId, bufferList); + // List bufferList; + // if (buffersByActor.containsKey(actorId)) { + // bufferList = buffersByActor.get(actorId); + // } else { + // bufferList = new ArrayList<>(); + // } + // bufferList.add(bufferId); + // buffersByActor.put(actorId, bufferList); assert position == start + Implementation.IMPL_CURRENT_ACTIVITY.getSize(); } @@ -329,8 +336,7 @@ private void writeSourceSection(final SourceSection origin) { } assert !origin.getSource() - .isInternal() - : "Need special handling to ensure we see user code reported to trace/debugger"; + .isInternal() : "Need special handling to ensure we see user code reported to trace/debugger"; putShort(Symbols.symbolFor(SourceCoordinate.getURI(origin.getSource())).getSymbolId()); putShort((short) origin.getStartLine()); putShort((short) origin.getStartColumn()); @@ -415,7 +421,8 @@ public void recordReceiveOperation(final ReceiveOp op, final long sourceId, } public void recordSendOperation(final SendOp op, final long entityId, - final long targetId, final Activity current, final short symbolId, long targetActorId, SourceSection msgSourceCoordinate, byte[] value) { + final long targetId, final Activity current, final short symbolId, long targetActorId, + SourceSection msgSourceCoordinate, byte[] value) { int requiredSpace; if (value == null) { requiredSpace = op.getSize(); @@ -433,10 +440,10 @@ public void recordSendOperation(final SendOp op, final long entityId, putShort(symbolId); if (VmSettings.KOMPOS_TRACING) { - writeSourceSection(msgSourceCoordinate); + writeSourceSection(msgSourceCoordinate); } - if(value != null) { + if (value != null) { putInt(value.length); for (byte b : value) { put(b); @@ -446,7 +453,8 @@ public void recordSendOperation(final SendOp op, final long entityId, assert position == start + requiredSpace; } - public void recordMessageReceived(MessageReception mr, final Activity current, final long messageId) { + public void recordMessageReceived(MessageReception mr, final Activity current, + final long messageId) { int requiredSpace = mr.getSize(); ensureSufficientSpace(requiredSpace, current); @@ -454,9 +462,9 @@ public void recordMessageReceived(MessageReception mr, final Activity current, f put(mr.getId()); putLong(messageId); -// System.out.println("-message received "+messageId +" actor "+current.getId()); + // System.out.println("-message received "+messageId +" actor "+current.getId()); - if (position != start + requiredSpace ) { + if (position != start + requiredSpace) { System.out.println(); } @@ -508,12 +516,15 @@ public synchronized void recordReceiveOperation(final ReceiveOp op, @Override public synchronized void recordSendOperation(final SendOp op, - final long entityId, final long targetId, final Activity current, final short symbol, final long targetActorId, final SourceSection section, byte[] value) { - super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, section, value); + final long entityId, final long targetId, final Activity current, final short symbol, + final long targetActorId, final SourceSection section, byte[] value) { + super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, + section, value); } @Override - public synchronized void recordMessageReceived(MessageReception mr, final Activity current, final long messageId) { + public synchronized void recordMessageReceived(MessageReception mr, + final Activity current, final long messageId) { super.recordMessageReceived(mr, current, messageId); } } diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index fc5b97fa8e..3a9bd281b5 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -50,7 +50,7 @@ public TracingActor(final VM vm) { if (VmSettings.SNAPSHOTS_ENABLED) { snapshotRecord = new SnapshotRecord(); } - if(VmSettings.TRUFFLE_DEBUGGER_ENABLED) { + if (VmSettings.TRUFFLE_DEBUGGER_ENABLED) { debugger = vm.getWebDebugger(); } } @@ -61,9 +61,11 @@ protected TracingActor(final VM vm, final long id) { } public static void saveMessageReceived(Actor actor, EventualMessage message) { - TracingActivityThread tracingActivityThread = TracingBackend.getTracingActivityThread(actor.getId()); + TracingActivityThread tracingActivityThread = + TracingBackend.getTracingActivityThread(actor.getId()); if (tracingActivityThread != null) { -// System.out.println("saveMessageReceived "+message.getMessageId() + " "+actor.getId()); + // System.out.println("saveMessageReceived "+message.getMessageId() + " + // "+actor.getId()); KomposTrace.actorMessageReception(message.getMessageId(), tracingActivityThread); } } @@ -168,10 +170,11 @@ public static Actor getActorById(long actorId) { * Stop actor execution if they are paused to avoid open threads before system shutdown */ public static void stopActorsIfSuspended() { - for (long actorId: allActors.keySet()) { - if (actorId > 0) { //do not stop Platform actor + for (long actorId : allActors.keySet()) { + if (actorId > 0) { // do not stop Platform actor Suspension suspension = debugger.getSuspension(actorId); - if (suspension != null && suspension.getEvent() != null && !suspension.getEvent().isDisposed()) { + if (suspension != null && suspension.getEvent() != null + && !suspension.getEvent().isDisposed()) { suspension.getEvent().prepareKill(); suspension.resume(); } @@ -387,8 +390,7 @@ private Queue determineNextMessagesSenderSide( } assert toProcess.size() - + orderedMessages.size() == numReceivedMsgs - : "We shouldn't lose any messages here."; + + orderedMessages.size() == numReceivedMsgs : "We shouldn't lose any messages here."; return toProcess; } diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index 9e63db7a20..65d8b9bbcd 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -251,7 +251,8 @@ public static TracingActivityThread getTracingActivityThread(long actorId) { TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); for (TracingActivityThread tracingActivityThread : result) { if ((tracingActivityThread instanceof ActorProcessingThread)) { - Actor currentActor = ((ActorProcessingThread) tracingActivityThread).getCurrentActor(); + Actor currentActor = + ((ActorProcessingThread) tracingActivityThread).getCurrentActor(); if (currentActor != null && currentActor.getId() == actorId) { return tracingActivityThread; } diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index dd426dcfe2..8035aa4bab 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -287,13 +287,14 @@ public void sendTracingData() { } public void sendTracingData(final ByteBuffer buffer) { -// log("[DEBUGGER] Trace buffers sent: "+buffer); + // log("[DEBUGGER] Trace buffers sent: "+buffer); traceSocket.send(buffer); } public void sendProgramInfo() { - //when the server has really started, i.e. the client has connected, then do the send - messageSocketInitialized.thenRun(() -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); + // when the server has really started, i.e. the client has connected, then do the send + messageSocketInitialized.thenRun( + () -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); } public void sendPauseActorResponse(long pausedActorId) { @@ -331,17 +332,18 @@ public void completeConnection(final WebSocket conn) { clientConnected.complete(conn); - //when the server has really started, i.e. the client has connected, then do the send + // when the server has really started, i.e. the client has connected, then do the send messageSocketInitialized.thenRun(() -> sendInitResponse()); } private void sendInitResponse() { -// log("[DEBUGGER] Message socket initialized "+messageSocketInitialized.isDone()); + // log("[DEBUGGER] Message socket initialized "+messageSocketInitialized.isDone()); send(InitializationResponse.create(EntityType.values(), - ActivityType.values(), PassiveEntityType.values(), - DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), - BreakpointType.values(), SteppingType.values(), Implementation.values(), MessageReception.values())); + ActivityType.values(), PassiveEntityType.values(), + DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), + BreakpointType.values(), SteppingType.values(), Implementation.values(), + MessageReception.values())); } private void closeAllSockets() { diff --git a/src/tools/debugger/WebSocketHandler.java b/src/tools/debugger/WebSocketHandler.java index 797cfdd95e..a111137836 100644 --- a/src/tools/debugger/WebSocketHandler.java +++ b/src/tools/debugger/WebSocketHandler.java @@ -34,7 +34,8 @@ public int awaitStartup() throws ExecutionException { while (true) { try { return connectionPort.get(); - } catch (InterruptedException e) { /* Retry on interrupt. */ } + } catch (InterruptedException e) { + /* Retry on interrupt. */ } } } @@ -65,7 +66,7 @@ public MessageHandler(final int port, final FrontendConnector connector, final Gson gson) { super(port); this.setReuseAddr(true); -// this.setConnectionLostTimeout(0); //uncomment if timeout fails + // this.setConnectionLostTimeout(0); //uncomment if timeout fails this.connector = connector; this.gson = gson; } @@ -89,7 +90,7 @@ public static class TraceHandler extends WebSocketHandler { public TraceHandler(final int port) { super(port); this.setReuseAddr(true); -// this.setConnectionLostTimeout(0); //uncomment if timeout fails + // this.setConnectionLostTimeout(0); //uncomment if timeout fails connection = new CompletableFuture<>(); } diff --git a/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java index 82bfb9e4bb..8f8fdab000 100644 --- a/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java @@ -9,128 +9,131 @@ import som.interpreter.actors.EventualMessage; import som.vm.VmSettings; -public class ShadowStackEntry { - - protected ShadowStackEntry previous; - protected final Node expression; - protected final long actorId; - - public static long numberOfAllocations; - public static final boolean ALLOCATION_COUNT = false; +public class ShadowStackEntry { - public Node getExpression() { - return expression; + protected ShadowStackEntry previous; + protected final Node expression; + protected final long actorId; + + public static long numberOfAllocations; + + public static final boolean ALLOCATION_COUNT = false; + + public Node getExpression() { + return expression; + } + + public ShadowStackEntry getPreviousShadowStackEntry() { + return previous; + } + + public static ShadowStackEntry createTop(final Node expr) { + return new ShadowStackEntry(null, expr); + } + + public static ShadowStackEntry create(final ShadowStackEntry previous, + final Node expr) { + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; + return new ShadowStackEntry(previous, unwrapNodeIfNecessary(expr)); + } + + public static ShadowStackEntry createAtAsyncSend(final ShadowStackEntry previous, + final Node expr) { + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; + return new EntryAtMessageSend(previous, unwrapNodeIfNecessary(expr)); + } + + public static ShadowStackEntry createAtPromiseResolution(final ShadowStackEntry previous, + final Node expr, final EntryForPromiseResolution.ResolutionLocation resolutionType, + final String resolutionValue) { + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; + return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr), resolutionType, + resolutionValue); + } + + public static Node unwrapNodeIfNecessary(final Node node) { + if (node instanceof WrapperNode) { + return ((WrapperNode) node).getDelegateNode(); + } else { + return node; } - - public ShadowStackEntry getPreviousShadowStackEntry() { - return previous; + } + + protected ShadowStackEntry(final ShadowStackEntry previous, final Node expr) { + assert VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; + this.previous = previous; + this.expression = expr; + if (ALLOCATION_COUNT) { + numberOfAllocations++; } - - public static ShadowStackEntry createTop(final Node expr) { - return new ShadowStackEntry(null, expr); + this.actorId = getCurrentActor(); + } + + public long getCurrentActor() { + Thread t = Thread.currentThread(); + if (t instanceof ActorProcessingThread) { + return EventualMessage.getActorCurrentMessageIsExecutionOn().getId(); + } else { + return -1l; } + } - public static ShadowStackEntry create(final ShadowStackEntry previous, - final Node expr) { - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; - return new ShadowStackEntry(previous, unwrapNodeIfNecessary(expr)); - } + public RootNode getRootNode() { + return expression.getRootNode(); + } - public static ShadowStackEntry createAtAsyncSend(final ShadowStackEntry previous, - final Node expr) { - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; - return new EntryAtMessageSend(previous, unwrapNodeIfNecessary(expr)); - } + public SourceSection getSourceSection() { + return expression.getSourceSection(); + } - public static ShadowStackEntry createAtPromiseResolution(final ShadowStackEntry previous, - final Node expr, final EntryForPromiseResolution.ResolutionLocation resolutionType, final String resolutionValue) { - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || previous != null; - return new EntryForPromiseResolution(previous, unwrapNodeIfNecessary(expr), resolutionType, resolutionValue); - } + public boolean isAsync() { + return false; + } - public static Node unwrapNodeIfNecessary(final Node node) { - if (node instanceof WrapperNode) { - return ((WrapperNode) node).getDelegateNode(); - } else { - return node; - } - } + public void setPreviousShadowStackEntry(ShadowStackEntry maybeEntry) { + previous = maybeEntry; + } - protected ShadowStackEntry(final ShadowStackEntry previous, final Node expr) { - assert VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE; - this.previous = previous; - this.expression = expr; - if (ALLOCATION_COUNT) { - numberOfAllocations++; - } - this.actorId = getCurrentActor(); - } + public static final class EntryAtMessageSend extends ShadowStackEntry { - public long getCurrentActor() { - Thread t = Thread.currentThread(); - if (t instanceof ActorProcessingThread) { - return EventualMessage.getActorCurrentMessageIsExecutionOn().getId(); - } else { - return -1l; - } + private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { + super(previous, expr); } + } - public RootNode getRootNode() { - return expression.getRootNode(); - } + public static final class EntryForPromiseResolution extends ShadowStackEntry { + public enum ResolutionLocation { + SUCCESSFUL("resolved with a value"), ERROR("resolved with an error"), + CHAINED("resolved with a promise"), ON_WHEN_RESOLVED_BLOCK("on whenResolved block"), + ON_WHEN_RESOLVED("on whenResolved"), ON_WHEN_RESOLVED_ERROR("on whenResolved error"), + ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE("on schedule"); - public SourceSection getSourceSection() { - return expression.getSourceSection(); - } + private final String label; - public boolean isAsync() { - return false; - } + ResolutionLocation(String label) { + this.label = label; + } - public void setPreviousShadowStackEntry(ShadowStackEntry maybeEntry) { - previous = maybeEntry; + public String getValue() { + return label; + } } - public static final class EntryAtMessageSend extends ShadowStackEntry { + public ResolutionLocation resolutionLocation; + public String resolutionValue; - private EntryAtMessageSend(final ShadowStackEntry previous, final Node expr) { - super(previous, expr); - } + private EntryForPromiseResolution(final ShadowStackEntry previous, + final Node expr, ResolutionLocation resolutionLocation, String resolutionValue) { + super(previous, expr); + this.resolutionLocation = resolutionLocation; + this.resolutionValue = resolutionValue; } - public static final class EntryForPromiseResolution extends ShadowStackEntry { - public enum ResolutionLocation { - SUCCESSFUL("resolved with a value"), ERROR("resolved with an error"), - CHAINED("resolved with a promise"), ON_WHEN_RESOLVED_BLOCK("on whenResolved block"), - ON_WHEN_RESOLVED("on whenResolved"), ON_WHEN_RESOLVED_ERROR("on whenResolved error"), - ON_RECEIVE_MESSAGE("on receive message"), ON_SCHEDULE_PROMISE("on schedule"); - - private final String label; - - ResolutionLocation(String label) { - this.label = label; - } - - public String getValue() { - return label; - } - } - - public ResolutionLocation resolutionLocation; - public String resolutionValue; - - private EntryForPromiseResolution(final ShadowStackEntry previous, - final Node expr, ResolutionLocation resolutionLocation, String resolutionValue) { - super(previous, expr); - this.resolutionLocation = resolutionLocation; - this.resolutionValue = resolutionValue; - } - - @Override - public boolean isAsync() { - return true; - } - + @Override + public boolean isAsync() { + return true; } + + } } diff --git a/src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java b/src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java index dc60a97756..7621d8b72a 100644 --- a/src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java +++ b/src/tools/debugger/asyncstacktraces/ShadowStackEntryLoad.java @@ -7,130 +7,131 @@ import som.interpreter.SArguments; import som.vm.VmSettings; -public abstract class ShadowStackEntryLoad extends Node { - public static final int NUM_SHADOW_STACK_ENTRIES = 6; - - public static final boolean ANALYSIS = false; - public static int cacheHit = 0; - public static int megaCacheHit = 0; - public static int megaMiss = 0; - @CompilerDirectives.TruffleBoundary - public static ShadowStackEntryLoad create() { - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - return new UninitializedShadowStackEntryLoad(); - } else { - return null; - } +public abstract class ShadowStackEntryLoad extends Node { + public static final int NUM_SHADOW_STACK_ENTRIES = 6; + + public static final boolean ANALYSIS = false; + public static int cacheHit = 0; + public static int megaCacheHit = 0; + public static int megaMiss = 0; + + @CompilerDirectives.TruffleBoundary + public static ShadowStackEntryLoad create() { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new UninitializedShadowStackEntryLoad(); + } else { + return null; } + } - public void loadShadowStackEntry(final Object[] arguments, final Node expression, - final VirtualFrame frame, final boolean async) { - ShadowStackEntry prevEntry = SArguments.getShadowStackEntry(frame); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || prevEntry != null; - loadShadowStackEntry(arguments, expression, prevEntry, this, async); - } + public void loadShadowStackEntry(final Object[] arguments, final Node expression, + final VirtualFrame frame, final boolean async) { + ShadowStackEntry prevEntry = SArguments.getShadowStackEntry(frame); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || prevEntry != null; + loadShadowStackEntry(arguments, expression, prevEntry, this, async); + } - protected abstract void loadShadowStackEntry(Object[] arguments, - Node expression, - ShadowStackEntry prevEntry, - ShadowStackEntryLoad firstShadowStackEntryLoad, - boolean async); + protected abstract void loadShadowStackEntry(Object[] arguments, + Node expression, + ShadowStackEntry prevEntry, + ShadowStackEntryLoad firstShadowStackEntryLoad, + boolean async); - public abstract int getCurrentCacheSize(); + public abstract int getCurrentCacheSize(); - protected void setShadowStackEntry(final ShadowStackEntry shadowStackEntry, - final Object[] arguments) { - SArguments.setShadowStackEntry(arguments, shadowStackEntry); - } + protected void setShadowStackEntry(final ShadowStackEntry shadowStackEntry, + final Object[] arguments) { + SArguments.setShadowStackEntry(arguments, shadowStackEntry); + } - private static final class UninitializedShadowStackEntryLoad extends ShadowStackEntryLoad { - - @CompilerDirectives.TruffleBoundary - @Override - protected void loadShadowStackEntry(final Object[] arguments, - final Node expression, - final ShadowStackEntry prevEntry, - final ShadowStackEntryLoad firstShadowStackEntryLoad, - final boolean async) { - if (!VmSettings.ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE) { - setShadowStackEntry( - SArguments.instantiateShadowStackEntry(prevEntry, expression, async), - arguments); - return; - } - ShadowStackEntry newEntry = - SArguments.instantiateShadowStackEntry(prevEntry, expression, async); - ShadowStackEntryLoad newLoad; - if (firstShadowStackEntryLoad.getCurrentCacheSize() > NUM_SHADOW_STACK_ENTRIES) { - newLoad = new GenericShadowStackEntryLoad(); - // firstShadowStackEntryLoad.replace(newLoad); - replace(newLoad); - } else { - newLoad = new CachedShadowStackEntryLoad(prevEntry, newEntry); - replace(newLoad); - } - newLoad.loadShadowStackEntry(arguments, expression, prevEntry, - firstShadowStackEntryLoad, async); - } + private static final class UninitializedShadowStackEntryLoad extends ShadowStackEntryLoad { - @Override - public int getCurrentCacheSize() { - return 0; - } + @CompilerDirectives.TruffleBoundary + @Override + protected void loadShadowStackEntry(final Object[] arguments, + final Node expression, + final ShadowStackEntry prevEntry, + final ShadowStackEntryLoad firstShadowStackEntryLoad, + final boolean async) { + if (!VmSettings.ACTOR_ASYNC_STACK_TRACE_INLINE_CACHE) { + setShadowStackEntry( + SArguments.instantiateShadowStackEntry(prevEntry, expression, async), + arguments); + return; + } + ShadowStackEntry newEntry = + SArguments.instantiateShadowStackEntry(prevEntry, expression, async); + ShadowStackEntryLoad newLoad; + if (firstShadowStackEntryLoad.getCurrentCacheSize() > NUM_SHADOW_STACK_ENTRIES) { + newLoad = new GenericShadowStackEntryLoad(); + // firstShadowStackEntryLoad.replace(newLoad); + replace(newLoad); + } else { + newLoad = new CachedShadowStackEntryLoad(prevEntry, newEntry); + replace(newLoad); + } + newLoad.loadShadowStackEntry(arguments, expression, prevEntry, + firstShadowStackEntryLoad, async); + } + @Override + public int getCurrentCacheSize() { + return 0; } - private static final class CachedShadowStackEntryLoad extends ShadowStackEntryLoad { + } - @Child protected ShadowStackEntryLoad nextInCache; - protected final ShadowStackEntry expectedShadowStackEntry; - protected final ShadowStackEntry cachedShadowStackEntry; + private static final class CachedShadowStackEntryLoad extends ShadowStackEntryLoad { - @CompilerDirectives.TruffleBoundary - CachedShadowStackEntryLoad(final ShadowStackEntry prevEntry, - final ShadowStackEntry newEntry) { - this.expectedShadowStackEntry = prevEntry; - this.cachedShadowStackEntry = newEntry; - nextInCache = new UninitializedShadowStackEntryLoad(); - } + @Child protected ShadowStackEntryLoad nextInCache; + protected final ShadowStackEntry expectedShadowStackEntry; + protected final ShadowStackEntry cachedShadowStackEntry; - @Override - public int getCurrentCacheSize() { - return 1 + nextInCache.getCurrentCacheSize(); - } + @CompilerDirectives.TruffleBoundary + CachedShadowStackEntryLoad(final ShadowStackEntry prevEntry, + final ShadowStackEntry newEntry) { + this.expectedShadowStackEntry = prevEntry; + this.cachedShadowStackEntry = newEntry; + nextInCache = new UninitializedShadowStackEntryLoad(); + } - @Override - protected void loadShadowStackEntry(final Object[] arguments, - final Node expression, - final ShadowStackEntry prevEntry, final ShadowStackEntryLoad firstShadowStackEntryLoad, - final boolean async) { - if (prevEntry == expectedShadowStackEntry) { - setShadowStackEntry(cachedShadowStackEntry, arguments); - if (ANALYSIS) { - cacheHit++; - } - } else { - nextInCache.loadShadowStackEntry(arguments, expression, prevEntry, - firstShadowStackEntryLoad, async); - } + @Override + public int getCurrentCacheSize() { + return 1 + nextInCache.getCurrentCacheSize(); + } + + @Override + protected void loadShadowStackEntry(final Object[] arguments, + final Node expression, + final ShadowStackEntry prevEntry, final ShadowStackEntryLoad firstShadowStackEntryLoad, + final boolean async) { + if (prevEntry == expectedShadowStackEntry) { + setShadowStackEntry(cachedShadowStackEntry, arguments); + if (ANALYSIS) { + cacheHit++; } + } else { + nextInCache.loadShadowStackEntry(arguments, expression, prevEntry, + firstShadowStackEntryLoad, async); + } } + } - private static final class GenericShadowStackEntryLoad extends ShadowStackEntryLoad { + private static final class GenericShadowStackEntryLoad extends ShadowStackEntryLoad { - @Override - protected void loadShadowStackEntry(final Object[] arguments, - final Node expression, - final ShadowStackEntry prevEntry, final ShadowStackEntryLoad firstShadowStackEntryLoad, - final boolean async) { - setShadowStackEntry(SArguments.instantiateShadowStackEntry(prevEntry, expression, async), - arguments); - } + @Override + protected void loadShadowStackEntry(final Object[] arguments, + final Node expression, + final ShadowStackEntry prevEntry, final ShadowStackEntryLoad firstShadowStackEntryLoad, + final boolean async) { + setShadowStackEntry(SArguments.instantiateShadowStackEntry(prevEntry, expression, async), + arguments); + } - @Override - public int getCurrentCacheSize() { - return 0; - } + @Override + public int getCurrentCacheSize() { + return 0; } + } } diff --git a/src/tools/debugger/asyncstacktraces/StackIterator.java b/src/tools/debugger/asyncstacktraces/StackIterator.java index 688df99b46..e00986705d 100644 --- a/src/tools/debugger/asyncstacktraces/StackIterator.java +++ b/src/tools/debugger/asyncstacktraces/StackIterator.java @@ -40,404 +40,410 @@ public abstract class StackIterator implements Iterator { - @Override - public abstract boolean hasNext(); + @Override + public abstract boolean hasNext(); + + @Override + public abstract StackFrame next(); + + protected StackFrame createStackFrame(final Frame localFrame, final RootNode rootNode, + final String name, final SourceSection location) { + return new StackFrame(name, rootNode, + location, localFrame, false); + } + + public static StackIterator createHaltIterator() { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new HaltShadowStackIterator(); + } else { + return new HaltIterator(); + } + } + + public static StackIterator createSuspensionIterator( + final Iterator localStack, long actorId) { + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + return new SuspensionShadowStackIterator(localStack, actorId); + } else { + return new SuspensionIterator(localStack); + } + } - @Override - public abstract StackFrame next(); + public static class SuspensionIterator extends StackIterator { - protected StackFrame createStackFrame(final Frame localFrame, final RootNode rootNode, - final String name, final SourceSection location) { - return new StackFrame(name, rootNode, - location, localFrame, false); - } + protected ArrayList frames; + protected int currentIndex = 0; - public static StackIterator createHaltIterator() { - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - return new HaltShadowStackIterator(); - } else { - return new HaltIterator(); - } + public SuspensionIterator(final Iterator localStack) { + assert localStack != null; + frames = new ArrayList(); + while (localStack.hasNext()) { + frames.add(localStack.next()); + } } - public static StackIterator createSuspensionIterator( - final Iterator localStack, long actorId) { - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - return new SuspensionShadowStackIterator(localStack, actorId); - } else { - return new SuspensionIterator(localStack); - } + @Override + public boolean hasNext() { + return currentIndex != frames.size(); } - public static class SuspensionIterator extends StackIterator { + @Override + public StackFrame next() { + DebugStackFrame next = frames.get(currentIndex); + currentIndex++; + return createStackFrame(next.getFrame(), + next.getRootNode(), + next.getRootNode().getName(), + next.getSourceSection()); + } + } - protected ArrayList frames; - protected int currentIndex = 0; + public static class HaltIterator extends StackIterator { - public SuspensionIterator(final Iterator localStack) { - assert localStack != null; - frames = new ArrayList(); - while (localStack.hasNext()) { - frames.add(localStack.next()); - } - } + protected ArrayList frameInstances; + protected int currentIndex = 0; + public HaltIterator() { + frameInstances = new ArrayList(); + Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { @Override - public boolean hasNext() { - return currentIndex != frames.size(); + public Object visitFrame(final FrameInstance frameInstance) { + frameInstances.add(frameInstance); + return null; } + }); + } - @Override - public StackFrame next() { - DebugStackFrame next = frames.get(currentIndex); - currentIndex++; - return createStackFrame(next.getFrame(), - next.getRootNode(), - next.getRootNode().getName(), - next.getSourceSection()); - } + @Override + public boolean hasNext() { + return currentIndex != frameInstances.size(); } - public static class HaltIterator extends StackIterator { + @Override + public StackFrame next() { + FrameInstance next = frameInstances.get(currentIndex); + currentIndex++; + RootCallTarget rt = (RootCallTarget) next.getCallTarget(); + if (!(rt.getRootNode() instanceof Invokable)) { + return null; + } + Invokable rootNode = (Invokable) rt.getRootNode(); + SourceSection ss = null; + if (next.getCallNode() != null) { + ss = next.getCallNode().getEncapsulatingSourceSection(); + } + return createStackFrame(next.getFrame(FrameAccess.READ_ONLY), + rootNode, + rootNode.getName(), + ss); + } + } + + /** + * @author clementbera + *

+ * By contrast to HaltIterator and Suspension Iterator, the ShadowStackIterator use + * the stack for the first frame only and then rely on shadow stack entry to get the + * following stack entries + */ + public abstract static class ShadowStackIterator extends StackIterator { + private ShadowStackEntry currentSSEntry; + protected boolean first; + private Node currentNode; + private Invokable currentMethod; + private ShadowStackEntry useAgainShadowEntry; + private Frame useAgainFrame; + private StackFrame topFrame; + + public ShadowStackIterator() { + currentSSEntry = null; + first = true; + topFrame = null; + } - protected ArrayList frameInstances; - protected int currentIndex = 0; + @Override + public boolean hasNext() { + return currentSSEntry != null || first || useAgainShadowEntry != null; + } - public HaltIterator() { - frameInstances = new ArrayList(); - Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { - @Override - public Object visitFrame(final FrameInstance frameInstance) { - frameInstances.add(frameInstance); - return null; - } - }); - } + protected abstract StackFrameDescription getFirstFrame(); - @Override - public boolean hasNext() { - return currentIndex != frameInstances.size(); - } + protected abstract StackFrameDescription getFrameBySource(SourceSection sourceSection); - @Override - public StackFrame next() { - FrameInstance next = frameInstances.get(currentIndex); - currentIndex++; - RootCallTarget rt = (RootCallTarget) next.getCallTarget(); - if (!(rt.getRootNode() instanceof Invokable)) { - return null; - } - Invokable rootNode = (Invokable) rt.getRootNode(); - SourceSection ss = null; - if (next.getCallNode() != null) { - ss = next.getCallNode().getEncapsulatingSourceSection(); - } - return createStackFrame(next.getFrame(FrameAccess.READ_ONLY), - rootNode, - rootNode.getName(), - ss); - } + @Override + public StackFrame next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE) { + return nextAsyncStackStructureMethodCache(); + } else { + return nextAsyncStackStructure(); + } } - /** - * @author clementbera - *

- * By contrast to HaltIterator and Suspension Iterator, the ShadowStackIterator use - * the stack for the first frame only and then rely on shadow stack entry to get the - * following stack entries - */ - public abstract static class ShadowStackIterator extends StackIterator { - private ShadowStackEntry currentSSEntry; - protected boolean first; - private Node currentNode; - private Invokable currentMethod; - private ShadowStackEntry useAgainShadowEntry; - private Frame useAgainFrame; - private StackFrame topFrame; - - public ShadowStackIterator() { - currentSSEntry = null; - first = true; - topFrame = null; + protected StackFrame nextAsyncStackStructure() { + ShadowStackEntry shadow = null; + Frame localFrame = null; + boolean usedAgain = false; + + if (first) { + StackFrameDescription firstFrame = getFirstFrame(); + localFrame = firstFrame.getFrame(); + Object[] args = localFrame.getArguments(); + // assert args[args.length - 1] instanceof ShadowStackEntry; + if (args[args.length - 1] instanceof ShadowStackEntry) { + currentSSEntry = (ShadowStackEntry) args[args.length - 1]; } - @Override - public boolean hasNext() { - return currentSSEntry != null || first || useAgainShadowEntry != null; + first = false; + + } else if (useAgainShadowEntry != null) { + shadow = useAgainShadowEntry; + usedAgain = true; + localFrame = useAgainFrame; + useAgainShadowEntry = null; + useAgainFrame = null; + } else { + shadow = currentSSEntry; + if (shadow != null) { + currentSSEntry = shadow.previous; } + } - protected abstract StackFrameDescription getFirstFrame(); - - protected abstract StackFrameDescription getFrameBySource(SourceSection sourceSection); + return createStackFrame(shadow, localFrame, usedAgain); + } - @Override - public StackFrame next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_METHOD_CACHE) { - return nextAsyncStackStructureMethodCache(); - } else { - return nextAsyncStackStructure(); - } + public StackFrame getTopFrame() { + if (first) { + StackFrameDescription frameDescription = getFirstFrame(); + String actor = "actor " + frameDescription.getActorId() + ", "; + String name; + if (frameDescription.getRootNode().getName() != null) { // case of ExecutorRootNode + String rootNodeName = frameDescription.getRootNode().getName(); + name = actor.concat(rootNodeName); + } else { + name = actor; } + topFrame = new StackFrame(name, frameDescription.getRootNode(), + frameDescription.getSourceSection(), frameDescription.getFrame(), false); - protected StackFrame nextAsyncStackStructure() { - ShadowStackEntry shadow = null; - Frame localFrame = null; - boolean usedAgain = false; - - if (first) { - StackFrameDescription firstFrame = getFirstFrame(); - localFrame = firstFrame.getFrame(); - Object[] args = localFrame.getArguments(); - // assert args[args.length - 1] instanceof ShadowStackEntry; - if(args[args.length - 1] instanceof ShadowStackEntry) { - currentSSEntry = (ShadowStackEntry) args[args.length - 1]; - } - - first = false; - - } else if (useAgainShadowEntry != null) { - shadow = useAgainShadowEntry; - usedAgain = true; - localFrame = useAgainFrame; - useAgainShadowEntry = null; - useAgainFrame = null; - } else { - shadow = currentSSEntry; - if (shadow != null) { - currentSSEntry = shadow.previous; - } - } - - return createStackFrame(shadow, localFrame, usedAgain); - } + } + return topFrame; + } - public StackFrame getTopFrame() { - if (first) { - StackFrameDescription frameDescription = getFirstFrame(); - String actor = "actor " + frameDescription.getActorId() + ", "; - String name; - if (frameDescription.getRootNode().getName() != null) { //case of ExecutorRootNode - String rootNodeName = frameDescription.getRootNode().getName(); - name = actor.concat(rootNodeName); - } else { - name = actor; - } - topFrame = new StackFrame(name, frameDescription.getRootNode(), - frameDescription.getSourceSection(), frameDescription.getFrame(), false); - - } - return topFrame; + protected StackFrame createStackFrame(final ShadowStackEntry shadow, + Frame localFrame, final boolean usedAgain) { + if (shadow == null) { + return null; + } + if (shadow.expression == null) { + return null; + } + boolean contextTransitionElement; + + String name = "actor " + shadow.actorId + ", " + shadow.getRootNode().getName(); + SourceSection location = shadow.getSourceSection(); + + if (!usedAgain && (shadow instanceof EntryAtMessageSend + || shadow instanceof EntryForPromiseResolution)) { + contextTransitionElement = true; + + if (shadow instanceof EntryAtMessageSend) { + Node sendNode = shadow.expression.getParent(); + String symbol = ((EventualSendNode) sendNode).getSentSymbol().getString(); + + if (sendNode instanceof EventualSendNode) { + name = "actor " + shadow.actorId + ", on async message send: " + symbol; + + } + useAgainShadowEntry = shadow; + useAgainFrame = localFrame; + } else if (shadow instanceof EntryForPromiseResolution) { + EntryForPromiseResolution.ResolutionLocation resolutionLocation = + ((EntryForPromiseResolution) shadow).resolutionLocation; + String resolutionValue = ((EntryForPromiseResolution) shadow).resolutionValue; + name = "actor " + shadow.actorId + ", " + resolutionLocation.getValue() + ": " + + shadow.expression.getRootNode().getName() + " " + resolutionValue; } - protected StackFrame createStackFrame(final ShadowStackEntry shadow, - Frame localFrame, final boolean usedAgain) { - if (shadow == null) { - return null; - } - if (shadow.expression == null) { - return null; - } - boolean contextTransitionElement; - - String name = "actor " + shadow.actorId + ", " + shadow.getRootNode().getName(); - SourceSection location = shadow.getSourceSection(); - - if (!usedAgain && (shadow instanceof EntryAtMessageSend - || shadow instanceof EntryForPromiseResolution)) { - contextTransitionElement = true; - - if (shadow instanceof EntryAtMessageSend) { - Node sendNode = shadow.expression.getParent(); - String symbol = ((EventualSendNode) sendNode).getSentSymbol().getString(); - - if (sendNode instanceof EventualSendNode) { - name = "actor " + shadow.actorId + ", on async message send: " + symbol; - - } - useAgainShadowEntry = shadow; - useAgainFrame = localFrame; - } else if (shadow instanceof EntryForPromiseResolution) { - EntryForPromiseResolution.ResolutionLocation resolutionLocation = ((EntryForPromiseResolution) shadow).resolutionLocation; - String resolutionValue = ((EntryForPromiseResolution) shadow).resolutionValue; - name = "actor " + shadow.actorId + ", " + resolutionLocation.getValue() + ": " + shadow.expression.getRootNode().getName() + " " + resolutionValue; - } - - } else { - StackFrameDescription frameByName = getFrameBySource(location); - if (frameByName != null && localFrame == null) { - localFrame = frameByName.frame; - } - contextTransitionElement = false; - } - - return new StackFrame(name, shadow.getRootNode(), - location, localFrame, contextTransitionElement); + } else { + StackFrameDescription frameByName = getFrameBySource(location); + if (frameByName != null && localFrame == null) { + localFrame = frameByName.frame; } + contextTransitionElement = false; + } - // This version has to skip missing shadow stack entry using method back pointer cache - protected StackFrame nextAsyncStackStructureMethodCache() { - ShadowStackEntry shadow = null; - Frame localFrame = null; - boolean usedAgain = false; - - if (first) { - localFrame = getFirstFrame().getFrame(); - Object[] args = localFrame.getArguments(); - assert args[args.length - 1] instanceof ShadowStackEntry; - currentSSEntry = (ShadowStackEntry) args[args.length - 1]; - currentMethod = (Invokable) getFirstFrame().getRootNode(); - first = false; - } - - if (useAgainShadowEntry != null) { - shadow = useAgainShadowEntry; - usedAgain = true; - localFrame = useAgainFrame; - useAgainShadowEntry = null; - useAgainFrame = null; - } else { - if (shouldUsePreviousShadowStackEntry(currentMethod, - currentSSEntry.getExpression())) { - shadow = currentSSEntry; - currentSSEntry = currentSSEntry.getPreviousShadowStackEntry(); - // null if start frame - if (currentSSEntry != null) { - currentNode = currentSSEntry.getExpression(); - } - } else { - assert currentMethod instanceof Method; - currentNode = (Node) ((Method) currentMethod).getUniqueCaller(); - } - } - - if (shadow != null) { - return createStackFrame(shadow, localFrame, usedAgain); - } else { - return createStackFrame(localFrame, currentNode.getRootNode(), - currentNode.getRootNode().getName(), currentNode.getSourceSection()); - } - } + return new StackFrame(name, shadow.getRootNode(), + location, localFrame, contextTransitionElement); + } - public boolean shouldUsePreviousShadowStackEntry(final Invokable currentMethod, - final Node prevExpression) { - if (!(currentMethod instanceof Method)) { - return true; - } - if (prevExpression instanceof BackCacheCallNode) { - BackCacheCallNode ssNode = - (BackCacheCallNode) prevExpression; - return currentMethod == ssNode.getCachedMethod(); - } - return true; + // This version has to skip missing shadow stack entry using method back pointer cache + protected StackFrame nextAsyncStackStructureMethodCache() { + ShadowStackEntry shadow = null; + Frame localFrame = null; + boolean usedAgain = false; + + if (first) { + localFrame = getFirstFrame().getFrame(); + Object[] args = localFrame.getArguments(); + assert args[args.length - 1] instanceof ShadowStackEntry; + currentSSEntry = (ShadowStackEntry) args[args.length - 1]; + currentMethod = (Invokable) getFirstFrame().getRootNode(); + first = false; + } + + if (useAgainShadowEntry != null) { + shadow = useAgainShadowEntry; + usedAgain = true; + localFrame = useAgainFrame; + useAgainShadowEntry = null; + useAgainFrame = null; + } else { + if (shouldUsePreviousShadowStackEntry(currentMethod, + currentSSEntry.getExpression())) { + shadow = currentSSEntry; + currentSSEntry = currentSSEntry.getPreviousShadowStackEntry(); + // null if start frame + if (currentSSEntry != null) { + currentNode = currentSSEntry.getExpression(); + } + } else { + assert currentMethod instanceof Method; + currentNode = (Node) ((Method) currentMethod).getUniqueCaller(); } + } + + if (shadow != null) { + return createStackFrame(shadow, localFrame, usedAgain); + } else { + return createStackFrame(localFrame, currentNode.getRootNode(), + currentNode.getRootNode().getName(), currentNode.getSourceSection()); + } + } - protected static final class StackFrameDescription { - SourceSection sourceSection; - Frame frame; - RootNode rootNode; - long actorId; - - public StackFrameDescription(final SourceSection sourceSection, - final Frame frame, final RootNode rootNode, long actorId) { - this.sourceSection = sourceSection; - this.frame = frame; - this.rootNode = rootNode; - this.actorId = actorId; - } - - public SourceSection getSourceSection() { - return sourceSection; - } - - public Frame getFrame() { - return frame; - } + public boolean shouldUsePreviousShadowStackEntry(final Invokable currentMethod, + final Node prevExpression) { + if (!(currentMethod instanceof Method)) { + return true; + } + if (prevExpression instanceof BackCacheCallNode) { + BackCacheCallNode ssNode = + (BackCacheCallNode) prevExpression; + return currentMethod == ssNode.getCachedMethod(); + } + return true; + } - public RootNode getRootNode() { - return rootNode; - } + protected static final class StackFrameDescription { + SourceSection sourceSection; + Frame frame; + RootNode rootNode; + long actorId; + + public StackFrameDescription(final SourceSection sourceSection, + final Frame frame, final RootNode rootNode, long actorId) { + this.sourceSection = sourceSection; + this.frame = frame; + this.rootNode = rootNode; + this.actorId = actorId; + } + + public SourceSection getSourceSection() { + return sourceSection; + } + + public Frame getFrame() { + return frame; + } + + public RootNode getRootNode() { + return rootNode; + } + + public long getActorId() { + return actorId; + } + } - public long getActorId() { - return actorId; - } + public static final class SuspensionShadowStackIterator extends ShadowStackIterator { + private final DebugStackFrame firstDebugFrame; + private StackFrameDescription firstFrameDescription; + private long actorId; + private List allFrames; + + public SuspensionShadowStackIterator(final Iterator localStack, + long actorId) { + assert localStack != null; + assert localStack.hasNext(); + firstDebugFrame = localStack.next(); // first frame + firstFrameDescription = null; + this.actorId = actorId; + + allFrames = new ArrayList(); + while (localStack.hasNext()) { + allFrames.add(localStack.next()); // save all frames } - - public static final class SuspensionShadowStackIterator extends ShadowStackIterator { - private final DebugStackFrame firstDebugFrame; - private StackFrameDescription firstFrameDescription; - private long actorId; - private List allFrames; - - public SuspensionShadowStackIterator(final Iterator localStack, long actorId) { - assert localStack != null; - assert localStack.hasNext(); - firstDebugFrame = localStack.next(); //first frame - firstFrameDescription = null; - this.actorId = actorId; - - allFrames = new ArrayList(); - while (localStack.hasNext()) { - allFrames.add(localStack.next()); //save all frames - } - } - - @Override - protected StackFrameDescription getFirstFrame() { - assert first; - if (firstFrameDescription == null) { - firstFrameDescription = new StackFrameDescription(firstDebugFrame.getSourceSection(), firstDebugFrame.getFrame(), - firstDebugFrame.getRootNode(), this.actorId); - } - return firstFrameDescription; - } - - public StackFrameDescription getFrameBySource(SourceSection sourceSection) { - for (DebugStackFrame debugStackFrame : allFrames) { - if (debugStackFrame.getSourceSection() != null && debugStackFrame.getSourceSection().equals(sourceSection)) { - return new StackFrameDescription(debugStackFrame.getSourceSection(), debugStackFrame.getFrame(), - debugStackFrame.getRootNode(), this.actorId); - } - } - - return null; - } + } + + @Override + protected StackFrameDescription getFirstFrame() { + assert first; + if (firstFrameDescription == null) { + firstFrameDescription = new StackFrameDescription(firstDebugFrame.getSourceSection(), + firstDebugFrame.getFrame(), + firstDebugFrame.getRootNode(), this.actorId); } + return firstFrameDescription; + } + + public StackFrameDescription getFrameBySource(SourceSection sourceSection) { + for (DebugStackFrame debugStackFrame : allFrames) { + if (debugStackFrame.getSourceSection() != null + && debugStackFrame.getSourceSection().equals(sourceSection)) { + return new StackFrameDescription(debugStackFrame.getSourceSection(), + debugStackFrame.getFrame(), + debugStackFrame.getRootNode(), this.actorId); + } + } + + return null; + } + } - public static final class HaltShadowStackIterator extends ShadowStackIterator { - private final FrameInstance firstFrameInstance; - - public HaltShadowStackIterator() { - firstFrameInstance = - Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { - @Override - public FrameInstance visitFrame(final FrameInstance frame) { - return frame; - } - }); - } - - @Override - protected StackFrameDescription getFirstFrame() { - assert first; - RootCallTarget rt = (RootCallTarget) firstFrameInstance.getCallTarget(); - assert rt.getRootNode() instanceof Invokable; - Invokable rootNode = (Invokable) rt.getRootNode(); - SourceSection ss = null; - if (firstFrameInstance.getCallNode() != null) { - ss = firstFrameInstance.getCallNode().getSourceSection(); - } - return new StackFrameDescription(ss, - firstFrameInstance.getFrame(FrameAccess.READ_ONLY), - rootNode, -1); - } - - @Override - protected StackFrameDescription getFrameBySource(SourceSection sourceSection) { - return null; - } + public static final class HaltShadowStackIterator extends ShadowStackIterator { + private final FrameInstance firstFrameInstance; + + public HaltShadowStackIterator() { + firstFrameInstance = + Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() { + @Override + public FrameInstance visitFrame(final FrameInstance frame) { + return frame; + } + }); + } + + @Override + protected StackFrameDescription getFirstFrame() { + assert first; + RootCallTarget rt = (RootCallTarget) firstFrameInstance.getCallTarget(); + assert rt.getRootNode() instanceof Invokable; + Invokable rootNode = (Invokable) rt.getRootNode(); + SourceSection ss = null; + if (firstFrameInstance.getCallNode() != null) { + ss = firstFrameInstance.getCallNode().getSourceSection(); } + return new StackFrameDescription(ss, + firstFrameInstance.getFrame(FrameAccess.READ_ONLY), + rootNode, -1); + } + + @Override + protected StackFrameDescription getFrameBySource(SourceSection sourceSection) { + return null; + } } + } } diff --git a/src/tools/debugger/breakpoints/Breakpoints.java b/src/tools/debugger/breakpoints/Breakpoints.java index f5e0e6fc1f..6b8149d517 100644 --- a/src/tools/debugger/breakpoints/Breakpoints.java +++ b/src/tools/debugger/breakpoints/Breakpoints.java @@ -60,12 +60,13 @@ public void prepareSteppingAfterNextRootNode(final Thread thread) { public synchronized void addOrUpdate(final LineBreakpoint bId) { Breakpoint bp = truffleBreakpoints.get(bId); if (bp == null) { - WebDebugger.log("[DEBUGGER] LineBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); + WebDebugger.log("[DEBUGGER] LineBreakpoint: " + bId + " Enabled: " + bId.isEnabled()); bp = Breakpoint.newBuilder(bId.getURI()).lineIs(bId.getLine()).build(); debuggerSession.install(bp); truffleBreakpoints.put(bId, bp); } else { - WebDebugger.log("[DEBUGGER] Update LineBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); + WebDebugger.log( + "[DEBUGGER] Update LineBreakpoint: " + bId + " Enabled: " + bId.isEnabled()); } bp.setEnabled(bId.isEnabled()); } @@ -76,10 +77,11 @@ public synchronized void addOrUpdate(final SectionBreakpoint bId) { if (existingBP == null) { existingBP = new BreakpointEnabling(bId); breakpoints.put(loc, existingBP); - WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId +" Enabled: "+bId.isEnabled()); + WebDebugger.log("[DEBUGGER] SectionBreakpoint: " + bId + " Enabled: " + bId.isEnabled()); } else { existingBP.setEnabled(bId.isEnabled()); - WebDebugger.log("[DEBUGGER] Update SectionBreakpoint: " + bId + " Enabled: "+bId.isEnabled()); + WebDebugger.log( + "[DEBUGGER] Update SectionBreakpoint: " + bId + " Enabled: " + bId.isEnabled()); } } diff --git a/src/tools/debugger/entities/Marker.java b/src/tools/debugger/entities/Marker.java index bfd510ed5b..d6d0cc9611 100644 --- a/src/tools/debugger/entities/Marker.java +++ b/src/tools/debugger/entities/Marker.java @@ -34,6 +34,6 @@ public class Marker { public static final byte PROMISE_MSG_SEND = 22; - public static final byte ACTOR_MSG_RECEIVE = 23; + public static final byte ACTOR_MSG_RECEIVE = 23; } diff --git a/src/tools/debugger/entities/MessageReception.java b/src/tools/debugger/entities/MessageReception.java index ddab06104b..07fce1dfbe 100644 --- a/src/tools/debugger/entities/MessageReception.java +++ b/src/tools/debugger/entities/MessageReception.java @@ -1,25 +1,25 @@ package tools.debugger.entities; public enum MessageReception { - MESSAGE_RCV(Marker.ACTOR_MSG_RECEIVE, EntityType.ACTOR); + MESSAGE_RCV(Marker.ACTOR_MSG_RECEIVE, EntityType.ACTOR); - private final byte id; - private final EntityType source; + private final byte id; + private final EntityType source; - MessageReception(final byte id, final EntityType source) { - this.id = id; - this.source = source; - } + MessageReception(final byte id, final EntityType source) { + this.id = id; + this.source = source; + } - public byte getId() { - return id; - } + public byte getId() { + return id; + } - public EntityType getSource() { - return source; - } + public EntityType getSource() { + return source; + } - public int getSize() { - return 9; - } + public int getSize() { + return 9; + } } diff --git a/src/tools/debugger/entities/SendOp.java b/src/tools/debugger/entities/SendOp.java index 3f41623fd7..2ec4d2aea2 100644 --- a/src/tools/debugger/entities/SendOp.java +++ b/src/tools/debugger/entities/SendOp.java @@ -2,6 +2,7 @@ import tools.TraceData; + public enum SendOp { ACTOR_MSG(Marker.ACTOR_MSG_SEND, EntityType.ACT_MSG, EntityType.ACTOR), PROMISE_MSG(Marker.PROMISE_MSG_SEND, EntityType.ACT_MSG, EntityType.PROMISE), @@ -12,9 +13,9 @@ public enum SendOp { private final EntityType entity; private final EntityType target; - private static final int SYMBOL_ID_SIZE = 2; + private static final int SYMBOL_ID_SIZE = 2; private static final int RECEIVER_ACTOR_ID_SIZE = 8; - private static final int PROMISE_VALUE_SIZE = 4; + private static final int PROMISE_VALUE_SIZE = 4; SendOp(final byte id, final EntityType entity, final EntityType target) { this.id = id; @@ -38,8 +39,10 @@ public int getSize() { return 17 + RECEIVER_ACTOR_ID_SIZE + SYMBOL_ID_SIZE + TraceData.SOURCE_SECTION_SIZE; } - //Adds the promise value size and the number of bytes for an integer (4), which is also recorded + // Adds the promise value size and the number of bytes for an integer (4), which is also + // recorded public int getSize(byte[] promiseValue) { - return 17 + RECEIVER_ACTOR_ID_SIZE + SYMBOL_ID_SIZE + TraceData.SOURCE_SECTION_SIZE + promiseValue.length + PROMISE_VALUE_SIZE; + return 17 + RECEIVER_ACTOR_ID_SIZE + SYMBOL_ID_SIZE + TraceData.SOURCE_SECTION_SIZE + + promiseValue.length + PROMISE_VALUE_SIZE; } } diff --git a/src/tools/debugger/entities/SteppingType.java b/src/tools/debugger/entities/SteppingType.java index 89f1821486..902750c97e 100644 --- a/src/tools/debugger/entities/SteppingType.java +++ b/src/tools/debugger/entities/SteppingType.java @@ -200,7 +200,7 @@ public void process(final Suspension susp) { @SerializedName("stepToEndTurn") STEP_TO_END_TURN("stepToEndTurn", "Step to End Turn", - Group.ACTOR_STEPPING, "msg-close", null, new ActivityType[] {ActivityType.ACTOR}) { + Group.ACTOR_STEPPING, "msg-close", null, new ActivityType[] {ActivityType.ACTOR}) { @Override public void process(final Suspension susp) { susp.getEvent().prepareContinue(); diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 267e1ca3b4..393da8837f 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -18,99 +18,102 @@ */ public class ApplicationThreadStack { - /** - * Track scopes that contain variables as well as objects. - * These have been identified in the debugger, i.e., they got an id for - * direct access. - */ - final ArrayList scopesAndObjects; - final HashMap scopesAndObjectsSet; - - private final ArrayList stackFrames; - private final SuspendedEvent event; - private final Suspension suspension; - - public static final class StackFrame { - public final String name; - public final SourceSection section; - public final Frame frame; - public final boolean asyncOperation; - private final RootNode root; - - public StackFrame(final String name, final RootNode root, final SourceSection section, - final Frame frame, final boolean asyncOperation) { - this.name = name; - this.root = root; - this.section = section; - this.frame = frame; - this.asyncOperation = asyncOperation; - } - - public RootNode getRootNode() { - return root; - } - - public boolean hasFrame() { - return frame != null; - } - } - - ApplicationThreadStack(final Suspension suspension) { - this.event = suspension.getEvent(); - this.stackFrames = new ArrayList<>(); - this.scopesAndObjects = new ArrayList<>(); - this.scopesAndObjectsSet = new HashMap<>(); - this.suspension = suspension; + /** + * Track scopes that contain variables as well as objects. + * These have been identified in the debugger, i.e., they got an id for + * direct access. + */ + final ArrayList scopesAndObjects; + final HashMap scopesAndObjectsSet; + + private final ArrayList stackFrames; + private final SuspendedEvent event; + private final Suspension suspension; + + public static final class StackFrame { + public final String name; + public final SourceSection section; + public final Frame frame; + public final boolean asyncOperation; + private final RootNode root; + + public StackFrame(final String name, final RootNode root, final SourceSection section, + final Frame frame, final boolean asyncOperation) { + this.name = name; + this.root = root; + this.section = section; + this.frame = frame; + this.asyncOperation = asyncOperation; } - ArrayList get() { - if (stackFrames.isEmpty()) { - StackIterator stack = - StackIterator.createSuspensionIterator(event.getStackFrames().iterator(), suspension.getActivity().getId()); - - if (stack instanceof StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) { - StackFrame topFrame = ((StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) stack).getTopFrame(); - //get top frame first - stackFrames.add(topFrame); - } - - while (stack.hasNext()) { - StackFrame next = stack.next(); - if (next != null) { //this validation is needed because at the moment ShadowStackIterator.next can return null values for null shadows - stackFrames.add(next); - } - } - assert !stackFrames.isEmpty() : "We expect that there is always at least one stack frame"; - - } - return stackFrames; + public RootNode getRootNode() { + return root; } - long addScope(final Frame frame, - final MethodScope lexicalScope) { - scopesAndObjects.add(new RuntimeScope(frame, lexicalScope)); - return getLastScopeOrVarId(); + public boolean hasFrame() { + return frame != null; } - - long addObject(final Object obj) { - Long idx = scopesAndObjectsSet.get(obj); - if (idx == null) { - scopesAndObjects.add(obj); - idx = getLastScopeOrVarId(); - scopesAndObjectsSet.put(obj, idx); + } + + ApplicationThreadStack(final Suspension suspension) { + this.event = suspension.getEvent(); + this.stackFrames = new ArrayList<>(); + this.scopesAndObjects = new ArrayList<>(); + this.scopesAndObjectsSet = new HashMap<>(); + this.suspension = suspension; + } + + ArrayList get() { + if (stackFrames.isEmpty()) { + StackIterator stack = + StackIterator.createSuspensionIterator(event.getStackFrames().iterator(), + suspension.getActivity().getId()); + + if (stack instanceof StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) { + StackFrame topFrame = + ((StackIterator.ShadowStackIterator.SuspensionShadowStackIterator) stack).getTopFrame(); + // get top frame first + stackFrames.add(topFrame); + } + + while (stack.hasNext()) { + StackFrame next = stack.next(); + if (next != null) { // this validation is needed because at the moment + // ShadowStackIterator.next can return null values for null shadows + stackFrames.add(next); } - return idx; - } + } + assert !stackFrames.isEmpty() : "We expect that there is always at least one stack frame"; - Object getScopeOrObject(final int localVarRef) { - // need to subtract 1, because getLastScopeOrVarId uses size - // instead of size - 1 for id, because VS code does not allow 0 as id - return scopesAndObjects.get(localVarRef - 1); } - - private long getLastScopeOrVarId() { - // using size() means ids start with 1, which seems to be needed - // otherwise, VS code ignores the top frame - return suspension.getGlobalId(scopesAndObjects.size()); + return stackFrames; + } + + long addScope(final Frame frame, + final MethodScope lexicalScope) { + scopesAndObjects.add(new RuntimeScope(frame, lexicalScope)); + return getLastScopeOrVarId(); + } + + long addObject(final Object obj) { + Long idx = scopesAndObjectsSet.get(obj); + if (idx == null) { + scopesAndObjects.add(obj); + idx = getLastScopeOrVarId(); + scopesAndObjectsSet.put(obj, idx); } + return idx; + } + + Object getScopeOrObject(final int localVarRef) { + // need to subtract 1, because getLastScopeOrVarId uses size + // instead of size - 1 for id, because VS code does not allow 0 as id + return scopesAndObjects.get(localVarRef - 1); + } + + private long getLastScopeOrVarId() { + // using size() means ids start with 1, which seems to be needed + // otherwise, VS code ignores the top frame + return suspension.getGlobalId(scopesAndObjects.size()); + } } diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 2418d773ae..6c3816c85c 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -97,8 +97,7 @@ public long getGlobalId(final int localId) { private int getLocalId(final long globalId) { assert TraceData.getActivityIdFromGlobalValId( - globalId) == activityId - : "should be an id for current activity, otherwise, something is wrong"; + globalId) == activityId : "should be an id for current activity, otherwise, something is wrong"; return TraceData.valIdFromGlobal(globalId); } @@ -180,20 +179,21 @@ public void suspendWithoutObjectSafepoints() { if (resolver != null) { resolver.getPromise().enableHaltOnResolution(); } - } - else if (activityThread.isStepping( - SteppingType.STEP_TO_END_TURN)) { + } else if (activityThread.isStepping( + SteppingType.STEP_TO_END_TURN)) { assert activity instanceof Actor; EventualMessage turnMessage = EventualMessage.getCurrentExecutingMessage(); String actorName = ""; String turnName = ""; Object[] args = turnMessage.getArgs(); - if (args.length > 0 && args[0] instanceof SObjectWithClass) { //e.g. PromiseSendMessage, DirectMessage + if (args.length > 0 && args[0] instanceof SObjectWithClass) { // e.g. + // PromiseSendMessage, + // DirectMessage final SObjectWithClass actorObject = (SObjectWithClass) args[0]; actorName = actorObject.getSOMClass().getName().getString(); } - if (args.length > 0 && args[0] instanceof SBlock) { //e.g. PromiseCallbackMessage + if (args.length > 0 && args[0] instanceof SBlock) { // e.g. PromiseCallbackMessage SBlock block = (SBlock) args[0]; turnName = block.getMethod().getInvokable().getName(); } @@ -202,22 +202,25 @@ else if (activityThread.isStepping( if (actorName.isEmpty()) { turnName = turnMessage.getSelector().getString(); } else { - turnName = actorName.concat(">>#").concat(turnMessage.getSelector().getString()); + turnName = + actorName.concat(">>#").concat(turnMessage.getSelector().getString()); } } Node suspendedNode = this.getEvent().getNode(); ArrayList stackFrames = this.getStackFrames(); ArrayList rootNodeFrames = new ArrayList<>(); - //get root nodes for the frames in the stack - for (StackFrame frame: stackFrames) { + // get root nodes for the frames in the stack + for (StackFrame frame : stackFrames) { rootNodeFrames.add(frame.getRootNode()); } - this.getEvent().getSession().prepareStepEndTurn(Thread.currentThread(), suspendedNode, turnName, rootNodeFrames); + this.getEvent().getSession().prepareStepEndTurn(Thread.currentThread(), + suspendedNode, turnName, rootNodeFrames); } } - } catch (InterruptedException e) { /* Just continue waiting */ } + } catch (InterruptedException e) { + /* Just continue waiting */ } } synchronized (this) { suspendedEvent = null; diff --git a/src/tools/debugger/message/InitializationResponse.java b/src/tools/debugger/message/InitializationResponse.java index 31a7cfc375..f6e3874114 100644 --- a/src/tools/debugger/message/InitializationResponse.java +++ b/src/tools/debugger/message/InitializationResponse.java @@ -265,7 +265,8 @@ public static InitializationResponse create(final EntityType[] supportedEntities final SendOp[] supportedSendOps, final ReceiveOp[] supportedReceiveOps, final BreakpointType[] supportedBreakpoints, - final SteppingType[] supportedSteps, final Implementation[] implData, final MessageReception[] msgReception) { + final SteppingType[] supportedSteps, final Implementation[] implData, + final MessageReception[] msgReception) { return new InitializationResponse(new ServerCapabilities(supportedEntities, supportedActivities, supportedPassiveEntities, supportedDynamicScopes, supportedSendOps, supportedReceiveOps, supportedBreakpoints, diff --git a/src/tools/debugger/message/PauseActorRequest.java b/src/tools/debugger/message/PauseActorRequest.java index 70788474b6..28f7149c03 100644 --- a/src/tools/debugger/message/PauseActorRequest.java +++ b/src/tools/debugger/message/PauseActorRequest.java @@ -4,23 +4,25 @@ import som.interpreter.actors.Actor; import tools.debugger.FrontendConnector; + public class PauseActorRequest extends Message.IncommingMessage { - private final long actorId; + private final long actorId; - public PauseActorRequest() { - actorId = -1; - } + public PauseActorRequest() { + actorId = -1; + } - public PauseActorRequest(long actorId) { - this.actorId = actorId; - } + public PauseActorRequest(long actorId) { + this.actorId = actorId; + } - @Override - public void process(FrontendConnector connector, WebSocket conn) { - Actor actor = connector.getActorById(this.actorId); - assert actor != null : "Failed to get actor for activityId: " + this.actorId; - actor.setStepToNextTurn(true); - FrontendConnector.log("[DEBUGGER] Actor "+actor.getId() +" will pause before processing the next message."); - connector.sendPauseActorResponse(this.actorId); - } + @Override + public void process(FrontendConnector connector, WebSocket conn) { + Actor actor = connector.getActorById(this.actorId); + assert actor != null : "Failed to get actor for activityId: " + this.actorId; + actor.setStepToNextTurn(true); + FrontendConnector.log("[DEBUGGER] Actor " + actor.getId() + + " will pause before processing the next message."); + connector.sendPauseActorResponse(this.actorId); + } } diff --git a/src/tools/debugger/message/PauseActorResponse.java b/src/tools/debugger/message/PauseActorResponse.java index 1786f53f0e..b2e5234b95 100644 --- a/src/tools/debugger/message/PauseActorResponse.java +++ b/src/tools/debugger/message/PauseActorResponse.java @@ -1,13 +1,13 @@ package tools.debugger.message; public class PauseActorResponse extends Message.OutgoingMessage { - private long actorId; + private long actorId; - public PauseActorResponse(long actorId) { - this.actorId = actorId; - } + public PauseActorResponse(long actorId) { + this.actorId = actorId; + } - public static Message create(long pausedActorId) { - return new PauseActorResponse(pausedActorId); - } + public static Message create(long pausedActorId) { + return new PauseActorResponse(pausedActorId); + } } diff --git a/src/tools/debugger/message/ResumeActorResponse.java b/src/tools/debugger/message/ResumeActorResponse.java index cf21d8c0f1..a5d4447090 100644 --- a/src/tools/debugger/message/ResumeActorResponse.java +++ b/src/tools/debugger/message/ResumeActorResponse.java @@ -1,13 +1,13 @@ package tools.debugger.message; public class ResumeActorResponse extends Message.OutgoingMessage { - private long actorId; + private long actorId; - public ResumeActorResponse(long actorId) { - this.actorId = actorId; - } + public ResumeActorResponse(long actorId) { + this.actorId = actorId; + } - public static Message create(long runningActorId) { - return new ResumeActorResponse(runningActorId); - } + public static Message create(long runningActorId) { + return new ResumeActorResponse(runningActorId); + } } diff --git a/src/tools/debugger/message/ScopesResponse.java b/src/tools/debugger/message/ScopesResponse.java index f8f32a543c..806019bca9 100644 --- a/src/tools/debugger/message/ScopesResponse.java +++ b/src/tools/debugger/message/ScopesResponse.java @@ -19,13 +19,14 @@ import com.oracle.truffle.api.frame.Frame; import tools.debugger.frontend.ApplicationThreadStack.StackFrame; + @SuppressWarnings("unused") public final class ScopesResponse extends Response { private final Scope[] scopes; - private final long variablesReference; + private final long variablesReference; private ScopesResponse(final long globalFrameId, final Scope[] scopes, - final int requestId) { + final int requestId) { super(requestId); assert TraceData.isWithinJSIntValueRange(globalFrameId); this.variablesReference = globalFrameId; @@ -50,7 +51,7 @@ private static final class Scope { private final boolean expensive; private Scope(final String name, final long globalVarRef, - final boolean expensive) { + final boolean expensive) { assert TraceData.isWithinJSIntValueRange(globalVarRef); this.name = name; this.variablesReference = globalVarRef; @@ -59,7 +60,7 @@ private Scope(final String name, final long globalVarRef, } private static void addScopes(final ArrayList scopes, - final MethodScope method, final Object rcvr, final Suspension suspension) { + final MethodScope method, final Object rcvr, final Suspension suspension) { MethodScope outer = method.getOuterScopeOrNull(); if (outer != null) { assert rcvr instanceof SBlock; @@ -72,7 +73,7 @@ private static void addScopes(final ArrayList scopes, private static final int SMALL_INITIAL_SIZE = 5; public static ScopesResponse create(final long globalFrameId, final Suspension suspension, - final int requestId) { + final int requestId) { StackFrame frame = suspension.getFrame(globalFrameId); ArrayList scopes = new ArrayList<>(SMALL_INITIAL_SIZE); if (frame.hasFrame()) { @@ -91,8 +92,8 @@ public static ScopesResponse create(final long globalFrameId, final Suspension s assert false : "This should not be reached. This scope should never get an id"; } else { assert invokable instanceof Primitive : "Got a " + invokable.getClass().getSimpleName() - + - " here. Means we need to add support"; + + + " here. Means we need to add support"; } } return new ScopesResponse(globalFrameId, scopes.toArray(new Scope[0]), requestId); diff --git a/src/tools/debugger/message/StackTraceResponse.java b/src/tools/debugger/message/StackTraceResponse.java index 4a5ab0f41a..b9198d5bbe 100644 --- a/src/tools/debugger/message/StackTraceResponse.java +++ b/src/tools/debugger/message/StackTraceResponse.java @@ -24,7 +24,7 @@ public final class StackTraceResponse extends Response { // but that would make tracking more difficult private final byte[] concurrentEntityScopes; private final long activityId; - private long messageId; + private long messageId; /** * Total number of frames available. @@ -35,7 +35,8 @@ public final class StackTraceResponse extends Response { private StackTraceResponse(final long activityId, final StackFrame[] stackFrames, final int totalFrames, - final int requestId, final byte[] concurrentEntityScopes, final long messageId, final boolean asyncStack) { + final int requestId, final byte[] concurrentEntityScopes, final long messageId, + final boolean asyncStack) { super(requestId); assert TraceData.isWithinJSIntValueRange(activityId); this.activityId = activityId; @@ -101,7 +102,8 @@ private static class StackFrame { } } - private static int getNumRootNodesToSkip(final ArrayList frames) { + private static int getNumRootNodesToSkip( + final ArrayList frames) { int skip = 0; int size = frames.size(); @@ -141,7 +143,8 @@ public static StackTraceResponse create(final int startFrame, final int levels, // TODO: remove the below assert once we are satisfied things work. because now we can // have received root nodes in the stack trace // assert !(frames.get( - // frameId).getRootNode() instanceof ReceivedRootNode) : "This should have been skipped in the + // frameId).getRootNode() instanceof ReceivedRootNode) : "This should have been skipped + // in the // code above"; StackFrame f = createFrame(suspension, frameId, frames.get(frameId)); arr[i] = f; @@ -152,7 +155,8 @@ public static StackTraceResponse create(final int startFrame, final int levels, // determine the message id to which this trace corresponds long messageId = -1; - Actor actorCurrentMessageIsExecutionOn = EventualMessage.getActorCurrentMessageIsExecutionOn(); + Actor actorCurrentMessageIsExecutionOn = + EventualMessage.getActorCurrentMessageIsExecutionOn(); if (actorCurrentMessageIsExecutionOn.getId() == suspension.getActivity().getId()) { EventualMessage message = EventualMessage.getCurrentExecutingMessage(); @@ -160,7 +164,8 @@ public static StackTraceResponse create(final int startFrame, final int levels, } return new StackTraceResponse(suspension.activityId, arr, frames.size(), - requestId, EntityType.getIds(concEntityScopes), messageId, VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE); + requestId, EntityType.getIds(concEntityScopes), messageId, + VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE); } private static StackFrame createFrame(final Suspension suspension, @@ -197,6 +202,7 @@ private static StackFrame createFrame(final Suspension suspension, boolean async = frame.asyncOperation; - return new StackFrame(id, name, sourceUri, line, column, endLine, endColumn, length, async); + return new StackFrame(id, name, sourceUri, line, column, endLine, endColumn, length, + async); } } diff --git a/src/tools/debugger/message/StepMessage.java b/src/tools/debugger/message/StepMessage.java index 9e430f4c4e..0918a9bdc6 100644 --- a/src/tools/debugger/message/StepMessage.java +++ b/src/tools/debugger/message/StepMessage.java @@ -29,27 +29,32 @@ public void process(final FrontendConnector connector, final WebSocket conn) { step.process(susp); susp.resume(); if (step != SteppingType.RESUME) { - FrontendConnector.log("[DEBUGGER] Executing "+ step.name +" for actor "+activityId); + FrontendConnector.log( + "[DEBUGGER] Executing " + step.name + " for actor " + activityId); } - } else if(step == SteppingType.RESUME) { - //notify frontend the actor that can be resumed in the GUI because the actor is not suspended, - //this is needed for actors that are paused explicitly in the frontend, and they are not actually suspended yet (mailbox is empty) + } else if (step == SteppingType.RESUME) { + // notify frontend the actor that can be resumed in the GUI because the actor is not + // suspended, + // this is needed for actors that are paused explicitly in the frontend, and they are not + // actually suspended yet (mailbox is empty) Actor actor = connector.getActorById(this.activityId); assert actor != null : "Failed to get actor for activityId: " + this.activityId; - //reset step next turn flag to false + // reset step next turn flag to false actor.setStepToNextTurn(false); } else { - FrontendConnector.log("[DEBUGGER]: Failed to get suspension for activityId: " + activityId); + FrontendConnector.log( + "[DEBUGGER]: Failed to get suspension for activityId: " + activityId); } sendResumeMessage(connector); } private void sendResumeMessage(FrontendConnector connector) { - if(step == SteppingType.RESUME || step == SteppingType.RETURN_FROM_TURN_TO_PROMISE_RESOLUTION) { - //send resume message + if (step == SteppingType.RESUME + || step == SteppingType.RETURN_FROM_TURN_TO_PROMISE_RESOLUTION) { + // send resume message connector.sendResumeActorResponse(this.activityId); - FrontendConnector.log("[DEBUGGER] Resuming actor "+activityId); + FrontendConnector.log("[DEBUGGER] Resuming actor " + activityId); } } } diff --git a/src/tools/debugger/message/StoppedMessage.java b/src/tools/debugger/message/StoppedMessage.java index 1cf686ce1c..d5e94cca14 100644 --- a/src/tools/debugger/message/StoppedMessage.java +++ b/src/tools/debugger/message/StoppedMessage.java @@ -50,7 +50,7 @@ public static StoppedMessage create(final Suspension suspension) { ActivityType type = suspension.getActivity().getType(); // TODO: look into additional details that can be provided as text - //at the moment pass the suspendedPosition as text + // at the moment pass the suspendedPosition as text return new StoppedMessage(reason, suspension.activityId, type, suspendedPosition); } } diff --git a/src/tools/dym/DynamicMetrics.java b/src/tools/dym/DynamicMetrics.java index 327461c3c8..f5478be12a 100644 --- a/src/tools/dym/DynamicMetrics.java +++ b/src/tools/dym/DynamicMetrics.java @@ -208,8 +208,7 @@ public DynamicMetrics() { assert "DefaultTruffleRuntime".equals( Truffle.getRuntime().getClass() - .getSimpleName()) - : "To get metrics for the lexical, unoptimized behavior, please run this tool without Graal"; + .getSimpleName()) : "To get metrics for the lexical, unoptimized behavior, please run this tool without Graal"; } public void enterMethod() { @@ -441,8 +440,7 @@ private void addLoopBodyInstrumentation( instrumenter.attachExecutionEventFactory(filters.build(), (final EventContext ctx) -> { ExecutionEventNode parent = ctx.findDirectParentEventNode(loopProfileFactory); - assert parent != null - : "Direct parent does not seem to be set up properly with event node and/or wrapping"; + assert parent != null : "Direct parent does not seem to be set up properly with event node and/or wrapping"; LoopProfilingNode p = (LoopProfilingNode) parent; return new LoopIterationReportNode(p.getProfile()); }); diff --git a/src/tools/dym/nodes/OperationProfilingNode.java b/src/tools/dym/nodes/OperationProfilingNode.java index cb340e91ef..e4f7d0491b 100644 --- a/src/tools/dym/nodes/OperationProfilingNode.java +++ b/src/tools/dym/nodes/OperationProfilingNode.java @@ -55,8 +55,7 @@ protected void onReturnExceptional(final VirtualFrame frame, final Throwable e) public int registerSubexpressionAndGetIdx(final Node subExpr) { int idx = getChildIdx(subExpr); - assert idx >= 0 - : "Subexpression was not found. Something seems to be wrong with the instrumentation."; + assert idx >= 0 : "Subexpression was not found. Something seems to be wrong with the instrumentation."; return idx + 1; // + 1 is used to represent the index of the storage array used to hold the // result. Return value is at 0 index. } diff --git a/tests/java/debugger/JsonTests.java b/tests/java/debugger/JsonTests.java index a17ec3634b..04a9b63ff5 100644 --- a/tests/java/debugger/JsonTests.java +++ b/tests/java/debugger/JsonTests.java @@ -184,7 +184,8 @@ public void initializeResponseSerialize() { String result = gson.toJson(InitializationResponse.create( EntityType.values(), ActivityType.values(), PassiveEntityType.values(), DynamicScopeType.values(), SendOp.values(), ReceiveOp.values(), - BreakpointType.values(), SteppingType.values(), Implementation.values(), MessageReception.values()), + BreakpointType.values(), SteppingType.values(), Implementation.values(), + MessageReception.values()), OutgoingMessage.class); // This test is only doing a very basic sanity check assertTrue(1000 < result.length()); From 7553098e34c6f57d086f4f93cb103b5c5543f0d8 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 5 Oct 2022 00:55:58 +0100 Subject: [PATCH 104/194] Fix checkstyle issues Signed-off-by: Stefan Marr --- src/som/interpreter/SArguments.java | 42 +++++++++-------- src/som/interpreter/actors/Actor.java | 2 +- .../actors/RegisterOnPromiseNode.java | 13 ++--- .../actors/SchedulePromiseHandlerNode.java | 8 ++-- .../nodes/dispatch/CachedDispatchNode.java | 9 ++-- src/tools/concurrency/KomposTrace.java | 47 ++++++++++++------- src/tools/concurrency/TracingActors.java | 19 +++++--- src/tools/debugger/WebSocketHandler.java | 4 +- .../asyncstacktraces/ShadowStackEntry.java | 9 ++-- src/tools/debugger/frontend/RuntimeScope.java | 1 - .../debugger/message/ScopesResponse.java | 4 +- .../debugger/message/StackTraceResponse.java | 4 +- 12 files changed, 87 insertions(+), 75 deletions(-) diff --git a/src/som/interpreter/SArguments.java b/src/som/interpreter/SArguments.java index 5600d020f0..c5f1f08184 100644 --- a/src/som/interpreter/SArguments.java +++ b/src/som/interpreter/SArguments.java @@ -1,21 +1,23 @@ package som.interpreter; -import com.oracle.truffle.api.frame.Frame; - -import som.primitives.SizeAndLengthPrim; -import som.primitives.arrays.AtPrim; -import som.vm.constants.Classes; -import som.vmobjects.SArray; -import som.vmobjects.SArray.SImmutableArray; - -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import som.interpreter.nodes.ExpressionNode; +import som.primitives.SizeAndLengthPrim; +import som.primitives.arrays.AtPrim; import som.vm.VmSettings; +import som.vm.constants.Classes; +import som.vmobjects.SArray; +import som.vmobjects.SArray.SImmutableArray; import som.vmobjects.SBlock; import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; @@ -229,8 +231,8 @@ public static int getLengthWithoutShadowStack(final Object[] arguments) { } // set the resolution of the promise for the registered callback or message sent to a promise - public static void saveCausalEntryForPromise(Object previousPromiseStack, - Object currentPromiseStack) { + public static void saveCausalEntryForPromise(final Object previousPromiseStack, + final Object currentPromiseStack) { assert previousPromiseStack != null && previousPromiseStack instanceof ShadowStackEntry; assert currentPromiseStack != null && currentPromiseStack instanceof ShadowStackEntry; ((ShadowStackEntry) currentPromiseStack).setPreviousShadowStackEntry( @@ -239,8 +241,8 @@ public static void saveCausalEntryForPromise(Object previousPromiseStack, private static Map previousPromiseInGroupByActor = new HashMap<>(); - public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, - Object callbackPromiseStack, long actorId) { + public static void saveCausalEntryForPromiseGroup(final Object previousPromiseStack, + final Object callbackPromiseStack, final long actorId) { if (previousPromiseInGroupByActor != null && previousPromiseInGroupByActor.containsKey(actorId)) { ShadowStackEntry firstPromise = @@ -259,8 +261,8 @@ public static void saveCausalEntryForPromiseGroup(Object previousPromiseStack, } // group non repeated frames - private static ShadowStackEntry groupFrames(ShadowStackEntry firstPromiseStack, - ShadowStackEntry secondPromiseStack) { + private static ShadowStackEntry groupFrames(final ShadowStackEntry firstPromiseStack, + final ShadowStackEntry secondPromiseStack) { List listSecond = getAllEntries(secondPromiseStack, new ArrayList<>()); List listFirst = getAllEntries(firstPromiseStack, new ArrayList<>()); @@ -270,8 +272,8 @@ private static ShadowStackEntry groupFrames(ShadowStackEntry firstPromiseStack, return group; } - private static List getAllEntries(ShadowStackEntry stackEntry, - List list) { + private static List getAllEntries(final ShadowStackEntry stackEntry, + final List list) { if (stackEntry == null) { return list; } else { @@ -284,8 +286,8 @@ private static List getAllEntries(ShadowStackEntry stackEntry, // equal source section corresponds to the turn node, from there on the stack frames are the // same for both promises stacks private static ShadowStackEntry setNewEntryAtEqualSourceSection( - ShadowStackEntry stackEntryToAdd, List listFirst, - List listSecond) { + final ShadowStackEntry stackEntryToAdd, final List listFirst, + final List listSecond) { for (ShadowStackEntry entrySecond : listSecond) { for (ShadowStackEntry entryFirst : listFirst) { boolean entryFirstNotNull = entryFirst.getPreviousShadowStackEntry() != null @@ -300,6 +302,6 @@ private static ShadowStackEntry setNewEntryAtEqualSourceSection( } } } - return listSecond.get(0);// return top entry + return listSecond.get(0); // return top entry } } diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 23584ec8a2..9b958fa463 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -147,7 +147,7 @@ private void doSend(final EventualMessage msg, } else { appendToMailbox(msg); } - // System.out.println("doSend "+msg.getMessageId() + " actor "+this.getId()); + // so.println("doSend "+msg.getMessageId() + " actor "+this.getId()); // save messages in the trace when they are received if (VmSettings.KOMPOS_TRACING) { TracingActor.saveMessageReceived(this, msg); diff --git a/src/som/interpreter/actors/RegisterOnPromiseNode.java b/src/som/interpreter/actors/RegisterOnPromiseNode.java index 9afe43c43f..aa78c7b535 100644 --- a/src/som/interpreter/actors/RegisterOnPromiseNode.java +++ b/src/som/interpreter/actors/RegisterOnPromiseNode.java @@ -7,12 +7,11 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import som.interpreter.SArguments; import som.interpreter.actors.EventualMessage.AbstractPromiseSendMessage; import som.interpreter.actors.EventualMessage.PromiseMessage; import som.interpreter.actors.SPromise.SReplayPromise; import som.interpreter.actors.SPromise.STracingPromise; -import som.interpreter.SArguments; -import som.interpreter.actors.EventualMessage.PromiseMessage; import som.vm.VmSettings; import som.vmobjects.SBlock; import tools.debugger.asyncstacktraces.ShadowStackEntry; @@ -21,8 +20,6 @@ import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; -import java.util.concurrent.ForkJoinPool; - public abstract class RegisterOnPromiseNode { private static final AtomicLong numScheduledWhenResolved = @@ -88,7 +85,7 @@ public void register(final VirtualFrame frame, final SPromise promise, // we want to know where it was resolved, where the value is coming from for (Object obj : msg.args) { boolean promiseComplete = - (obj instanceof SPromise) && ((SPromise) promise).isCompleted(); + (obj instanceof SPromise) && promise.isCompleted(); // boolean promiseChained = (obj instanceof SPromise) && !((SPromise) // promise).isCompleted(); if (obj instanceof SBlock || promiseComplete) { @@ -110,10 +107,10 @@ public void register(final VirtualFrame frame, final SPromise promise, // assert entry != null && entry instanceof ShadowStackEntry.EntryAtMessageSend; // ShadowStackEntry shadowStackEntry = SArguments.getShadowStackEntry(frame); // - //// entry.setPreviousShadowStackEntry(shadowStackEntry); + // // entry.setPreviousShadowStackEntry(shadowStackEntry); // - // System.out.println("-register msg args: "+entry.getSourceSection()); - // System.out.println("shadow: "+shadowStackEntry.getSourceSection()); + // so.println("-register msg args: "+entry.getSourceSection()); + // so.println("shadow: "+shadowStackEntry.getSourceSection()); // assert maybeEntry != null && maybeEntry instanceof // ShadowStackEntry.EntryForPromiseResolution; diff --git a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java index 1561552394..5ef8c76f47 100644 --- a/src/som/interpreter/actors/SchedulePromiseHandlerNode.java +++ b/src/som/interpreter/actors/SchedulePromiseHandlerNode.java @@ -4,23 +4,21 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.IntValueProfile; import som.VM; +import som.interpreter.SArguments; import som.interpreter.actors.EventualMessage.PromiseCallbackMessage; import som.interpreter.actors.EventualMessage.PromiseMessage; import som.interpreter.actors.EventualMessage.PromiseSendMessage; import som.vm.VmSettings; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.replay.ReplayRecord; import tools.replay.TraceRecord; -import com.oracle.truffle.api.frame.VirtualFrame; -import som.interpreter.SArguments; -import som.vm.VmSettings; -import tools.debugger.asyncstacktraces.ShadowStackEntry; - /** * WARNING: This node needs to be used in a context that makes sure diff --git a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java index f24ab89440..4a5cbe4259 100644 --- a/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/CachedDispatchNode.java @@ -2,21 +2,20 @@ import java.util.Map; +import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.impl.DefaultCallTarget; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.InvalidAssumptionException; import som.instrumentation.CountingDirectCallNode; import som.interpreter.Invokable; import som.vm.VmSettings; -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.impl.DefaultCallTarget; -import som.interpreter.Invokable; import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; diff --git a/src/tools/concurrency/KomposTrace.java b/src/tools/concurrency/KomposTrace.java index 303648f531..0cd8922625 100644 --- a/src/tools/concurrency/KomposTrace.java +++ b/src/tools/concurrency/KomposTrace.java @@ -1,5 +1,10 @@ package tools.concurrency; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.source.SourceSection; @@ -14,9 +19,13 @@ import som.vmobjects.SInvokable; import som.vmobjects.SSymbol; import tools.debugger.PrimitiveCallOrigin; -import tools.debugger.entities.*; - -import java.util.*; +import tools.debugger.entities.ActivityType; +import tools.debugger.entities.DynamicScopeType; +import tools.debugger.entities.Implementation; +import tools.debugger.entities.MessageReception; +import tools.debugger.entities.PassiveEntityType; +import tools.debugger.entities.ReceiveOp; +import tools.debugger.entities.SendOp; public class KomposTrace { @@ -135,8 +144,8 @@ public static void promiseChained(final long promiseValueId, final long promiseI } public static void sendOperation(final SendOp op, final long entityId, - final long targetId, final SSymbol selector, long targetActorId, - SourceSection msgSourceCoordinate) { + final long targetId, final SSymbol selector, final long targetActorId, + final SourceSection msgSourceCoordinate) { TracingActivityThread t = getThread(); ((KomposTraceBuffer) t.getBuffer()).recordSendOperation(op, entityId, targetId, t.getActivity(), selector.getSymbolId(), targetActorId, msgSourceCoordinate, null); @@ -160,12 +169,13 @@ private static TracingActivityThread getThread() { return (TracingActivityThread) current; } - public static void recordSuspendedActivityByDebugger(TracingActivityThread t) { + public static void recordSuspendedActivityByDebugger(final TracingActivityThread t) { ((KomposTraceBuffer) t.getBuffer()).recordPausedActivity(t.getActivity()); } - public static void actorMessageReception(long messageId, TracingActivityThread t) { - // System.out.println("***** "+((Actor.ActorProcessingThread)t).getCurrentActor() +" + public static void actorMessageReception(final long messageId, + final TracingActivityThread t) { + // so.println("***** "+((Actor.ActorProcessingThread)t).getCurrentActor() +" // activity "+((Actor.ActorProcessingThread)t).getActivity()); Activity activity = t.getActivity(); if (activity == null) { @@ -190,7 +200,7 @@ public static void actorMessageReception(long messageId, TracingActivityThread t * @param actorId * @return */ - private static boolean messageReceivedRecorded(long messageId, long actorId) { + private static boolean messageReceivedRecorded(final long messageId, final long actorId) { List messages; if (!messagesReceivedByActor.containsKey(actorId)) { messages = new ArrayList<>(); @@ -421,8 +431,9 @@ public void recordReceiveOperation(final ReceiveOp op, final long sourceId, } public void recordSendOperation(final SendOp op, final long entityId, - final long targetId, final Activity current, final short symbolId, long targetActorId, - SourceSection msgSourceCoordinate, byte[] value) { + final long targetId, final Activity current, final short symbolId, + final long targetActorId, + final SourceSection msgSourceCoordinate, final byte[] value) { int requiredSpace; if (value == null) { requiredSpace = op.getSize(); @@ -453,7 +464,7 @@ public void recordSendOperation(final SendOp op, final long entityId, assert position == start + requiredSpace; } - public void recordMessageReceived(MessageReception mr, final Activity current, + public void recordMessageReceived(final MessageReception mr, final Activity current, final long messageId) { int requiredSpace = mr.getSize(); ensureSufficientSpace(requiredSpace, current); @@ -462,11 +473,11 @@ public void recordMessageReceived(MessageReception mr, final Activity current, put(mr.getId()); putLong(messageId); - // System.out.println("-message received "+messageId +" actor "+current.getId()); + // so.println("-message received "+messageId +" actor "+current.getId()); - if (position != start + requiredSpace) { - System.out.println(); - } + // if (position != start + requiredSpace) { + // so.println(); + // } assert position == start + requiredSpace; } @@ -517,13 +528,13 @@ public synchronized void recordReceiveOperation(final ReceiveOp op, @Override public synchronized void recordSendOperation(final SendOp op, final long entityId, final long targetId, final Activity current, final short symbol, - final long targetActorId, final SourceSection section, byte[] value) { + final long targetActorId, final SourceSection section, final byte[] value) { super.recordSendOperation(op, entityId, targetId, current, symbol, targetActorId, section, value); } @Override - public synchronized void recordMessageReceived(MessageReception mr, + public synchronized void recordMessageReceived(final MessageReception mr, final Activity current, final long messageId) { super.recordMessageReceived(mr, current, messageId); } diff --git a/src/tools/concurrency/TracingActors.java b/src/tools/concurrency/TracingActors.java index 3a9bd281b5..538054f178 100644 --- a/src/tools/concurrency/TracingActors.java +++ b/src/tools/concurrency/TracingActors.java @@ -1,6 +1,13 @@ package tools.concurrency; -import java.util.*; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.WeakHashMap; import java.util.concurrent.ForkJoinPool; import java.util.function.BiConsumer; @@ -60,11 +67,11 @@ protected TracingActor(final VM vm, final long id) { this.activityId = id; } - public static void saveMessageReceived(Actor actor, EventualMessage message) { + public static void saveMessageReceived(final Actor actor, final EventualMessage message) { TracingActivityThread tracingActivityThread = TracingBackend.getTracingActivityThread(actor.getId()); if (tracingActivityThread != null) { - // System.out.println("saveMessageReceived "+message.getMessageId() + " + // so.println("saveMessageReceived "+message.getMessageId() + " // "+actor.getId()); KomposTrace.actorMessageReception(message.getMessageId(), tracingActivityThread); } @@ -158,16 +165,16 @@ public DeserializationBuffer getDeserializationBuffer() { return null; } - public static void saveActor(Actor actor) { + public static void saveActor(final Actor actor) { allActors.put(actor.getId(), actor); } - public static Actor getActorById(long actorId) { + public static Actor getActorById(final long actorId) { return allActors.get(actorId); } /** - * Stop actor execution if they are paused to avoid open threads before system shutdown + * Stop actor execution if they are paused to avoid open threads before system shutdown. */ public static void stopActorsIfSuspended() { for (long actorId : allActors.keySet()) { diff --git a/src/tools/debugger/WebSocketHandler.java b/src/tools/debugger/WebSocketHandler.java index a111137836..d0955ab815 100644 --- a/src/tools/debugger/WebSocketHandler.java +++ b/src/tools/debugger/WebSocketHandler.java @@ -66,7 +66,7 @@ public MessageHandler(final int port, final FrontendConnector connector, final Gson gson) { super(port); this.setReuseAddr(true); - // this.setConnectionLostTimeout(0); //uncomment if timeout fails + // this.setConnectionLostTimeout(0); // uncomment if timeout fails this.connector = connector; this.gson = gson; } @@ -90,7 +90,7 @@ public static class TraceHandler extends WebSocketHandler { public TraceHandler(final int port) { super(port); this.setReuseAddr(true); - // this.setConnectionLostTimeout(0); //uncomment if timeout fails + // this.setConnectionLostTimeout(0); // uncomment if timeout fails connection = new CompletableFuture<>(); } diff --git a/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java index 8f8fdab000..20445dc44f 100644 --- a/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java +++ b/src/tools/debugger/asyncstacktraces/ShadowStackEntry.java @@ -75,7 +75,7 @@ public long getCurrentActor() { if (t instanceof ActorProcessingThread) { return EventualMessage.getActorCurrentMessageIsExecutionOn().getId(); } else { - return -1l; + return -1L; } } @@ -91,7 +91,7 @@ public boolean isAsync() { return false; } - public void setPreviousShadowStackEntry(ShadowStackEntry maybeEntry) { + public void setPreviousShadowStackEntry(final ShadowStackEntry maybeEntry) { previous = maybeEntry; } @@ -111,7 +111,7 @@ public enum ResolutionLocation { private final String label; - ResolutionLocation(String label) { + ResolutionLocation(final String label) { this.label = label; } @@ -124,7 +124,8 @@ public String getValue() { public String resolutionValue; private EntryForPromiseResolution(final ShadowStackEntry previous, - final Node expr, ResolutionLocation resolutionLocation, String resolutionValue) { + final Node expr, final ResolutionLocation resolutionLocation, + final String resolutionValue) { super(previous, expr); this.resolutionLocation = resolutionLocation; this.resolutionValue = resolutionValue; diff --git a/src/tools/debugger/frontend/RuntimeScope.java b/src/tools/debugger/frontend/RuntimeScope.java index 5302227cad..607117f92a 100644 --- a/src/tools/debugger/frontend/RuntimeScope.java +++ b/src/tools/debugger/frontend/RuntimeScope.java @@ -4,7 +4,6 @@ import som.compiler.Variable; import som.interpreter.LexicalScope.MethodScope; -import com.oracle.truffle.api.frame.Frame; public class RuntimeScope { diff --git a/src/tools/debugger/message/ScopesResponse.java b/src/tools/debugger/message/ScopesResponse.java index 806019bca9..2b78496d59 100644 --- a/src/tools/debugger/message/ScopesResponse.java +++ b/src/tools/debugger/message/ScopesResponse.java @@ -2,7 +2,6 @@ import java.util.ArrayList; -import com.oracle.truffle.api.debug.DebugStackFrame; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.nodes.RootNode; @@ -14,10 +13,9 @@ import som.interpreter.actors.ReceivedRootNode; import som.vmobjects.SBlock; import tools.TraceData; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; import tools.debugger.frontend.Suspension; import tools.debugger.message.Message.Response; -import com.oracle.truffle.api.frame.Frame; -import tools.debugger.frontend.ApplicationThreadStack.StackFrame; @SuppressWarnings("unused") diff --git a/src/tools/debugger/message/StackTraceResponse.java b/src/tools/debugger/message/StackTraceResponse.java index b9198d5bbe..9013365b43 100644 --- a/src/tools/debugger/message/StackTraceResponse.java +++ b/src/tools/debugger/message/StackTraceResponse.java @@ -11,9 +11,9 @@ import som.vm.VmSettings; import tools.TraceData; import tools.debugger.entities.EntityType; +import tools.debugger.frontend.ApplicationThreadStack; import tools.debugger.frontend.Suspension; import tools.debugger.message.Message.Response; -import tools.debugger.frontend.ApplicationThreadStack; @SuppressWarnings("unused") @@ -83,7 +83,7 @@ private static class StackFrame { /** An optional number of characters in the range. */ private final int length; - /** Indicates if the frame corresponds to an async operation */ + /** Indicates if the frame corresponds to an async operation. */ private final boolean async; StackFrame(final long globalId, final String name, final String sourceUri, From 8d820d3e35508db1760f7a6eaaf5c6b584fd6df1 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 11 Oct 2022 17:41:18 +0100 Subject: [PATCH 105/194] Fix imports Signed-off-by: Stefan Marr --- src/som/Launcher.java | 1 - src/som/compiler/MixinDefinition.java | 5 ++--- src/som/interpreter/Method.java | 2 +- src/som/interpreter/SNodeFactory.java | 2 +- .../actors/AbstractPromiseResolutionNode.java | 22 +++++++++---------- .../interpreter/actors/EventualSendNode.java | 6 ++--- .../interpreter/actors/ReceivedMessage.java | 8 +++---- .../nodes/ExceptionSignalingNode.java | 2 +- .../interpreter/nodes/InstantiationNode.java | 2 +- .../nodes/InternalObjectArrayNode.java | 2 +- .../interpreter/nodes/MessageSendNode.java | 4 ++-- .../nodes/dispatch/BlockDispatchNode.java | 2 +- .../nodes/dispatch/CachedSlotRead.java | 2 +- .../nodes/dispatch/ClassSlotAccessNode.java | 3 --- .../nodes/nary/EagerBinaryPrimitiveNode.java | 2 +- .../nodes/specialized/SomLoop.java | 4 ++-- .../transactions/CachedTxSlotRead.java | 3 ++- src/som/primitives/ActivitySpawn.java | 2 +- src/som/primitives/BlockPrims.java | 4 ++-- src/som/primitives/ExceptionsPrims.java | 4 ++-- src/som/primitives/FilePrims.java | 2 +- src/som/primitives/SystemPrims.java | 15 +++++-------- src/som/primitives/actors/PromisePrims.java | 8 +++---- src/som/primitives/arrays/AtPutPrim.java | 2 +- src/som/primitives/arrays/DoPrim.java | 2 +- .../processes/ChannelPrimitives.java | 2 +- .../primitives/transactions/AtomicPrim.java | 2 +- src/som/vm/ObjectSystem.java | 2 +- src/som/vmobjects/SInvokable.java | 3 +-- .../concurrency/TracingActivityThread.java | 1 - src/tools/concurrency/TracingBackend.java | 8 ++++--- src/tools/debugger/Tags.java | 2 ++ src/tools/debugger/WebDebugger.java | 2 +- .../asyncstacktraces/StackIterator.java | 11 +++++----- .../frontend/ApplicationThreadStack.java | 2 +- src/tools/debugger/frontend/Suspension.java | 9 ++++---- .../message/InitializeConnection.java | 2 +- .../debugger/message/PauseActorRequest.java | 1 + .../debugger/message/UpdateBreakpoint.java | 2 +- .../nodes/MessageSerializationNode.java | 2 +- tests/java/debugger/JsonTests.java | 17 ++++++++++---- 41 files changed, 91 insertions(+), 88 deletions(-) diff --git a/src/som/Launcher.java b/src/som/Launcher.java index 66654c0081..8d4db42903 100644 --- a/src/som/Launcher.java +++ b/src/som/Launcher.java @@ -10,7 +10,6 @@ import som.interpreter.SomLanguage; import som.vm.VmSettings; import tools.concurrency.TracingActors; -import tools.concurrency.TracingActors.ReplayActor; import tools.concurrency.TracingBackend; import tools.parser.KomposTraceParser; import tools.snapshot.SnapshotBackend; diff --git a/src/som/compiler/MixinDefinition.java b/src/som/compiler/MixinDefinition.java index 44c4d63025..20847c2f30 100644 --- a/src/som/compiler/MixinDefinition.java +++ b/src/som/compiler/MixinDefinition.java @@ -17,6 +17,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -32,6 +33,7 @@ import som.interpreter.LexicalScope.MethodScope; import som.interpreter.LexicalScope.MixinScope; import som.interpreter.Method; +import som.interpreter.SArguments; import som.interpreter.SNodeFactory; import som.interpreter.SomLanguage; import som.interpreter.nodes.ExceptionSignalingNode; @@ -66,9 +68,6 @@ import tools.snapshot.nodes.ObjectSerializationNodesFactory.UninitializedObjectSerializationNodeFactory; import tools.snapshot.nodes.PrimitiveSerializationNodesFactory.ClassSerializationNodeFactory; -import com.oracle.truffle.api.frame.VirtualFrame; -import som.interpreter.SArguments; - /** * Produced by a {@link MixinBuilder}, contains all static information on a diff --git a/src/som/interpreter/Method.java b/src/som/interpreter/Method.java index 46aeaff232..5611497c54 100644 --- a/src/som/interpreter/Method.java +++ b/src/som/interpreter/Method.java @@ -32,8 +32,8 @@ import som.interpreter.LexicalScope.MethodScope; import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.SOMNode; -import som.vmobjects.SInvokable; import som.interpreter.nodes.dispatch.BackCacheCallNode; +import som.vmobjects.SInvokable; public final class Method extends Invokable { diff --git a/src/som/interpreter/SNodeFactory.java b/src/som/interpreter/SNodeFactory.java index 1ac835ca3a..d09705acc3 100644 --- a/src/som/interpreter/SNodeFactory.java +++ b/src/som/interpreter/SNodeFactory.java @@ -13,8 +13,8 @@ import som.interpreter.actors.EventualSendNode; import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.InternalObjectArrayNode; -import som.interpreter.nodes.MessageSendNode; import som.interpreter.nodes.InternalObjectArrayNode.ArgumentEvaluationNode; +import som.interpreter.nodes.MessageSendNode; import som.interpreter.nodes.OuterObjectReadNodeGen; import som.interpreter.nodes.ResolvingImplicitReceiverSend; import som.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode; diff --git a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java index c334d41575..6310a6109c 100644 --- a/src/som/interpreter/actors/AbstractPromiseResolutionNode.java +++ b/src/som/interpreter/actors/AbstractPromiseResolutionNode.java @@ -3,6 +3,8 @@ import java.util.concurrent.ForkJoinPool; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.NodeChildren; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.GenerateWrapper; @@ -17,23 +19,19 @@ import som.interpreter.actors.SPromise.SReplayPromise; import som.interpreter.actors.SPromise.SResolver; import som.interpreter.actors.SPromise.STracingPromise; -import som.interpreter.nodes.nary.QuaternaryExpressionNode; +import som.interpreter.nodes.ExpressionNode; +import som.interpreter.nodes.nary.EagerPrimitiveNode; +import som.interpreter.nodes.nary.EagerlySpecializableNode; import som.interpreter.nodes.nary.UnaryExpressionNode; +import som.vm.NotYetImplementedException; import som.vm.VmSettings; +import som.vmobjects.SSymbol; import tools.concurrency.KomposTrace; import tools.concurrency.TracingActivityThread; import tools.replay.ReplayRecord; import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.NodeChildren; -import som.interpreter.nodes.ExpressionNode; -import som.interpreter.nodes.nary.EagerPrimitiveNode; -import som.interpreter.nodes.nary.EagerlySpecializableNode; -import som.vm.NotYetImplementedException; -import som.vmobjects.SSymbol; - @GenerateWrapper @NodeChildren({ @@ -182,7 +180,7 @@ protected void chainPromise(final VirtualFrame frame, final SResolver resolver, protected void resolvePromise(final Resolution type, final SResolver resolver, final Object result, final Object maybeEntry, - final boolean haltOnResolution, final VirtualFrame frame, Node expression) { + final boolean haltOnResolution, final VirtualFrame frame, final Node expression) { SPromise promise = resolver.getPromise(); Actor current = EventualMessage.getActorCurrentMessageIsExecutionOn(); @@ -194,9 +192,9 @@ protected void resolvePromise(final Resolution type, public static void resolve(final Resolution type, final WrapReferenceNode wrapper, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, - Object maybeEntry, + final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile, - final VirtualFrame frame, Node expression, + final VirtualFrame frame, final Node expression, final RecordOneEvent tracePromiseResolution2, final RecordOneEvent tracePromiseResolutionEnd2) { Object wrapped = wrapper.execute(result, promise.owner, current); diff --git a/src/som/interpreter/actors/EventualSendNode.java b/src/som/interpreter/actors/EventualSendNode.java index 1abc49255b..465471f6ba 100644 --- a/src/som/interpreter/actors/EventualSendNode.java +++ b/src/som/interpreter/actors/EventualSendNode.java @@ -19,6 +19,7 @@ import com.oracle.truffle.api.source.SourceSection; import som.VM; +import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.interpreter.actors.EventualMessage.DirectMessage; import som.interpreter.actors.EventualMessage.PromiseSendMessage; @@ -27,6 +28,7 @@ import som.interpreter.actors.RegisterOnPromiseNode.RegisterWhenResolved; import som.interpreter.actors.SPromise.SResolver; import som.interpreter.nodes.ExpressionNode; +import som.interpreter.nodes.InternalObjectArrayNode.ArgumentEvaluationNode; import som.interpreter.nodes.MessageSendNode; import som.interpreter.nodes.MessageSendNode.AbstractMessageSendNode; import som.interpreter.nodes.SOMNode; @@ -37,12 +39,10 @@ import tools.concurrency.KomposTrace; import tools.concurrency.Tags.EventualMessageSend; import tools.concurrency.Tags.ExpressionBreakpoint; +import tools.debugger.breakpoints.Breakpoints; import tools.debugger.entities.BreakpointType; import tools.debugger.entities.SendOp; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.breakpoints.Breakpoints; -import som.interpreter.SArguments; -import som.interpreter.nodes.InternalObjectArrayNode.ArgumentEvaluationNode; import tools.dym.DynamicMetrics; import tools.replay.ReplayRecord; import tools.replay.TraceRecord; diff --git a/src/som/interpreter/actors/ReceivedMessage.java b/src/som/interpreter/actors/ReceivedMessage.java index 66e9b3f6cf..592835c334 100644 --- a/src/som/interpreter/actors/ReceivedMessage.java +++ b/src/som/interpreter/actors/ReceivedMessage.java @@ -8,15 +8,15 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.source.SourceSection; -import som.interpreter.SomException; -import som.interpreter.SomLanguage; -import som.interpreter.nodes.MessageSendNode.AbstractMessageSendNode; -import som.vmobjects.SSymbol; import som.interpreter.Invokable; import som.interpreter.SArguments; +import som.interpreter.SomException; +import som.interpreter.SomLanguage; import som.interpreter.nodes.ExpressionNode; +import som.interpreter.nodes.MessageSendNode.AbstractMessageSendNode; import som.vm.VmSettings; import som.vmobjects.SInvokable; +import som.vmobjects.SSymbol; import tools.debugger.asyncstacktraces.ShadowStackEntry; diff --git a/src/som/interpreter/nodes/ExceptionSignalingNode.java b/src/som/interpreter/nodes/ExceptionSignalingNode.java index ceedac7be8..413875f068 100644 --- a/src/som/interpreter/nodes/ExceptionSignalingNode.java +++ b/src/som/interpreter/nodes/ExceptionSignalingNode.java @@ -3,6 +3,7 @@ import java.util.function.Supplier; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.SourceSection; @@ -12,7 +13,6 @@ import som.vmobjects.SClass; import som.vmobjects.SObject; import som.vmobjects.SSymbol; -import com.oracle.truffle.api.frame.VirtualFrame; public abstract class ExceptionSignalingNode extends Node { diff --git a/src/som/interpreter/nodes/InstantiationNode.java b/src/som/interpreter/nodes/InstantiationNode.java index 3209db9595..0d7a9ebe2a 100644 --- a/src/som/interpreter/nodes/InstantiationNode.java +++ b/src/som/interpreter/nodes/InstantiationNode.java @@ -3,6 +3,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import som.compiler.MixinDefinition; @@ -12,7 +13,6 @@ import som.vmobjects.SClass; import som.vmobjects.SObjectWithClass; import tools.snapshot.nodes.ObjectSerializationNodesFactory.UninitializedObjectSerializationNodeFactory; -import com.oracle.truffle.api.frame.VirtualFrame; public abstract class InstantiationNode extends Node { diff --git a/src/som/interpreter/nodes/InternalObjectArrayNode.java b/src/som/interpreter/nodes/InternalObjectArrayNode.java index 647bd74f41..0a19bdd0b2 100644 --- a/src/som/interpreter/nodes/InternalObjectArrayNode.java +++ b/src/som/interpreter/nodes/InternalObjectArrayNode.java @@ -5,8 +5,8 @@ import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; -import som.interpreter.nodes.nary.ExprWithTagsNode; import som.interpreter.SArguments; +import som.interpreter.nodes.nary.ExprWithTagsNode; import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; diff --git a/src/som/interpreter/nodes/MessageSendNode.java b/src/som/interpreter/nodes/MessageSendNode.java index 5970eea07e..c5acd5fe93 100644 --- a/src/som/interpreter/nodes/MessageSendNode.java +++ b/src/som/interpreter/nodes/MessageSendNode.java @@ -24,6 +24,7 @@ import som.VM; import som.compiler.AccessModifier; import som.interpreter.Invokable; +import som.interpreter.SArguments; import som.interpreter.TruffleCompiler; import som.interpreter.actors.ReceivedMessage; import som.interpreter.nodes.dispatch.AbstractDispatchNode; @@ -36,10 +37,9 @@ import som.vm.NotYetImplementedException; import som.vm.Primitives; import som.vmobjects.SSymbol; +import tools.debugger.asyncstacktraces.ShadowStackEntry; import tools.dym.Tags.VirtualInvoke; import tools.dym.profiles.DispatchProfile; -import som.interpreter.SArguments; -import tools.debugger.asyncstacktraces.ShadowStackEntry; public final class MessageSendNode { diff --git a/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java b/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java index ee779f4ce8..a7dff3f020 100644 --- a/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/BlockDispatchNode.java @@ -12,9 +12,9 @@ import com.oracle.truffle.api.nodes.RootNode; import som.interpreter.Invokable; +import som.vm.VmSettings; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; -import som.vm.VmSettings; public abstract class BlockDispatchNode extends Node { diff --git a/src/som/interpreter/nodes/dispatch/CachedSlotRead.java b/src/som/interpreter/nodes/dispatch/CachedSlotRead.java index b4fa94de9d..c0590c17bf 100644 --- a/src/som/interpreter/nodes/dispatch/CachedSlotRead.java +++ b/src/som/interpreter/nodes/dispatch/CachedSlotRead.java @@ -11,6 +11,7 @@ import com.oracle.truffle.api.profiles.IntValueProfile; import som.interpreter.Invokable; +import som.interpreter.SArguments; import som.interpreter.nodes.dispatch.DispatchGuard.CheckSObject; import som.interpreter.objectstorage.StorageAccessor.AbstractObjectAccessor; import som.interpreter.objectstorage.StorageAccessor.AbstractPrimitiveAccessor; @@ -18,7 +19,6 @@ import som.vmobjects.SObject; import tools.dym.Tags.ClassRead; import tools.dym.Tags.FieldRead; -import som.interpreter.SArguments; /** diff --git a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java index 7879b22ed4..a556131cab 100644 --- a/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java +++ b/src/som/interpreter/nodes/dispatch/ClassSlotAccessNode.java @@ -19,9 +19,6 @@ import som.vm.constants.Nil; import som.vmobjects.SClass; import som.vmobjects.SObject; -import com.oracle.truffle.api.frame.VirtualFrame; -import som.interpreter.SArguments; -import som.vm.VmSettings; import tools.debugger.asyncstacktraces.ShadowStackEntry; diff --git a/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java b/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java index be5ee3e3da..4a5b06a08f 100644 --- a/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java +++ b/src/som/interpreter/nodes/nary/EagerBinaryPrimitiveNode.java @@ -10,8 +10,8 @@ import som.interpreter.nodes.MessageSendNode; import som.interpreter.nodes.MessageSendNode.GenericMessageSendNode; import som.vm.NotYetImplementedException; -import som.vmobjects.SSymbol; import som.vm.VmSettings; +import som.vmobjects.SSymbol; public final class EagerBinaryPrimitiveNode extends EagerPrimitiveNode { diff --git a/src/som/interpreter/nodes/specialized/SomLoop.java b/src/som/interpreter/nodes/specialized/SomLoop.java index 9130aab158..781ab1ad91 100644 --- a/src/som/interpreter/nodes/specialized/SomLoop.java +++ b/src/som/interpreter/nodes/specialized/SomLoop.java @@ -1,11 +1,11 @@ package som.interpreter.nodes.specialized; -import som.interpreter.Invokable; - import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; +import som.interpreter.Invokable; + public abstract class SomLoop { diff --git a/src/som/interpreter/transactions/CachedTxSlotRead.java b/src/som/interpreter/transactions/CachedTxSlotRead.java index 7f1e06d747..3a2af5386b 100644 --- a/src/som/interpreter/transactions/CachedTxSlotRead.java +++ b/src/som/interpreter/transactions/CachedTxSlotRead.java @@ -1,11 +1,12 @@ package som.interpreter.transactions; +import com.oracle.truffle.api.frame.VirtualFrame; + import som.interpreter.nodes.dispatch.AbstractDispatchNode; import som.interpreter.nodes.dispatch.CachedSlotRead; import som.interpreter.nodes.dispatch.DispatchGuard.CheckSObject; import som.vmobjects.SObject; import som.vmobjects.SObject.SMutableObject; -import com.oracle.truffle.api.frame.VirtualFrame; public final class CachedTxSlotRead extends CachedSlotRead { diff --git a/src/som/primitives/ActivitySpawn.java b/src/som/primitives/ActivitySpawn.java index dcefd16298..05baa9cbe3 100644 --- a/src/som/primitives/ActivitySpawn.java +++ b/src/som/primitives/ActivitySpawn.java @@ -45,10 +45,10 @@ import tools.concurrency.KomposTrace; import tools.concurrency.Tags.ActivityCreation; import tools.concurrency.Tags.ExpressionBreakpoint; +import tools.debugger.breakpoints.Breakpoints; import tools.debugger.entities.ActivityType; import tools.debugger.entities.BreakpointType; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.breakpoints.Breakpoints; import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; diff --git a/src/som/primitives/BlockPrims.java b/src/som/primitives/BlockPrims.java index 8f0a82623f..ae4f793a25 100644 --- a/src/som/primitives/BlockPrims.java +++ b/src/som/primitives/BlockPrims.java @@ -10,6 +10,7 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; @@ -31,10 +32,9 @@ import som.vmobjects.SArray; import som.vmobjects.SBlock; import som.vmobjects.SInvokable; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; import tools.dym.Tags.OpClosureApplication; import tools.dym.profiles.DispatchProfile; -import com.oracle.truffle.api.frame.VirtualFrame; -import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public abstract class BlockPrims { diff --git a/src/som/primitives/ExceptionsPrims.java b/src/som/primitives/ExceptionsPrims.java index fab2659e56..a3c2c56272 100644 --- a/src/som/primitives/ExceptionsPrims.java +++ b/src/som/primitives/ExceptionsPrims.java @@ -4,10 +4,12 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import bd.primitives.Primitive; +import som.interpreter.SArguments; import som.interpreter.SomException; import som.interpreter.nodes.dispatch.BlockDispatchNode; import som.interpreter.nodes.dispatch.BlockDispatchNodeGen; @@ -19,8 +21,6 @@ import som.vmobjects.SBlock; import som.vmobjects.SClass; import som.vmobjects.SInvokable; -import com.oracle.truffle.api.frame.VirtualFrame; -import som.interpreter.SArguments; import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; diff --git a/src/som/primitives/FilePrims.java b/src/som/primitives/FilePrims.java index e6b21b8fc4..586a1940b5 100644 --- a/src/som/primitives/FilePrims.java +++ b/src/som/primitives/FilePrims.java @@ -7,6 +7,7 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.source.SourceSection; @@ -28,7 +29,6 @@ import som.vmobjects.SClass; import som.vmobjects.SFileDescriptor; import som.vmobjects.SSymbol; -import com.oracle.truffle.api.frame.VirtualFrame; public final class FilePrims { diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index 38d70a066f..d8959a4810 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -7,16 +7,16 @@ import java.io.IOException; import java.net.URI; import java.util.ArrayList; +import java.util.Arrays; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; @@ -59,6 +59,10 @@ import som.vmobjects.SSymbol; import tools.concurrency.TracingActors.TracingActor; import tools.concurrency.TracingBackend; +import tools.debugger.asyncstacktraces.ShadowStackEntry; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.asyncstacktraces.StackIterator; +import tools.debugger.frontend.ApplicationThreadStack.StackFrame; import tools.dym.Tags.BasicPrimitiveOperation; import tools.replay.actors.UniformExecutionTrace; import tools.replay.nodes.TraceContextNode; @@ -67,13 +71,6 @@ import tools.snapshot.SnapshotBuffer; import tools.snapshot.deserialization.DeserializationBuffer; -import java.util.Arrays; -import com.oracle.truffle.api.frame.VirtualFrame; -import tools.debugger.asyncstacktraces.ShadowStackEntry; -import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; -import tools.debugger.asyncstacktraces.StackIterator; -import tools.debugger.frontend.ApplicationThreadStack.StackFrame; - public final class SystemPrims { diff --git a/src/som/primitives/actors/PromisePrims.java b/src/som/primitives/actors/PromisePrims.java index 1cdc1c88a0..2695015900 100644 --- a/src/som/primitives/actors/PromisePrims.java +++ b/src/som/primitives/actors/PromisePrims.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -17,6 +18,7 @@ import bd.tools.nodes.Operation; import som.VM; import som.compiler.AccessModifier; +import som.interpreter.SArguments; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage; import som.interpreter.actors.EventualMessage.PromiseCallbackMessage; @@ -42,13 +44,11 @@ import tools.concurrency.Tags.OnError; import tools.concurrency.Tags.WhenResolved; import tools.concurrency.Tags.WhenResolvedOnError; +import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; +import tools.debugger.breakpoints.Breakpoints; import tools.debugger.entities.BreakpointType; import tools.debugger.entities.SendOp; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.breakpoints.Breakpoints; -import com.oracle.truffle.api.frame.VirtualFrame; -import som.interpreter.SArguments; -import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; public final class PromisePrims { diff --git a/src/som/primitives/arrays/AtPutPrim.java b/src/som/primitives/arrays/AtPutPrim.java index 70795edb8a..8491804e8e 100644 --- a/src/som/primitives/arrays/AtPutPrim.java +++ b/src/som/primitives/arrays/AtPutPrim.java @@ -6,6 +6,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; @@ -29,7 +30,6 @@ import som.vmobjects.SSymbol; import tools.dym.Tags.ArrayWrite; import tools.dym.Tags.BasicPrimitiveOperation; -import com.oracle.truffle.api.frame.VirtualFrame; @GenerateNodeFactory diff --git a/src/som/primitives/arrays/DoPrim.java b/src/som/primitives/arrays/DoPrim.java index 33cabf0e24..99fc00bcc4 100644 --- a/src/som/primitives/arrays/DoPrim.java +++ b/src/som/primitives/arrays/DoPrim.java @@ -3,9 +3,9 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import bd.primitives.Primitive; -import com.oracle.truffle.api.frame.VirtualFrame; import som.interpreter.SArguments; import som.interpreter.nodes.ExpressionNode; import som.interpreter.nodes.dispatch.BlockDispatchNode; diff --git a/src/som/primitives/processes/ChannelPrimitives.java b/src/som/primitives/processes/ChannelPrimitives.java index 75c0ddec44..ef288090f4 100644 --- a/src/som/primitives/processes/ChannelPrimitives.java +++ b/src/som/primitives/processes/ChannelPrimitives.java @@ -40,11 +40,11 @@ import tools.concurrency.Tags.ExpressionBreakpoint; import tools.concurrency.TracingActivityThread; import tools.debugger.WebDebugger; +import tools.debugger.breakpoints.Breakpoints; import tools.debugger.entities.ActivityType; import tools.debugger.entities.BreakpointType; import tools.debugger.entities.PassiveEntityType; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.breakpoints.Breakpoints; import tools.replay.ReplayRecord; import tools.replay.TraceParser; import tools.replay.TraceRecord; diff --git a/src/som/primitives/transactions/AtomicPrim.java b/src/som/primitives/transactions/AtomicPrim.java index 5ed827a8f3..39994b00c1 100644 --- a/src/som/primitives/transactions/AtomicPrim.java +++ b/src/som/primitives/transactions/AtomicPrim.java @@ -18,11 +18,11 @@ import tools.concurrency.Tags.Atomic; import tools.concurrency.Tags.ExpressionBreakpoint; import tools.concurrency.TracingActivityThread; +import tools.debugger.breakpoints.Breakpoints; import tools.debugger.entities.BreakpointType; import tools.debugger.entities.EntityType; import tools.debugger.entities.SteppingType; import tools.debugger.nodes.AbstractBreakpointNode; -import tools.debugger.breakpoints.Breakpoints; import tools.replay.TraceRecord; import tools.replay.nodes.RecordEventNodes.RecordOneEvent; diff --git a/src/som/vm/ObjectSystem.java b/src/som/vm/ObjectSystem.java index cf5e7aa771..139700653c 100644 --- a/src/som/vm/ObjectSystem.java +++ b/src/som/vm/ObjectSystem.java @@ -30,6 +30,7 @@ import som.compiler.SourcecodeCompiler; import som.compiler.Variable; import som.interpreter.LexicalScope.MixinScope; +import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage.DirectMessage; @@ -64,7 +65,6 @@ import tools.snapshot.nodes.PrimitiveSerializationNodesFactory.SymbolSerializationNodeFactory; import tools.snapshot.nodes.PrimitiveSerializationNodesFactory.TrueSerializationNodeFactory; import tools.snapshot.nodes.SerializerRootNode; -import som.interpreter.SArguments; public final class ObjectSystem { diff --git a/src/som/vmobjects/SInvokable.java b/src/som/vmobjects/SInvokable.java index e34cf359d7..d466a5dfe1 100644 --- a/src/som/vmobjects/SInvokable.java +++ b/src/som/vmobjects/SInvokable.java @@ -44,11 +44,10 @@ import som.interpreter.nodes.dispatch.CachedDispatchNode; import som.interpreter.nodes.dispatch.DispatchGuard; import som.interpreter.nodes.dispatch.Dispatchable; -import som.interpreter.nodes.dispatch.LexicallyBoundDispatchNode; +import som.interpreter.nodes.dispatch.LexicallyBoundDispatchNodeGen; import som.vm.Symbols; import som.vm.VmSettings; import som.vm.constants.Classes; -import som.interpreter.nodes.dispatch.LexicallyBoundDispatchNodeGen; public class SInvokable extends SAbstractObject implements Dispatchable { diff --git a/src/tools/concurrency/TracingActivityThread.java b/src/tools/concurrency/TracingActivityThread.java index d476b04523..2f1463137b 100644 --- a/src/tools/concurrency/TracingActivityThread.java +++ b/src/tools/concurrency/TracingActivityThread.java @@ -1,7 +1,6 @@ package tools.concurrency; import java.util.ArrayList; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/tools/concurrency/TracingBackend.java b/src/tools/concurrency/TracingBackend.java index 65d8b9bbcd..7ea551022b 100644 --- a/src/tools/concurrency/TracingBackend.java +++ b/src/tools/concurrency/TracingBackend.java @@ -12,7 +12,10 @@ import java.lang.management.MemoryType; import java.lang.management.MemoryUsage; import java.nio.ByteBuffer; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; @@ -27,7 +30,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.sun.management.GarbageCollectionNotificationInfo; -import som.Output; import som.interpreter.actors.Actor; import som.interpreter.actors.Actor.ActorProcessingThread; import som.vm.VmSettings; @@ -246,7 +248,7 @@ public static void unregisterThread(final TracingActivityThread t) { } } - public static TracingActivityThread getTracingActivityThread(long actorId) { + public static TracingActivityThread getTracingActivityThread(final long actorId) { synchronized (tracingThreads) { TracingActivityThread[] result = tracingThreads.toArray(new TracingActivityThread[0]); for (TracingActivityThread tracingActivityThread : result) { diff --git a/src/tools/debugger/Tags.java b/src/tools/debugger/Tags.java index 69fd083e85..82dcedf6aa 100644 --- a/src/tools/debugger/Tags.java +++ b/src/tools/debugger/Tags.java @@ -24,6 +24,8 @@ import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.source.SourceSection; +import som.VM; + public abstract class Tags { private Tags() {} diff --git a/src/tools/debugger/WebDebugger.java b/src/tools/debugger/WebDebugger.java index c3fdc7ddab..4670c45ecc 100644 --- a/src/tools/debugger/WebDebugger.java +++ b/src/tools/debugger/WebDebugger.java @@ -31,8 +31,8 @@ import tools.TraceData; import tools.concurrency.TracingActivityThread; import tools.concurrency.TracingActors; -import tools.debugger.frontend.Suspension; import tools.debugger.breakpoints.Breakpoints; +import tools.debugger.frontend.Suspension; /** diff --git a/src/tools/debugger/asyncstacktraces/StackIterator.java b/src/tools/debugger/asyncstacktraces/StackIterator.java index e00986705d..6ecab93196 100644 --- a/src/tools/debugger/asyncstacktraces/StackIterator.java +++ b/src/tools/debugger/asyncstacktraces/StackIterator.java @@ -1,5 +1,10 @@ package tools.debugger.asyncstacktraces; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.debug.DebugStackFrame; @@ -10,6 +15,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; + import som.interpreter.Invokable; import som.interpreter.Method; import som.interpreter.actors.EventualSendNode; @@ -21,11 +27,6 @@ import tools.debugger.asyncstacktraces.StackIterator.ShadowStackIterator.SuspensionShadowStackIterator; import tools.debugger.frontend.ApplicationThreadStack.StackFrame; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - /** * This iterator traverses the run time stack and all available calling context diff --git a/src/tools/debugger/frontend/ApplicationThreadStack.java b/src/tools/debugger/frontend/ApplicationThreadStack.java index 393da8837f..079d6c571b 100644 --- a/src/tools/debugger/frontend/ApplicationThreadStack.java +++ b/src/tools/debugger/frontend/ApplicationThreadStack.java @@ -7,9 +7,9 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; -import tools.debugger.asyncstacktraces.StackIterator; import som.interpreter.LexicalScope.MethodScope; +import tools.debugger.asyncstacktraces.StackIterator; /** diff --git a/src/tools/debugger/frontend/Suspension.java b/src/tools/debugger/frontend/Suspension.java index 6c3816c85c..c8634b52fd 100644 --- a/src/tools/debugger/frontend/Suspension.java +++ b/src/tools/debugger/frontend/Suspension.java @@ -1,11 +1,14 @@ package tools.debugger.frontend; +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; + import com.oracle.truffle.api.debug.SuspendedEvent; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; + import som.interpreter.LexicalScope.MethodScope; -import som.interpreter.Method; import som.interpreter.actors.Actor; import som.interpreter.actors.EventualMessage; import som.interpreter.actors.SPromise.SResolver; @@ -25,10 +28,6 @@ import tools.debugger.frontend.ApplicationThreadTask.SendStackTrace; import tools.debugger.message.VariablesRequest.FilterType; -import java.util.ArrayList; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.CompletableFuture; - /** * Suspension controls the interaction between the debugger front-end and the diff --git a/src/tools/debugger/message/InitializeConnection.java b/src/tools/debugger/message/InitializeConnection.java index 8b9effa95d..cd1619c655 100644 --- a/src/tools/debugger/message/InitializeConnection.java +++ b/src/tools/debugger/message/InitializeConnection.java @@ -3,8 +3,8 @@ import org.java_websocket.WebSocket; import tools.debugger.FrontendConnector; -import tools.debugger.message.Message.IncommingMessage; import tools.debugger.breakpoints.BreakpointInfo; +import tools.debugger.message.Message.IncommingMessage; public class InitializeConnection extends IncommingMessage { diff --git a/src/tools/debugger/message/PauseActorRequest.java b/src/tools/debugger/message/PauseActorRequest.java index 28f7149c03..342e3803ea 100644 --- a/src/tools/debugger/message/PauseActorRequest.java +++ b/src/tools/debugger/message/PauseActorRequest.java @@ -1,6 +1,7 @@ package tools.debugger.message; import org.java_websocket.WebSocket; + import som.interpreter.actors.Actor; import tools.debugger.FrontendConnector; diff --git a/src/tools/debugger/message/UpdateBreakpoint.java b/src/tools/debugger/message/UpdateBreakpoint.java index a70c0fda08..1aafe4c689 100644 --- a/src/tools/debugger/message/UpdateBreakpoint.java +++ b/src/tools/debugger/message/UpdateBreakpoint.java @@ -3,8 +3,8 @@ import org.java_websocket.WebSocket; import tools.debugger.FrontendConnector; -import tools.debugger.message.Message.IncommingMessage; import tools.debugger.breakpoints.BreakpointInfo; +import tools.debugger.message.Message.IncommingMessage; public class UpdateBreakpoint extends IncommingMessage { diff --git a/src/tools/snapshot/nodes/MessageSerializationNode.java b/src/tools/snapshot/nodes/MessageSerializationNode.java index 57d1566719..b68d25c36e 100644 --- a/src/tools/snapshot/nodes/MessageSerializationNode.java +++ b/src/tools/snapshot/nodes/MessageSerializationNode.java @@ -5,6 +5,7 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.interpreter.Types; import som.interpreter.actors.Actor; @@ -27,7 +28,6 @@ import tools.snapshot.SnapshotBuffer; import tools.snapshot.deserialization.DeserializationBuffer; import tools.snapshot.deserialization.FixupInformation; -import som.interpreter.SArguments; @GenerateNodeFactory diff --git a/tests/java/debugger/JsonTests.java b/tests/java/debugger/JsonTests.java index 04a9b63ff5..188a8316b3 100644 --- a/tests/java/debugger/JsonTests.java +++ b/tests/java/debugger/JsonTests.java @@ -17,15 +17,24 @@ import bd.source.FullSourceCoordinate; import bd.source.SourceCoordinate; import tools.debugger.RuntimeReflectionRegistration; -import tools.debugger.entities.*; +import tools.debugger.breakpoints.BreakpointInfo; +import tools.debugger.breakpoints.LineBreakpoint; +import tools.debugger.breakpoints.SectionBreakpoint; +import tools.debugger.entities.ActivityType; +import tools.debugger.entities.BreakpointType; +import tools.debugger.entities.DynamicScopeType; +import tools.debugger.entities.EntityType; +import tools.debugger.entities.Implementation; +import tools.debugger.entities.MessageReception; +import tools.debugger.entities.PassiveEntityType; +import tools.debugger.entities.ReceiveOp; +import tools.debugger.entities.SendOp; +import tools.debugger.entities.SteppingType; import tools.debugger.message.InitializationResponse; import tools.debugger.message.InitializeConnection; import tools.debugger.message.Message.IncommingMessage; import tools.debugger.message.Message.OutgoingMessage; import tools.debugger.message.UpdateBreakpoint; -import tools.debugger.breakpoints.BreakpointInfo; -import tools.debugger.breakpoints.LineBreakpoint; -import tools.debugger.breakpoints.SectionBreakpoint; public class JsonTests { From 322f7574bcc4559fdbbb8d3a146f9f968db1a12a Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 12 Oct 2022 23:13:39 +0100 Subject: [PATCH 106/194] Update number of classes, was changed to add support for some debugger commands Signed-off-by: Stefan Marr --- tests/java/debugger/ReflectionRegistrationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/java/debugger/ReflectionRegistrationTests.java b/tests/java/debugger/ReflectionRegistrationTests.java index ce2bffa9bd..3be5b4e5c9 100644 --- a/tests/java/debugger/ReflectionRegistrationTests.java +++ b/tests/java/debugger/ReflectionRegistrationTests.java @@ -17,6 +17,6 @@ public void runtimeRegistration() { rrr.beforeAnalysis(null); HashSet> registeredClasses = rrr.getRegisteredClasses(); - assertEquals(56, registeredClasses.size()); + assertEquals(59, registeredClasses.size()); } } From 7ba86b6f42fa1b04392d796e3135b2de109b9417 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 12 Oct 2022 23:14:05 +0100 Subject: [PATCH 107/194] Remove duplicate safepoint unregister, might be a rebase bug Signed-off-by: Stefan Marr --- src/som/interpreter/actors/Actor.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/som/interpreter/actors/Actor.java b/src/som/interpreter/actors/Actor.java index 9b958fa463..50c3f6ea10 100644 --- a/src/som/interpreter/actors/Actor.java +++ b/src/som/interpreter/actors/Actor.java @@ -252,13 +252,9 @@ private void doRunWithObjectSafepoints(final ActorProcessingThread t) { KomposTrace.currentActivity(actor); } - try { - while (getCurrentMessagesOrCompleteExecution()) { - saveReceivedMessages(t); - processCurrentMessages(t, dbg); - } - } finally { - ObjectTransitionSafepoint.INSTANCE.unregister(); + while (getCurrentMessagesOrCompleteExecution()) { + saveReceivedMessages(t); + processCurrentMessages(t, dbg); } if (VmSettings.UNIFORM_TRACING || VmSettings.KOMPOS_TRACING) { From 113bd5b1f7c7e485e3413078c39d4d83ae7bb025 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 12 Oct 2022 23:14:29 +0100 Subject: [PATCH 108/194] Add -Dpolyglot.engine.WarnInterpreterOnly=false to launch config Signed-off-by: Stefan Marr --- .settings/SOMns-tests.launch | 40 ++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/.settings/SOMns-tests.launch b/.settings/SOMns-tests.launch index b744733820..b898f7e828 100644 --- a/.settings/SOMns-tests.launch +++ b/.settings/SOMns-tests.launch @@ -1,21 +1,25 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + From fb5c701bfbaac6ae2c8fae4d260dd288da8d601d Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 12 Oct 2022 23:34:36 +0100 Subject: [PATCH 109/194] Fix guard to take frame so that it is not just asserted but actually checked The TruffleDSL will try to avoid checking simple guards that are not expected to change. Signed-off-by: Stefan Marr --- .../dispatch/LexicallyBoundDispatchNode.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java index 64e1da22be..ef120bf0ef 100644 --- a/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java +++ b/src/som/interpreter/nodes/dispatch/LexicallyBoundDispatchNode.java @@ -2,22 +2,21 @@ import java.util.Map; +import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.impl.DefaultCallTarget; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.source.SourceSection; import som.instrumentation.CountingDirectCallNode; import som.interpreter.Invokable; -import som.vm.VmSettings; - -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.impl.DefaultCallTarget; import som.interpreter.Method; +import som.vm.VmSettings; import tools.debugger.asyncstacktraces.ShadowStackEntryLoad; @@ -56,6 +55,10 @@ public void makeMultipleCaller() { stillUniqueCaller.invalidate(); } + public boolean isUniqueCaller(final VirtualFrame frame) { + return uniqueCaller; + } + @Override public Method getCachedMethod() { RootCallTarget ct = (DefaultCallTarget) cachedMethod.getCallTarget(); @@ -65,14 +68,14 @@ public Method getCachedMethod() { @Override public abstract Object executeDispatch(VirtualFrame frame, Object[] arguments); - @Specialization(assumptions = "stillUniqueCaller", guards = "uniqueCaller") + @Specialization(assumptions = "stillUniqueCaller", guards = "isUniqueCaller(frame)") public Object uniqueCallerDispatch(final VirtualFrame frame, final Object[] arguments) { BackCacheCallNode.setShadowStackEntry(frame, true, arguments, this, shadowStackEntryLoad); return cachedMethod.call(arguments); } - @Specialization(guards = "!uniqueCaller") + @Specialization(guards = "!isUniqueCaller(frame)") public Object multipleCallerDispatch(final VirtualFrame frame, final Object[] arguments) { BackCacheCallNode.setShadowStackEntry(frame, false, arguments, this, shadowStackEntryLoad); From 7b1b8fd6f360c130810f933b4717c7a9d42050ec Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 00:15:46 +0100 Subject: [PATCH 110/194] Revert "Extend loadModule to accept internal files" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cf6babd72cc44d00dfa8e08f1aef2b2dde0b86cf. This seems to be problematic. I don’t really understand what this is for, but it breaks tests with ant. Signed-off-by: Stefan Marr --- src/som/primitives/SystemPrims.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index d8959a4810..f560fae364 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -162,12 +162,7 @@ private static Object loadModule(final VM vm, final String path) throws IOExcept if (path.endsWith(EXTENSION_EXT)) { return vm.loadExtensionModule(path); } else { - String modulePath = path; - if (path.startsWith("core-lib")) { - String classPath = System.getProperty("java.class.path").split("build")[0]; - modulePath = classPath.concat(path); - } - MixinDefinition module = vm.loadModule(modulePath); + MixinDefinition module = vm.loadModule(path); return module.instantiateModuleClass(); } } @@ -209,15 +204,6 @@ public final Object load(final VirtualFrame frame, final String filename, final SObjectWithClass moduleObj) { String path = moduleObj.getSOMClass().getMixinDefinition().getSourceSection().getSource() .getPath(); - - if (filename.startsWith("src")) { - path = path.split("test")[0].concat("test"); - } - - if (filename.startsWith("core-lib")) { - return loadModule(frame, vm, filename, ioException); - } - File file = new File(URI.create(path).getPath()); return loadModule(frame, vm, file.getParent() + File.separator + filename, ioException); From 8a8f68d1535147c292c11888f808c357ac304047 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 02:04:52 +0100 Subject: [PATCH 111/194] Add missing transfer and invalidate Signed-off-by: Stefan Marr --- src/som/interpreter/actors/ResolveNode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/som/interpreter/actors/ResolveNode.java b/src/som/interpreter/actors/ResolveNode.java index cf2828b460..e59cfd366d 100644 --- a/src/som/interpreter/actors/ResolveNode.java +++ b/src/som/interpreter/actors/ResolveNode.java @@ -3,6 +3,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; + import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.vm.VmSettings; @@ -22,6 +23,7 @@ public SPromise.SResolver normalResolution(final VirtualFrame frame, final SPromise.SResolver resolver, final Object result, final Object maybeEntry, final boolean haltOnResolver, final boolean haltOnResolution) { if (!initialized) { + CompilerDirectives.transferToInterpreterAndInvalidate(); initialized = true; this.initialize(SomLanguage.getVM(this)); } From c7893f533779fa350184b41c4e7458858e1303a9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 14:20:34 +0100 Subject: [PATCH 112/194] Put path operations behind boundary for native image compilation Signed-off-by: Stefan Marr --- src/som/primitives/SystemPrims.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index f560fae364..392975d730 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -202,11 +202,18 @@ public BinarySystemOperation initialize(final VM vm) { @Specialization public final Object load(final VirtualFrame frame, final String filename, final SObjectWithClass moduleObj) { + String pathWithBasePath = getPathWithBase(filename, moduleObj); + return loadModule(frame, vm, pathWithBasePath, ioException); + } + + @TruffleBoundary + private String getPathWithBase(final String filename, final SObjectWithClass moduleObj) { String path = moduleObj.getSOMClass().getMixinDefinition().getSourceSection().getSource() .getPath(); File file = new File(URI.create(path).getPath()); - return loadModule(frame, vm, file.getParent() + File.separator + filename, ioException); + String pathWithBasePath = file.getParent() + File.separator + filename; + return pathWithBasePath; } } From 42bf5f91ccaf8116ad9ac6c9eafbfcc319153213 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 14:46:57 +0100 Subject: [PATCH 113/194] Re-add missing boundaries Signed-off-by: Stefan Marr --- src/som/interpreter/actors/ErrorNode.java | 2 + src/som/interpreter/actors/SPromise.java | 89 +++++++++++++---------- src/som/primitives/StringPrims.java | 4 + 3 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/som/interpreter/actors/ErrorNode.java b/src/som/interpreter/actors/ErrorNode.java index 2910792e82..b49983022f 100644 --- a/src/som/interpreter/actors/ErrorNode.java +++ b/src/som/interpreter/actors/ErrorNode.java @@ -3,6 +3,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; + import som.interpreter.SArguments; import som.interpreter.SomLanguage; import som.vm.VmSettings; @@ -21,6 +22,7 @@ public SPromise.SResolver standardError(final VirtualFrame frame, final boolean haltOnResolver, final boolean haltOnResolution) { if (!initialized) { + CompilerDirectives.transferToInterpreterAndInvalidate(); initialized = true; this.initialize(SomLanguage.getVM(this)); } diff --git a/src/som/interpreter/actors/SPromise.java b/src/som/interpreter/actors/SPromise.java index 779be4b363..c38d3a9752 100644 --- a/src/som/interpreter/actors/SPromise.java +++ b/src/som/interpreter/actors/SPromise.java @@ -9,6 +9,7 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicLong; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; @@ -780,7 +781,6 @@ public boolean assertNotCompleted() { */ // TODO: solve the TODO and then remove the TruffleBoundary, this might even need to go // into a node - // @TruffleBoundary protected static void resolveChainedPromisesUnsync(final Resolution type, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, @@ -792,57 +792,68 @@ protected static void resolveChainedPromisesUnsync(final Resolution type, // don't need to worry about traversing the chain, which can // lead to a stack overflow. // TODO: restore 10000 as parameter in testAsyncDeeplyChainedResolution - if (promise.chainedPromise != null) { - SPromise chainedPromise = promise.chainedPromise; - promise.chainedPromise = null; - Object wrapped = - WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); - - ShadowStackEntry resolutionEntry = null; - if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { - // MaterializedFrame context = promise.getContext(); - - ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); - assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || maybeEntry != null; - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = - ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.CHAINED; - resolutionEntry = - ShadowStackEntry.createAtPromiseResolution(entry, expression, location, - "promise: " + promise.toString()); - - SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); - } + if (promise.chainedPromise == null) { + return; + } + + // We do not want to invalidate here, + // but we can't have a boundary because we need the frame + CompilerDirectives.transferToInterpreter(); + + SPromise chainedPromise = promise.chainedPromise; + promise.chainedPromise = null; + Object wrapped = + WrapReferenceNode.wrapForUse(chainedPromise.owner, result, current, null); + + ShadowStackEntry resolutionEntry = null; + if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { + // MaterializedFrame context = promise.getContext(); + + ShadowStackEntry entry = SArguments.getShadowStackEntry(frame.getArguments()); + assert !VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE || maybeEntry != null; + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation location = + ShadowStackEntry.EntryForPromiseResolution.ResolutionLocation.CHAINED; + resolutionEntry = + ShadowStackEntry.createAtPromiseResolution(entry, expression, location, + "promise: " + promise.toString()); - resolveAndTriggerListenersUnsynced(type, result, wrapped, - chainedPromise, current, actorPool, resolutionEntry, - chainedPromise.haltOnResolution, whenResolvedProfile, frame, expression, record, - recordStop); - resolveMoreChainedPromisesUnsynced(type, promise, result, current, - actorPool, resolutionEntry, haltOnResolution, whenResolvedProfile, - frame, expression, record, recordStop); + SArguments.saveCausalEntryForPromise(maybeEntry, resolutionEntry); } + + resolveAndTriggerListenersUnsynced(type, result, wrapped, + chainedPromise, current, actorPool, resolutionEntry, + chainedPromise.haltOnResolution, whenResolvedProfile, frame, expression, record, + recordStop); + resolveMoreChainedPromisesUnsynced(type, promise, result, current, + actorPool, resolutionEntry, haltOnResolution, whenResolvedProfile, + frame, expression, record, recordStop); } /** * Resolve the other promises that has been chained to the first promise. */ - // @TruffleBoundary private static void resolveMoreChainedPromisesUnsynced(final Resolution type, final SPromise promise, final Object result, final Actor current, final ForkJoinPool actorPool, final Object maybeEntry, final boolean haltOnResolution, final ValueProfile whenResolvedProfile, final VirtualFrame frame, final Node expression, final RecordOneEvent record, final RecordOneEvent recordStop) { - if (promise.chainedPromiseExt != null) { - ArrayList chainedPromiseExt = promise.chainedPromiseExt; - promise.chainedPromiseExt = null; - - for (SPromise p : chainedPromiseExt) { - Object wrapped = WrapReferenceNode.wrapForUse(p.owner, result, current, null); - resolveAndTriggerListenersUnsynced(type, result, wrapped, p, current, - actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, - record, recordStop); - } + + if (promise.chainedPromiseExt == null) { + return; + } + + // We do not want to invalidate here, + // but we can't have a boundary because we need the frame + CompilerDirectives.transferToInterpreter(); + ArrayList chainedPromiseExt = promise.chainedPromiseExt; + promise.chainedPromiseExt = null; + + for (SPromise p : chainedPromiseExt) { + Object wrapped = WrapReferenceNode.wrapForUse(p.owner, result, current, null); + resolveAndTriggerListenersUnsynced(type, result, wrapped, p, current, + actorPool, maybeEntry, haltOnResolution, whenResolvedProfile, frame, expression, + record, recordStop); } } diff --git a/src/som/primitives/StringPrims.java b/src/som/primitives/StringPrims.java index fbc038f18b..b7c40cec8f 100644 --- a/src/som/primitives/StringPrims.java +++ b/src/som/primitives/StringPrims.java @@ -1,5 +1,6 @@ package som.primitives; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.GenerateNodeFactory; @@ -190,6 +191,9 @@ public final String doString(final VirtualFrame frame, final SArray chars) { } private String doStringWithBoundary(final VirtualFrame frame, final SArray chars) { + // Because of the frame, we can't have a boundary, so, just transferToInterpreter + CompilerDirectives.transferToInterpreter(); + Object[] storage = chars.getObjectStorage(); StringBuilder sb = new StringBuilder(storage.length); for (Object o : storage) { From 6600585890391a7ec47793f8acf4efdb7e5b5d23 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 14:47:40 +0100 Subject: [PATCH 114/194] Carefully put boundaries on string operations and exception.getMessage() Signed-off-by: Stefan Marr --- src/som/primitives/PathPrims.java | 15 ++++++++++----- src/som/primitives/SystemPrims.java | 23 ++++++++++++++++++++--- src/som/vmobjects/SFileDescriptor.java | 9 +++++++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/som/primitives/PathPrims.java b/src/som/primitives/PathPrims.java index 17a4d87d6c..0208789130 100644 --- a/src/som/primitives/PathPrims.java +++ b/src/som/primitives/PathPrims.java @@ -17,6 +17,7 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.source.SourceSection; import bd.primitives.Primitive; @@ -34,12 +35,16 @@ import som.vmobjects.SBlock; import som.vmobjects.SObject; import som.vmobjects.SObject.SImmutableObject; -import com.oracle.truffle.api.frame.VirtualFrame; public final class PathPrims { @CompilationFinal private static SImmutableObject fileObject; + @TruffleBoundary + private static String getMessage(final Exception e) { + return e.getMessage(); + } + public static final class FileModule implements Supplier { @Override public SObject get() { @@ -197,10 +202,10 @@ public final Object lastModified(final VirtualFrame frame, final String dir) { try { return lastModifiedTime(dir); } catch (FileNotFoundException e) { - fileNotFound.signal(frame, dir, e.getMessage()); + fileNotFound.signal(frame, dir, getMessage(e)); return Nil.nilObject; } catch (IOException e) { - ioException.signal(frame, e.getMessage()); + ioException.signal(frame, getMessage(e)); return Nil.nilObject; } } @@ -254,9 +259,9 @@ public final long getSize(final VirtualFrame frame, final String dir) { try { return size(dir); } catch (NoSuchFileException e) { - fileNotFound.signal(frame, dir, e.getMessage()); + fileNotFound.signal(frame, dir, getMessage(e)); } catch (IOException e) { - ioException.signal(frame, e.getMessage()); + ioException.signal(frame, getMessage(e)); } return -1; } diff --git a/src/som/primitives/SystemPrims.java b/src/som/primitives/SystemPrims.java index 392975d730..4e360171e9 100644 --- a/src/som/primitives/SystemPrims.java +++ b/src/som/primitives/SystemPrims.java @@ -141,17 +141,34 @@ public final Object doSObject(final Object module) { } } + @TruffleBoundary + private static String concat(final String a, final Exception e) { + return a.concat(e.getMessage()); + } + + @TruffleBoundary + private static String concat(final String a, final String b) { + return a.concat(b); + } + + @TruffleBoundary + private static String getMessage(final IOException e) { + return e.getMessage(); + } + public static Object loadModule(final VirtualFrame frame, final VM vm, final String path, final ExceptionSignalingNode ioException) { // TODO: a single node for the different exceptions? try { return loadModule(vm, path); } catch (FileNotFoundException e) { - ioException.signal(frame, path, "Could not find module file. " + e.getMessage()); + ioException.signal(frame, path, + concat("Could not find module file. ", e)); } catch (NotAFileException e) { - ioException.signal(frame, path, "Path does not seem to be a file. " + e.getMessage()); + ioException.signal(frame, path, + concat("Path does not seem to be a file. ", e)); } catch (IOException e) { - ioException.signal(frame, e.getMessage()); + ioException.signal(frame, getMessage(e)); } assert false : "This should never be reached, because exceptions do not return"; return Nil.nilObject; diff --git a/src/som/vmobjects/SFileDescriptor.java b/src/som/vmobjects/SFileDescriptor.java index 3ecfe5b0ff..f534ba3f51 100644 --- a/src/som/vmobjects/SFileDescriptor.java +++ b/src/som/vmobjects/SFileDescriptor.java @@ -66,6 +66,11 @@ private RandomAccessFile open() throws FileNotFoundException { return new RandomAccessFile(f, accessMode.mode); } + @TruffleBoundary + private String getMessage(final IOException e) { + return e.getMessage(); + } + public void closeFile(final VirtualFrame frame, final ExceptionSignalingNode ioException) { if (raf == null) { return; @@ -74,7 +79,7 @@ public void closeFile(final VirtualFrame frame, final ExceptionSignalingNode ioE try { closeFile(); } catch (IOException e) { - ioException.signal(frame, e.getMessage()); + ioException.signal(frame, getMessage(e)); } } @@ -184,7 +189,7 @@ public long getFileSize(final VirtualFrame frame, final ExceptionSignalingNode i try { return length(); } catch (IOException e) { - ioException.signal(frame, e.getMessage()); + ioException.signal(frame, getMessage(e)); } return 0; } From e5935bade09c3deb36103fcaf445c09218cca36d Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 18:43:05 +0100 Subject: [PATCH 115/194] =?UTF-8?q?Use=20explicit=20imports,=20no=20?= =?UTF-8?q?=E2=80=9C.*=E2=80=9D=20wildcards.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Marr --- src/som/primitives/TimerPrim.java | 19 ++++++---- src/tools/debugger/FrontendConnector.java | 36 +++++++++++++++---- .../RuntimeReflectionRegistration.java | 24 +++++++++++-- .../message/InitializationResponse.java | 11 +++++- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/som/primitives/TimerPrim.java b/src/som/primitives/TimerPrim.java index 21d2f053f0..877eabf1af 100644 --- a/src/som/primitives/TimerPrim.java +++ b/src/som/primitives/TimerPrim.java @@ -1,11 +1,21 @@ package som.primitives; -import bd.primitives.Primitive; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; + import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; + +import bd.primitives.Primitive; import som.VM; import som.compiler.AccessModifier; import som.interpreter.SArguments; @@ -22,16 +32,11 @@ import som.vmobjects.SSymbol; import tools.concurrency.TracingActors.ReplayActor; import tools.replay.TraceParser; -import tools.replay.actors.UniformExecutionTrace; import tools.replay.actors.ExternalEventualMessage.ExternalDirectMessage; +import tools.replay.actors.UniformExecutionTrace; import tools.replay.nodes.TraceContextNode; import tools.replay.nodes.TraceContextNodeGen; -import java.util.*; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; - @GenerateNodeFactory @Primitive(primitive = "actorDo:after:") diff --git a/src/tools/debugger/FrontendConnector.java b/src/tools/debugger/FrontendConnector.java index 8035aa4bab..151342f093 100644 --- a/src/tools/debugger/FrontendConnector.java +++ b/src/tools/debugger/FrontendConnector.java @@ -4,7 +4,10 @@ import java.net.BindException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Function; @@ -29,14 +32,33 @@ import tools.concurrency.TracingBackend; import tools.debugger.WebSocketHandler.MessageHandler; import tools.debugger.WebSocketHandler.TraceHandler; -import tools.debugger.entities.*; +import tools.debugger.breakpoints.Breakpoints; +import tools.debugger.breakpoints.LineBreakpoint; +import tools.debugger.entities.ActivityType; +import tools.debugger.entities.BreakpointType; +import tools.debugger.entities.DynamicScopeType; +import tools.debugger.entities.EntityType; +import tools.debugger.entities.Implementation; +import tools.debugger.entities.MessageReception; +import tools.debugger.entities.PassiveEntityType; +import tools.debugger.entities.ReceiveOp; +import tools.debugger.entities.SendOp; +import tools.debugger.entities.SteppingType; import tools.debugger.frontend.Suspension; -import tools.debugger.message.*; +import tools.debugger.message.InitializationResponse; +import tools.debugger.message.Message; import tools.debugger.message.Message.OutgoingMessage; +import tools.debugger.message.PauseActorResponse; +import tools.debugger.message.ProgramInfoResponse; +import tools.debugger.message.ResumeActorResponse; +import tools.debugger.message.ScopesResponse; +import tools.debugger.message.SourceMessage; import tools.debugger.message.SourceMessage.SourceData; +import tools.debugger.message.StackTraceResponse; +import tools.debugger.message.StoppedMessage; +import tools.debugger.message.SymbolMessage; import tools.debugger.message.VariablesRequest.FilterType; -import tools.debugger.breakpoints.Breakpoints; -import tools.debugger.breakpoints.LineBreakpoint; +import tools.debugger.message.VariablesResponse; /** @@ -297,11 +319,11 @@ public void sendProgramInfo() { () -> send(ProgramInfoResponse.create(webDebugger.vm.getArguments()))); } - public void sendPauseActorResponse(long pausedActorId) { + public void sendPauseActorResponse(final long pausedActorId) { send(PauseActorResponse.create(pausedActorId)); } - public void sendResumeActorResponse(long actorId) { + public void sendResumeActorResponse(final long actorId) { send(ResumeActorResponse.create(actorId)); } diff --git a/src/tools/debugger/RuntimeReflectionRegistration.java b/src/tools/debugger/RuntimeReflectionRegistration.java index e3882e35fc..0d8fcf766a 100644 --- a/src/tools/debugger/RuntimeReflectionRegistration.java +++ b/src/tools/debugger/RuntimeReflectionRegistration.java @@ -13,12 +13,30 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import tools.debugger.message.*; -import tools.debugger.message.Message.IncommingMessage; -import tools.debugger.message.Message.OutgoingMessage; import tools.debugger.breakpoints.BreakpointInfo; import tools.debugger.breakpoints.LineBreakpoint; import tools.debugger.breakpoints.SectionBreakpoint; +import tools.debugger.message.InitializationResponse; +import tools.debugger.message.InitializeConnection; +import tools.debugger.message.Message.IncommingMessage; +import tools.debugger.message.Message.OutgoingMessage; +import tools.debugger.message.PauseActorRequest; +import tools.debugger.message.PauseActorResponse; +import tools.debugger.message.ProgramInfoRequest; +import tools.debugger.message.ProgramInfoResponse; +import tools.debugger.message.ResumeActorResponse; +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; /** diff --git a/src/tools/debugger/message/InitializationResponse.java b/src/tools/debugger/message/InitializationResponse.java index f6e3874114..c21d24b9f1 100644 --- a/src/tools/debugger/message/InitializationResponse.java +++ b/src/tools/debugger/message/InitializationResponse.java @@ -2,7 +2,16 @@ import com.oracle.truffle.api.instrumentation.Tag; -import tools.debugger.entities.*; +import tools.debugger.entities.ActivityType; +import tools.debugger.entities.BreakpointType; +import tools.debugger.entities.DynamicScopeType; +import tools.debugger.entities.EntityType; +import tools.debugger.entities.Implementation; +import tools.debugger.entities.MessageReception; +import tools.debugger.entities.PassiveEntityType; +import tools.debugger.entities.ReceiveOp; +import tools.debugger.entities.SendOp; +import tools.debugger.entities.SteppingType; import tools.debugger.message.Message.OutgoingMessage; From c5465389f920d95914dd95a7d4e6d157ed26665b Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 18:55:24 +0100 Subject: [PATCH 116/194] Revert "Change comparison operator in Vector remove" This reverts commit 8b3a7ed62ee633f416c44d983a170a6f759d131e. We need to preserve this behavior for now, because this breaks DeltaBlue. --- core-lib/Kernel.ns | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-lib/Kernel.ns b/core-lib/Kernel.ns index 79ce3871eb..b039711552 100644 --- a/core-lib/Kernel.ns +++ b/core-lib/Kernel.ns @@ -777,7 +777,7 @@ class Kernel vmMirror: vmMirror = Object <: Value ( found:: false. self do: [ :it | - it = object + it == object ifTrue: [ found:: true ] ifFalse: [ newArray at: newLast put: it. From 913a8aaef3a96a0cc2ab8230ccbcf0147e45d356 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 21:19:26 +0100 Subject: [PATCH 117/194] Pass call target to CountingDirectCallNode, it is used at some later point Signed-off-by: Stefan Marr --- src/som/instrumentation/CountingDirectCallNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/som/instrumentation/CountingDirectCallNode.java b/src/som/instrumentation/CountingDirectCallNode.java index a57014b24c..30b8e0cb65 100644 --- a/src/som/instrumentation/CountingDirectCallNode.java +++ b/src/som/instrumentation/CountingDirectCallNode.java @@ -15,7 +15,7 @@ public final class CountingDirectCallNode extends DirectCallNode { private final AtomicInteger counter; public CountingDirectCallNode(final DirectCallNode callNode) { - super(null); + super(callNode.getCallTarget()); this.callNode = callNode; this.counter = new AtomicInteger(); } From e37b36c2b65f61263cf468c483006bbb21e64b0b Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 21:19:55 +0100 Subject: [PATCH 118/194] Generate wrapper for instrumentation of ResolvePromiseNode - rename argument to abstract method to avoid name clash Signed-off-by: Stefan Marr --- src/som/interpreter/actors/ResolvePromiseNode.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/som/interpreter/actors/ResolvePromiseNode.java b/src/som/interpreter/actors/ResolvePromiseNode.java index 855c64f695..0e28d23374 100644 --- a/src/som/interpreter/actors/ResolvePromiseNode.java +++ b/src/som/interpreter/actors/ResolvePromiseNode.java @@ -3,6 +3,8 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.instrumentation.GenerateWrapper; +import com.oracle.truffle.api.instrumentation.ProbeNode; import com.oracle.truffle.api.instrumentation.Tag; import bd.primitives.Primitive; @@ -15,6 +17,7 @@ import tools.dym.Tags.ComplexPrimitiveOperation; +@GenerateWrapper @GenerateNodeFactory @Primitive(primitive = "actorsResolve:with:") public abstract class ResolvePromiseNode extends BinaryExpressionNode implements Operation { @@ -25,7 +28,7 @@ public ResolvePromiseNode() { } public abstract SResolver executeEvaluated(VirtualFrame frame, SResolver resolver, - Object result); + Object resultObj); @Specialization public SResolver normalResolution(final VirtualFrame frame, final SResolver resolver, @@ -53,6 +56,11 @@ public String getOperation() { } } + @Override + public WrapperNode createWrapper(final ProbeNode probe) { + return new ResolvePromiseNodeWrapper(this, probe); + } + @Override public int getNumArguments() { return 5; From 13a15bc0e7dd58c48037333db5580966d5d2b7e4 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 21:24:17 +0100 Subject: [PATCH 119/194] =?UTF-8?q?Work=20around=20null=20issue,=20not=20e?= =?UTF-8?q?ntirely=20sure=20why=20there=E2=80=99s=20a=20null,=20but=20well?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Marr --- src/tools/dym/profiles/Arguments.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tools/dym/profiles/Arguments.java b/src/tools/dym/profiles/Arguments.java index a796cce9c2..c7c5adbe8b 100644 --- a/src/tools/dym/profiles/Arguments.java +++ b/src/tools/dym/profiles/Arguments.java @@ -20,9 +20,11 @@ public final class Arguments { private final ClassFactory[] argSomTypes; Arguments(final Object[] arguments) { - Object[] argsToProfile = arguments; + Object[] argsToProfile; if (VmSettings.ACTOR_ASYNC_STACK_TRACE_STRUCTURE) { argsToProfile = Arrays.copyOf(arguments, arguments.length - 1); + } else { + argsToProfile = arguments; } this.argJavaTypes = getJavaTypes(argsToProfile); this.argSomTypes = getSomTypes(argsToProfile); @@ -92,14 +94,22 @@ public JSONObjectBuilder toJson() { JSONArrayBuilder javaTypes = JSONHelper.array(); for (Class c : argJavaTypes) { - javaTypes.add(c.getSimpleName()); + if (c == null) { + javaTypes.add((String) null); + } else { + javaTypes.add(c.getSimpleName()); + } } result.add("javaTypes", javaTypes); JSONArrayBuilder somTypes = JSONHelper.array(); for (ClassFactory c : argSomTypes) { - somTypes.add(c.getClassName().getString()); + if (c == null) { + somTypes.add((String) null); + } else { + somTypes.add(c.getClassName().getString()); + } } result.add("somTypes", somTypes); return result; From 63d34a742b7613bec00c5be5909ab6575a13bc29 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 13 Oct 2022 23:04:26 +0100 Subject: [PATCH 120/194] Disable the affinity logging Signed-off-by: Stefan Marr --- som | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/som b/som index 8d8167d2b5..0c685d63cb 100755 --- a/som +++ b/som @@ -461,7 +461,7 @@ if args.use_pinning: bit_mask = 0 for c in range(core_set[0], core_set[1] + 1): bit_mask += 1 << c - flags += ['-Daffinity.reserved=' + hex(bit_mask).lstrip("0x")] + flags += ['-Daffinity.reserved=' + hex(bit_mask).lstrip("0x"), '-Dorg.slf4j.simpleLogger.defaultLogLevel=off'] else: flags += ['-Dsom.usePinning=false'] flags += ['-Dorg.slf4j.simpleLogger.defaultLogLevel=off'] From 513d2c336c9aebe1975e8f9d463ac9d07f35406d Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 14 Oct 2022 10:21:08 +0100 Subject: [PATCH 121/194] [WIP] Update test data, though this loses details on implicitPromiseResolve, and possibly other bits Signed-off-by: Stefan Marr --- tests/dym/expected-results.tar.bz2 | Bin 353049 -> 347706 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/dym/expected-results.tar.bz2 b/tests/dym/expected-results.tar.bz2 index 6756e0d7a2c8b4a018c3eb46bc0dc39d9fd73073..f14bc2f010901594e8ddacb0472af6adfb500147 100644 GIT binary patch literal 347706 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

Tj-b_mXmV@^iZa=e3Qo6zwLS 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� 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