[wasm] Split Result/ResultBase in WasmError and Result

We often use ResultBase or VoidResult to store or pass wasm errors
(errors with locations). This CL extracts a WasmError class which can
store an error (can also be empty), and Result<T> which stores an error
or a T (exactly one of them).

R=titzer@chromium.org

Bug: v8:8689
Change-Id: I3f5203559984a0ae8757e0130a9184957fa28df5
Reviewed-on: https://chromium-review.googlesource.com/c/1409365
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58827}
This commit is contained in:
Clemens Hammacher 2019-01-14 18:51:56 +01:00 committed by Commit Bot
parent 3b6d179b71
commit 57fa8f5ba3
16 changed files with 152 additions and 167 deletions

View File

@ -5847,10 +5847,11 @@ bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
if (graph_construction_result.failed()) {
if (FLAG_trace_wasm_compiler) {
StdoutStream{} << "Compilation failed: "
<< graph_construction_result.error_msg() << std::endl;
<< graph_construction_result.error().message()
<< std::endl;
}
native_module->compilation_state()->SetError(
wasm_unit_->func_index_, std::move(graph_construction_result));
wasm_unit_->func_index_, std::move(graph_construction_result).error());
return false;
}

View File

@ -14,7 +14,7 @@ namespace internal {
namespace wasm {
class NativeModule;
class ResultBase;
class WasmError;
enum RuntimeExceptionSupport : bool {
kRuntimeExceptionSupport = true,
@ -96,12 +96,12 @@ enum class CompilationEvent : uint8_t {
// This is the PIMPL interface to that private class.
class CompilationState {
public:
using callback_t = std::function<void(CompilationEvent, const ResultBase*)>;
using callback_t = std::function<void(CompilationEvent, const WasmError*)>;
~CompilationState();
void CancelAndWait();
void SetError(uint32_t func_index, const ResultBase& error_result);
void SetError(uint32_t func_index, const WasmError& error);
void SetWireBytesStorage(std::shared_ptr<WireBytesStorage>);

View File

@ -218,10 +218,10 @@ class Decoder {
template <typename T, typename U = typename std::remove_reference<T>::type>
Result<U> toResult(T&& val) {
if (failed()) {
TRACE("Result error: %s\n", error_msg_.c_str());
return Result<U>::Error(error_offset_, std::move(error_msg_));
TRACE("Result error: %s\n", error_.message().c_str());
return Result<U>{error_};
}
return Result<U>(std::forward<T>(val));
return Result<U>{std::forward<T>(val)};
}
// Resets the boundaries of this decoder.
@ -232,17 +232,17 @@ class Decoder {
pc_ = start;
end_ = end;
buffer_offset_ = buffer_offset;
error_offset_ = 0;
error_msg_.clear();
error_ = {};
}
void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
Reset(bytes.begin(), bytes.end(), buffer_offset);
}
bool ok() const { return error_msg_.empty(); }
bool ok() const { return error_.empty(); }
bool failed() const { return !ok(); }
bool more() const { return pc_ < end_; }
const WasmError& error() const { return error_; }
const byte* start() const { return start_; }
const byte* pc() const { return pc_; }
@ -271,8 +271,7 @@ class Decoder {
const byte* end_;
// The offset of the current buffer in the module. Needed for streaming.
uint32_t buffer_offset_;
uint32_t error_offset_ = 0;
std::string error_msg_;
WasmError error_;
private:
void verrorf(uint32_t offset, const char* format, va_list args) {
@ -287,8 +286,7 @@ class Decoder {
EmbeddedVector<char, kMaxErrorMsg> buffer;
int len = VSNPrintF(buffer, format, args);
CHECK_LT(0, len);
error_msg_.assign(buffer.start(), len);
error_offset_ = offset;
error_ = {offset, {buffer.start(), static_cast<size_t>(len)}};
onFirstError();
}

View File

@ -1423,9 +1423,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
bool TraceFailed() {
TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_offset_,
this->GetBufferRelativeOffset(this->error_offset_),
this->error_msg_.c_str());
TRACE("wasm-error module+%-6d func+%d: %s\n\n", this->error_.offset(),
this->GetBufferRelativeOffset(this->error_.offset()),
this->error_.message().c_str());
return false;
}
@ -2707,7 +2707,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
void onFirstError() override {
this->end_ = this->pc_; // Terminate decoding loop.
TRACE(" !%s\n", this->error_msg_.c_str());
TRACE(" !%s\n", this->error_.message().c_str());
CALL_INTERFACE(OnFirstError);
}

View File

@ -96,7 +96,7 @@ class CompilationStateImpl {
void Abort();
void SetError(uint32_t func_index, const ResultBase& error_result);
void SetError(uint32_t func_index, const WasmError& error);
Isolate* isolate() const { return isolate_; }
@ -117,7 +117,7 @@ class CompilationStateImpl {
// Call {GetCompileError} from foreground threads only, since we access
// NativeModule::wire_bytes, which is set from the foreground thread once the
// stream has finished.
VoidResult GetCompileError() {
WasmError GetCompileError() {
CompilationError* error = compile_error_.load(std::memory_order_acquire);
DCHECK_NOT_NULL(error);
std::ostringstream error_msg;
@ -131,8 +131,8 @@ class CompilationStateImpl {
} else {
error_msg << "wasm-function[" << error->func_index << "]";
}
error_msg << "\" failed: " << error->result.error_msg();
return VoidResult::Error(error->result.error_offset(), error_msg.str());
error_msg << "\" failed: " << error->error.message();
return WasmError{error->error.offset(), error_msg.str()};
}
std::shared_ptr<WireBytesStorage> GetSharedWireBytesStorage() const {
@ -155,10 +155,9 @@ class CompilationStateImpl {
private:
struct CompilationError {
uint32_t const func_index;
VoidResult const result;
CompilationError(uint32_t func_index, const ResultBase& compile_result)
: func_index(func_index),
result(VoidResult::ErrorFrom(compile_result)) {}
WasmError const error;
CompilationError(uint32_t func_index, WasmError error)
: func_index(func_index), error(std::move(error)) {}
};
class LogCodesTask : public CancelableTask {
@ -208,7 +207,7 @@ class CompilationStateImpl {
CompilationStateImpl* const compilation_state_;
};
void NotifyOnEvent(CompilationEvent event, const VoidResult* error_result);
void NotifyOnEvent(CompilationEvent event, const WasmError* error);
std::vector<std::unique_ptr<WasmCompilationUnit>>& finish_units() {
return baseline_compilation_finished() ? tiering_finish_units_
@ -305,9 +304,8 @@ CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
void CompilationState::CancelAndWait() { Impl(this)->CancelAndWait(); }
void CompilationState::SetError(uint32_t func_index,
const ResultBase& error_result) {
Impl(this)->SetError(func_index, error_result);
void CompilationState::SetError(uint32_t func_index, const WasmError& error) {
Impl(this)->SetError(func_index, error);
}
void CompilationState::SetWireBytesStorage(
@ -656,7 +654,8 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
TruncatedUserString<> name(wire_bytes.GetNameOrNull(&func, module));
thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i,
name.length(), name.start(),
result.error_msg().c_str(), result.error_offset());
result.error().message().c_str(),
result.error().offset());
break;
}
}
@ -894,7 +893,7 @@ class AsyncStreamingProcessor final : public StreamingProcessor {
void OnFinishedStream(OwnedVector<uint8_t> bytes) override;
void OnError(DecodeResult result) override;
void OnError(const WasmError&) override;
void OnAbort() override;
@ -903,7 +902,7 @@ class AsyncStreamingProcessor final : public StreamingProcessor {
private:
// Finishes the AsyncCompileJob with an error.
void FinishAsyncCompileJobWithError(ResultBase result);
void FinishAsyncCompileJobWithError(const WasmError&);
void CommitCompilationUnits();
@ -1027,7 +1026,7 @@ class AsyncCompileJob::CompilationStateCallback {
public:
explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
void operator()(CompilationEvent event, const ResultBase* error_result) {
void operator()(CompilationEvent event, const WasmError* error) {
// This callback is only being called from a foreground task.
switch (event) {
case CompilationEvent::kFinishedBaselineCompilation:
@ -1049,7 +1048,7 @@ class AsyncCompileJob::CompilationStateCallback {
break;
case CompilationEvent::kFailedCompilation:
DCHECK(!last_event_.has_value());
DCHECK_NOT_NULL(error_result);
DCHECK_NOT_NULL(error);
// Tier-up compilation should not fail if baseline compilation
// did not fail.
DCHECK(!Impl(job_->native_module_->compilation_state())
@ -1059,7 +1058,7 @@ class AsyncCompileJob::CompilationStateCallback {
SaveContext saved_context(job_->isolate());
job_->isolate()->set_context(*job_->native_context_);
ErrorThrower thrower(job_->isolate(), "AsyncCompilation");
thrower.CompileFailed(*error_result);
thrower.CompileFailed(nullptr, *error);
Handle<Object> error = thrower.Reify();
DeferredHandleScope deferred(job_->isolate());
@ -1230,7 +1229,7 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
}
if (result.failed()) {
// Decoding failure; reject the promise and clean up.
job->DoSync<DecodeFail>(std::move(result));
job->DoSync<DecodeFail>(std::move(result).error());
} else {
// Decode passed.
job->DoSync<PrepareAndStartCompile>(std::move(result).value(), true);
@ -1246,14 +1245,15 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
//==========================================================================
class AsyncCompileJob::DecodeFail : public CompileStep {
public:
explicit DecodeFail(ModuleResult result) : result_(std::move(result)) {}
explicit DecodeFail(WasmError error) : error_(std::move(error)) {}
private:
ModuleResult result_;
WasmError error_;
void RunInForeground(AsyncCompileJob* job) override {
TRACE_COMPILE("(1b) Decoding failed.\n");
ErrorThrower thrower(job->isolate_, "AsyncCompile");
thrower.CompileFailed("Wasm decoding failed", result_);
thrower.CompileFailed("Wasm decoding failed", error_);
// {job_} is deleted in AsyncCompileFailed, therefore the {return}.
return job->AsyncCompileFailed(thrower.Reify());
}
@ -1359,31 +1359,27 @@ AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
job_(job),
compilation_unit_builder_(nullptr) {}
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
DCHECK(error.failed());
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
const WasmError& error) {
DCHECK(error.has_error());
// Make sure all background tasks stopped executing before we change the state
// of the AsyncCompileJob to DecodeFail.
job_->background_task_manager_.CancelAndWait();
// Create a ModuleResult from the result we got as parameter. Since there was
// an error, we don't have to provide a real wasm module to the ModuleResult.
ModuleResult result = ModuleResult::ErrorFrom(std::move(error));
// Check if there is already a CompiledModule, in which case we have to clean
// up the CompilationStateImpl as well.
if (job_->native_module_) {
Impl(job_->native_module_->compilation_state())->Abort();
job_->DoSync<AsyncCompileJob::DecodeFail,
AsyncCompileJob::kUseExistingForegroundTask>(
std::move(result));
AsyncCompileJob::kUseExistingForegroundTask>(error);
// Clear the {compilation_unit_builder_} if it exists. This is needed
// because there is a check in the destructor of the
// {CompilationUnitBuilder} that it is empty.
if (compilation_unit_builder_) compilation_unit_builder_->Clear();
} else {
job_->DoSync<AsyncCompileJob::DecodeFail>(std::move(result));
job_->DoSync<AsyncCompileJob::DecodeFail>(error);
}
}
@ -1395,7 +1391,7 @@ bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
job_->isolate()->wasm_engine()->allocator());
decoder_.DecodeModuleHeader(bytes, offset);
if (!decoder_.ok()) {
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
return false;
}
return true;
@ -1427,7 +1423,7 @@ bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
constexpr bool verify_functions = false;
decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
if (!decoder_.ok()) {
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
return false;
}
return true;
@ -1441,7 +1437,7 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
functions_count);
if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
offset)) {
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false).error());
return false;
}
// Execute the PrepareAndStartCompile step immediately and not in a separate
@ -1493,7 +1489,7 @@ void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
TRACE_STREAMING("Finish stream...\n");
ModuleResult result = decoder_.FinishDecoding(false);
if (result.failed()) {
FinishAsyncCompileJobWithError(std::move(result));
FinishAsyncCompileJobWithError(result.error());
return;
}
// We have to open a HandleScope and prepare the Context for
@ -1518,9 +1514,9 @@ void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
}
// Report an error detected in the StreamingDecoder.
void AsyncStreamingProcessor::OnError(DecodeResult result) {
void AsyncStreamingProcessor::OnError(const WasmError& error) {
TRACE_STREAMING("Stream error...\n");
FinishAsyncCompileJobWithError(std::move(result));
FinishAsyncCompileJobWithError(error);
}
void AsyncStreamingProcessor::OnAbort() {
@ -1780,7 +1776,7 @@ void CompilationStateImpl::ScheduleFinisherTask() {
}
void CompilationStateImpl::Abort() {
SetError(0, VoidResult::Error(0, "Compilation aborted"));
SetError(0, WasmError{0, "Compilation aborted"});
background_task_manager_.CancelAndWait();
// No more callbacks after abort. Don't free the std::function objects here,
// since this might clear references in the embedder, which is only allowed on
@ -1793,32 +1789,32 @@ void CompilationStateImpl::Abort() {
}
void CompilationStateImpl::SetError(uint32_t func_index,
const ResultBase& error_result) {
DCHECK(error_result.failed());
std::unique_ptr<CompilationError> error =
base::make_unique<CompilationError>(func_index, error_result);
const WasmError& error) {
DCHECK(error.has_error());
std::unique_ptr<CompilationError> compile_error =
base::make_unique<CompilationError>(func_index, error);
CompilationError* expected = nullptr;
bool set = compile_error_.compare_exchange_strong(expected, error.get(),
std::memory_order_acq_rel);
bool set = compile_error_.compare_exchange_strong(
expected, compile_error.get(), std::memory_order_acq_rel);
// Ignore all but the first error. If the previous value is not nullptr, just
// return (and free the allocated error).
if (!set) return;
// If set successfully, give up ownership.
error.release();
compile_error.release();
// Schedule a foreground task to call the callback and notify users about the
// compile error.
foreground_task_runner_->PostTask(
MakeCancelableTask(&foreground_task_manager_, [this] {
VoidResult error_result = GetCompileError();
NotifyOnEvent(CompilationEvent::kFailedCompilation, &error_result);
WasmError error = GetCompileError();
NotifyOnEvent(CompilationEvent::kFailedCompilation, &error);
}));
}
void CompilationStateImpl::NotifyOnEvent(CompilationEvent event,
const VoidResult* error_result) {
const WasmError* error) {
if (aborted_.load()) return;
HandleScope scope(isolate_);
for (auto& callback : callbacks_) callback(event, error_result);
for (auto& callback : callbacks_) callback(event, error);
// If no more events are expected after this one, clear the callbacks to free
// memory. We can safely do this here, as this method is only called from
// foreground tasks.

View File

@ -1000,9 +1000,9 @@ class ModuleDecoderImpl : public Decoder {
CalculateGlobalOffsets(module_.get());
}
ModuleResult result = toResult(std::move(module_));
if (verify_functions && result.ok() && intermediate_result_.failed()) {
// Copy error code and location.
result = ModuleResult::ErrorFrom(std::move(intermediate_result_));
if (verify_functions && result.ok() && intermediate_error_.has_error()) {
// Copy error message and location.
return ModuleResult{std::move(intermediate_error_)};
}
return result;
}
@ -1057,8 +1057,8 @@ class ModuleDecoderImpl : public Decoder {
VerifyFunctionBody(zone->allocator(), 0, wire_bytes, module,
function.get());
if (intermediate_result_.failed()) {
return FunctionResult::ErrorFrom(std::move(intermediate_result_));
if (intermediate_error_.has_error()) {
return FunctionResult{std::move(intermediate_error_)};
}
return FunctionResult(std::move(function));
@ -1105,7 +1105,7 @@ class ModuleDecoderImpl : public Decoder {
sizeof(ModuleDecoderImpl::seen_unordered_sections_) >
kLastKnownModuleSection,
"not enough bits");
VoidResult intermediate_result_;
WasmError intermediate_error_;
ModuleOrigin origin_;
bool has_seen_unordered_section(SectionCode section_code) {
@ -1224,12 +1224,12 @@ class ModuleDecoderImpl : public Decoder {
// If the decode failed and this is the first error, set error code and
// location.
if (result.failed() && intermediate_result_.ok()) {
if (result.failed() && intermediate_error_.empty()) {
// Wrap the error message from the function decoder.
std::ostringstream error_msg;
error_msg << "in function " << func_name << ": " << result.error_msg();
intermediate_result_ =
VoidResult::Error(result.error_offset(), error_msg.str());
error_msg << "in function " << func_name << ": "
<< result.error().message();
intermediate_error_ = WasmError{result.error().offset(), error_msg.str()};
}
}
@ -1620,8 +1620,8 @@ ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
size_t size = module_end - module_start;
CHECK_LE(module_start, module_end);
if (size >= kV8MaxWasmModuleSize) {
return ModuleResult::Error(0, "size > maximum module size (%zu): %zu",
kV8MaxWasmModuleSize, size);
return ModuleResult{WasmError{0, "size > maximum module size (%zu): %zu",
kV8MaxWasmModuleSize, size}};
}
// TODO(bradnelson): Improve histogram handling of size_t.
auto size_counter =
@ -1740,8 +1740,9 @@ FunctionResult DecodeWasmFunctionForTesting(
// TODO(bradnelson): Improve histogram handling of ptrdiff_t.
size_histogram->AddSample(static_cast<int>(size));
if (size > kV8MaxWasmFunctionSize) {
return FunctionResult::Error(0, "size > maximum function size (%zu): %zu",
kV8MaxWasmFunctionSize, size);
return FunctionResult{WasmError{0,
"size > maximum function size (%zu): %zu",
kV8MaxWasmFunctionSize, size}};
}
ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin);
decoder.SetCounters(counters);

View File

@ -128,10 +128,9 @@ class TopTierCompiledCallback {
: native_module_(std::move(native_module)),
callback_(std::move(callback)) {}
void operator()(CompilationEvent event,
const ResultBase* error_result) const {
void operator()(CompilationEvent event, const WasmError* error) const {
if (event != CompilationEvent::kFinishedTopTierCompilation) return;
DCHECK_NULL(error_result);
DCHECK_NULL(error);
callback_(native_module_);
#ifdef DEBUG
DCHECK(!called_);
@ -327,7 +326,7 @@ size_t StreamingDecoder::DecodeVarInt32::ReadBytes(
if (decoder.failed()) {
if (new_bytes == remaining_buf.size()) {
// We only report an error if we read all bytes.
streaming->Error(decoder.toResult(nullptr));
streaming->Error(decoder.error());
}
set_offset(offset() + new_bytes);
return new_bytes;

View File

@ -51,7 +51,7 @@ class V8_EXPORT_PRIVATE StreamingProcessor {
// empty array is passed.
virtual void OnFinishedStream(OwnedVector<uint8_t> bytes) = 0;
// Report an error detected in the StreamingDecoder.
virtual void OnError(VoidResult result) = 0;
virtual void OnError(const WasmError&) = 0;
// Report the abortion of the stream.
virtual void OnAbort() = 0;
@ -202,14 +202,14 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
size_t length,
Vector<const uint8_t> length_bytes);
std::unique_ptr<DecodingState> Error(VoidResult result) {
if (ok()) processor_->OnError(std::move(result));
std::unique_ptr<DecodingState> Error(const WasmError& error) {
if (ok()) processor_->OnError(error);
Fail();
return std::unique_ptr<DecodingState>(nullptr);
}
std::unique_ptr<DecodingState> Error(std::string message) {
return Error(VoidResult::Error(module_offset_ - 1, std::move(message)));
return Error(WasmError{module_offset_ - 1, std::move(message)});
}
void ProcessModuleHeader() {

View File

@ -93,7 +93,7 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
isolate->counters(), allocator());
if (result.failed()) {
thrower->CompileFailed("Wasm decoding failed", result);
thrower->CompileFailed("Wasm decoding failed", result.error());
return {};
}

View File

@ -50,7 +50,7 @@ void PrintFToString(std::string& str, size_t str_offset, const char* format,
} // namespace
// static
std::string ResultBase::FormatError(const char* format, va_list args) {
std::string WasmError::FormatError(const char* format, va_list args) {
std::string result;
VPrintFToString(result, 0, format, args);
return result;

View File

@ -22,42 +22,44 @@ class Handle;
namespace wasm {
// Base class for Result<T>.
class V8_EXPORT_PRIVATE ResultBase {
protected:
ResultBase() = default;
ResultBase& operator=(ResultBase&& other) V8_NOEXCEPT = default;
class V8_EXPORT_PRIVATE WasmError {
public:
ResultBase(ResultBase&& other) V8_NOEXCEPT
: error_offset_(other.error_offset_),
error_msg_(std::move(other.error_msg_)) {}
WasmError() = default;
bool ok() const { return error_msg_.empty(); }
bool failed() const { return !ok(); }
uint32_t error_offset() const { return error_offset_; }
const std::string& error_msg() const & { return error_msg_; }
std::string&& error_msg() && { return std::move(error_msg_); }
protected:
ResultBase(uint32_t error_offset, std::string error_msg)
: error_offset_(error_offset), error_msg_(std::move(error_msg)) {
// The error message must not be empty, otherwise {failed()} will be false.
DCHECK(!error_msg_.empty());
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());
}
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());
}
bool empty() const { return message_.empty(); }
bool has_error() const { return !message_.empty(); }
uint32_t offset() const { return offset_; }
const std::string& message() const& { return message_; }
std::string&& message() && { return std::move(message_); }
protected:
static std::string FormatError(const char* format, va_list args);
private:
uint32_t error_offset_ = 0;
std::string error_msg_;
uint32_t offset_ = 0;
std::string message_;
};
// The overall result of decoding a function or a module.
// Either a result of type T, or a WasmError.
template <typename T>
class Result : public ResultBase {
class Result {
public:
Result() = default;
@ -65,33 +67,22 @@ class Result : public ResultBase {
explicit Result(S&& value) : value_(std::forward<S>(value)) {}
template <typename S>
Result(Result<S>&& other) V8_NOEXCEPT : ResultBase(std::move(other)),
value_(std::move(other).value()) {}
Result(Result<S>&& other) V8_NOEXCEPT : value_(std::move(other.value_)),
error_(std::move(other.error_)) {}
Result& operator=(Result&& other) V8_NOEXCEPT = default;
explicit Result(WasmError error) : error_(std::move(error)) {}
static Result<T> PRINTF_FORMAT(2, 3)
Error(uint32_t offset, const char* format, ...) {
va_list args;
va_start(args, format);
Result<T> error_result{offset, FormatError(format, args)};
va_end(args);
return error_result;
template <typename S>
Result& operator=(Result<S>&& other) V8_NOEXCEPT {
value_ = std::move(other.value_);
error_ = std::move(other.error_);
return *this;
}
static Result<T> Error(uint32_t error_offset, std::string error_msg) {
// Call private constructor.
return Result<T>{error_offset, std::move(error_msg)};
}
static Result<T> ErrorFrom(ResultBase&& error_result) {
return Error(error_result.error_offset(),
std::move(error_result).error_msg());
}
static Result<T> ErrorFrom(const ResultBase& error_result) {
return Error(error_result.error_offset(), error_result.error_msg());
}
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_); }
// 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
@ -107,10 +98,11 @@ class Result : public ResultBase {
}
private:
T value_ = T{};
template <typename S>
friend class Result;
Result(uint32_t error_offset, std::string error_msg)
: ResultBase(error_offset, std::move(error_msg)) {}
T value_ = T{};
WasmError error_;
DISALLOW_COPY_AND_ASSIGN(Result);
};
@ -130,15 +122,15 @@ class V8_EXPORT_PRIVATE ErrorThrower {
PRINTF_FORMAT(2, 3) void LinkError(const char* fmt, ...);
PRINTF_FORMAT(2, 3) void RuntimeError(const char* fmt, ...);
void CompileFailed(const char* error, const ResultBase& result) {
DCHECK(result.failed());
CompileError("%s: %s @+%u", error, result.error_msg().c_str(),
result.error_offset());
void CompileFailed(const char* context, const WasmError& error) {
DCHECK(error.has_error());
CompileError("%s: %s @+%u", context, error.message().c_str(),
error.offset());
}
void CompileFailed(const ResultBase& result) {
DCHECK(result.failed());
CompileError("%s @+%u", result.error_msg().c_str(), result.error_offset());
void CompileFailed(const WasmError& error) {
DCHECK(error.has_error());
CompileError("%s @+%u", error.message().c_str(), error.offset());
}
// Create and return exception object.

View File

@ -241,9 +241,8 @@ void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
}
#endif
uint32_t pc = result.error_offset();
FATAL("Verification failed; pc = +%x, msg = %s", pc,
result.error_msg().c_str());
FATAL("Verification failed; pc = +%x, msg = %s", result.error().offset(),
result.error().message().c_str());
}
builder->LowerInt64();
if (!CpuFeatures::SupportsWasmSimd128()) {

View File

@ -51,7 +51,7 @@ std::shared_ptr<WasmModule> DecodeWasmModuleForTesting(
if (decoding_result.failed()) {
// Module verification failed. throw.
thrower->CompileError("DecodeWasmModule failed: %s",
decoding_result.error_msg().c_str());
decoding_result.error().message().c_str());
}
return std::move(decoding_result).value();

View File

@ -138,17 +138,16 @@ class FunctionBodyDecoderTest : public TestWithZone {
VerifyWasmCode(zone()->allocator(), enabled_features_, module,
&unused_detected_features, body);
uint32_t pc = result.error_offset();
std::ostringstream str;
if (expected_success) {
str << "Verification failed: pc = +" << pc
<< ", msg = " << result.error_msg();
if (result.failed()) {
str << "Verification failed: pc = +" << result.error().offset()
<< ", msg = " << result.error().message();
} else {
str << "Verification successed, expected failure; pc = +" << pc;
str << "Verification successed, expected failure";
}
EXPECT_EQ(result.ok(), expected_success) << str.str();
if (!expected_success && message) {
EXPECT_THAT(result.error_msg(), ::testing::HasSubstr(message));
if (result.failed() && message) {
EXPECT_THAT(result.error().message(), ::testing::HasSubstr(message));
}
}

View File

@ -135,10 +135,10 @@ struct CheckLEB1 : std::integral_constant<size_t, num> {
if (!result.ok()) return; \
} while (false)
#define EXPECT_NOT_OK(result, msg) \
do { \
EXPECT_FALSE(result.ok()); \
EXPECT_THAT(result.error_msg(), HasSubstr(msg)); \
#define EXPECT_NOT_OK(result, msg) \
do { \
EXPECT_FALSE(result.ok()); \
EXPECT_THAT(result.error().message(), HasSubstr(msg)); \
} while (false)
static size_t SizeOfVarInt(size_t value) {

View File

@ -74,7 +74,7 @@ class MockStreamingProcessor : public StreamingProcessor {
}
// Report an error detected in the StreamingDecoder.
void OnError(DecodeResult result) override { result_->ok = false; }
void OnError(const WasmError&) override { result_->ok = false; }
void OnAbort() override {}