Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle PanicSentinel in Interpreter #1436

Merged
merged 21 commits into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions distribution/std-lib/Base/src/Data/Number/Extensions.enso
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from Base import all
polyglot java import java.lang.Math
polyglot java import java.lang.Double
polyglot java import java.lang.Integer as Java_Integer
polyglot java import java.lang.String

## Computes the inverse of the sine function
Expand Down Expand Up @@ -102,3 +103,16 @@ Decimal.parse : Text -> Decimal | Nothing
Decimal.parse text =
Panic.recover (Double.parseDouble [text]) . catch (_ -> Nothing)

## Parses a textual representation of an integer into an integer number.
Returns `Nothing` if the text does not represent a valid integer.
Integer.parse : Text -> Integer | Nothing
Integer.parse text =
Panic.recover (Java_Integer.parseInt [text]) . catch (_ -> Nothing)

## Parses a textual representation of a number into an integer or decimal number.
Returns `Nothing` if the text does not represent a valid number.
Number.parse : Text -> Number | Nothing
Number.parse text =
case Integer.parse text of
Nothing -> Decimal.parse text
value -> value
4e6 marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 1 addition & 12 deletions docs/language-server/protocol-language-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ interface ExpressionUpdate {
An information about the computed value.

```typescript
type ExpressionUpdatePayload = Value | DatafalowError | RuntimeError | Poisoned;
type ExpressionUpdatePayload = Value | DatafalowError | RuntimeError;
4e6 marked this conversation as resolved.
Show resolved Hide resolved

/**
* An empty payload. Indicates that the expression was computed to a value.
Expand Down Expand Up @@ -350,17 +350,6 @@ interface RuntimeError {
*/
trace: ExpressionId[];
}

/**
* Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*/
interface Poisoned {
/**
* The list of expressions leading to the root expression that failed.
*/
trace: ExpressionId[];
}
```

### `VisualisationConfiguration`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,6 @@ final class ContextEventsListener(
case Api.ExpressionUpdate.Payload.RuntimeError(message, trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload
.RuntimeError(message, trace)

case Api.ExpressionUpdate.Payload.Poisoned(trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload.Poisoned(trace)
}

/** Convert the runtime profiling info to the context registry protocol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,6 @@ object ContextRegistryProtocol {
trace: Seq[UUID]
) extends Payload

/** Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*
* @param trace the list of expressions leading to the root error.
*/
case class Poisoned(trace: Seq[UUID]) extends Payload

private object CodecField {

val Type = "type"
Expand All @@ -168,7 +161,6 @@ object ContextRegistryProtocol {

val RuntimeError = "RuntimeError"

val Poisoned = "Poisoned"
}

implicit val encoder: Encoder[Payload] =
Expand All @@ -189,13 +181,6 @@ object ContextRegistryProtocol {
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.RuntimeError.asJson)
)

case m: Payload.Poisoned =>
Encoder[Payload.Poisoned]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.Poisoned.asJson)
)
}

implicit val decoder: Decoder[Payload] =
Expand All @@ -209,9 +194,6 @@ object ContextRegistryProtocol {

case PayloadType.RuntimeError =>
Decoder[Payload.RuntimeError].tryDecode(cursor)

case PayloadType.Poisoned =>
Decoder[Payload.Poisoned].tryDecode(cursor)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ final class SuggestionsHandler(

override def preStart(): Unit = {
context.system.eventStream
.subscribe(self, classOf[Api.ExpressionValuesComputed])
.subscribe(self, classOf[Api.ExpressionUpdates])
context.system.eventStream
.subscribe(self, classOf[Api.SuggestionsDatabaseModuleUpdateNotification])
context.system.eventStream.subscribe(self, classOf[ProjectNameChangedEvent])
Expand Down Expand Up @@ -167,11 +167,11 @@ final class SuggestionsHandler(
)
}

case Api.ExpressionValuesComputed(_, updates) =>
case Api.ExpressionUpdates(_, updates) =>
log.debug(
s"ExpressionValuesComputed ${updates.map(u => (u.expressionId, u.expressionType))}"
)
val types = updates
val types = updates.toSeq
.flatMap(update => update.expressionType.map(update.expressionId -> _))
suggestionsRepo
.updateAll(types)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,46 +208,6 @@ class ContextEventsListenerSpec
)
}

