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

DataflowError.withoutTrace shall not store a trace #8608

Merged
merged 29 commits into from
Dec 24, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0226b4a
DataflowError.withoutTrace shall not store a trace
JaroslavTulach Dec 20, 2023
2350c6b
Source location of Error.throw is recorded
JaroslavTulach Dec 21, 2023
1cd87cc
Panic.recover records whole stacktrace
JaroslavTulach Dec 21, 2023
bfc9893
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Datafl…
JaroslavTulach Dec 21, 2023
9a029fd
Skip HTTP and Cloud tests when pending_has_url
JaroslavTulach Dec 21, 2023
97c5b3b
Concentrate stack trace handling into GetStackTraceNode
JaroslavTulach Dec 21, 2023
8d57904
DataflowError.stack_trace shows the most important line at index 0
JaroslavTulach Dec 21, 2023
bcb8960
Using GetStackTraceNode.stackTraceToArray to obtain standard Enso sta…
JaroslavTulach Dec 21, 2023
1355b7a
Ensure correctness of the tests
JaroslavTulach Dec 21, 2023
7e68aba
Keep stacktrace of index out of bounds DataflowError
JaroslavTulach Dec 21, 2023
eaa8be1
Depp locations of DataflowError aren't tracked
JaroslavTulach Dec 21, 2023
086c1d9
Adding changelog note
JaroslavTulach Dec 21, 2023
4849ef9
Always sent in InteropLibrary
JaroslavTulach Dec 21, 2023
8271b26
Merging and resolving conficts
JaroslavTulach Dec 21, 2023
891b08d
Make sure RuntimeVisualizationsTest passes OK
JaroslavTulach Dec 21, 2023
10a54f1
Merging with latest develop branch
JaroslavTulach Dec 22, 2023
2b2f253
Drop just a single frame in Runtime.get_stack_trace
JaroslavTulach Dec 22, 2023
c068407
Giving the field ownTrace name
JaroslavTulach Dec 22, 2023
9d4c333
Report unexpected exceptions when assertions are on
JaroslavTulach Dec 22, 2023
13e1da6
Centralized ownTrace check
JaroslavTulach Dec 22, 2023
1152e3d
Format multiline strings properly
JaroslavTulach Dec 22, 2023
10a8452
Record full stack traces when running with assertions
JaroslavTulach Dec 22, 2023
a5616da
Adjusting to -ea and not -ea difference
JaroslavTulach Dec 22, 2023
80dc1cb
Check for != -1
JaroslavTulach Dec 23, 2023
f943a2b
Verify polyglot Enso/Java stacktrace is mixed
JaroslavTulach Dec 24, 2023
2e7199f
Get ready for error_message being Nothing
JaroslavTulach Dec 24, 2023
e98ded3
Location doesn't have to be a Text
JaroslavTulach Dec 24, 2023
903e7d9
Record stacktrace without using PanicException
JaroslavTulach Dec 24, 2023
c678799
Documenting how to get full stack trace
JaroslavTulach Dec 24, 2023
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@
- [Export of non-existing symbols results in error][7960]
- [Upgrade GraalVM to 23.1.0 JDK21][7991]
- [Added opt-in type checks of return type][8502]
- [DataflowError.withoutTrace doesn't store stacktrace][8608]
- [Added text_length to Column][8606]

[3227]: https://github.com/enso-org/enso/pull/3227
Expand Down Expand Up @@ -1162,6 +1163,7 @@
[7960]: https://github.com/enso-org/enso/pull/7960
[7991]: https://github.com/enso-org/enso/pull/7991
[8502]: https://github.com/enso-org/enso/pull/8502
[8608]: https://github.com/enso-org/enso/pull/8608
[8606]: https://github.com/enso-org/enso/pull/8606

# Enso 2.0.0-alpha.18 (2021-10-12)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ error_preprocessor x =
message = err.to_display_text
stack_trace = x.get_stack_trace_text.if_nothing "" . split '\n'
truncated_message = Helpers.truncate message
full_message = truncated_message + if stack_trace.length > 1 then " (" + stack_trace.at 1 . trim +")" else ""
full_message = truncated_message + if stack_trace.length > 0 then " (" + stack_trace.at 0 . trim +")" else ""
JS_Object.from_pairs [['kind', 'Dataflow'], ['message', full_message]] . to_json

if result.is_error then result.catch else ok
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.enso.interpreter.instrument.execution

import com.oracle.truffle.api.{TruffleStackTrace, TruffleStackTraceElement}
import com.oracle.truffle.api.interop.InteropLibrary
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.interpreter.node.expression.builtin.runtime.GetStackTraceNode

import java.io.File
import scala.jdk.CollectionConverters._
import scala.jdk.OptionConverters.RichOptional

/** Methods for handling exceptions in the interpreter. */
Expand All @@ -19,42 +19,50 @@ object ErrorResolver {
def getStackTrace(
throwable: Throwable
)(implicit ctx: RuntimeContext): Vector[Api.StackTraceElement] = {
TruffleStackTrace
.getStackTrace(throwable)
.asScala
.flatMap(toStackElement)
.toVector
val iop = InteropLibrary.getUncached
val arr = GetStackTraceNode.stackTraceToArray(iop, throwable)
val len = iop.getArraySize(arr)
val stackWithOptions = for (i <- 0L until len) yield {
val elem = iop.readArrayElement(arr, i)
toStackElement(iop, elem)
}
val stack = stackWithOptions.map(op => op.get)
stack.toVector
}

/** Convert from the truffle stack element to the runtime API representation.
*
* @param iop interop library to use
* @param element the trufle stack trace element
* @param ctx the runtime context
* @return the runtime API representation of the stack trace element
*/
private def toStackElement(
element: TruffleStackTraceElement
iop: InteropLibrary,
element: Any
)(implicit ctx: RuntimeContext): Option[Api.StackTraceElement] = {
val node = Option(element.getLocation)
node.flatMap(x => {
x.getEncapsulatingSourceSection match {
case null if x.getRootNode == null =>
if (!iop.hasExecutableName(element)) {
None
} else {
val name = iop.asString(iop.getExecutableName(element))
if (!iop.hasSourceLocation(element)) {
Some(Api.StackTraceElement(name, None, None, None))
} else {
val section = iop.getSourceLocation(element)
if (section.getSource.isInternal) {
None
case null if x.getRootNode.isInternal =>
None
case null =>
Some(Api.StackTraceElement(x.getRootNode.getName, None, None, None))
case section =>
} else {
Some(
Api.StackTraceElement(
element.getTarget.getRootNode.getName,
name,
findFileByModuleName(section.getSource.getName),
Some(LocationResolver.sectionToRange(section)),
LocationResolver.getExpressionId(section).map(_.externalId)
)
)
}
}
})
}
}

/** Find source file path by the module name.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
package org.enso.interpreter.node.expression.builtin.error;

import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.AcceptsError;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.runtime.GetStackTraceNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.error.PanicException;

@BuiltinMethod(
type = "Panic",
name = "primitive_get_attached_stack_trace",
description = "Gets the stack trace attached to the throwable.")
public class GetAttachedStackTraceNode extends Node {
EnsoObject execute(@AcceptsError Object error) {
if (error instanceof Throwable) {
return GetStackTraceNode.stackTraceToArray((Throwable) error);
} else {
Builtins builtins = EnsoContext.get(this).getBuiltins();
throw new PanicException(
builtins.error().makeTypeError("Throwable", error, "throwable"), this);
}
@Child private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(3);

Object execute(@AcceptsError Object error) {
return GetStackTraceNode.stackTraceToArray(iop, error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
@BuiltinMethod(
type = "Error",
name = "throw",
description = "Returns a new value error with given payload.")
description = "Returns a new value error with given payload.",
inlineable = true)
public class ThrowErrorNode extends Node {
public Object execute(VirtualFrame giveMeAStackFrame, Object payload) {
return DataflowError.withoutTrace(payload, this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode;
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;

@BuiltinMethod(
type = "Array_Like_Helpers",
Expand All @@ -25,7 +26,7 @@ Object execute(Object arrayLike, long index) {
var len = len(arrayLike);
var ctx = EnsoContext.get(this);
var payload = ctx.getBuiltins().error().makeIndexOutOfBounds(index, len);
return DataflowError.withoutTrace(payload, this);
return DataflowError.withTrace(payload, new PanicException(payload, this));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleStackTrace;
import com.oracle.truffle.api.TruffleStackTraceElement;
import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.Node;
import java.util.List;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.data.text.Text;
Expand All @@ -23,34 +28,87 @@ public static GetStackTraceNode create() {
return new GetStackTraceNode();
}

@CompilerDirectives.TruffleBoundary
private static EnsoObject wrapStackTraceElements(List<TruffleStackTraceElement> elements) {
var arr = new Object[elements.size()];
for (var i = 0; i < arr.length; i++) {
var e = elements.get(i);
arr[i] = e.getGuestObject();
}
var vector = ArrayLikeHelpers.asVectorWithCheckAt(arr);
try {
return filterStackTraceVector(InteropLibrary.getUncached(), vector);
} catch (UnsupportedMessageException ex) {
return ArrayLikeHelpers.empty();
}
}

private static boolean includeFrame(InteropLibrary iop, Object elem)
throws UnsupportedMessageException {
if (!iop.hasSourceLocation(elem)) {
return false;
}
var ss = iop.getSourceLocation(elem);
if (ss == null) {
return false;
}
var src = ss.getSource();
return src != null && src.hasCharacters() && !src.isInternal();
}

private static EnsoObject filterStackTraceVector(InteropLibrary iop, Object elements)
throws UnsupportedMessageException {
var size = iop.getArraySize(elements);
var count = 0;
for (long i = 0; i < size; i++) {
try {
var element = iop.readArrayElement(elements, i);
if (includeFrame(iop, element)) {
count++;
}
} catch (InvalidArrayIndexException ex) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
}
}
var arr = new Object[count];
var at = 0;
for (long i = 0; i < size; i++) {
try {
var element = iop.readArrayElement(elements, i);
if (includeFrame(iop, element)) {
arr[at++] = element;
}
} catch (InvalidArrayIndexException ex) {
}
}
return ArrayLikeHelpers.wrapObjectsWithCheckAt(arr);
}

EnsoObject execute(VirtualFrame requestOwnStackFrame) {
var exception = new PanicException(Text.create("Stacktrace"), this);
TruffleStackTrace.fillIn(exception);
return stackTraceToArray(exception);
}

public static EnsoObject stackTraceToArray(InteropLibrary iop, Object exception) {
if (iop.hasExceptionStackTrace(exception)) {
try {
var elements = iop.getExceptionStackTrace(exception);
return filterStackTraceVector(iop, elements);
} catch (UnsupportedMessageException ex) {
// return empty
}
} else if (exception instanceof Throwable t) {
return stackTraceToArray(t);
}
return ArrayLikeHelpers.empty();
}

@CompilerDirectives.TruffleBoundary
public static EnsoObject stackTraceToArray(Throwable exception) {
private static EnsoObject stackTraceToArray(Throwable exception) {
var elements = TruffleStackTrace.getStackTrace(exception);
if (elements == null) {
return ArrayLikeHelpers.empty();
}
int count = 0;
for (int i = 0; i < elements.size(); i++) {
var element = elements.get(i);
if (element.getTarget().getRootNode().isInternal()) {
continue;
}
count++;
}
var arr = new Object[count];
for (int i = 0, at = 0; i < elements.size(); i++) {
var element = elements.get(i);
if (element.getTarget().getRootNode().isInternal()) {
continue;
}
arr[at++] = element.getGuestObject();
}
return ArrayLikeHelpers.wrapObjectsWithCheckAt(arr);
return wrapStackTraceElements(elements);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleStackTrace;
import com.oracle.truffle.api.TruffleStackTraceElement;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.interop.InteropLibrary;
Expand All @@ -13,6 +14,7 @@
import java.util.Objects;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;

/**
Expand All @@ -28,6 +30,7 @@ public final class DataflowError extends AbstractTruffleException {
public static final DataflowError UNINITIALIZED = new DataflowError(null, (Node) null);

private final Object payload;
private final boolean without;
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved

/**
* Construct a new dataflow error with the default stack trace.
Expand All @@ -40,8 +43,7 @@ public final class DataflowError extends AbstractTruffleException {
*/
public static DataflowError withoutTrace(Object payload, Node location) {
assert payload != null;
DataflowError result = new DataflowError(payload, location);
TruffleStackTrace.fillIn(result);
var result = new DataflowError(payload, location);
return result;
}

Expand All @@ -57,17 +59,21 @@ public static DataflowError withoutTrace(Object payload, Node location) {
*/
public static DataflowError withTrace(Object payload, AbstractTruffleException prototype) {
assert payload != null;
return new DataflowError(payload, prototype);
var result = new DataflowError(payload, prototype);
TruffleStackTrace.fillIn(result);
return result;
}

DataflowError(Object payload, Node location) {
super(location);
super(null, null, 1, location);
this.payload = payload;
this.without = true;
}

DataflowError(Object payload, AbstractTruffleException prototype) {
super(prototype);
this.payload = payload;
this.without = false;
}

/**
Expand Down Expand Up @@ -116,6 +122,22 @@ boolean isException() {
return true;
}

@ExportMessage
boolean hasExceptionStackTrace() {
var node = this.getLocation();
return node != null && node.getRootNode() != null && without;
}

@ExportMessage
Object getExceptionStackTrace() throws UnsupportedMessageException {
var node = this.getLocation();
if (node == null || node.getRootNode() == null || !without) {
throw UnsupportedMessageException.create();
}
var frame = TruffleStackTraceElement.create(node, node.getRootNode().getCallTarget(), null);
return ArrayLikeHelpers.asVectorWithCheckAt(frame.getGuestObject());
}

@ExportMessage
boolean isNull() {
return payload == null;
Expand Down
Loading
Loading