// 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. #include "src/wasm/wasm-result.h" #include "src/execution/isolate-inl.h" #include "src/heap/factory.h" #include "src/heap/heap.h" #include "src/objects/objects.h" #include "src/base/platform/platform.h" namespace v8 { namespace internal { namespace wasm { namespace { PRINTF_FORMAT(3, 0) void VPrintFToString(std::string& str, size_t str_offset, const char* format, va_list args) { DCHECK_LE(str_offset, str.size()); size_t len = str_offset + strlen(format); // Allocate increasingly large buffers until the message fits. for (;; len = base::bits::RoundUpToPowerOfTwo64(len + 1)) { DCHECK_GE(kMaxInt, len); str.resize(len); va_list args_copy; va_copy(args_copy, args); int written = VSNPrintF(Vector(&str.front() + str_offset, static_cast(len - str_offset)), format, args_copy); va_end(args_copy); if (written < 0) continue; // not enough space. str.resize(str_offset + written); return; } } PRINTF_FORMAT(3, 4) void PrintFToString(std::string& str, size_t str_offset, const char* format, ...) { va_list args; va_start(args, format); VPrintFToString(str, str_offset, format, args); va_end(args); } } // namespace // static std::string WasmError::FormatError(const char* format, va_list args) { std::string result; VPrintFToString(result, 0, format, args); return result; } void ErrorThrower::Format(ErrorType type, const char* format, va_list args) { DCHECK_NE(kNone, type); // Only report the first error. if (error()) return; size_t context_len = 0; if (context_) { PrintFToString(error_msg_, 0, "%s: ", context_); context_len = error_msg_.size(); } VPrintFToString(error_msg_, context_len, format, args); error_type_ = type; } void ErrorThrower::TypeError(const char* format, ...) { va_list arguments; va_start(arguments, format); Format(kTypeError, format, arguments); va_end(arguments); } void ErrorThrower::RangeError(const char* format, ...) { va_list arguments; va_start(arguments, format); Format(kRangeError, format, arguments); va_end(arguments); } void ErrorThrower::CompileError(const char* format, ...) { va_list arguments; va_start(arguments, format); Format(kCompileError, format, arguments); va_end(arguments); } void ErrorThrower::LinkError(const char* format, ...) { va_list arguments; va_start(arguments, format); Format(kLinkError, format, arguments); va_end(arguments); } void ErrorThrower::RuntimeError(const char* format, ...) { va_list arguments; va_start(arguments, format); Format(kRuntimeError, format, arguments); va_end(arguments); } Handle ErrorThrower::Reify() { Handle constructor; switch (error_type_) { case kNone: UNREACHABLE(); case kTypeError: constructor = isolate_->type_error_function(); break; case kRangeError: constructor = isolate_->range_error_function(); break; case kCompileError: constructor = isolate_->wasm_compile_error_function(); break; case kLinkError: constructor = isolate_->wasm_link_error_function(); break; case kRuntimeError: constructor = isolate_->wasm_runtime_error_function(); break; } Handle message = isolate_->factory() ->NewStringFromUtf8(VectorOf(error_msg_)) .ToHandleChecked(); Reset(); return isolate_->factory()->NewError(constructor, message); } void ErrorThrower::Reset() { error_type_ = kNone; error_msg_.clear(); } ErrorThrower::ErrorThrower(ErrorThrower&& other) V8_NOEXCEPT : isolate_(other.isolate_), context_(other.context_), error_type_(other.error_type_), error_msg_(std::move(other.error_msg_)) { other.error_type_ = kNone; } ErrorThrower::~ErrorThrower() { if (error() && !isolate_->has_pending_exception()) { // We don't want to mix pending exceptions and scheduled exceptions, hence // an existing exception should be pending, never scheduled. DCHECK(!isolate_->has_scheduled_exception()); isolate_->Throw(*Reify()); } } } // namespace wasm } // namespace internal } // namespace v8