"send poisoning error updates" taggedAs Retry in withDb {
(clientId, contextId, _, router, listener) =>
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false,
Api.ExpressionUpdate.Payload.Poisoned(
Seq(Suggestions.method.externalId.get)
)
)
)
)

router.expectMsg(
DeliverToJsonController(
clientId,
ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload
.Poisoned(Seq(Suggestions.method.externalId.get))
)
),
None
)
)
)
}

"send expression updates grouped" taggedAs Retry in withDb(0.seconds) {
(clientId, contextId, repo, router, listener) =>
Await.result(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,6 @@ object Runtime {
value = classOf[Api.VisualisationModified],
name = "visualisationModified"
),
new JsonSubTypes.Type(
value = classOf[Api.ExpressionValuesComputed],
name = "expressionValuesComputed"
),
new JsonSubTypes.Type(
value = classOf[Api.ExpressionUpdates],
name = "expressionUpdates"
Expand Down Expand Up @@ -251,24 +247,6 @@ object Runtime {
case class LocalCall(expressionId: ExpressionId) extends StackItem
}

/** An update containing information about expression.
*
* @param expressionId expression id.
* @param expressionType the type of expression.
* @param methodCall the pointer to a method definition.
* @param profilingInfo profiling information about the execution of this
* expression
* @param fromCache whether or not the value for this expression came from
* the cache
*/
case class ExpressionValueUpdate(
expressionId: ExpressionId,
expressionType: Option[String],
methodCall: Option[MethodPointer],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean
)

/** An update about the computed expression.
*
* @param expressionId the expression id
Expand Down Expand Up @@ -305,10 +283,6 @@ object Runtime {
new JsonSubTypes.Type(
value = classOf[Payload.RuntimeError],
name = "expressionUpdatePayloadRuntimeError"
),
new JsonSubTypes.Type(
value = classOf[Payload.Poisoned],
name = "expressionUpdatePayloadPoisoned"
)
)
)
Expand Down Expand Up @@ -336,12 +310,6 @@ object Runtime {
trace: Seq[ExpressionId]
) extends Payload

/** Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*
* @param trace the list of expressions leading to the root error.
*/
case class Poisoned(trace: Seq[ExpressionId]) extends Payload
}
}

Expand Down Expand Up @@ -397,17 +365,6 @@ object Runtime {
extends InvalidatedExpressions
}

// TODO: [DB] Remove when IDE implements new updates API
/** A notification about updated expressions of the context.
*
* @param contextId the context's id.
* @param updates a list of updates.
*/
case class ExpressionValuesComputed(
contextId: ContextId,
updates: Vector[ExpressionValueUpdate]
) extends ApiNotification

/** A notification about updated expressions of the context.
*
* @param contextId the context's id.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import java.util.Arrays;
import org.enso.interpreter.instrument.execution.Timer;
import org.enso.interpreter.instrument.profiling.ExecutionTime;
import org.enso.interpreter.instrument.profiling.ProfilingInfo;
Expand All @@ -19,14 +18,13 @@
import org.enso.interpreter.node.MethodRootNode;
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
import org.enso.interpreter.runtime.control.TailCallException;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.PanicSentinel;
import org.enso.interpreter.runtime.tag.IdentifiedTag;
import org.enso.interpreter.runtime.type.Types;
import org.enso.pkg.QualifiedName;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.*;
import java.util.function.Consumer;

/** An instrument for getting values from AST-identified expressions. */
Expand All @@ -51,7 +49,8 @@ protected void onCreate(Env env) {
this.env = env;
}

/** Override the default nanosecond timer with the specified {@code timer}.
/**
* Override the default nanosecond timer with the specified {@code timer}.
*
* @param timer the timer to override with
*/
Expand Down Expand Up @@ -270,7 +269,7 @@ private static class IdExecutionEventListener implements ExecutionEventListener
private final Consumer<ExpressionCall> functionCallCallback;
private final Consumer<ExpressionValue> onComputedCallback;
private final Consumer<ExpressionValue> onCachedCallback;
private final Consumer<Throwable> onExceptionalCallback;
private final Consumer<Exception> onExceptionalCallback;
private final RuntimeCache cache;
private final MethodCallsCache callsCache;
private final UUID nextExecutionItem;
Expand Down Expand Up @@ -299,7 +298,7 @@ public IdExecutionEventListener(
Consumer<ExpressionCall> functionCallCallback,
Consumer<ExpressionValue> onComputedCallback,
Consumer<ExpressionValue> onCachedCallback,
Consumer<Throwable> onExceptionalCallback,
Consumer<Exception> onExceptionalCallback,
Timer timer) {
this.entryCallTarget = entryCallTarget;
this.cache = cache;
Expand All @@ -322,15 +321,7 @@ public void onEnter(EventContext context, VirtualFrame frame) {
if (!isTopFrame(entryCallTarget)) {
return;
}

Node node = context.getInstrumentedNode();

UUID nodeId = null;
if (node instanceof ExpressionNode) {
nodeId = ((ExpressionNode) node).getId();
} else if (node instanceof FunctionCallInstrumentationNode) {
nodeId = ((FunctionCallInstrumentationNode) node).getId();
}
UUID nodeId = getNodeId(context.getInstrumentedNode());

// Add a flag to say it was cached.
// An array of `ProfilingInfo` in the value update.
Expand Down Expand Up @@ -396,6 +387,9 @@ public void onReturnValue(EventContext context, VirtualFrame frame, Object resul
onComputedCallback.accept(
new ExpressionValue(
nodeId, result, resultType, cachedType, call, cachedCall, profilingInfo, false));
if (result instanceof PanicSentinel) {
throw context.createUnwind(result);
}
}
}

Expand All @@ -414,6 +408,11 @@ public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwa
} catch (InteropException e) {
onExceptionalCallback.accept(e);
}
} else if (exception instanceof PanicException) {
PanicException panicException = (PanicException) exception;
onReturnValue(context, frame, new PanicSentinel(panicException, context.getInstrumentedNode()));
} else if (exception instanceof PanicSentinel) {
onReturnValue(context, frame, exception);
}
}

