Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(832)

Side by Side Diff: Source/bindings/core/v8/V8Initializer.cpp

Issue 693183002: Show correct location of unhandled promise rejection messages when DevTools closed. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: rebased Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved. 2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 return 0; 83 return 0;
84 } 84 }
85 85
86 static void reportFatalErrorInMainThread(const char* location, const char* messa ge) 86 static void reportFatalErrorInMainThread(const char* location, const char* messa ge)
87 { 87 {
88 int memoryUsageMB = blink::Platform::current()->actualMemoryUsageMB(); 88 int memoryUsageMB = blink::Platform::current()->actualMemoryUsageMB();
89 printf("V8 error: %s (%s). Current memory usage: %d MB\n", message, locatio n, memoryUsageMB); 89 printf("V8 error: %s (%s). Current memory usage: %d MB\n", message, locatio n, memoryUsageMB);
90 CRASH(); 90 CRASH();
91 } 91 }
92 92
93 static PassRefPtrWillBeRawPtr<ScriptCallStack> extractCallStack(v8::Isolate* iso late, v8::Handle<v8::Message> message, int* const scriptId)
94 {
95 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
96 RefPtrWillBeRawPtr<ScriptCallStack> callStack = nullptr;
97 *scriptId = message->GetScriptOrigin().ScriptID()->Value();
98 // Currently stack trace is only collected when inspector is open.
99 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) {
100 callStack = createScriptCallStack(isolate, stackTrace, ScriptCallStack:: maxCallStackSizeToCapture);
101 bool success = false;
102 int topScriptId = callStack->at(0).scriptId().toInt(&success);
103 if (success && topScriptId == *scriptId)
104 *scriptId = 0;
105 } else {
106 Vector<ScriptCallFrame> callFrames;
107 callStack = ScriptCallStack::create(callFrames);
108 }
109 return callStack.release();
110 }
111
112 static String extractResourceName(v8::Handle<v8::Message> message, const Documen t* document)
113 {
114 v8::Handle<v8::Value> resourceName = message->GetScriptOrigin().ResourceName ();
115 bool shouldUseDocumentURL = document && (resourceName.IsEmpty() || !resource Name->IsString());
116 return shouldUseDocumentURL ? document->url() : toCoreString(resourceName.As <v8::String>());
117 }
118
93 static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Hand le<v8::Value> data) 119 static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Hand le<v8::Value> data)
94 { 120 {
95 ASSERT(isMainThread()); 121 ASSERT(isMainThread());
96 // It's possible that messageHandlerInMainThread() is invoked while we're in itializing a window. 122 // It's possible that messageHandlerInMainThread() is invoked while we're in itializing a window.
97 // In that half-baked situation, we don't have a valid context nor a valid w orld, 123 // In that half-baked situation, we don't have a valid context nor a valid w orld,
98 // so just return immediately. 124 // so just return immediately.
99 if (DOMWrapperWorld::windowIsBeingInitialized()) 125 if (DOMWrapperWorld::windowIsBeingInitialized())
100 return; 126 return;
101 127
102 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 128 v8::Isolate* isolate = v8::Isolate::GetCurrent();
103 // If called during context initialization, there will be no entered window. 129 // If called during context initialization, there will be no entered window.
104 LocalDOMWindow* enteredWindow = enteredDOMWindow(isolate); 130 LocalDOMWindow* enteredWindow = enteredDOMWindow(isolate);
105 if (!enteredWindow || !enteredWindow->isCurrentlyDisplayedInFrame()) 131 if (!enteredWindow || !enteredWindow->isCurrentlyDisplayedInFrame())
106 return; 132 return;
107 133
108 String errorMessage = toCoreString(message->Get()); 134 int scriptId = 0;
109 135 RefPtrWillBeRawPtr<ScriptCallStack> callStack = extractCallStack(isolate, me ssage, &scriptId);
110 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace(); 136 String resourceName = extractResourceName(message, enteredWindow->document() );
111 RefPtrWillBeRawPtr<ScriptCallStack> callStack = nullptr;
112 int scriptId = message->GetScriptOrigin().ScriptID()->Value();
113 // Currently stack trace is only collected when inspector is open.
114 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) {
115 callStack = createScriptCallStack(isolate, stackTrace, ScriptCallStack:: maxCallStackSizeToCapture);
116 bool success = false;
117 int topScriptId = callStack->at(0).scriptId().toInt(&success);
118 if (success && topScriptId == scriptId)
119 scriptId = 0;
120 } else {
121 Vector<ScriptCallFrame> callFrames;
122 callStack = ScriptCallStack::create(callFrames);
123 }
124
125 v8::Handle<v8::Value> resourceName = message->GetScriptOrigin().ResourceName ();
126 bool shouldUseDocumentURL = resourceName.IsEmpty() || !resourceName->IsStrin g();
127 String resource = shouldUseDocumentURL ? enteredWindow->document()->url() : toCoreString(resourceName.As<v8::String>());
128 AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCr ossOrigin : NotSharableCrossOrigin; 137 AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCr ossOrigin : NotSharableCrossOrigin;
129 138
130 ScriptState* scriptState = ScriptState::current(isolate); 139 ScriptState* scriptState = ScriptState::current(isolate);
131 RefPtrWillBeRawPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, reso urce, message->GetLineNumber(), message->GetStartColumn() + 1, &scriptState->wor ld()); 140 String errorMessage = toCoreString(message->Get());
141 RefPtrWillBeRawPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, reso urceName, message->GetLineNumber(), message->GetStartColumn() + 1, &scriptState- >world());
132 if (V8DOMWrapper::isDOMWrapper(data)) { 142 if (V8DOMWrapper::isDOMWrapper(data)) {
133 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(data); 143 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(data);
134 const WrapperTypeInfo* type = toWrapperTypeInfo(obj); 144 const WrapperTypeInfo* type = toWrapperTypeInfo(obj);
135 if (V8DOMException::wrapperTypeInfo.isSubclass(type)) { 145 if (V8DOMException::wrapperTypeInfo.isSubclass(type)) {
136 DOMException* exception = V8DOMException::toImpl(obj); 146 DOMException* exception = V8DOMException::toImpl(obj);
137 if (exception && !exception->messageForConsole().isEmpty()) 147 if (exception && !exception->messageForConsole().isEmpty())
138 event->setUnsanitizedMessage("Uncaught " + exception->toStringFo rConsole()); 148 event->setUnsanitizedMessage("Uncaught " + exception->toStringFo rConsole());
139 } 149 }
140 } 150 }
141 151
(...skipping 17 matching lines...) Expand all
159 } else { 169 } else {
160 enteredWindow->document()->reportException(event.release(), scriptId, ca llStack, corsStatus); 170 enteredWindow->document()->reportException(event.release(), scriptId, ca llStack, corsStatus);
161 } 171 }
162 } 172 }
163 173
164 namespace { 174 namespace {
165 175
166 class PromiseRejectMessage { 176 class PromiseRejectMessage {
167 ALLOW_ONLY_INLINE_ALLOCATION(); 177 ALLOW_ONLY_INLINE_ALLOCATION();
168 public: 178 public:
169 PromiseRejectMessage(const ScriptValue& promise, PassRefPtrWillBeRawPtr<Scri ptCallStack> callStack) 179 PromiseRejectMessage(const ScriptValue& promise, const String& resourceName, int scriptId, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCa llStack> callStack)
170 : m_promise(promise) 180 : m_promise(promise)
181 , m_resourceName(resourceName)
182 , m_scriptId(scriptId)
183 , m_lineNumber(lineNumber)
184 , m_columnNumber(columnNumber)
171 , m_callStack(callStack) 185 , m_callStack(callStack)
172 { 186 {
173 } 187 }
174 188
175 void trace(Visitor* visitor) 189 void trace(Visitor* visitor)
176 { 190 {
177 visitor->trace(m_callStack); 191 visitor->trace(m_callStack);
178 } 192 }
179 193
180 const ScriptValue m_promise; 194 const ScriptValue m_promise;
195 const String m_resourceName;
196 const int m_scriptId;
197 const int m_lineNumber;
198 const int m_columnNumber;
181 const RefPtrWillBeMember<ScriptCallStack> m_callStack; 199 const RefPtrWillBeMember<ScriptCallStack> m_callStack;
182 }; 200 };
183 201
184 } // namespace 202 } // namespace
185 203
186 typedef Deque<PromiseRejectMessage> PromiseRejectMessageQueue; 204 typedef Deque<PromiseRejectMessage> PromiseRejectMessageQueue;
187 205
188 static PromiseRejectMessageQueue& promiseRejectMessageQueue() 206 static PromiseRejectMessageQueue& promiseRejectMessageQueue()
189 { 207 {
190 AtomicallyInitializedStatic(ThreadSpecific<PromiseRejectMessageQueue>*, queu e = new ThreadSpecific<PromiseRejectMessageQueue>); 208 AtomicallyInitializedStatic(ThreadSpecific<PromiseRejectMessageQueue>*, queu e = new ThreadSpecific<PromiseRejectMessageQueue>);
(...skipping 22 matching lines...) Expand all
213 ASSERT(!value.IsEmpty() && value->IsPromise()); 231 ASSERT(!value.IsEmpty() && value->IsPromise());
214 if (v8::Handle<v8::Promise>::Cast(value)->HasHandler()) 232 if (v8::Handle<v8::Promise>::Cast(value)->HasHandler())
215 continue; 233 continue;
216 234
217 const String errorMessage = "Unhandled promise rejection"; 235 const String errorMessage = "Unhandled promise rejection";
218 Vector<ScriptValue> args; 236 Vector<ScriptValue> args;
219 args.append(ScriptValue(scriptState, v8String(scriptState->isolate(), er rorMessage))); 237 args.append(ScriptValue(scriptState, v8String(scriptState->isolate(), er rorMessage)));
220 args.append(message.m_promise); 238 args.append(message.m_promise);
221 RefPtrWillBeRawPtr<ScriptArguments> arguments = ScriptArguments::create( scriptState, args); 239 RefPtrWillBeRawPtr<ScriptArguments> arguments = ScriptArguments::create( scriptState, args);
222 240
223 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::crea te(JSMessageSource, ErrorMessageLevel, errorMessage); 241 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::crea te(JSMessageSource, ErrorMessageLevel, errorMessage, message.m_resourceName, mes sage.m_lineNumber, message.m_columnNumber);
224 consoleMessage->setScriptArguments(arguments); 242 consoleMessage->setScriptArguments(arguments);
225 consoleMessage->setCallStack(message.m_callStack); 243 consoleMessage->setCallStack(message.m_callStack);
244 consoleMessage->setScriptId(message.m_scriptId);
226 executionContext->addConsoleMessage(consoleMessage.release()); 245 executionContext->addConsoleMessage(consoleMessage.release());
227 } 246 }
228 } 247 }
229 248
230 static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage message) 249 static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data)
231 { 250 {
232 ASSERT(isMainThread()); 251 ASSERT(isMainThread());
233 252
234 if (message.GetEvent() != v8::kPromiseRejectWithNoHandler) 253 if (data.GetEvent() != v8::kPromiseRejectWithNoHandler)
235 return; 254 return;
236 255
237 // It's possible that promiseRejectHandlerInMainThread() is invoked while we 're initializing a window. 256 // It's possible that promiseRejectHandlerInMainThread() is invoked while we 're initializing a window.
238 // In that half-baked situation, we don't have a valid context nor a valid w orld, 257 // In that half-baked situation, we don't have a valid context nor a valid w orld,
239 // so just return immediately. 258 // so just return immediately.
240 if (DOMWrapperWorld::windowIsBeingInitialized()) 259 if (DOMWrapperWorld::windowIsBeingInitialized())
241 return; 260 return;
242 261
243 v8::Handle<v8::Promise> promise = message.GetPromise(); 262 v8::Handle<v8::Promise> promise = data.GetPromise();
244 263
245 // Bail out if called during context initialization. 264 // Bail out if called during context initialization.
246 v8::Isolate* isolate = promise->GetIsolate(); 265 v8::Isolate* isolate = promise->GetIsolate();
247 v8::Handle<v8::Context> context = isolate->GetCurrentContext(); 266 v8::Handle<v8::Context> context = isolate->GetCurrentContext();
248 if (context.IsEmpty()) 267 if (context.IsEmpty())
249 return; 268 return;
250 v8::Handle<v8::Value> global = V8Window::findInstanceInPrototypeChain(contex t->Global(), context->GetIsolate()); 269 v8::Handle<v8::Value> global = V8Window::findInstanceInPrototypeChain(contex t->Global(), context->GetIsolate());
251 if (global.IsEmpty()) 270 if (global.IsEmpty())
252 return; 271 return;
253 if (!toFrameIfNotDetached(context)) 272
273 // There is no entered window during microtask callbacks from V8,
274 // thus we call toDOMWindow() instead of enteredDOMWindow().
275 LocalDOMWindow* window = toLocalDOMWindow(toDOMWindow(context));
276 if (!window || !window->isCurrentlyDisplayedInFrame())
254 return; 277 return;
255 278
279 v8::Handle<v8::Value> exception = data.GetValue();
280 if (V8DOMWrapper::isDOMWrapper(exception)) {
281 // Try to get the stack & location from a wrapped exception object (e.g. DOMException).
282 ASSERT(exception->IsObject());
283 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(exception);
284 v8::Handle<v8::Value> error = V8HiddenValue::getHiddenValue(isolate, obj , V8HiddenValue::error(isolate));
285 if (!error.IsEmpty())
286 exception = error;
287 }
288
289 int scriptId = 0;
290 int lineNumber = 0;
291 int columnNumber = 0;
292 String resourceName;
256 RefPtrWillBeRawPtr<ScriptCallStack> callStack = nullptr; 293 RefPtrWillBeRawPtr<ScriptCallStack> callStack = nullptr;
257 v8::Handle<v8::StackTrace> stackTrace = message.GetStackTrace();
258 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
259 callStack = createScriptCallStack(isolate, stackTrace, ScriptCallStack:: maxCallStackSizeToCapture);
260 294
261 if (!callStack && V8DOMWrapper::isDOMWrapper(message.GetValue())) { 295 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(exception);
262 // Try to get the stack from a wrapped exception object (e.g. DOMExcepti on). 296 if (!message.IsEmpty()) {
263 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(message.GetVal ue()); 297 lineNumber = message->GetLineNumber();
264 v8::Handle<v8::Value> error = V8HiddenValue::getHiddenValue(isolate, obj , V8HiddenValue::error(isolate)); 298 columnNumber = message->GetStartColumn() + 1;
265 if (!error.IsEmpty()) { 299 callStack = extractCallStack(isolate, message, &scriptId);
266 stackTrace = v8::Exception::GetStackTrace(error); 300 resourceName = extractResourceName(message, window->document());
267 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
268 callStack = createScriptCallStack(isolate, stackTrace, ScriptCal lStack::maxCallStackSizeToCapture);
269 }
270 } 301 }
271 302
272 ScriptState* scriptState = ScriptState::from(context); 303 ScriptState* scriptState = ScriptState::from(context);
273 promiseRejectMessageQueue().append(PromiseRejectMessage(ScriptValue(scriptSt ate, promise), callStack)); 304 promiseRejectMessageQueue().append(PromiseRejectMessage(ScriptValue(scriptSt ate, promise), resourceName, scriptId, lineNumber, columnNumber, callStack));
vsevik 2014/11/12 15:43:00 Please see https://code.google.com/p/chromium/issu
274 } 305 }
275 306
276 static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage message) 307 static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data)
277 { 308 {
278 if (message.GetEvent() != v8::kPromiseRejectWithNoHandler) 309 if (data.GetEvent() != v8::kPromiseRejectWithNoHandler)
279 return; 310 return;
280 311
281 v8::Handle<v8::Promise> promise = message.GetPromise(); 312 v8::Handle<v8::Promise> promise = data.GetPromise();
282 313
283 // Bail out if called during context initialization. 314 // Bail out if called during context initialization.
284 v8::Isolate* isolate = promise->GetIsolate(); 315 v8::Isolate* isolate = promise->GetIsolate();
285 v8::Handle<v8::Context> context = isolate->GetCurrentContext(); 316 v8::Handle<v8::Context> context = isolate->GetCurrentContext();
286 if (context.IsEmpty()) 317 if (context.IsEmpty())
287 return; 318 return;
288 319
289 RefPtrWillBeRawPtr<ScriptCallStack> callStack = nullptr; 320 int scriptId = 0;
290 v8::Handle<v8::StackTrace> stackTrace = message.GetStackTrace(); 321 int lineNumber = 0;
291 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) 322 int columnNumber = 0;
292 callStack = createScriptCallStack(isolate, stackTrace, ScriptCallStack:: maxCallStackSizeToCapture); 323 String resourceName;
324
325 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(data.GetValue ());
326 if (!message.IsEmpty()) {
327 TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin ().ResourceName());
328 scriptId = message->GetScriptOrigin().ScriptID()->Value();
329 lineNumber = message->GetLineNumber();
330 columnNumber = message->GetStartColumn() + 1;
331 }
293 332
294 ScriptState* scriptState = ScriptState::from(context); 333 ScriptState* scriptState = ScriptState::from(context);
295 promiseRejectMessageQueue().append(PromiseRejectMessage(ScriptValue(scriptSt ate, promise), callStack)); 334 promiseRejectMessageQueue().append(PromiseRejectMessage(ScriptValue(scriptSt ate, promise), resourceName, scriptId, lineNumber, columnNumber, nullptr));
296 } 335 }
297 336
298 static void failedAccessCheckCallbackInMainThread(v8::Local<v8::Object> host, v8 ::AccessType type, v8::Local<v8::Value> data) 337 static void failedAccessCheckCallbackInMainThread(v8::Local<v8::Object> host, v8 ::AccessType type, v8::Local<v8::Value> data)
299 { 338 {
300 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 339 v8::Isolate* isolate = v8::Isolate::GetCurrent();
301 Frame* target = findFrame(host, data, isolate); 340 Frame* target = findFrame(host, data, isolate);
302 if (!target) 341 if (!target)
303 return; 342 return;
304 DOMWindow* targetWindow = target->domWindow(); 343 DOMWindow* targetWindow = target->domWindow();
305 344
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 474
436 v8::V8::AddMessageListener(messageHandlerInWorker); 475 v8::V8::AddMessageListener(messageHandlerInWorker);
437 v8::V8::SetFatalErrorHandler(reportFatalErrorInWorker); 476 v8::V8::SetFatalErrorHandler(reportFatalErrorInWorker);
438 477
439 uint32_t here; 478 uint32_t here;
440 isolate->SetStackLimit(reinterpret_cast<uintptr_t>(&here - kWorkerMaxStackSi ze / sizeof(uint32_t*))); 479 isolate->SetStackLimit(reinterpret_cast<uintptr_t>(&here - kWorkerMaxStackSi ze / sizeof(uint32_t*)));
441 isolate->SetPromiseRejectCallback(promiseRejectHandlerInWorker); 480 isolate->SetPromiseRejectCallback(promiseRejectHandlerInWorker);
442 } 481 }
443 482
444 } // namespace blink 483 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698