com.oracle.truffle.api.exception.AbstractTruffleException Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of truffle-api Show documentation
Show all versions of truffle-api Show documentation
Truffle is a multi-language framework for executing dynamic languages
that achieves high performance when combined with Graal.
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.truffle.api.exception;
import org.graalvm.polyglot.PolyglotException;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleStackTrace;
import com.oracle.truffle.api.interop.ExceptionType;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;
/**
* A base class for an exception thrown during the execution of a guest language program.
* The following snippet shows the guest language exception implementation.
*
*
* final class MyLanguageException extends AbstractTruffleException {
* MyLanguageException(String message, Node location) {
* super(message, location);
* }
* }
*
*
* The following snippet shows a typical implementation of a syntax error exception supporting also
* incomplete sources.
*
*
* @ExportLibrary(InteropLibrary.class)
* final class MyLanguageParseError extends AbstractTruffleException {
* private final Source source;
* private final int line;
* private final int column;
* private final int length;
* private final boolean incompleteSource;
*
* MyLanguageParseError(Source source, int line, int column, int length, boolean incomplete, String message) {
* super(message);
* this.source = source;
* this.line = line;
* this.column = column;
* this.length = length;
* this.incompleteSource = incomplete;
* }
*
* @ExportMessage
* ExceptionType getExceptionType() {
* return ExceptionType.PARSE_ERROR;
* }
*
* @ExportMessage
* boolean isExceptionIncompleteSource() {
* return incompleteSource;
* }
*
* @ExportMessage
* boolean hasSourceLocation() {
* return source != null;
* }
*
* @ExportMessage(name = "getSourceLocation")
* SourceSection getSourceSection() throws UnsupportedMessageException {
* if (source == null) {
* throw UnsupportedMessageException.create();
* }
* return source.createSection(line, column, length);
* }
* }
*
*
* The following snippet shows a typical implementation of an interrupt exception.
*
*
* @ExportLibrary(InteropLibrary.class)
* final class MyLanguageInterruptException extends AbstractTruffleException {
*
* MyLanguageInterruptException(String message, Node location) {
* super(message, location);
* }
*
* @ExportMessage
* ExceptionType getExceptionType() {
* return ExceptionType.INTERRUPT;
* }
* }
*
*
* The following snippet shows a typical implementation of an soft exit exception.
*
*
* @ExportLibrary(InteropLibrary.class)
* final class MyLanguageExitException extends AbstractTruffleException {
*
* private final int exitStatus;
*
* MyLanguageExitException(String message, int exitStatus, Node location) {
* super(message, location);
* this.exitStatus = exitStatus;
* }
*
* @ExportMessage
* ExceptionType getExceptionType() {
* return ExceptionType.EXIT;
* }
*
* @ExportMessage
* int getExceptionExitStatus() {
* return exitStatus;
* }
* }
*
*
* @since 20.3
*/
@SuppressWarnings({"serial", "deprecation"})
public abstract class AbstractTruffleException extends RuntimeException implements TruffleObject, com.oracle.truffle.api.TruffleException {
/**
* The constant for an unlimited stack trace element limit.
*
* @since 20.3
*/
public static final int UNLIMITED_STACK_TRACE = -1;
private final int stackTraceElementLimit;
private final Throwable cause;
private final Node location;
private Throwable lazyStackTrace;
/**
* Creates a new AbstractTruffleException.
*
* @since 20.3
*/
protected AbstractTruffleException() {
this(null, null, UNLIMITED_STACK_TRACE, null);
}
/**
* Creates a new AbstractTruffleException with given location.
*
* @since 20.3
*/
protected AbstractTruffleException(Node location) {
this(null, null, UNLIMITED_STACK_TRACE, location);
}
/**
* Creates a new AbstractTruffleException with given message.
*
* @since 20.3
*/
protected AbstractTruffleException(String message) {
this(message, null, UNLIMITED_STACK_TRACE, null);
}
/**
* Creates a new AbstractTruffleException with given message and location.
*
* @since 20.3
*/
protected AbstractTruffleException(String message, Node location) {
this(message, null, UNLIMITED_STACK_TRACE, location);
}
/**
* Creates a new AbstractTruffleException initialized from the given prototype. The exception
* message, internal cause, stack trace limit, location, suppressed exceptions and Truffle stack
* trace of a newly created {@link AbstractTruffleException} are inherited from the given
* {@link AbstractTruffleException}.
*
* @since 20.3
*/
@TruffleBoundary
protected AbstractTruffleException(AbstractTruffleException prototype) {
this(prototype.getMessage(), prototype.getCause(), prototype.getStackTraceElementLimit(), prototype.getLocation());
for (Throwable t : prototype.getSuppressed()) {
this.addSuppressed(t);
}
TruffleStackTrace.fillIn(prototype);
assert prototype.lazyStackTrace != null : "Prototype must have a stack trace after fillIn.";
this.lazyStackTrace = prototype.lazyStackTrace;
}
/**
* Creates a new AbstractTruffleException.
*
* @param message the exception message or {@code null}
* @param cause an internal or {@link AbstractTruffleException} causing this exception or
* {@code null}. If internal errors are passed as cause, they are not accessible by
* other languages or the embedder. In other words,
* {@link InteropLibrary#getExceptionCause(Object)} or
* {@link PolyglotException#getCause()} will return null
for internal
* errors.
* @param stackTraceElementLimit a stack trace limit. Use {@link #UNLIMITED_STACK_TRACE} for
* unlimited stack trace length.
*
* @since 20.3
*/
protected AbstractTruffleException(String message, Throwable cause, int stackTraceElementLimit, Node location) {
super(message, cause);
this.stackTraceElementLimit = stackTraceElementLimit;
this.cause = cause;
this.location = location;
}
/**
* {@inheritDoc}
*
* @since 20.3
*/
@Override
@SuppressWarnings("sync-override")
public final Throwable fillInStackTrace() {
return this;
}
/**
* Returns a node indicating the location where this exception occurred in the AST. This method
* may return {@code null} to indicate that the location is not available.
*
* @since 20.3
*/
@Override
public final Node getLocation() {
return location;
}
/**
* Returns the number of guest language frames that should be collected for this exception.
* Returns a negative integer by default for unlimited guest language frames. This is intended
* to be used by guest languages to limit the number of guest language stack frames. Languages
* might want to limit the number of frames for performance reasons. Only frames whose
* {@link RootNode#countsTowardsStackTraceLimit()} method return true count towards the limit.
*
* @since 20.3
*/
@Override
public final int getStackTraceElementLimit() {
return stackTraceElementLimit;
}
/**
* Returns a location where this exception occurred in the AST.
*
* @deprecated Use {@link InteropLibrary#getSourceLocation(Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final SourceSection getSourceLocation() {
InteropLibrary interop = InteropLibrary.getUncached();
if (interop.hasSourceLocation(this)) {
try {
return interop.getSourceLocation(this);
} catch (UnsupportedMessageException um) {
throw CompilerDirectives.shouldNotReachHere(um);
}
} else {
return null;
}
}
/**
* Returns {@code this} as an additional guest language object.
*
* @since 20.3
*/
@Deprecated
@Override
public final Object getExceptionObject() {
return this;
}
/**
* Returns {@code true} if this exception indicates a parser or syntax error.
*
* @deprecated Use {@link InteropLibrary#getExceptionType(Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final boolean isSyntaxError() {
return getExceptionType() == ExceptionType.PARSE_ERROR;
}
/**
* Returns {@code true} if this exception indicates a syntax error that is indicating that the
* syntax is incomplete.
*
* @deprecated Use {@link InteropLibrary#isExceptionIncompleteSource(Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final boolean isIncompleteSource() {
try {
return InteropLibrary.getUncached().isExceptionIncompleteSource(this);
} catch (UnsupportedMessageException um) {
throw CompilerDirectives.shouldNotReachHere(um);
}
}
/**
* Returns {@code false} as internal error is no {@link InteropLibrary#isException(Object)
* exception object}.
*
* @deprecated Use {@link InteropLibrary#isException(java.lang.Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final boolean isInternalError() {
return false;
}
/**
* Returns {@code true} if this exception indicates that guest language application was
* cancelled during its execution.
*
* @deprecated Use {@link InteropLibrary#getExceptionType(Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final boolean isCancelled() {
return false;
}
/**
* Returns {@code true} if the exception indicates that the application was exited within the
* guest language program.
*
* @deprecated Use {@link InteropLibrary#getExceptionType(Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final boolean isExit() {
return getExceptionType() == ExceptionType.EXIT;
}
/**
* Returns the exit status if this exception indicates that the application was exited.
*
* @deprecated Use {@link InteropLibrary#getExceptionExitStatus(Object)}.
* @since 20.3
*/
@Deprecated
@Override
public final int getExitStatus() {
try {
return InteropLibrary.getUncached().getExceptionExitStatus(this);
} catch (UnsupportedMessageException um) {
throw CompilerDirectives.shouldNotReachHere(um);
}
}
/**
* Setting a cause is not supported.
*
* @deprecated Pass in the cause using the constructors instead.
* @since 20.3
*/
@Deprecated
@TruffleBoundary
@Override
@SuppressWarnings("sync-override")
public final Throwable initCause(Throwable throwable) {
throw new UnsupportedOperationException("Not supported. Pass in the cause using the constructors instead.");
}
/**
* {@inheritDoc}
*
* @since 20.3
*/
@Override
@SuppressWarnings("sync-override")
public final Throwable getCause() {
return cause;
}
Throwable getLazyStackTrace() {
return lazyStackTrace;
}
void setLazyStackTrace(Throwable stackTrace) {
this.lazyStackTrace = stackTrace;
}
private ExceptionType getExceptionType() {
try {
return InteropLibrary.getUncached().getExceptionType(this);
} catch (UnsupportedMessageException um) {
throw CompilerDirectives.shouldNotReachHere(um);
}
}
@SuppressWarnings("deprecation")
static boolean isTruffleException(Throwable t) {
return t instanceof com.oracle.truffle.api.TruffleException;
}
}