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 #include "src/wasm/wasm-result.h"
6
7 #include "src/heap/factory.h"
8 #include "src/heap/heap.h"
9 #include "src/isolate-inl.h"
10 #include "src/objects.h"
11
12 #include "src/base/platform/platform.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace wasm {
17
18 namespace {
19
20 PRINTF_FORMAT(3, 0)
VPrintFToString(std::string & str,size_t str_offset,const char * format,va_list args)21 void VPrintFToString(std::string& str, size_t str_offset, const char* format,
22 va_list args) {
23 DCHECK_LE(str_offset, str.size());
24 size_t len = str_offset + strlen(format);
25 // Allocate increasingly large buffers until the message fits.
26 for (;; len = base::bits::RoundUpToPowerOfTwo64(len + 1)) {
27 DCHECK_GE(kMaxInt, len);
28 str.resize(len);
29 va_list args_copy;
30 va_copy(args_copy, args);
31 int written = VSNPrintF(Vector<char>(&str.front() + str_offset,
32 static_cast<int>(len - str_offset)),
33 format, args_copy);
34 va_end(args_copy);
35 if (written < 0) continue; // not enough space.
36 str.resize(str_offset + written);
37 return;
38 }
39 }
40
41 PRINTF_FORMAT(3, 4)
PrintFToString(std::string & str,size_t str_offset,const char * format,...)42 void PrintFToString(std::string& str, size_t str_offset, const char* format,
43 ...) {
44 va_list args;
45 va_start(args, format);
46 VPrintFToString(str, str_offset, format, args);
47 va_end(args);
48 }
49
50 } // namespace
51
error(uint32_t offset,std::string error_msg)52 void ResultBase::error(uint32_t offset, std::string error_msg) {
53 // The error message must not be empty, otherwise Result::failed() will be
54 // false.
55 DCHECK(!error_msg.empty());
56 error_offset_ = offset;
57 error_msg_ = std::move(error_msg);
58 }
59
verror(const char * format,va_list args)60 void ResultBase::verror(const char* format, va_list args) {
61 VPrintFToString(error_msg_, 0, format, args);
62 // Assign default message such that ok() and failed() work.
63 if (error_msg_.empty() == 0) error_msg_.assign("Error");
64 }
65
Format(ErrorType type,const char * format,va_list args)66 void ErrorThrower::Format(ErrorType type, const char* format, va_list args) {
67 DCHECK_NE(kNone, type);
68 // Only report the first error.
69 if (error()) return;
70
71 size_t context_len = 0;
72 if (context_) {
73 PrintFToString(error_msg_, 0, "%s: ", context_);
74 context_len = error_msg_.size();
75 }
76 VPrintFToString(error_msg_, context_len, format, args);
77 error_type_ = type;
78 }
79
TypeError(const char * format,...)80 void ErrorThrower::TypeError(const char* format, ...) {
81 va_list arguments;
82 va_start(arguments, format);
83 Format(kTypeError, format, arguments);
84 va_end(arguments);
85 }
86
RangeError(const char * format,...)87 void ErrorThrower::RangeError(const char* format, ...) {
88 va_list arguments;
89 va_start(arguments, format);
90 Format(kRangeError, format, arguments);
91 va_end(arguments);
92 }
93
CompileError(const char * format,...)94 void ErrorThrower::CompileError(const char* format, ...) {
95 va_list arguments;
96 va_start(arguments, format);
97 Format(kCompileError, format, arguments);
98 va_end(arguments);
99 }
100
LinkError(const char * format,...)101 void ErrorThrower::LinkError(const char* format, ...) {
102 va_list arguments;
103 va_start(arguments, format);
104 Format(kLinkError, format, arguments);
105 va_end(arguments);
106 }
107
RuntimeError(const char * format,...)108 void ErrorThrower::RuntimeError(const char* format, ...) {
109 va_list arguments;
110 va_start(arguments, format);
111 Format(kRuntimeError, format, arguments);
112 va_end(arguments);
113 }
114
Reify()115 Handle<Object> ErrorThrower::Reify() {
116 Handle<JSFunction> constructor;
117 switch (error_type_) {
118 case kNone:
119 UNREACHABLE();
120 case kTypeError:
121 constructor = isolate_->type_error_function();
122 break;
123 case kRangeError:
124 constructor = isolate_->range_error_function();
125 break;
126 case kCompileError:
127 constructor = isolate_->wasm_compile_error_function();
128 break;
129 case kLinkError:
130 constructor = isolate_->wasm_link_error_function();
131 break;
132 case kRuntimeError:
133 constructor = isolate_->wasm_runtime_error_function();
134 break;
135 }
136 Vector<const char> msg_vec(error_msg_.data(), error_msg_.size());
137 Handle<String> message =
138 isolate_->factory()->NewStringFromUtf8(msg_vec).ToHandleChecked();
139 Reset();
140 return isolate_->factory()->NewError(constructor, message);
141 }
142
Reset()143 void ErrorThrower::Reset() {
144 error_type_ = kNone;
145 error_msg_.clear();
146 }
147
ErrorThrower(ErrorThrower && other)148 ErrorThrower::ErrorThrower(ErrorThrower&& other) V8_NOEXCEPT
149 : isolate_(other.isolate_),
150 context_(other.context_),
151 error_type_(other.error_type_),
152 error_msg_(other.error_msg_) {
153 other.error_type_ = kNone;
154 }
155
~ErrorThrower()156 ErrorThrower::~ErrorThrower() {
157 if (error() && !isolate_->has_pending_exception()) {
158 // We don't want to mix pending exceptions and scheduled exceptions, hence
159 // an existing exception should be pending, never scheduled.
160 DCHECK(!isolate_->has_scheduled_exception());
161 isolate_->Throw(*Reify());
162 }
163 }
164
165 } // namespace wasm
166 } // namespace internal
167 } // namespace v8
168