Expand Down Expand Up @@ -446,6 +445,16 @@ public Object visitFrame(FrameInstance frameInstance) {
});
return result == null;
}

private UUID getNodeId(Node node) {
if (node instanceof ExpressionNode) {
return ((ExpressionNode) node).getId();
}
if (node instanceof FunctionCallInstrumentationNode) {
return ((FunctionCallInstrumentationNode) node).getId();
}
return null;
}
}

/**
Expand Down Expand Up @@ -473,7 +482,7 @@ public EventBinding<ExecutionEventListener> bind(
Consumer<IdExecutionInstrument.ExpressionCall> functionCallCallback,
Consumer<IdExecutionInstrument.ExpressionValue> onComputedCallback,
Consumer<IdExecutionInstrument.ExpressionValue> onCachedCallback,
Consumer<Throwable> onExceptionalCallback) {
Consumer<Exception> onExceptionalCallback) {
SourceSectionFilter filter =
SourceSectionFilter.newBuilder()
.tagIs(StandardTags.ExpressionTag.class, StandardTags.CallTag.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class Constants {
public static final String INTEGER = "Builtins.Main.Integer";
public static final String DECIMAL = "Builtins.Main.Decimal";
public static final String NOTHING = "Builtins.Main.Nothing";
public static final String PANIC = "Builtins.Main.Panic";
public static final String REF = "Builtins.Main.Ref";
public static final String TEXT = "Builtins.Main.Text";
public static final String THUNK = "Builtins.Main.Thunk";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ public static String getName(Object value) {
return Constants.ARRAY;
} else if (TypesGen.isRef(value)) {
return Constants.REF;
} else if (TypesGen.isPanicSentinel(value)) {
return Constants.PANIC;
} else {
return null;
}
Expand Down
Loading