Report AbstractTruffleException as a Panic (#5794)

Report `AbstractTruffleException` as a `Panic`. Fixes #5260.
This commit is contained in:
Jaroslav Tulach 2023-03-06 20:05:25 +01:00 committed by GitHub
parent 2d29456ed1
commit 161ea45019
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 6 deletions

View File

@ -1,6 +1,5 @@
package org.enso.polyglot; package org.enso.polyglot;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.PolyglotException;
public final class HostEnsoUtils { public final class HostEnsoUtils {

View File

@ -4,6 +4,7 @@ import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstanceVisitor; import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
@ -244,13 +245,13 @@ public class IdExecutionInstrument extends TruffleInstrument implements IdExecut
} else if (exception instanceof PanicException) { } else if (exception instanceof PanicException) {
PanicException panicException = (PanicException) exception; PanicException panicException = (PanicException) exception;
onReturnValue(frame, new PanicSentinel(panicException, context.getInstrumentedNode())); onReturnValue(frame, new PanicSentinel(panicException, context.getInstrumentedNode()));
} else if (exception instanceof PanicSentinel) { } else if (exception instanceof AbstractTruffleException) {
onReturnValue(frame, exception); onReturnValue(frame, exception);
} }
} }
private void onExpressionReturn(Object result, Node node, EventContext context) throws ThreadDeath { private void onExpressionReturn(Object result, Node node, EventContext context) throws ThreadDeath {
boolean isPanic = result instanceof PanicSentinel; boolean isPanic = result instanceof AbstractTruffleException;
UUID nodeId = ((ExpressionNode) node).getId(); UUID nodeId = ((ExpressionNode) node).getId();
String resultType = typeOf(result); String resultType = typeOf(result);

View File

@ -1313,6 +1313,74 @@ class RuntimeErrorsTest
context.consumeOut shouldEqual List("3") context.consumeOut shouldEqual List("3")
} }
it should "send updates when NPE is resolved in method" in {
val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID()
val moduleName = "Enso_Test.Test.Main"
val metadata = new Metadata
val xId = metadata.addItem(146, 3, "aaa")
val code =
"""from Standard.Base import all
|polyglot java import java.lang.NullPointerException
|
|foo =
| Panic.throw NullPointerException.new
|
|main =
| x = foo
| x
|""".stripMargin.linesIterator.mkString("\n")
val contents = metadata.appendToCode(code)
val mainFile = context.writeMain(contents)
metadata.assertInCode(xId, code, "foo")
// create context
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
context.receive shouldEqual Some(
Api.Response(requestId, Api.CreateContextResponse(contextId))
)
// Open the new file
context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents))
)
context.receiveNone shouldEqual None
// push main
context.send(
Api.Request(
requestId,
Api.PushContextRequest(
contextId,
Api.StackItem.ExplicitCall(
Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"),
None,
Vector()
)
)
)
)
context.receiveNIgnorePendingExpressionUpdates(
3
) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)),
TestMessages.panic(
contextId,
xId,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.ExpressionUpdate.Payload.Panic(
"java.lang.NullPointerException",
Seq(xId)
),
None
),
context.executionComplete(contextId)
)
context.consumeOut shouldEqual Seq()
}
it should "send updates when dataflow error is resolved in method" in { it should "send updates when dataflow error is resolved in method" in {
val contextId = UUID.randomUUID() val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()

View File

@ -345,6 +345,12 @@ object ProgramExecutionSupport {
Api.ExpressionUpdate.Payload.DataflowError( Api.ExpressionUpdate.Payload.DataflowError(
ErrorResolver.getStackTrace(error).flatMap(_.expressionId) ErrorResolver.getStackTrace(error).flatMap(_.expressionId)
) )
case panic: AbstractTruffleException =>
Api.ExpressionUpdate.Payload
.Panic(
VisualizationResult.findExceptionMessage(panic),
ErrorResolver.getStackTrace(panic).flatMap(_.expressionId)
)
case withWarnings: WithWarnings => case withWarnings: WithWarnings =>
val warningsCount = withWarnings.getWarningsCount val warningsCount = withWarnings.getWarningsCount
val warning = val warning =

View File

@ -293,6 +293,24 @@ object TestMessages {
): Api.Response = ): Api.Response =
panicBuilder(contextId, expressionId, Some(methodPointer), payload, builtin) panicBuilder(contextId, expressionId, Some(methodPointer), payload, builtin)
/** Create a panic update response.
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointer a pointer to the method definition
* @param payload the error payload
* @param builtin the type to use
* @return the expression update response
*/
def panic(
contextId: UUID,
expressionId: UUID,
methodPointer: Api.MethodPointer,
payload: Api.ExpressionUpdate.Payload,
builtin: Option[String]
): Api.Response =
panicBuilder(contextId, expressionId, Some(methodPointer), payload, builtin)
/** Create a panic update response. /** Create a panic update response.
* *
* @param contextId an identifier of the context * @param contextId an identifier of the context
@ -308,6 +326,22 @@ object TestMessages {
methodPointer: Option[Api.MethodPointer], methodPointer: Option[Api.MethodPointer],
payload: Api.ExpressionUpdate.Payload, payload: Api.ExpressionUpdate.Payload,
builtin: Boolean builtin: Boolean
): Api.Response = panicBuilder(
contextId,
expressionId,
methodPointer,
payload,
Some(
if (builtin) ConstantsGen.PANIC_BUILTIN else ConstantsGen.PANIC
)
)
private def panicBuilder(
contextId: UUID,
expressionId: UUID,
methodPointer: Option[Api.MethodPointer],
payload: Api.ExpressionUpdate.Payload,
builtin: Option[String]
): Api.Response = ): Api.Response =
Api.Response( Api.Response(
Api.ExpressionUpdates( Api.ExpressionUpdates(
@ -315,9 +349,7 @@ object TestMessages {
Set( Set(
Api.ExpressionUpdate( Api.ExpressionUpdate(
expressionId, expressionId,
Some( builtin,
if (builtin) ConstantsGen.PANIC_BUILTIN else ConstantsGen.PANIC
),
methodPointer, methodPointer,
Vector(Api.ProfilingInfo.ExecutionTime(0)), Vector(Api.ProfilingInfo.ExecutionTime(0)),
false, false,