xref: /third_party/node/deps/v8/src/wasm/wasm-result.cc (revision 1cb0ef41)
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
14namespace v8 {
15namespace internal {
16namespace wasm {
17
18namespace {
19
20PRINTF_FORMAT(3, 0)
21void 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
42PRINTF_FORMAT(3, 4)
43void 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
54std::string WasmError::FormatError(const char* format, va_list args) {
55  std::string result;
56  VPrintFToString(&result, 0, format, args);
57  return result;
58}
59
60void 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
74void 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
81void 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
88void 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
95void 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
102void 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
109Handle<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
137void ErrorThrower::Reset() {
138  error_type_ = kNone;
139  error_msg_.clear();
140}
141
142ErrorThrower::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
150ErrorThrower::~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
159ScheduledErrorThrower::~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