pending-compilation-error-handler.cc 7.2 KB
Newer Older
1 2 3 4
// 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.

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 12
#include "src/execution/isolate.h"
#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 18 19

namespace v8 {
namespace internal {

20 21
void PendingCompilationErrorHandler::MessageDetails::SetString(
    Handle<String> string, Isolate* isolate) {
22 23 24
  DCHECK_NE(args_[0].type, kMainThreadHandle);
  args_[0].type = kMainThreadHandle;
  args_[0].js_string = string;
25 26 27
}

void PendingCompilationErrorHandler::MessageDetails::SetString(
28
    Handle<String> string, LocalIsolate* isolate) {
29 30 31
  DCHECK_NE(args_[0].type, kMainThreadHandle);
  args_[0].type = kMainThreadHandle;
  args_[0].js_string = isolate->heap()->NewPersistentHandle(string);
32 33
}

34
template <typename IsolateT>
35
void PendingCompilationErrorHandler::MessageDetails::Prepare(
36
    IsolateT* isolate) {
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
  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;
    }
52 53 54
  }
}

55 56 57 58 59 60
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) {
61
    case kMainThreadHandle:
62
      return args_[index].js_string;
63
    case kNone:
64
      return Handle<String>::null();
65 66
    case kConstCharString:
      return isolate->factory()
67
          ->NewStringFromUtf8(base::CStrVector(args_[index].c_string),
68
                              AllocationType::kOld)
69 70 71
          .ToHandleChecked();
    case kAstRawString:
      UNREACHABLE();
72 73 74 75 76 77 78 79
  }
}

MessageLocation PendingCompilationErrorHandler::MessageDetails::GetLocation(
    Handle<Script> script) const {
  return MessageLocation(script, start_position_, end_position_);
}

80 81 82 83
void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
                                                     int end_position,
                                                     MessageTemplate message,
                                                     const char* arg) {
84 85 86
  if (has_pending_error_) return;
  has_pending_error_ = true;

87
  error_details_ = MessageDetails(start_position, end_position, message, arg);
88 89
}

90 91 92 93
void PendingCompilationErrorHandler::ReportMessageAt(int start_position,
                                                     int end_position,
                                                     MessageTemplate message,
                                                     const AstRawString* arg) {
94 95 96
  if (has_pending_error_) return;
  has_pending_error_ = true;

97
  error_details_ = MessageDetails(start_position, end_position, message, arg);
98 99
}

100 101 102 103 104 105 106 107 108 109 110
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);
}

111 112 113 114
void PendingCompilationErrorHandler::ReportWarningAt(int start_position,
                                                     int end_position,
                                                     MessageTemplate message,
                                                     const char* arg) {
115
  warning_messages_.emplace_front(
116
      MessageDetails(start_position, end_position, message, arg));
117 118
}

119 120
template <typename IsolateT>
void PendingCompilationErrorHandler::PrepareWarnings(IsolateT* isolate) {
121 122 123 124 125 126 127 128
  DCHECK(!has_pending_error());

  for (MessageDetails& warning : warning_messages_) {
    warning.Prepare(isolate);
  }
}
template void PendingCompilationErrorHandler::PrepareWarnings(Isolate* isolate);
template void PendingCompilationErrorHandler::PrepareWarnings(
129
    LocalIsolate* isolate);
130 131 132

void PendingCompilationErrorHandler::ReportWarnings(
    Isolate* isolate, Handle<Script> script) const {
133 134 135 136
  DCHECK(!has_pending_error());

  for (const MessageDetails& warning : warning_messages_) {
    MessageLocation location = warning.GetLocation(script);
137 138
    Handle<String> argument = warning.ArgString(isolate, 0);
    DCHECK_LT(warning.ArgCount(), 2);  // Arg1 is only used for errors.
139 140 141 142 143 144 145 146
    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);
  }
}

147
template <typename IsolateT>
148
void PendingCompilationErrorHandler::PrepareErrors(
149
    IsolateT* isolate, AstValueFactory* ast_value_factory) {
150
  if (stack_overflow()) return;
151

152 153 154 155
  DCHECK(has_pending_error());
  // Internalize ast values for throwing the pending error.
  ast_value_factory->Internalize(isolate);
  error_details_.Prepare(isolate);
156
}
157 158 159 160 161
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::
162
    PrepareErrors(LocalIsolate* isolate, AstValueFactory* ast_value_factory);
163

164 165
void PendingCompilationErrorHandler::ReportErrors(Isolate* isolate,
                                                  Handle<Script> script) const {
166 167 168 169 170 171 172 173
  if (stack_overflow()) {
    isolate->StackOverflow();
  } else {
    DCHECK(has_pending_error());
    ThrowPendingError(isolate, script);
  }
}

174 175
void PendingCompilationErrorHandler::ThrowPendingError(
    Isolate* isolate, Handle<Script> script) const {
176
  if (!has_pending_error_) return;
177 178

  MessageLocation location = error_details_.GetLocation(script);
179 180
  Handle<String> arg0 = error_details_.ArgString(isolate, 0);
  Handle<String> arg1 = error_details_.ArgString(isolate, 1);
181 182
  isolate->debug()->OnCompileError(script);

183
  Factory* factory = isolate->factory();
184
  Handle<JSObject> error =
185
      factory->NewSyntaxError(error_details_.message(), arg0, arg1);
186
  isolate->ThrowAt(error, &location);
187
}
188 189

Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest(
190 191
    Isolate* isolate) {
  error_details_.Prepare(isolate);
192
  return MessageFormatter::Format(isolate, error_details_.message(),
193 194
                                  error_details_.ArgString(isolate, 0),
                                  error_details_.ArgString(isolate, 1));
195 196
}

197 198
}  // namespace internal
}  // namespace v8