| OLD | NEW |
| 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 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 // Currently stack trace is only collected when inspector is open. | 104 // Currently stack trace is only collected when inspector is open. |
| 105 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) { | 105 if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) { |
| 106 callStack = ScriptCallStack::create(isolate, stackTrace); | 106 callStack = ScriptCallStack::create(isolate, stackTrace); |
| 107 int topScriptId = stackTrace->GetFrame(0)->GetScriptId(); | 107 int topScriptId = stackTrace->GetFrame(0)->GetScriptId(); |
| 108 if (topScriptId == *scriptId) | 108 if (topScriptId == *scriptId) |
| 109 *scriptId = 0; | 109 *scriptId = 0; |
| 110 } | 110 } |
| 111 return callStack.release(); | 111 return callStack.release(); |
| 112 } | 112 } |
| 113 | 113 |
| 114 static String extractResourceName(v8::Local<v8::Message> message, const Document
* document) | 114 static String extractResourceName(v8::Local<v8::Message> message, const Executio
nContext* context) |
| 115 { | 115 { |
| 116 v8::Local<v8::Value> resourceName = message->GetScriptOrigin().ResourceName(
); | 116 v8::Local<v8::Value> resourceName = message->GetScriptOrigin().ResourceName(
); |
| 117 bool shouldUseDocumentURL = document && (resourceName.IsEmpty() || !resource
Name->IsString()); | 117 bool shouldUseDocumentURL = context->isDocument() && (resourceName.IsEmpty()
|| !resourceName->IsString()); |
| 118 return shouldUseDocumentURL ? document->url() : toCoreString(resourceName.As
<v8::String>()); | 118 return shouldUseDocumentURL ? context->url() : toCoreString(resourceName.As<
v8::String>()); |
| 119 } | 119 } |
| 120 | 120 |
| 121 static String extractMessageForConsole(v8::Isolate* isolate, v8::Local<v8::Value
> data) | 121 static String extractMessageForConsole(v8::Isolate* isolate, v8::Local<v8::Value
> data) |
| 122 { | 122 { |
| 123 if (V8DOMWrapper::isWrapper(isolate, data)) { | 123 if (V8DOMWrapper::isWrapper(isolate, data)) { |
| 124 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(data); | 124 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(data); |
| 125 const WrapperTypeInfo* type = toWrapperTypeInfo(obj); | 125 const WrapperTypeInfo* type = toWrapperTypeInfo(obj); |
| 126 if (V8DOMException::wrapperTypeInfo.isSubclass(type)) { | 126 if (V8DOMException::wrapperTypeInfo.isSubclass(type)) { |
| 127 DOMException* exception = V8DOMException::toImpl(obj); | 127 DOMException* exception = V8DOMException::toImpl(obj); |
| 128 if (exception && !exception->messageForConsole().isEmpty()) | 128 if (exception && !exception->messageForConsole().isEmpty()) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 140 if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber) | 140 if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber) |
| 141 && v8Call(message->GetStartColumn(scriptState->context()), columnNumber)
) | 141 && v8Call(message->GetStartColumn(scriptState->context()), columnNumber)
) |
| 142 ++columnNumber; | 142 ++columnNumber; |
| 143 return ErrorEvent::create(errorMessage, resourceName, lineNumber, columnNumb
er, &scriptState->world()); | 143 return ErrorEvent::create(errorMessage, resourceName, lineNumber, columnNumb
er, &scriptState->world()); |
| 144 } | 144 } |
| 145 | 145 |
| 146 static void messageHandlerInMainThread(v8::Local<v8::Message> message, v8::Local
<v8::Value> data) | 146 static void messageHandlerInMainThread(v8::Local<v8::Message> message, v8::Local
<v8::Value> data) |
| 147 { | 147 { |
| 148 ASSERT(isMainThread()); | 148 ASSERT(isMainThread()); |
| 149 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 149 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 150 // If called during context initialization, there will be no entered window. | 150 |
| 151 // TODO(haraken): Add a helper method to get an entered window that may be n
ull. | 151 // If called during context initialization, there will be no entered context
. |
| 152 LocalDOMWindow* enteredWindow = toLocalDOMWindow(toDOMWindow(isolate->GetEnt
eredContext())); | 152 ScriptState* scriptState = ScriptState::current(isolate); |
| 153 if (!enteredWindow || !enteredWindow->isCurrentlyDisplayedInFrame()) | 153 if (!scriptState->contextIsValid()) |
| 154 return; | 154 return; |
| 155 | 155 |
| 156 int scriptId = 0; | 156 int scriptId = 0; |
| 157 RefPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &scri
ptId); | 157 RefPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &scri
ptId); |
| 158 | 158 |
| 159 AccessControlStatus accessControlStatus = NotSharableCrossOrigin; | 159 AccessControlStatus accessControlStatus = NotSharableCrossOrigin; |
| 160 if (message->IsOpaque()) | 160 if (message->IsOpaque()) |
| 161 accessControlStatus = OpaqueResource; | 161 accessControlStatus = OpaqueResource; |
| 162 else if (message->IsSharedCrossOrigin()) | 162 else if (message->IsSharedCrossOrigin()) |
| 163 accessControlStatus = SharableCrossOrigin; | 163 accessControlStatus = SharableCrossOrigin; |
| 164 | 164 |
| 165 ScriptState* scriptState = ScriptState::current(isolate); | 165 ExecutionContext* context = scriptState->getExecutionContext(); |
| 166 | 166 String resourceName = extractResourceName(message, context); |
| 167 String resourceName = extractResourceName(message, enteredWindow->document()
); | |
| 168 ErrorEvent* event = createErrorEventFromMesssage(scriptState, message, resou
rceName); | 167 ErrorEvent* event = createErrorEventFromMesssage(scriptState, message, resou
rceName); |
| 169 | 168 |
| 170 String messageForConsole = extractMessageForConsole(isolate, data); | 169 String messageForConsole = extractMessageForConsole(isolate, data); |
| 171 if (!messageForConsole.isEmpty()) | 170 if (!messageForConsole.isEmpty()) |
| 172 event->setUnsanitizedMessage("Uncaught " + messageForConsole); | 171 event->setUnsanitizedMessage("Uncaught " + messageForConsole); |
| 173 | 172 |
| 174 // This method might be called while we're creating a new context. In this c
ase, we | 173 // This method might be called while we're creating a new context. In this c
ase, we |
| 175 // avoid storing the exception object, as we can't create a wrapper during c
ontext creation. | 174 // avoid storing the exception object, as we can't create a wrapper during c
ontext creation. |
| 176 // FIXME: Can we even get here during initialization now that we bail out wh
en GetEntered returns an empty handle? | 175 // FIXME: Can we even get here during initialization now that we bail out wh
en GetEntered returns an empty handle? |
| 177 LocalFrame* frame = enteredWindow->document()->frame(); | 176 if (context->isDocument()) { |
| 178 if (frame && frame->script().existingWindowProxy(scriptState->world())) { | 177 LocalFrame* frame = toDocument(context)->frame(); |
| 179 V8ErrorHandler::storeExceptionOnErrorEventWrapper(scriptState, event, da
ta, scriptState->context()->Global()); | 178 if (frame && frame->script().existingWindowProxy(scriptState->world()))
{ |
| 179 V8ErrorHandler::storeExceptionOnErrorEventWrapper(scriptState, event
, data, scriptState->context()->Global()); |
| 180 } |
| 180 } | 181 } |
| 181 | 182 |
| 182 if (scriptState->world().isPrivateScriptIsolatedWorld()) { | 183 if (scriptState->world().isPrivateScriptIsolatedWorld()) { |
| 183 // We allow a private script to dispatch error events even in a EventDis
patchForbiddenScope scope. | 184 // We allow a private script to dispatch error events even in a EventDis
patchForbiddenScope scope. |
| 184 // Without having this ability, it's hard to debug the private script be
cause syntax errors | 185 // Without having this ability, it's hard to debug the private script be
cause syntax errors |
| 185 // in the private script are not reported to console (the private script
just crashes silently). | 186 // in the private script are not reported to console (the private script
just crashes silently). |
| 186 // Allowing error events in private scripts is safe because error events
don't propagate to | 187 // Allowing error events in private scripts is safe because error events
don't propagate to |
| 187 // other isolated worlds (which means that the error events won't fire a
ny event listeners | 188 // other isolated worlds (which means that the error events won't fire a
ny event listeners |
| 188 // in user's scripts). | 189 // in user's scripts). |
| 189 EventDispatchForbiddenScope::AllowUserAgentEvents allowUserAgentEvents; | 190 EventDispatchForbiddenScope::AllowUserAgentEvents allowUserAgentEvents; |
| 190 enteredWindow->document()->reportException(event, scriptId, callStack, a
ccessControlStatus); | 191 context->reportException(event, scriptId, callStack, accessControlStatus
); |
| 191 } else { | 192 } else { |
| 192 enteredWindow->document()->reportException(event, scriptId, callStack, a
ccessControlStatus); | 193 context->reportException(event, scriptId, callStack, accessControlStatus
); |
| 193 } | 194 } |
| 194 } | 195 } |
| 195 | 196 |
| 196 namespace { | 197 namespace { |
| 197 | 198 |
| 198 static RejectedPromises& rejectedPromisesOnMainThread() | 199 static RejectedPromises& rejectedPromisesOnMainThread() |
| 199 { | 200 { |
| 200 ASSERT(isMainThread()); | 201 ASSERT(isMainThread()); |
| 201 DEFINE_STATIC_LOCAL(RefPtr<RejectedPromises>, rejectedPromises, (RejectedPro
mises::create())); | 202 DEFINE_STATIC_LOCAL(RefPtr<RejectedPromises>, rejectedPromises, (RejectedPro
mises::create())); |
| 202 return *rejectedPromises; | 203 return *rejectedPromises; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 rejectedPromises.rejectedWithNoHandler(scriptState, data, errorMessage, reso
urceName, scriptId, lineNumber, columnNumber, callStack, corsStatus); | 264 rejectedPromises.rejectedWithNoHandler(scriptState, data, errorMessage, reso
urceName, scriptId, lineNumber, columnNumber, callStack, corsStatus); |
| 264 } | 265 } |
| 265 | 266 |
| 266 static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data) | 267 static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data) |
| 267 { | 268 { |
| 268 ASSERT(isMainThread()); | 269 ASSERT(isMainThread()); |
| 269 | 270 |
| 270 v8::Local<v8::Promise> promise = data.GetPromise(); | 271 v8::Local<v8::Promise> promise = data.GetPromise(); |
| 271 | 272 |
| 272 v8::Isolate* isolate = promise->GetIsolate(); | 273 v8::Isolate* isolate = promise->GetIsolate(); |
| 273 // There is no entered window during microtask callbacks from V8, | 274 |
| 274 // thus we call toDOMWindow() instead of enteredDOMWindow(). | 275 // TODO(ikilpatrick): Remove this check, extensions tests that use |
| 276 // extensions::ModuleSystemTest incorrectly don't have a valid script state. |
| 275 LocalDOMWindow* window = currentDOMWindow(isolate); | 277 LocalDOMWindow* window = currentDOMWindow(isolate); |
| 276 if (!window || !window->isCurrentlyDisplayedInFrame()) | 278 if (!window || !window->isCurrentlyDisplayedInFrame()) |
| 277 return; | 279 return; |
| 278 | 280 |
| 279 promiseRejectHandler(data, rejectedPromisesOnMainThread(), window->document(
) ? window->document()->url() : String()); | 281 // Bail out if called during context initialization. |
| 282 ScriptState* scriptState = ScriptState::current(isolate); |
| 283 if (!scriptState->contextIsValid()) |
| 284 return; |
| 285 |
| 286 promiseRejectHandler(data, rejectedPromisesOnMainThread(), scriptState->getE
xecutionContext()->url()); |
| 280 } | 287 } |
| 281 | 288 |
| 282 static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data) | 289 static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data) |
| 283 { | 290 { |
| 284 v8::Local<v8::Promise> promise = data.GetPromise(); | 291 v8::Local<v8::Promise> promise = data.GetPromise(); |
| 285 | 292 |
| 286 // Bail out if called during context initialization. | 293 // Bail out if called during context initialization. |
| 287 v8::Isolate* isolate = promise->GetIsolate(); | 294 v8::Isolate* isolate = promise->GetIsolate(); |
| 288 ScriptState* scriptState = ScriptState::current(isolate); | 295 ScriptState* scriptState = ScriptState::current(isolate); |
| 289 if (!scriptState->contextIsValid()) | 296 if (!scriptState->contextIsValid()) |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 static void reportFatalErrorInWorker(const char* location, const char* message) | 419 static void reportFatalErrorInWorker(const char* location, const char* message) |
| 413 { | 420 { |
| 414 // FIXME: We temporarily deal with V8 internal error situations such as out-
of-memory by crashing the worker. | 421 // FIXME: We temporarily deal with V8 internal error situations such as out-
of-memory by crashing the worker. |
| 415 CRASH(); | 422 CRASH(); |
| 416 } | 423 } |
| 417 | 424 |
| 418 static void messageHandlerInWorker(v8::Local<v8::Message> message, v8::Local<v8:
:Value> data) | 425 static void messageHandlerInWorker(v8::Local<v8::Message> message, v8::Local<v8:
:Value> data) |
| 419 { | 426 { |
| 420 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 427 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 421 V8PerIsolateData* perIsolateData = V8PerIsolateData::from(isolate); | 428 V8PerIsolateData* perIsolateData = V8PerIsolateData::from(isolate); |
| 429 |
| 430 // During the frame teardown, there may not be a valid context. |
| 431 ScriptState* scriptState = ScriptState::current(isolate); |
| 432 if (!scriptState->contextIsValid()) |
| 433 return; |
| 434 |
| 422 // Exceptions that occur in error handler should be ignored since in that ca
se | 435 // Exceptions that occur in error handler should be ignored since in that ca
se |
| 423 // WorkerGlobalScope::reportException will send the exception to the worker
object. | 436 // WorkerGlobalScope::reportException will send the exception to the worker
object. |
| 424 if (perIsolateData->isReportingException()) | 437 if (perIsolateData->isReportingException()) |
| 425 return; | 438 return; |
| 439 |
| 426 perIsolateData->setReportingException(true); | 440 perIsolateData->setReportingException(true); |
| 427 | 441 |
| 428 ScriptState* scriptState = ScriptState::current(isolate); | 442 TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin().R
esourceName()); |
| 429 // During the frame teardown, there may not be a valid context. | 443 ErrorEvent* event = createErrorEventFromMesssage(scriptState, message, resou
rceName); |
| 430 if (ExecutionContext* context = scriptState->getExecutionContext()) { | |
| 431 TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin
().ResourceName()); | |
| 432 ErrorEvent* event = createErrorEventFromMesssage(scriptState, message, r
esourceName); | |
| 433 | 444 |
| 434 int scriptId = 0; | 445 int scriptId = 0; |
| 435 RefPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &
scriptId); | 446 RefPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &scri
ptId); |
| 436 | 447 |
| 437 AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? Sharab
leCrossOrigin : NotSharableCrossOrigin; | 448 AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCr
ossOrigin : NotSharableCrossOrigin; |
| 438 | 449 |
| 439 // If execution termination has been triggered as part of constructing | 450 // If execution termination has been triggered as part of constructing |
| 440 // the error event from the v8::Message, quietly leave. | 451 // the error event from the v8::Message, quietly leave. |
| 441 if (!isolate->IsExecutionTerminating()) { | 452 if (!isolate->IsExecutionTerminating()) { |
| 442 V8ErrorHandler::storeExceptionOnErrorEventWrapper(scriptState, event
, data, scriptState->context()->Global()); | 453 V8ErrorHandler::storeExceptionOnErrorEventWrapper(scriptState, event, da
ta, scriptState->context()->Global()); |
| 443 context->reportException(event, scriptId, callStack, corsStatus); | 454 scriptState->getExecutionContext()->reportException(event, scriptId, cal
lStack, corsStatus); |
| 444 } | |
| 445 } | 455 } |
| 446 | 456 |
| 447 perIsolateData->setReportingException(false); | 457 perIsolateData->setReportingException(false); |
| 448 } | 458 } |
| 449 | 459 |
| 450 static const int kWorkerMaxStackSize = 500 * 1024; | 460 static const int kWorkerMaxStackSize = 500 * 1024; |
| 451 | 461 |
| 452 // This function uses a local stack variable to determine the isolate's stack li
mit. AddressSanitizer may | 462 // This function uses a local stack variable to determine the isolate's stack li
mit. AddressSanitizer may |
| 453 // relocate that local variable to a fake stack, which may lead to problems duri
ng JavaScript execution. | 463 // relocate that local variable to a fake stack, which may lead to problems duri
ng JavaScript execution. |
| 454 // Therefore we disable AddressSanitizer for V8Initializer::initializeWorker(). | 464 // Therefore we disable AddressSanitizer for V8Initializer::initializeWorker(). |
| 455 NO_SANITIZE_ADDRESS | 465 NO_SANITIZE_ADDRESS |
| 456 void V8Initializer::initializeWorker(v8::Isolate* isolate) | 466 void V8Initializer::initializeWorker(v8::Isolate* isolate) |
| 457 { | 467 { |
| 458 initializeV8Common(isolate); | 468 initializeV8Common(isolate); |
| 459 | 469 |
| 460 isolate->AddMessageListener(messageHandlerInWorker); | 470 isolate->AddMessageListener(messageHandlerInWorker); |
| 461 isolate->SetFatalErrorHandler(reportFatalErrorInWorker); | 471 isolate->SetFatalErrorHandler(reportFatalErrorInWorker); |
| 462 | 472 |
| 463 uint32_t here; | 473 uint32_t here; |
| 464 isolate->SetStackLimit(reinterpret_cast<uintptr_t>(&here - kWorkerMaxStackSi
ze / sizeof(uint32_t*))); | 474 isolate->SetStackLimit(reinterpret_cast<uintptr_t>(&here - kWorkerMaxStackSi
ze / sizeof(uint32_t*))); |
| 465 isolate->SetPromiseRejectCallback(promiseRejectHandlerInWorker); | 475 isolate->SetPromiseRejectCallback(promiseRejectHandlerInWorker); |
| 466 } | 476 } |
| 467 | 477 |
| 468 } // namespace blink | 478 } // namespace blink |
| OLD | NEW |