| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/parsing/pending-compilation-error-handler.h" |
| |
| #include "src/ast/ast-value-factory.h" |
| #include "src/base/export-template.h" |
| #include "src/base/logging.h" |
| #include "src/debug/debug.h" |
| #include "src/execution/isolate.h" |
| #include "src/execution/messages.h" |
| #include "src/handles/handles.h" |
| #include "src/heap/local-heap-inl.h" |
| #include "src/objects/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| void PendingCompilationErrorHandler::MessageDetails::SetString( |
| Handle<String> string, Isolate* isolate) { |
| DCHECK_NE(args_[0].type, kMainThreadHandle); |
| args_[0].type = kMainThreadHandle; |
| args_[0].js_string = string; |
| } |
| |
| void PendingCompilationErrorHandler::MessageDetails::SetString( |
| Handle<String> string, LocalIsolate* isolate) { |
| DCHECK_NE(args_[0].type, kMainThreadHandle); |
| args_[0].type = kMainThreadHandle; |
| args_[0].js_string = isolate->heap()->NewPersistentHandle(string); |
| } |
| |
| template <typename IsolateT> |
| void PendingCompilationErrorHandler::MessageDetails::Prepare( |
| IsolateT* isolate) { |
| for (int i = 0; i < kMaxArgumentCount; i++) { |
| switch (args_[i].type) { |
| case kAstRawString: |
| return SetString(args_[i].ast_string->string(), isolate); |
| |
| case kNone: |
| case kConstCharString: |
| // We can delay allocation until ArgString(isolate). |
| return; |
| |
| case kMainThreadHandle: |
| // The message details might already be prepared, so skip them if this |
| // is the case. |
| return; |
| } |
| } |
| } |
| |
| Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgString( |
| Isolate* isolate, int index) const { |
| // `index` may be >= argc; in that case we return a default value to pass on |
| // elsewhere. |
| DCHECK_LT(index, kMaxArgumentCount); |
| switch (args_[index].type) { |
| case kMainThreadHandle: |
| return args_[index].js_string; |
| case kNone: |
| return Handle<String>::null(); |
| case kConstCharString: |
| return isolate->factory() |
| ->NewStringFromUtf8(base::CStrVector(args_[index].c_string), |
| AllocationType::kOld) |
| .ToHandleChecked(); |
| case kAstRawString: |
| UNREACHABLE(); |
| } |
| } |
| |
| MessageLocation PendingCompilationErrorHandler::MessageDetails::GetLocation( |
| Handle<Script> script) const { |
| return MessageLocation(script, start_position_, end_position_); |
| } |
| |
| void PendingCompilationErrorHandler::ReportMessageAt(int start_position, |
| int end_position, |
| MessageTemplate message, |
| const char* arg) { |
| if (has_pending_error_) return; |
| has_pending_error_ = true; |
| |
| error_details_ = MessageDetails(start_position, end_position, message, arg); |
| } |
| |
| void PendingCompilationErrorHandler::ReportMessageAt(int start_position, |
| int end_position, |
| MessageTemplate message, |
| const AstRawString* arg) { |
| if (has_pending_error_) return; |
| has_pending_error_ = true; |
| |
| error_details_ = MessageDetails(start_position, end_position, message, arg); |
| } |
| |
| void PendingCompilationErrorHandler::ReportMessageAt(int start_position, |
| int end_position, |
| MessageTemplate message, |
| const AstRawString* arg0, |
| const char* arg1) { |
| if (has_pending_error_) return; |
| has_pending_error_ = true; |
| error_details_ = |
| MessageDetails(start_position, end_position, message, arg0, arg1); |
| } |
| |
| void PendingCompilationErrorHandler::ReportWarningAt(int start_position, |
| int end_position, |
| MessageTemplate message, |
| const char* arg) { |
| warning_messages_.emplace_front( |
| MessageDetails(start_position, end_position, message, arg)); |
| } |
| |
| template <typename IsolateT> |
| void PendingCompilationErrorHandler::PrepareWarnings(IsolateT* isolate) { |
| DCHECK(!has_pending_error()); |
| |
| for (MessageDetails& warning : warning_messages_) { |
| warning.Prepare(isolate); |
| } |
| } |
| template void PendingCompilationErrorHandler::PrepareWarnings(Isolate* isolate); |
| template void PendingCompilationErrorHandler::PrepareWarnings( |
| LocalIsolate* isolate); |
| |
| void PendingCompilationErrorHandler::ReportWarnings( |
| Isolate* isolate, Handle<Script> script) const { |
| DCHECK(!has_pending_error()); |
| |
| for (const MessageDetails& warning : warning_messages_) { |
| MessageLocation location = warning.GetLocation(script); |
| Handle<String> argument = warning.ArgString(isolate, 0); |
| DCHECK_LT(warning.ArgCount(), 2); // Arg1 is only used for errors. |
| Handle<JSMessageObject> message = |
| MessageHandler::MakeMessageObject(isolate, warning.message(), &location, |
| argument, Handle<FixedArray>::null()); |
| message->set_error_level(v8::Isolate::kMessageWarning); |
| MessageHandler::ReportMessage(isolate, &location, message); |
| } |
| } |
| |
| template <typename IsolateT> |
| void PendingCompilationErrorHandler::PrepareErrors( |
| IsolateT* isolate, AstValueFactory* ast_value_factory) { |
| if (stack_overflow()) return; |
| |
| DCHECK(has_pending_error()); |
| // Internalize ast values for throwing the pending error. |
| ast_value_factory->Internalize(isolate); |
| error_details_.Prepare(isolate); |
| } |
| template EXPORT_TEMPLATE_DEFINE( |
| V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler:: |
| PrepareErrors(Isolate* isolate, AstValueFactory* ast_value_factory); |
| template EXPORT_TEMPLATE_DEFINE( |
| V8_EXPORT_PRIVATE) void PendingCompilationErrorHandler:: |
| PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory); |
| |
| void PendingCompilationErrorHandler::ReportErrors(Isolate* isolate, |
| Handle<Script> script) const { |
| if (stack_overflow()) { |
| isolate->StackOverflow(); |
| } else { |
| DCHECK(has_pending_error()); |
| ThrowPendingError(isolate, script); |
| } |
| } |
| |
| void PendingCompilationErrorHandler::ThrowPendingError( |
| Isolate* isolate, Handle<Script> script) const { |
| if (!has_pending_error_) return; |
| |
| MessageLocation location = error_details_.GetLocation(script); |
| Handle<String> arg0 = error_details_.ArgString(isolate, 0); |
| Handle<String> arg1 = error_details_.ArgString(isolate, 1); |
| isolate->debug()->OnCompileError(script); |
| |
| Factory* factory = isolate->factory(); |
| Handle<JSObject> error = |
| factory->NewSyntaxError(error_details_.message(), arg0, arg1); |
| isolate->ThrowAt(error, &location); |
| } |
| |
| Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest( |
| Isolate* isolate) { |
| error_details_.Prepare(isolate); |
| return MessageFormatter::Format(isolate, error_details_.message(), |
| error_details_.ArgString(isolate, 0), |
| error_details_.ArgString(isolate, 1)); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |