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/base/platform/platform.h"
8 #include "src/base/strings.h"
9 #include "src/execution/isolate-inl.h"
10 #include "src/heap/factory.h"
11 #include "src/heap/heap.h"
12 #include "src/objects/objects.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 =
32 base::VSNPrintF(base::Vector<char>(&str->front() + str_offset,
33 static_cast<int>(len - str_offset)),
34 format, args_copy);
35 va_end(args_copy);
36 if (written < 0) continue; // not enough space.
37 str->resize(str_offset + written);
38 return;
39 }
40 }
41
42 PRINTF_FORMAT(3, 4)
PrintFToString(std::string * str,size_t str_offset,const char * format,...)43 void PrintFToString(std::string* str, size_t str_offset, const char* format,
44 ...) {
45 va_list args;
46 va_start(args, format);
47 VPrintFToString(str, str_offset, format, args);
48 va_end(args);
49 }
50
51 } // namespace
52
53 // static
FormatError(const char * format,va_list args)54 std::string WasmError::FormatError(const char* format, va_list args) {
55 std::string result;
56 VPrintFToString(&result, 0, format, args);
57 return result;
58 }
59
Format(ErrorType type,const char * format,va_list args)60 void ErrorThrower::Format(ErrorType type, const char* format, va_list args) {
61 DCHECK_NE(kNone, type);
62 // Only report the first error.
63 if (error()) return;
64
65 size_t context_len = 0;
66 if (context_) {
67 PrintFToString(&error_msg_, 0, "%s: ", context_);
68 context_len = error_msg_.size();
69 }
70 VPrintFToString(&error_msg_, context_len, format, args);
71 error_type_ = type;
72 }
73
TypeError(const char * format,...)74 void ErrorThrower::TypeError(const char* format, ...) {
75 va_list arguments;
76 va_start(arguments, format);
77 Format(kTypeError, format, arguments);
78 va_end(arguments);
79 }
80
RangeError(const char * format,...)81 void ErrorThrower::RangeError(const char* format, ...) {
82 va_list arguments;
83 va_start(arguments, format);
84 Format(kRangeError, format, arguments);
85 va_end(arguments);
86 }
87
CompileError(const char * format,...)88 void ErrorThrower::CompileError(const char* format, ...) {
89 va_list arguments;
90 va_start(arguments, format);
91 Format(kCompileError, format, arguments);
92 va_end(arguments);
93 }
94
LinkError(const char * format,...)95 void ErrorThrower::LinkError(const char* format, ...) {
96 va_list arguments;
97 va_start(arguments, format);
98 Format(kLinkError, format, arguments);
99 va_end(arguments);
100 }
101
RuntimeError(const char * format,...)102 void ErrorThrower::RuntimeError(const char* format, ...) {
103 va_list arguments;
104 va_start(arguments, format);
105 Format(kRuntimeError, format, arguments);
106 va_end(arguments);
107 }
108
Reify()109 Handle<Object> ErrorThrower::Reify() {
110 Handle<JSFunction> constructor;
111 switch (error_type_) {
112 case kNone:
113 UNREACHABLE();
114 case kTypeError:
115 constructor = isolate_->type_error_function();
116 break;
117 case kRangeError:
118 constructor = isolate_->range_error_function();
119 break;
120 case kCompileError:
121 constructor = isolate_->wasm_compile_error_function();
122 break;
123 case kLinkError:
124 constructor = isolate_->wasm_link_error_function();
125 break;
126 case kRuntimeError:
127 constructor = isolate_->wasm_runtime_error_function();
128 break;
129 }
130 Handle<String> message = isolate_->factory()
131 ->NewStringFromUtf8(base::VectorOf(error_msg_))
132 .ToHandleChecked();
133 Reset();
134 return isolate_->factory()->NewError(constructor, message);
135 }
136
Reset()137 void ErrorThrower::Reset() {
138 error_type_ = kNone;
139 error_msg_.clear();
140 }
141
ErrorThrower(ErrorThrower && other)142 ErrorThrower::ErrorThrower(ErrorThrower&& other) V8_NOEXCEPT
143 : isolate_(other.isolate_),
144 context_(other.context_),
145 error_type_(other.error_type_),
146 error_msg_(std::move(other.error_msg_)) {
147 other.error_type_ = kNone;
148 }
149
~ErrorThrower()150 ErrorThrower::~ErrorThrower() {
151 if (error() && !isolate_->has_pending_exception()) {
152 // We don't want to mix pending exceptions and scheduled exceptions, hence
153 // an existing exception should be pending, never scheduled.
154 DCHECK(!isolate_->has_scheduled_exception());
155 isolate_->Throw(*Reify());
156 }
157 }
158
~ScheduledErrorThrower()159 ScheduledErrorThrower::~ScheduledErrorThrower() {
160 // There should never be both a pending and a scheduled exception.
161 DCHECK(!isolate()->has_scheduled_exception() ||
162 !isolate()->has_pending_exception());
163 // Don't throw another error if there is already a scheduled error.
164 if (isolate()->has_scheduled_exception()) {
165 Reset();
166 } else if (isolate()->has_pending_exception()) {
167 Reset();
168 isolate()->OptionalRescheduleException(false);
169 } else if (error()) {
170 isolate()->ScheduleThrow(*Reify());
171 }
172 }
173
174 } // namespace wasm
175 } // namespace internal
176 } // namespace v8
177