2015-12-11 12:26:16 +00:00
|
|
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2018-02-02 12:05:19 +00:00
|
|
|
#ifndef V8_WASM_WASM_RESULT_H_
|
|
|
|
#define V8_WASM_WASM_RESULT_H_
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2017-04-11 17:12:07 +00:00
|
|
|
#include <cstdarg>
|
2016-07-25 10:24:45 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2016-04-12 16:13:08 +00:00
|
|
|
#include "src/base/compiler-specific.h"
|
2019-02-25 16:48:13 +00:00
|
|
|
#include "src/base/macros.h"
|
|
|
|
#include "src/base/platform/platform.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
#include "src/globals.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
class Isolate;
|
2018-11-05 12:43:43 +00:00
|
|
|
template <typename T>
|
|
|
|
class Handle;
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
namespace wasm {
|
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
class V8_EXPORT_PRIVATE WasmError {
|
|
|
|
public:
|
|
|
|
WasmError() = default;
|
2017-04-28 11:21:00 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
WasmError(uint32_t offset, std::string message)
|
|
|
|
: offset_(offset), message_(std::move(message)) {
|
|
|
|
// The error message must not be empty, otherwise {empty()} would be true.
|
|
|
|
DCHECK(!message_.empty());
|
|
|
|
}
|
2017-04-28 11:21:00 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
PRINTF_FORMAT(3, 4)
|
|
|
|
WasmError(uint32_t offset, const char* format, ...) : offset_(offset) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
message_ = FormatError(format, args);
|
|
|
|
va_end(args);
|
|
|
|
// The error message must not be empty, otherwise {empty()} would be true.
|
|
|
|
DCHECK(!message_.empty());
|
|
|
|
}
|
2017-09-14 17:34:15 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
bool empty() const { return message_.empty(); }
|
|
|
|
bool has_error() const { return !message_.empty(); }
|
2017-04-28 11:21:00 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
uint32_t offset() const { return offset_; }
|
|
|
|
const std::string& message() const& { return message_; }
|
|
|
|
std::string&& message() && { return std::move(message_); }
|
2017-04-28 11:21:00 +00:00
|
|
|
|
2018-10-22 13:03:14 +00:00
|
|
|
protected:
|
|
|
|
static std::string FormatError(const char* format, va_list args);
|
|
|
|
|
2017-04-28 11:21:00 +00:00
|
|
|
private:
|
2019-01-14 17:51:56 +00:00
|
|
|
uint32_t offset_ = 0;
|
|
|
|
std::string message_;
|
2017-04-28 11:21:00 +00:00
|
|
|
};
|
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
// Either a result of type T, or a WasmError.
|
2015-12-11 12:26:16 +00:00
|
|
|
template <typename T>
|
2019-01-14 17:51:56 +00:00
|
|
|
class Result {
|
2017-04-10 10:48:48 +00:00
|
|
|
public:
|
|
|
|
Result() = default;
|
|
|
|
|
|
|
|
template <typename S>
|
2018-10-19 12:35:56 +00:00
|
|
|
explicit Result(S&& value) : value_(std::forward<S>(value)) {}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2017-04-10 10:48:48 +00:00
|
|
|
template <typename S>
|
2019-01-14 17:51:56 +00:00
|
|
|
Result(Result<S>&& other) V8_NOEXCEPT : value_(std::move(other.value_)),
|
|
|
|
error_(std::move(other.error_)) {}
|
2017-04-10 10:48:48 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
explicit Result(WasmError error) : error_(std::move(error)) {}
|
2017-04-10 10:48:48 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
template <typename S>
|
|
|
|
Result& operator=(Result<S>&& other) V8_NOEXCEPT {
|
|
|
|
value_ = std::move(other.value_);
|
|
|
|
error_ = std::move(other.error_);
|
|
|
|
return *this;
|
2018-10-23 12:21:42 +00:00
|
|
|
}
|
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
bool ok() const { return error_.empty(); }
|
|
|
|
bool failed() const { return error_.has_error(); }
|
|
|
|
const WasmError& error() const& { return error_; }
|
|
|
|
WasmError&& error() && { return std::move(error_); }
|
2018-10-30 12:46:04 +00:00
|
|
|
|
2018-10-19 12:35:56 +00:00
|
|
|
// Accessor for the value. Returns const reference if {this} is l-value or
|
|
|
|
// const, and returns r-value reference if {this} is r-value. This allows to
|
|
|
|
// extract non-copyable values like {std::unique_ptr} by using
|
|
|
|
// {std::move(result).value()}.
|
|
|
|
const T& value() const & {
|
|
|
|
DCHECK(ok());
|
|
|
|
return value_;
|
|
|
|
}
|
|
|
|
T&& value() && {
|
|
|
|
DCHECK(ok());
|
|
|
|
return std::move(value_);
|
|
|
|
}
|
2017-04-28 11:21:00 +00:00
|
|
|
|
2017-04-10 10:48:48 +00:00
|
|
|
private:
|
2019-01-14 17:51:56 +00:00
|
|
|
template <typename S>
|
|
|
|
friend class Result;
|
2018-10-19 12:35:56 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
T value_ = T{};
|
|
|
|
WasmError error_;
|
2018-10-22 13:03:14 +00:00
|
|
|
|
2017-04-10 10:48:48 +00:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(Result);
|
|
|
|
};
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
// A helper for generating error messages that bubble up to JS exceptions.
|
2016-09-26 07:40:24 +00:00
|
|
|
class V8_EXPORT_PRIVATE ErrorThrower {
|
2015-12-11 12:26:16 +00:00
|
|
|
public:
|
2017-04-30 09:03:38 +00:00
|
|
|
ErrorThrower(Isolate* isolate, const char* context)
|
2016-06-21 12:52:57 +00:00
|
|
|
: isolate_(isolate), context_(context) {}
|
2017-04-30 11:35:53 +00:00
|
|
|
// Explicitly allow move-construction. Disallow copy (below).
|
2018-08-02 08:16:29 +00:00
|
|
|
ErrorThrower(ErrorThrower&& other) V8_NOEXCEPT;
|
2016-06-21 12:52:57 +00:00
|
|
|
~ErrorThrower();
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2016-09-21 10:40:16 +00:00
|
|
|
PRINTF_FORMAT(2, 3) void TypeError(const char* fmt, ...);
|
|
|
|
PRINTF_FORMAT(2, 3) void RangeError(const char* fmt, ...);
|
2016-10-13 16:17:44 +00:00
|
|
|
PRINTF_FORMAT(2, 3) void CompileError(const char* fmt, ...);
|
2016-12-16 14:23:35 +00:00
|
|
|
PRINTF_FORMAT(2, 3) void LinkError(const char* fmt, ...);
|
2016-10-13 16:17:44 +00:00
|
|
|
PRINTF_FORMAT(2, 3) void RuntimeError(const char* fmt, ...);
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2019-01-14 17:51:56 +00:00
|
|
|
void CompileFailed(const WasmError& error) {
|
|
|
|
DCHECK(error.has_error());
|
|
|
|
CompileError("%s @+%u", error.message().c_str(), error.offset());
|
2018-10-30 12:46:04 +00:00
|
|
|
}
|
|
|
|
|
2017-05-02 14:37:19 +00:00
|
|
|
// Create and return exception object.
|
2018-04-09 15:12:07 +00:00
|
|
|
V8_WARN_UNUSED_RESULT Handle<Object> Reify();
|
2017-05-02 14:37:19 +00:00
|
|
|
|
|
|
|
// Reset any error which was set on this thrower.
|
|
|
|
void Reset();
|
2016-06-21 12:52:57 +00:00
|
|
|
|
2017-04-30 09:03:38 +00:00
|
|
|
bool error() const { return error_type_ != kNone; }
|
|
|
|
bool wasm_error() { return error_type_ >= kFirstWasmError; }
|
2018-08-06 15:01:26 +00:00
|
|
|
const char* error_msg() { return error_msg_.c_str(); }
|
2015-12-11 12:26:16 +00:00
|
|
|
|
[wasm] Use pending exceptions consistently
In our internal code, we should only use pending exceptions. They will
be converted to scheduled exceptions on the API boundary.
Hence, the ErrorThrower just sets a pending exception; it should never
have to think about scheduled exceptions. The new
ScheduledErrorThrower inherits from ErrorThrower and reschedules any
pending exceptions in its destructor (turning them into scheduled
exceptions).
In some situations, there might already be a scheduled exception, e.g.
when calling other API methods (v8::Value::Get). In this case, the
ErrorThrower should also not set another pending exception. For the
reasons mentioned above, this can only be handled in the
ScheduledErrorThrower, which is used the API methods.
This fixes one DCHECK failure and one TODO about scheduled exceptions
if no instance can be created, because the start function throws.
R=mtrofin@chromium.org, mstarzinger@chromium.org
BUG=v8:6232,chromium:736256
Change-Id: I4905be04c565df9495de18fb26adbb5c05d193d2
Reviewed-on: https://chromium-review.googlesource.com/548641
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46314}
2017-06-29 08:16:29 +00:00
|
|
|
Isolate* isolate() const { return isolate_; }
|
|
|
|
|
2015-12-11 12:26:16 +00:00
|
|
|
private:
|
2017-04-30 09:03:38 +00:00
|
|
|
enum ErrorType {
|
|
|
|
kNone,
|
|
|
|
// General errors.
|
|
|
|
kTypeError,
|
|
|
|
kRangeError,
|
|
|
|
// Wasm errors.
|
|
|
|
kCompileError,
|
|
|
|
kLinkError,
|
|
|
|
kRuntimeError,
|
|
|
|
|
|
|
|
// Marker.
|
|
|
|
kFirstWasmError = kCompileError
|
|
|
|
};
|
|
|
|
|
|
|
|
void Format(ErrorType error_type_, const char* fmt, va_list);
|
|
|
|
|
|
|
|
Isolate* isolate_;
|
2015-12-11 12:26:16 +00:00
|
|
|
const char* context_;
|
2017-04-30 09:03:38 +00:00
|
|
|
ErrorType error_type_ = kNone;
|
|
|
|
std::string error_msg_;
|
2017-04-30 11:35:53 +00:00
|
|
|
|
[wasm] Use pending exceptions consistently
In our internal code, we should only use pending exceptions. They will
be converted to scheduled exceptions on the API boundary.
Hence, the ErrorThrower just sets a pending exception; it should never
have to think about scheduled exceptions. The new
ScheduledErrorThrower inherits from ErrorThrower and reschedules any
pending exceptions in its destructor (turning them into scheduled
exceptions).
In some situations, there might already be a scheduled exception, e.g.
when calling other API methods (v8::Value::Get). In this case, the
ErrorThrower should also not set another pending exception. For the
reasons mentioned above, this can only be handled in the
ScheduledErrorThrower, which is used the API methods.
This fixes one DCHECK failure and one TODO about scheduled exceptions
if no instance can be created, because the start function throws.
R=mtrofin@chromium.org, mstarzinger@chromium.org
BUG=v8:6232,chromium:736256
Change-Id: I4905be04c565df9495de18fb26adbb5c05d193d2
Reviewed-on: https://chromium-review.googlesource.com/548641
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46314}
2017-06-29 08:16:29 +00:00
|
|
|
// ErrorThrower should always be stack-allocated, since it constitutes a scope
|
|
|
|
// (things happen in the destructor).
|
2019-02-13 00:33:17 +00:00
|
|
|
DISALLOW_NEW_AND_DELETE()
|
2018-12-10 13:00:02 +00:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(ErrorThrower);
|
2015-12-11 12:26:16 +00:00
|
|
|
};
|
2017-04-10 10:48:48 +00:00
|
|
|
|
2018-10-19 12:49:39 +00:00
|
|
|
// Use {nullptr_t} as data value to indicate that this only stores the error,
|
|
|
|
// but no result value (the only valid value is {nullptr}).
|
|
|
|
// [Storing {void} would require template specialization.]
|
|
|
|
using VoidResult = Result<std::nullptr_t>;
|
|
|
|
|
2015-12-11 12:26:16 +00:00
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|
|
|
|
|
2018-02-02 12:05:19 +00:00
|
|
|
#endif // V8_WASM_WASM_RESULT_H_
|