1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #if !V8_ENABLE_WEBASSEMBLY 6 #error This header should only be included if WebAssembly is enabled. 7 #endif // !V8_ENABLE_WEBASSEMBLY 8 9 #ifndef V8_WASM_WASM_RESULT_H_ 10 #define V8_WASM_WASM_RESULT_H_ 11 12 #include <cstdarg> 13 #include <memory> 14 15 #include "src/base/compiler-specific.h" 16 #include "src/base/macros.h" 17 #include "src/base/platform/platform.h" 18 19 #include "src/common/globals.h" 20 21 namespace v8 { 22 namespace internal { 23 24 class Isolate; 25 template <typename T> 26 class Handle; 27 28 namespace wasm { 29 30 class V8_EXPORT_PRIVATE WasmError { 31 public: 32 WasmError() = default; 33 WasmError(uint32_t offset,std::string message)34 WasmError(uint32_t offset, std::string message) 35 : offset_(offset), message_(std::move(message)) { 36 // The error message must not be empty, otherwise {empty()} would be true. 37 DCHECK(!message_.empty()); 38 } 39 40 PRINTF_FORMAT(3, 4) WasmError(uint32_t offset,const char * format,...)41 WasmError(uint32_t offset, const char* format, ...) : offset_(offset) { 42 va_list args; 43 va_start(args, format); 44 message_ = FormatError(format, args); 45 va_end(args); 46 // The error message must not be empty, otherwise {empty()} would be true. 47 DCHECK(!message_.empty()); 48 } 49 empty()50 bool empty() const { return message_.empty(); } has_error()51 bool has_error() const { return !message_.empty(); } 52 offset()53 uint32_t offset() const { return offset_; } message()54 const std::string& message() const& { return message_; } message()55 std::string&& message() && { return std::move(message_); } 56 57 protected: 58 static std::string FormatError(const char* format, va_list args); 59 60 private: 61 uint32_t offset_ = 0; 62 std::string message_; 63 }; 64 65 // Either a result of type T, or a WasmError. 66 template <typename T> 67 class Result { 68 public: 69 Result() = default; 70 Result(const Result&) = delete; 71 Result& operator=(const Result&) = delete; 72 73 template <typename S> Result(S && value)74 explicit Result(S&& value) : value_(std::forward<S>(value)) {} 75 76 template <typename S> Result(Result<S> && other)77 Result(Result<S>&& other) V8_NOEXCEPT : value_(std::move(other.value_)), 78 error_(std::move(other.error_)) {} 79 Result(WasmError error)80 explicit Result(WasmError error) : error_(std::move(error)) {} 81 82 template <typename S> 83 Result& operator=(Result<S>&& other) V8_NOEXCEPT { 84 value_ = std::move(other.value_); 85 error_ = std::move(other.error_); 86 return *this; 87 } 88 ok()89 bool ok() const { return error_.empty(); } failed()90 bool failed() const { return error_.has_error(); } error()91 const WasmError& error() const& { return error_; } error()92 WasmError&& error() && { return std::move(error_); } 93 94 // Accessor for the value. Returns const reference if {this} is l-value or 95 // const, and returns r-value reference if {this} is r-value. This allows to 96 // extract non-copyable values like {std::unique_ptr} by using 97 // {std::move(result).value()}. value()98 const T& value() const & { 99 DCHECK(ok()); 100 return value_; 101 } value()102 T&& value() && { 103 DCHECK(ok()); 104 return std::move(value_); 105 } 106 107 private: 108 template <typename S> 109 friend class Result; 110 111 T value_ = T{}; 112 WasmError error_; 113 }; 114 115 // A helper for generating error messages that bubble up to JS exceptions. 116 class V8_EXPORT_PRIVATE ErrorThrower { 117 public: ErrorThrower(Isolate * isolate,const char * context)118 ErrorThrower(Isolate* isolate, const char* context) 119 : isolate_(isolate), context_(context) {} 120 // Explicitly allow move-construction. Disallow copy. 121 ErrorThrower(ErrorThrower&& other) V8_NOEXCEPT; 122 ErrorThrower(const ErrorThrower&) = delete; 123 ErrorThrower& operator=(const ErrorThrower&) = delete; 124 ~ErrorThrower(); 125 126 PRINTF_FORMAT(2, 3) void TypeError(const char* fmt, ...); 127 PRINTF_FORMAT(2, 3) void RangeError(const char* fmt, ...); 128 PRINTF_FORMAT(2, 3) void CompileError(const char* fmt, ...); 129 PRINTF_FORMAT(2, 3) void LinkError(const char* fmt, ...); 130 PRINTF_FORMAT(2, 3) void RuntimeError(const char* fmt, ...); 131 CompileFailed(const WasmError & error)132 void CompileFailed(const WasmError& error) { 133 DCHECK(error.has_error()); 134 CompileError("%s @+%u", error.message().c_str(), error.offset()); 135 } 136 137 // Create and return exception object. 138 V8_WARN_UNUSED_RESULT Handle<Object> Reify(); 139 140 // Reset any error which was set on this thrower. 141 void Reset(); 142 error()143 bool error() const { return error_type_ != kNone; } wasm_error()144 bool wasm_error() { return error_type_ >= kFirstWasmError; } error_msg()145 const char* error_msg() { return error_msg_.c_str(); } 146 isolate()147 Isolate* isolate() const { return isolate_; } 148 149 private: 150 enum ErrorType { 151 kNone, 152 // General errors. 153 kTypeError, 154 kRangeError, 155 // Wasm errors. 156 kCompileError, 157 kLinkError, 158 kRuntimeError, 159 160 // Marker. 161 kFirstWasmError = kCompileError 162 }; 163 164 void Format(ErrorType error_type_, const char* fmt, va_list); 165 166 Isolate* isolate_; 167 const char* context_; 168 ErrorType error_type_ = kNone; 169 std::string error_msg_; 170 171 // ErrorThrower should always be stack-allocated, since it constitutes a scope 172 // (things happen in the destructor). 173 DISALLOW_NEW_AND_DELETE() 174 }; 175 176 // Like an ErrorThrower, but turns all pending exceptions into scheduled 177 // exceptions when going out of scope. Use this in API methods. 178 // Note that pending exceptions are not necessarily created by the ErrorThrower, 179 // but e.g. by the wasm start function. There might also be a scheduled 180 // exception, created by another API call (e.g. v8::Object::Get). But there 181 // should never be both pending and scheduled exceptions. 182 class V8_EXPORT_PRIVATE ScheduledErrorThrower : public ErrorThrower { 183 public: ScheduledErrorThrower(i::Isolate * isolate,const char * context)184 ScheduledErrorThrower(i::Isolate* isolate, const char* context) 185 : ErrorThrower(isolate, context) {} 186 187 ~ScheduledErrorThrower(); 188 }; 189 190 // Use {nullptr_t} as data value to indicate that this only stores the error, 191 // but no result value (the only valid value is {nullptr}). 192 // [Storing {void} would require template specialization.] 193 using VoidResult = Result<std::nullptr_t>; 194 195 } // namespace wasm 196 } // namespace internal 197 } // namespace v8 198 199 #endif // V8_WASM_WASM_RESULT_H_ 200