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