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/parsing/pending-compilation-error-handler.h"
6
7#include "src/ast/ast-value-factory.h"
8#include "src/base/export-template.h"
9#include "src/base/logging.h"
10#include "src/debug/debug.h"
11#include "src/execution/isolate.h"
12#include "src/execution/messages.h"
13#include "src/handles/handles.h"
14#include "src/heap/local-heap-inl.h"
15#include "src/objects/objects-inl.h"
16
17namespace v8 {
18namespace internal {
19
20void PendingCompilationErrorHandler::MessageDetails::SetString(
21    Handle<String> string, Isolate* isolate) {
22  DCHECK_NE(args_[0].type, kMainThreadHandle);
23  args_[0].type = kMainThreadHandle;
24  args_[0].js_string = string;
25}
26
27void PendingCompilationErrorHandler::MessageDetails::SetString(
28    Handle<String> string, LocalIsolate* isolate) {
29  DCHECK_NE(args_[0].type, kMainThreadHandle);
30  args_[0].type = kMainThreadHandle;
31  args_[0].js_string = isolate->heap()->NewPersistentHandle(string);
32}
33
34template <typename IsolateT>
35void PendingCompilationErrorHandler::MessageDetails::Prepare(
36    IsolateT* isolate) {
37  for (int i = 0; i < kMaxArgumentCount; i++) {
38    switch (args_[i].type) {
39      case kAstRawString:
40        return SetString(args_[i].ast_string->string(), isolate);
41
42      case kNone:
43      case kConstCharString:
44        // We can delay allocation until ArgString(isolate).
45        return;
46
47      case kMainThreadHandle:
48        // The message details might already be prepared, so skip them if this
49        // is the case.
50        return;
51    }
52  }
53}
54
55Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgString(
56    Isolate* isolate, int index) const {
57  // `index` may be >= argc; in that case we return a default value to pass on
58  // elsewhere.
59  DCHECK_LT(index, kMaxArgumentCount);
60  switch (args_[index].type) {
61    case kMainThreadHandle:
62      return args_[index].js_string;
63    case kNone:
64      return Handle<String>::null();
65    case kConstCharString:
66      return isolate->factory()
67          ->NewStringFromUtf8(base::CStrVector(args_[index].c_string),
68                              AllocationType::kOld)
69          .ToHandleChecked();
70    case kAstRawString:
71      UNREACHABLE();
72  }
73}
74
75MessageLocation PendingCompilationErrorHandler::MessageDetails::GetLocation(
76    Handle<Script> script) const {
77  return MessageLocation(script, start_position_, end_position_);
78}
79
80void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
81                                                     int end_position,
82                                                     MessageTemplate message,
83                                                     const char* arg) {
84  if (has_pending_error_) return;
85  has_pending_error_ = true;
86
87  error_details_ = MessageDetails(start_position, end_position, message, arg);
88}
89
90void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
91                                                     int end_position,
92                                                     MessageTemplate message,
93                                                     const AstRawString* arg) {
94  if (has_pending_error_) return;
95  has_pending_error_ = true;
96
97  error_details_ = MessageDetails(start_position, end_position, message, arg);
98}
99
100void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
101                                                     int end_position,
102                                                     MessageTemplate message,
103                                                     const AstRawString* arg0,
104                                                     const char* arg1) {
105  if (has_pending_error_) return;
106  has_pending_error_ = true;
107  error_details_ =
108      MessageDetails(start_position, end_position, message, arg0, arg1);
109}
110
111void PendingCompilationErrorHandler::ReportWarningAt(int start_position,
112                                                     int end_position,
113                                                     MessageTemplate message,
114                                                     const char* arg) {
115  warning_messages_.emplace_front(
116      MessageDetails(start_position, end_position, message, arg));
117}
118
119template <typename IsolateT>
120void PendingCompilationErrorHandler::PrepareWarnings(IsolateT* isolate) {
121  DCHECK(!has_pending_error());
122
123  for (MessageDetails& warning : warning_messages_) {
124    warning.Prepare(isolate);
125  }
126}
127template void PendingCompilationErrorHandler::PrepareWarnings(Isolate* isolate);
128template void PendingCompilationErrorHandler::PrepareWarnings(
129    LocalIsolate* isolate);
130
131void PendingCompilationErrorHandler::ReportWarnings(
132    Isolate* isolate, Handle<Script> script) const {
133  DCHECK(!has_pending_error());
134
135  for (const MessageDetails& warning : warning_messages_) {
136    MessageLocation location = warning.GetLocation(script);
137    Handle<String> argument = warning.ArgString(isolate, 0);
138    DCHECK_LT(warning.ArgCount(), 2);  // Arg1 is only used for errors.
139    Handle<JSMessageObject> message =
140        MessageHandler::MakeMessageObject(isolate, warning.message(), &location,
141                                          argument, Handle<FixedArray>::null());
142    message->set_error_level(v8::Isolate::kMessageWarning);
143    MessageHandler::ReportMessage(isolate, &location, message);
144  }
145}
146
147template <typename IsolateT>
148void PendingCompilationErrorHandler::PrepareErrors(
149    IsolateT* isolate, AstValueFactory* ast_value_factory) {
150  if (stack_overflow()) return;
151
152  DCHECK(has_pending_error());
153  // Internalize ast values for throwing the pending error.
154  ast_value_factory->Internalize(isolate);
155  error_details_.Prepare(isolate);
156}
157template EXPORT_TEMPLATE_DEFINE(
158    V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler::
159    PrepareErrors(Isolate* isolate, AstValueFactory* ast_value_factory);
160template EXPORT_TEMPLATE_DEFINE(
161    V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler::
162    PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory);
163
164void PendingCompilationErrorHandler::ReportErrors(Isolate* isolate,
165                                                  Handle<Script> script) const {
166  if (stack_overflow()) {
167    isolate->StackOverflow();
168  } else {
169    DCHECK(has_pending_error());
170    ThrowPendingError(isolate, script);
171  }
172}
173
174void PendingCompilationErrorHandler::ThrowPendingError(
175    Isolate* isolate, Handle<Script> script) const {
176  if (!has_pending_error_) return;
177
178  MessageLocation location = error_details_.GetLocation(script);
179  Handle<String> arg0 = error_details_.ArgString(isolate, 0);
180  Handle<String> arg1 = error_details_.ArgString(isolate, 1);
181  isolate->debug()->OnCompileError(script);
182
183  Factory* factory = isolate->factory();
184  Handle<JSObject> error =
185      factory->NewSyntaxError(error_details_.message(), arg0, arg1);
186  isolate->ThrowAt(error, &location);
187}
188
189Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest(
190    Isolate* isolate) {
191  error_details_.Prepare(isolate);
192  return MessageFormatter::Format(isolate, error_details_.message(),
193                                  error_details_.ArgString(isolate, 0),
194                                  error_details_.ArgString(isolate, 1));
195}
196
197}  // namespace internal
198}  // namespace v8
199