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(type_, kMainThreadHandle);
23 type_ = kMainThreadHandle;
24 arg_handle_ = string;
25 }
26
SetString(Handle<String> string,LocalIsolate * isolate)27 void PendingCompilationErrorHandler::MessageDetails::SetString(
28 Handle<String> string, LocalIsolate* isolate) {
29 DCHECK_NE(type_, kMainThreadHandle);
30 type_ = kMainThreadHandle;
31 arg_handle_ = isolate->heap()->NewPersistentHandle(string);
32 }
33
34 template <typename LocalIsolate>
Prepare(LocalIsolate * isolate)35 void PendingCompilationErrorHandler::MessageDetails::Prepare(
36 LocalIsolate* isolate) {
37 switch (type_) {
38 case kAstRawString:
39 return SetString(arg_->string(), isolate);
40
41 case kNone:
42 case kConstCharString:
43 // We can delay allocation until ArgumentString(isolate).
44 // TODO(leszeks): We don't actually have to transfer this string, since
45 // it's a root.
46 return;
47
48 case kMainThreadHandle:
49 // The message details might already be prepared, so skip them if this is
50 // the case.
51 return;
52 }
53 }
54
ArgumentString(Isolate * isolate) const55 Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString(
56 Isolate* isolate) const {
57 switch (type_) {
58 case kMainThreadHandle:
59 return arg_handle_;
60 case kNone:
61 return isolate->factory()->undefined_string();
62 case kConstCharString:
63 return isolate->factory()
64 ->NewStringFromUtf8(CStrVector(char_arg_), AllocationType::kOld)
65 .ToHandleChecked();
66 case kAstRawString:
67 UNREACHABLE();
68 }
69 }
70
GetLocation(Handle<Script> script) const71 MessageLocation PendingCompilationErrorHandler::MessageDetails::GetLocation(
72 Handle<Script> script) const {
73 return MessageLocation(script, start_position_, end_position_);
74 }
75
ReportMessageAt(int start_position,int end_position,MessageTemplate message,const char * arg)76 void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
77 int end_position,
78 MessageTemplate message,
79 const char* arg) {
80 if (has_pending_error_) return;
81 has_pending_error_ = true;
82
83 error_details_ = MessageDetails(start_position, end_position, message, arg);
84 }
85
ReportMessageAt(int start_position,int end_position,MessageTemplate message,const AstRawString * arg)86 void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
87 int end_position,
88 MessageTemplate message,
89 const AstRawString* arg) {
90 if (has_pending_error_) return;
91 has_pending_error_ = true;
92
93 error_details_ = MessageDetails(start_position, end_position, message, arg);
94 }
95
ReportWarningAt(int start_position,int end_position,MessageTemplate message,const char * arg)96 void PendingCompilationErrorHandler::ReportWarningAt(int start_position,
97 int end_position,
98 MessageTemplate message,
99 const char* arg) {
100 warning_messages_.emplace_front(
101 MessageDetails(start_position, end_position, message, arg));
102 }
103
104 template <typename LocalIsolate>
PrepareWarnings(LocalIsolate * isolate)105 void PendingCompilationErrorHandler::PrepareWarnings(LocalIsolate* isolate) {
106 DCHECK(!has_pending_error());
107
108 for (MessageDetails& warning : warning_messages_) {
109 warning.Prepare(isolate);
110 }
111 }
112 template void PendingCompilationErrorHandler::PrepareWarnings(Isolate* isolate);
113 template void PendingCompilationErrorHandler::PrepareWarnings(
114 LocalIsolate* isolate);
115
ReportWarnings(Isolate * isolate,Handle<Script> script) const116 void PendingCompilationErrorHandler::ReportWarnings(
117 Isolate* isolate, Handle<Script> script) const {
118 DCHECK(!has_pending_error());
119
120 for (const MessageDetails& warning : warning_messages_) {
121 MessageLocation location = warning.GetLocation(script);
122 Handle<String> argument = warning.ArgumentString(isolate);
123 Handle<JSMessageObject> message =
124 MessageHandler::MakeMessageObject(isolate, warning.message(), &location,
125 argument, Handle<FixedArray>::null());
126 message->set_error_level(v8::Isolate::kMessageWarning);
127 MessageHandler::ReportMessage(isolate, &location, message);
128 }
129 }
130
131 template <typename LocalIsolate>
PrepareErrors(LocalIsolate * isolate,AstValueFactory * ast_value_factory)132 void PendingCompilationErrorHandler::PrepareErrors(
133 LocalIsolate* isolate, AstValueFactory* ast_value_factory) {
134 if (stack_overflow()) return;
135
136 DCHECK(has_pending_error());
137 // Internalize ast values for throwing the pending error.
138 ast_value_factory->Internalize(isolate);
139 error_details_.Prepare(isolate);
140 }
141 template EXPORT_TEMPLATE_DEFINE(
142 V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler::
143 PrepareErrors(Isolate* isolate, AstValueFactory* ast_value_factory);
144 template EXPORT_TEMPLATE_DEFINE(
145 V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler::
146 PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory);
147
ReportErrors(Isolate * isolate,Handle<Script> script) const148 void PendingCompilationErrorHandler::ReportErrors(Isolate* isolate,
149 Handle<Script> script) const {
150 if (stack_overflow()) {
151 isolate->StackOverflow();
152 } else {
153 DCHECK(has_pending_error());
154 ThrowPendingError(isolate, script);
155 }
156 }
157
ThrowPendingError(Isolate * isolate,Handle<Script> script) const158 void PendingCompilationErrorHandler::ThrowPendingError(
159 Isolate* isolate, Handle<Script> script) const {
160 if (!has_pending_error_) return;
161
162 MessageLocation location = error_details_.GetLocation(script);
163 Handle<String> argument = error_details_.ArgumentString(isolate);
164 isolate->debug()->OnCompileError(script);
165
166 Factory* factory = isolate->factory();
167 Handle<JSObject> error =
168 factory->NewSyntaxError(error_details_.message(), argument);
169 isolate->ThrowAt(error, &location);
170 }
171
FormatErrorMessageForTest(Isolate * isolate)172 Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest(
173 Isolate* isolate) {
174 error_details_.Prepare(isolate);
175 return MessageFormatter::Format(isolate, error_details_.message(),
176 error_details_.ArgumentString(isolate));
177 }
178
179 } // namespace internal
180 } // namespace v8
181