|  | // 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(type_, kMainThreadHandle); | 
|  | type_ = kMainThreadHandle; | 
|  | arg_handle_ = string; | 
|  | } | 
|  |  | 
|  | void PendingCompilationErrorHandler::MessageDetails::SetString( | 
|  | Handle<String> string, LocalIsolate* isolate) { | 
|  | DCHECK_NE(type_, kMainThreadHandle); | 
|  | type_ = kMainThreadHandle; | 
|  | arg_handle_ = isolate->heap()->NewPersistentHandle(string); | 
|  | } | 
|  |  | 
|  | template <typename LocalIsolate> | 
|  | void PendingCompilationErrorHandler::MessageDetails::Prepare( | 
|  | LocalIsolate* isolate) { | 
|  | switch (type_) { | 
|  | case kAstRawString: | 
|  | return SetString(arg_->string(), isolate); | 
|  |  | 
|  | case kNone: | 
|  | case kConstCharString: | 
|  | // We can delay allocation until ArgumentString(isolate). | 
|  | // TODO(leszeks): We don't actually have to transfer this string, since | 
|  | // it's a root. | 
|  | return; | 
|  |  | 
|  | case kMainThreadHandle: | 
|  | // The message details might already be prepared, so skip them if this is | 
|  | // the case. | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString( | 
|  | Isolate* isolate) const { | 
|  | switch (type_) { | 
|  | case kMainThreadHandle: | 
|  | return arg_handle_; | 
|  | case kNone: | 
|  | return isolate->factory()->undefined_string(); | 
|  | case kConstCharString: | 
|  | return isolate->factory() | 
|  | ->NewStringFromUtf8(CStrVector(char_arg_), 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::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 LocalIsolate> | 
|  | void PendingCompilationErrorHandler::PrepareWarnings(LocalIsolate* 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.ArgumentString(isolate); | 
|  | 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 LocalIsolate> | 
|  | void PendingCompilationErrorHandler::PrepareErrors( | 
|  | LocalIsolate* 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> argument = error_details_.ArgumentString(isolate); | 
|  | isolate->debug()->OnCompileError(script); | 
|  |  | 
|  | Factory* factory = isolate->factory(); | 
|  | Handle<JSObject> error = | 
|  | factory->NewSyntaxError(error_details_.message(), argument); | 
|  | isolate->ThrowAt(error, &location); | 
|  | } | 
|  |  | 
|  | Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest( | 
|  | Isolate* isolate) { | 
|  | error_details_.Prepare(isolate); | 
|  | return MessageFormatter::Format(isolate, error_details_.message(), | 
|  | error_details_.ArgumentString(isolate)); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace v8 |