Skip to content

Commit

Permalink
Use step-after-root node to realize promise resolver breakpoint
Browse files Browse the repository at this point in the history
This change improves the source attribution for the promise resolver breakpoint.
Previously, we use a haltNode (SuspendExecutionNode) to trigger a breakpoint in the promise resolution node with a source section that could not be attributed to the concrete method executed (because of polymorphic message sends).

Now, we stop execution after the rootNode finished executing, which means before exiting the concrete method that was activated.

Signed-off-by: Stefan Marr <git@stefan-marr.de>
  • Loading branch information
smarr committed Nov 28, 2016
1 parent af9e0cc commit f8cad7e
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 51 deletions.
2 changes: 1 addition & 1 deletion core-lib/Actors.som
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ 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 resolve: value = ( vmMirror actorsResolve: self with: value isBPResolution: false)
public error: value = ( self notYetImplemented )
)

Expand Down
17 changes: 15 additions & 2 deletions src/som/interpreter/actors/ReceivedMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;

import som.VmSettings;
import som.interpreter.SArguments;
import som.interpreter.SomLanguage;
import som.interpreter.nodes.MessageSendNode.AbstractMessageSendNode;
Expand All @@ -30,9 +31,13 @@ public ReceivedMessage(final AbstractMessageSendNode onReceive, final SSymbol se
public Object execute(final VirtualFrame frame) {
EventualMessage msg = (EventualMessage) SArguments.rcvr(frame);

if (VmSettings.TRUFFLE_DEBUGGER_ENABLED && msg.triggerPromiseResolverBreakpoint) {
dbg.prepareSteppingAfterNextRootNode();
}

Object result = onReceive.doPreEvaluated(frame, msg.args);

resolvePromise(frame, msg.resolver, result, msg.triggerPromiseResolverBreakpoint, msg.triggerPromiseResolutionBreakpoint);
resolvePromise(frame, msg.resolver, result, msg.triggerPromiseResolutionBreakpoint);
return null;
}

Expand All @@ -54,6 +59,10 @@ public ReceivedMessageForVMMain(final AbstractMessageSendNode onReceive,
public Object execute(final VirtualFrame frame) {
EventualMessage msg = (EventualMessage) SArguments.rcvr(frame);

if (VmSettings.TRUFFLE_DEBUGGER_ENABLED && msg.triggerPromiseResolverBreakpoint) {
dbg.prepareSteppingAfterNextRootNode();
}

Object result = onReceive.doPreEvaluated(frame, msg.args);
future.complete(result);
return result;
Expand All @@ -72,9 +81,13 @@ public ReceivedCallback(final RootCallTarget onReceive) {
public Object execute(final VirtualFrame frame) {
EventualMessage msg = (EventualMessage) SArguments.rcvr(frame);

if (VmSettings.TRUFFLE_DEBUGGER_ENABLED && msg.triggerPromiseResolverBreakpoint) {
dbg.prepareSteppingAfterNextRootNode();
}

Object result = onReceive.call(frame, msg.args);

resolvePromise(frame, msg.resolver, result, msg.triggerPromiseResolverBreakpoint, msg.triggerPromiseResolutionBreakpoint);
resolvePromise(frame, msg.resolver, result, msg.triggerPromiseResolutionBreakpoint);
return null;
}
}
Expand Down
30 changes: 19 additions & 11 deletions src/som/interpreter/actors/ReceivedRootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,44 @@
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;

import som.VM;
import som.VmSettings;
import som.interpreter.actors.SPromise.SResolver;
import tools.debugger.WebDebugger;


public abstract class ReceivedRootNode extends RootNode {

@Child protected ResolvePromiseNode resolve;

protected final WebDebugger dbg;

protected ReceivedRootNode(final Class<? extends TruffleLanguage<?>> language,
final SourceSection sourceSection, final FrameDescriptor frameDescriptor) {
super(language, sourceSection, frameDescriptor);
assert sourceSection != null;
if (VmSettings.TRUFFLE_DEBUGGER_ENABLED) {
this.dbg = VM.getWebDebugger();
} else {
this.dbg = null;
}
}

protected final void resolvePromise(final VirtualFrame frame, final SResolver resolver, final Object result,
final boolean isBreakpointOnPromiseResolver, final boolean isBreakpointOnPromiseResolution) {
protected final void resolvePromise(final VirtualFrame frame,
final SResolver resolver, final Object result,
final boolean isBreakpointOnPromiseResolution) {
// lazy initialization of resolution node
if (resolve == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
if (resolver == null) {
this.resolve = insert(new NullResolver(getSourceSection()));
} else {
this.resolve = insert(ResolvePromiseNodeFactory.create(false, getSourceSection(), null, null, null, null));
this.resolve = insert(ResolvePromiseNodeFactory.create(false, getSourceSection(), null, null, null));
}
}

// resolve promise
resolve.executeEvaluated(frame, resolver, result, isBreakpointOnPromiseResolver, isBreakpointOnPromiseResolution);
resolve.executeEvaluated(frame, resolver, result, isBreakpointOnPromiseResolution);
}

/**
Expand All @@ -46,21 +57,18 @@ public NullResolver(final SourceSection source) {
}

@Override
public Object executeEvaluated(final VirtualFrame frame, final SResolver receiver, final Object argument,
final boolean isBreakpointOnPromiseResolver, final boolean isBreakpointOnPromiseResolution) {
public Object executeEvaluated(final VirtualFrame frame,
final SResolver receiver, final Object argument,
final boolean isBreakpointOnPromiseResolution) {
assert receiver == null;
if (isBreakpointOnPromiseResolver) {
haltNode.executeEvaluated(frame, argument);
}
/* TODO: add a tag to the send node to disable or remove the button
* if (isBreakpointOnResolutionAtRcvr) {} */
return null;
}

@Override
public Object executeEvaluated(final VirtualFrame frame, final Object receiver,
final Object argument, final Object isBreakpointOnPromiseResolver,
final Object isBreakpointOnPromiseResolution) {
final Object argument, final Object isBreakpointOnPromiseResolution) {
return null;
}

Expand Down
51 changes: 16 additions & 35 deletions src/som/interpreter/actors/ResolvePromiseNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,47 @@
import com.oracle.truffle.api.instrumentation.Instrumentable;
import com.oracle.truffle.api.source.SourceSection;

import som.VM;
import som.interpreter.actors.SPromise.SResolver;
import som.interpreter.nodes.nary.QuaternaryExpressionNode;
import som.interpreter.nodes.nary.UnaryExpressionNode;
import som.interpreter.nodes.nary.TernaryExpressionNode;
import som.primitives.Primitive;
import som.vm.NotYetImplementedException;


@GenerateNodeFactory
@Primitive(primitive = "actorsResolve:with:isBPResolver:isBPResolution:")
@Primitive(primitive = "actorsResolve:with:isBPResolution:")
@Instrumentable(factory = ResolvePromiseNodeWrapper.class)
public abstract class ResolvePromiseNode extends QuaternaryExpressionNode {
@Child protected UnaryExpressionNode haltNode;
public abstract class ResolvePromiseNode extends TernaryExpressionNode {

protected ResolvePromiseNode(final boolean eagWrap, final SourceSection source) {
super(eagWrap, source);
haltNode = insert(SuspendExecutionNodeGen.create(false, source, null));
VM.insertInstrumentationWrapper(haltNode);
}

protected ResolvePromiseNode(final ResolvePromiseNode node) {
super(node);
haltNode = insert(SuspendExecutionNodeGen.create(false, node.getSourceSection(), null));
VM.insertInstrumentationWrapper(haltNode);
}
protected ResolvePromiseNode(final boolean eagWrap, final SourceSection source) { super(eagWrap, source); }
protected ResolvePromiseNode(final ResolvePromiseNode node) { super(node); }

public abstract Object executeEvaluated(VirtualFrame frame, final SResolver receiver, Object argument,
boolean isBreakpointOnPromiseResolver, final boolean isBreakpointOnPromiseResolution);
public abstract Object executeEvaluated(final VirtualFrame frame,
final SResolver receiver, Object argument,
final boolean isBreakpointOnPromiseResolution);

/**
* To avoid cycles in the promise chain, do nothing when a promise is resolved with itself.
*/
@Specialization(guards = {"resolver.getPromise() == result"})
public SResolver selfResolution(final SResolver resolver, final SPromise result,
final boolean isBreakpointOnPromiseResolver, final boolean isBreakpointOnPromiseResolution) {
final boolean isBreakpointOnPromiseResolution) {
return resolver;
}

/**
* Handle the case that a promise is resolved with another promise, which is not itself.
*/
@Specialization(guards = {"resolver.getPromise() != result"})
public SResolver chainedPromise(final VirtualFrame frame, final SResolver resolver, final SPromise result,
final boolean isBreakpointOnPromiseResolver, final boolean isBreakpointOnPromiseResolution) {
public SResolver chainedPromise(final VirtualFrame frame,
final SResolver resolver, final SPromise result,
final boolean isBreakpointOnPromiseResolution) {
assert resolver.assertNotCompleted();
SPromise promise = resolver.getPromise();

synchronized (result) {
if (result.isResolvedUnsync()) {
normalResolution(frame, resolver, result.getValueUnsync(),
isBreakpointOnPromiseResolver, isBreakpointOnPromiseResolution);
isBreakpointOnPromiseResolution);
} else if (result.isErroredUnsync()) {
CompilerDirectives.transferToInterpreter();
throw new NotYetImplementedException();
Expand All @@ -68,10 +58,6 @@ public SResolver chainedPromise(final VirtualFrame frame, final SResolver resolv
}
}

if (isBreakpointOnPromiseResolver) {
haltNode.executeEvaluated(frame, result);
}

return resolver;
}

Expand All @@ -85,19 +71,14 @@ protected static boolean notAPromise(final Object result) {
* Normal case, when the promise is resolved with a value that's not a promise.
*/
@Specialization(guards = {"notAPromise(result)"})
public SResolver normalResolution(final VirtualFrame frame, final SResolver resolver, final Object result,
final boolean isBreakpointOnPromiseResolver, final boolean isBreakpointOnPromiseResolution) {
public SResolver normalResolution(final VirtualFrame frame,
final SResolver resolver, final Object result,
final boolean isBreakpointOnPromiseResolution) {
SPromise promise = resolver.getPromise();
Actor current = EventualMessage.getActorCurrentMessageIsExecutionOn();
Object wrapped = wrapper.execute(result, promise.owner, current);

if (isBreakpointOnPromiseResolver) {
haltNode.executeEvaluated(frame, result);
}

SResolver.resolveAndTriggerListenersUnsynced(result, wrapped, promise, current, isBreakpointOnPromiseResolution);

return resolver;
}

}
6 changes: 5 additions & 1 deletion src/tools/debugger/WebDebugger.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
import tools.debugger.message.StoppedMessage;
import tools.debugger.message.SuspendedEventMessage;
import tools.debugger.message.UpdateBreakpoint;
import tools.debugger.session.AsyncMessageReceiverBreakpoint;
import tools.debugger.message.VariablesRequest;
import tools.debugger.message.VariablesResponse;
import tools.debugger.session.AsyncMessageReceiverBreakpoint;
import tools.debugger.session.BreakpointInfo;
import tools.debugger.session.Breakpoints;
import tools.debugger.session.LineBreakpoint;
Expand Down Expand Up @@ -101,6 +101,10 @@ public void prepareSteppingUntilNextRootNode() {
breakpoints.prepareSteppingUntilNextRootNode();
}

public void prepareSteppingAfterNextRootNode() {
breakpoints.prepareSteppingAfterNextRootNode();
}

synchronized SuspendedEvent getSuspendedEvent(final int activityId) {
Suspension suspension = idToSuspension.get(activityId);
assert suspension != null;
Expand Down
4 changes: 4 additions & 0 deletions src/tools/debugger/session/Breakpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public void prepareSteppingUntilNextRootNode() {
debuggerSession.prepareSteppingUntilNextRootNode();
}

public void prepareSteppingAfterNextRootNode() {
debuggerSession.prepareSteppingAfterNextRootNode();
}

public synchronized void addOrUpdate(final LineBreakpoint bId) {
Breakpoint bp = truffleBreakpoints.get(bId);
if (bp == null) {
Expand Down

0 comments on commit f8cad7e

Please sign in to comment.