Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "bindings/v8/V8Initializer.h"
     28 
     29 #include "V8ErrorEvent.h"
     30 #include "V8History.h"
     31 #include "V8Location.h"
     32 #include "V8Window.h"
     33 #include "bindings/v8/DOMWrapperWorld.h"
     34 #include "bindings/v8/ScriptCallStackFactory.h"
     35 #include "bindings/v8/ScriptController.h"
     36 #include "bindings/v8/ScriptProfiler.h"
     37 #include "bindings/v8/V8Binding.h"
     38 #include "bindings/v8/V8GCController.h"
     39 #include "bindings/v8/V8HiddenPropertyName.h"
     40 #include "bindings/v8/V8PerContextData.h"
     41 #include "core/dom/Document.h"
     42 #include "core/dom/ExceptionCode.h"
     43 #include "core/inspector/ScriptCallStack.h"
     44 #include "core/page/ConsoleTypes.h"
     45 #include "core/page/ContentSecurityPolicy.h"
     46 #include "core/page/DOMWindow.h"
     47 #include "core/page/Frame.h"
     48 #include "core/platform/MemoryUsageSupport.h"
     49 #include <v8-debug.h>
     50 #include "wtf/RefPtr.h"
     51 #include "wtf/text/WTFString.h"
     52 
     53 namespace WebCore {
     54 
     55 static Frame* findFrame(v8::Local<v8::Object> host, v8::Local<v8::Value> data, v8::Isolate* isolate)
     56 {
     57     WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
     58 
     59     if (V8Window::info.equals(type)) {
     60         v8::Handle<v8::Object> windowWrapper = host->FindInstanceInPrototypeChain(V8Window::GetTemplate(isolate, worldTypeInMainThread(isolate)));
     61         if (windowWrapper.IsEmpty())
     62             return 0;
     63         return V8Window::toNative(windowWrapper)->frame();
     64     }
     65 
     66     if (V8History::info.equals(type))
     67         return V8History::toNative(host)->frame();
     68 
     69     if (V8Location::info.equals(type))
     70         return V8Location::toNative(host)->frame();
     71 
     72     // This function can handle only those types listed above.
     73     ASSERT_NOT_REACHED();
     74     return 0;
     75 }
     76 
     77 static void reportFatalErrorInMainThread(const char* location, const char* message)
     78 {
     79     int memoryUsageMB = MemoryUsageSupport::actualMemoryUsageMB();
     80     printf("V8 error: %s (%s).  Current memory usage: %d MB\n", message, location, memoryUsageMB);
     81     CRASH();
     82 }
     83 
     84 static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data)
     85 {
     86     DOMWindow* firstWindow = firstDOMWindow();
     87     if (!firstWindow->isCurrentlyDisplayedInFrame())
     88         return;
     89 
     90     String errorMessage = toWebCoreString(message->Get());
     91 
     92     v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
     93     RefPtr<ScriptCallStack> callStack;
     94     // Currently stack trace is only collected when inspector is open.
     95     if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
     96         callStack = createScriptCallStack(stackTrace, ScriptCallStack::maxCallStackSizeToCapture);
     97 
     98     v8::Handle<v8::Value> resourceName = message->GetScriptResourceName();
     99     bool shouldUseDocumentURL = resourceName.IsEmpty() || !resourceName->IsString();
    100     String resource = shouldUseDocumentURL ? firstWindow->document()->url() : toWebCoreString(resourceName);
    101     RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resource, message->GetLineNumber(), message->GetStartColumn());
    102 
    103     // messageHandlerInMainThread can be called while we're creating a new context.
    104     // Since we cannot create a wrapper in the intermediate timing, we need to skip
    105     // creating a wrapper for |event|.
    106     DOMWrapperWorld* world = DOMWrapperWorld::current();
    107     Frame* frame = firstWindow->document()->frame();
    108     if (world && frame && frame->script()->existingWindowShell(world)) {
    109         v8::Local<v8::Value> wrappedEvent = toV8(event.get(), v8::Handle<v8::Object>(), v8::Isolate::GetCurrent());
    110         if (!wrappedEvent.IsEmpty()) {
    111             ASSERT(wrappedEvent->IsObject());
    112             v8::Local<v8::Object>::Cast(wrappedEvent)->SetHiddenValue(V8HiddenPropertyName::error(), data);
    113         }
    114     }
    115     AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin;
    116     firstWindow->document()->reportException(event.release(), callStack, corsStatus);
    117 }
    118 
    119 static void failedAccessCheckCallbackInMainThread(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data)
    120 {
    121     Frame* target = findFrame(host, data, v8::Isolate::GetCurrent());
    122     if (!target)
    123         return;
    124     DOMWindow* targetWindow = target->domWindow();
    125 
    126     setDOMException(SecurityError, targetWindow->crossDomainAccessErrorMessage(activeDOMWindow()), v8::Isolate::GetCurrent());
    127 }
    128 
    129 static bool codeGenerationCheckCallbackInMainThread(v8::Local<v8::Context> context)
    130 {
    131     if (ScriptExecutionContext* scriptExecutionContext = toScriptExecutionContext(context)) {
    132         if (ContentSecurityPolicy* policy = toDocument(scriptExecutionContext)->contentSecurityPolicy())
    133             return policy->allowEval(ScriptState::forContext(context));
    134     }
    135     return false;
    136 }
    137 
    138 static void initializeV8Common()
    139 {
    140     v8::V8::AddGCPrologueCallback(V8GCController::gcPrologue);
    141     v8::V8::AddGCEpilogueCallback(V8GCController::gcEpilogue);
    142     v8::V8::IgnoreOutOfMemoryException();
    143 
    144     v8::Debug::SetLiveEditEnabled(false);
    145 }
    146 
    147 void V8Initializer::initializeMainThreadIfNeeded(v8::Isolate* isolate)
    148 {
    149     ASSERT(isMainThread());
    150 
    151     static bool initialized = false;
    152     if (initialized)
    153         return;
    154     initialized = true;
    155 
    156     initializeV8Common();
    157 
    158     v8::V8::SetFatalErrorHandler(reportFatalErrorInMainThread);
    159     v8::V8::AddMessageListener(messageHandlerInMainThread);
    160     v8::V8::SetFailedAccessCheckCallbackFunction(failedAccessCheckCallbackInMainThread);
    161     v8::V8::SetAllowCodeGenerationFromStringsCallback(codeGenerationCheckCallbackInMainThread);
    162     ScriptProfiler::initialize();
    163     V8PerIsolateData::ensureInitialized(isolate);
    164 }
    165 
    166 static void reportFatalErrorInWorker(const char* location, const char* message)
    167 {
    168     // FIXME: We temporarily deal with V8 internal error situations such as out-of-memory by crashing the worker.
    169     CRASH();
    170 }
    171 
    172 static void messageHandlerInWorker(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data)
    173 {
    174     static bool isReportingException = false;
    175     // Exceptions that occur in error handler should be ignored since in that case
    176     // WorkerGlobalScope::reportException will send the exception to the worker object.
    177     if (isReportingException)
    178         return;
    179     isReportingException = true;
    180 
    181     // During the frame teardown, there may not be a valid context.
    182     if (ScriptExecutionContext* context = getScriptExecutionContext()) {
    183         String errorMessage = toWebCoreString(message->Get());
    184         String sourceURL = toWebCoreString(message->GetScriptResourceName());
    185         RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, sourceURL, message->GetLineNumber(), message->GetStartColumn());
    186         v8::Local<v8::Value> wrappedEvent = toV8(event.get(), v8::Handle<v8::Object>(), v8::Isolate::GetCurrent());
    187         if (!wrappedEvent.IsEmpty()) {
    188             ASSERT(wrappedEvent->IsObject());
    189             v8::Local<v8::Object>::Cast(wrappedEvent)->SetHiddenValue(V8HiddenPropertyName::error(), data);
    190         }
    191         AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin;
    192         context->reportException(event.release(), 0, corsStatus);
    193     }
    194 
    195     isReportingException = false;
    196 }
    197 
    198 static const int kWorkerMaxStackSize = 500 * 1024;
    199 
    200 void V8Initializer::initializeWorker(v8::Isolate* isolate)
    201 {
    202     initializeV8Common();
    203 
    204     v8::V8::AddMessageListener(messageHandlerInWorker);
    205     v8::V8::SetFatalErrorHandler(reportFatalErrorInWorker);
    206 
    207     v8::ResourceConstraints resourceConstraints;
    208     uint32_t here;
    209     resourceConstraints.set_stack_limit(&here - kWorkerMaxStackSize / sizeof(uint32_t*));
    210     v8::SetResourceConstraints(&resourceConstraints);
    211 
    212     V8PerIsolateData::ensureInitialized(isolate);
    213 }
    214 
    215 } // namespace WebCore
    216