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
17 namespace v8 {
18 namespace internal {
19
SetString(Handle<String> string,Isolate * isolate)20 void 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
SetString(Handle<String> string,LocalIsolate * isolate)27 void 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
34 template <typename IsolateT>
Prepare(IsolateT * isolate)35 void 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
ArgString(Isolate * isolate,int index) const55 Handle<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
GetLocation(Handle<Script> script) const75 MessageLocation PendingCompilationErrorHandler::MessageDetails::GetLocation(
76 Handle<Script> script) const {
77 return MessageLocation(script, start_position_, end_position_);
78 }
79
ReportMessageAt(int start_position,int end_position,MessageTemplate message,const char * arg)80 void 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
ReportMessageAt(int start_position,int end_position,MessageTemplate message,const AstRawString * arg)90 void 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
ReportMessageAt(int start_position,int end_position,MessageTemplate message,const AstRawString * arg0,const char * arg1)100 void 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
ReportWarningAt(int start_position,int end_position,MessageTemplate message,const char * arg)111 void 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
119 template <typename IsolateT>
PrepareWarnings(IsolateT * isolate)120 void PendingCompilationErrorHandler::PrepareWarnings(IsolateT* isolate) {
121 DCHECK(!has_pending_error());
122
123 for (MessageDetails& warning : warning_messages_) {
124 warning.Prepare(isolate);
125 }
126 }
127 template void PendingCompilationErrorHandler::PrepareWarnings(Isolate* isolate);
128 template void PendingCompilationErrorHandler::PrepareWarnings(
129 LocalIsolate* isolate);
130
ReportWarnings(Isolate * isolate,Handle<Script> script) const131 void 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
147 template <typename IsolateT>
PrepareErrors(IsolateT * isolate,AstValueFactory * ast_value_factory)148 void 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 }
157 template EXPORT_TEMPLATE_DEFINE(
158 V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler::
159 PrepareErrors(Isolate* isolate, AstValueFactory* ast_value_factory);
160 template EXPORT_TEMPLATE_DEFINE(
161 V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler::
162 PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory);
163
ReportErrors(Isolate * isolate,Handle<Script> script) const164 void 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
ThrowPendingError(Isolate * isolate,Handle<Script> script) const174 void 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
FormatErrorMessageForTest(Isolate * isolate)189 Handle<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