Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2008, 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "V8Proxy.h"
     33 
     34 #include "CSSMutableStyleDeclaration.h"
     35 #include "CachedMetadata.h"
     36 #include "DateExtension.h"
     37 #include "DocumentLoader.h"
     38 #include "Frame.h"
     39 #include "FrameLoaderClient.h"
     40 #include "IDBDatabaseException.h"
     41 #include "IDBFactoryBackendInterface.h"
     42 #include "IDBPendingTransactionMonitor.h"
     43 #include "InspectorInstrumentation.h"
     44 #include "Page.h"
     45 #include "PageGroup.h"
     46 #include "PlatformBridge.h"
     47 #include "ScriptController.h"
     48 #include "Settings.h"
     49 #include "StorageNamespace.h"
     50 #include "V8Binding.h"
     51 #include "V8BindingState.h"
     52 #include "V8Collection.h"
     53 #include "V8DOMCoreException.h"
     54 #include "V8DOMMap.h"
     55 #include "V8DOMWindow.h"
     56 #include "V8EventException.h"
     57 #include "V8FileException.h"
     58 #include "V8HiddenPropertyName.h"
     59 #include "V8IsolatedContext.h"
     60 #include "V8RangeException.h"
     61 #include "V8SQLException.h"
     62 #include "V8XMLHttpRequestException.h"
     63 #include "V8XPathException.h"
     64 #include "WorkerContext.h"
     65 #include "WorkerContextExecutionProxy.h"
     66 
     67 #if ENABLE(INDEXED_DATABASE)
     68 #include "V8IDBDatabaseException.h"
     69 #endif
     70 
     71 #if ENABLE(SVG)
     72 #include "V8SVGException.h"
     73 #endif
     74 
     75 #include <algorithm>
     76 #include <stdio.h>
     77 #include <utility>
     78 #include <wtf/Assertions.h>
     79 #include <wtf/OwnArrayPtr.h>
     80 #include <wtf/OwnPtr.h>
     81 #include <wtf/StdLibExtras.h>
     82 #include <wtf/StringExtras.h>
     83 #include <wtf/UnusedParam.h>
     84 #include <wtf/text/StringConcatenate.h>
     85 
     86 #ifdef ANDROID_INSTRUMENT
     87 #include "TimeCounter.h"
     88 #endif
     89 
     90 #if PLATFORM(ANDROID)
     91 #include <wtf/text/CString.h>
     92 #endif
     93 
     94 namespace WebCore {
     95 
     96 // Static list of registered extensions
     97 V8Extensions V8Proxy::m_extensions;
     98 
     99 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance,
    100                               v8::Handle<v8::ObjectTemplate> proto,
    101                               const BatchedAttribute* attributes,
    102                               size_t attributeCount)
    103 {
    104     for (size_t i = 0; i < attributeCount; ++i)
    105         configureAttribute(instance, proto, attributes[i]);
    106 }
    107 
    108 void batchConfigureCallbacks(v8::Handle<v8::ObjectTemplate> proto,
    109                              v8::Handle<v8::Signature> signature,
    110                              v8::PropertyAttribute attributes,
    111                              const BatchedCallback* callbacks,
    112                              size_t callbackCount)
    113 {
    114     for (size_t i = 0; i < callbackCount; ++i) {
    115         proto->Set(v8::String::New(callbacks[i].name),
    116                    v8::FunctionTemplate::New(callbacks[i].callback,
    117                                              v8::Handle<v8::Value>(),
    118                                              signature),
    119                    attributes);
    120     }
    121 }
    122 
    123 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor,
    124                              v8::Handle<v8::ObjectTemplate> proto,
    125                              const BatchedConstant* constants,
    126                              size_t constantCount)
    127 {
    128     for (size_t i = 0; i < constantCount; ++i) {
    129         const BatchedConstant* constant = &constants[i];
    130         functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
    131         proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
    132     }
    133 }
    134 
    135 typedef HashMap<Node*, v8::Object*> DOMNodeMap;
    136 typedef HashMap<void*, v8::Object*> DOMObjectMap;
    137 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
    138 
    139 bool AllowAllocation::m_current = false;
    140 
    141 static void addMessageToConsole(Page* page, const String& message, const String& sourceID, unsigned lineNumber)
    142 {
    143     ASSERT(page);
    144     Console* console = page->mainFrame()->domWindow()->console();
    145     console->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, lineNumber, sourceID);
    146 }
    147 
    148 void logInfo(Frame* frame, const String& message, const String& url)
    149 {
    150     Page* page = frame->page();
    151     if (!page)
    152         return;
    153     addMessageToConsole(page, message, url, 0);
    154 }
    155 
    156 void V8Proxy::reportUnsafeAccessTo(Frame* target)
    157 {
    158     ASSERT(target);
    159     Document* targetDocument = target->document();
    160     if (!targetDocument)
    161         return;
    162 
    163     Frame* source = V8Proxy::retrieveFrameForEnteredContext();
    164     if (!source)
    165         return;
    166     Page* page = source->page();
    167     if (!page)
    168         return;
    169 
    170     Document* sourceDocument = source->document();
    171     if (!sourceDocument)
    172         return; // Ignore error if the source document is gone.
    173 
    174     // FIXME: This error message should contain more specifics of why the same
    175     // origin check has failed.
    176     String str = makeString("Unsafe JavaScript attempt to access frame with URL ", targetDocument->url().string(),
    177                             " from frame with URL ", sourceDocument->url().string(), ". Domains, protocols and ports must match.\n");
    178 
    179     // Build a console message with fake source ID and line number.
    180     const String kSourceID = "";
    181     const int kLineNumber = 1;
    182 
    183     // NOTE: Safari prints the message in the target page, but it seems like
    184     // it should be in the source page. Even for delayed messages, we put it in
    185     // the source page.
    186     addMessageToConsole(page, str, kSourceID, kLineNumber);
    187 }
    188 
    189 static void handleFatalErrorInV8()
    190 {
    191     // FIXME: We temporarily deal with V8 internal error situations
    192     // such as out-of-memory by crashing the renderer.
    193     CRASH();
    194 }
    195 
    196 V8Proxy::V8Proxy(Frame* frame)
    197     : m_frame(frame)
    198     , m_windowShell(V8DOMWindowShell::create(frame))
    199     , m_inlineCode(false)
    200     , m_timerCallback(false)
    201     , m_recursion(0)
    202 {
    203 }
    204 
    205 V8Proxy::~V8Proxy()
    206 {
    207     clearForClose();
    208     windowShell()->destroyGlobal();
    209 }
    210 
    211 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition0& scriptStartPosition, v8::ScriptData* scriptData)
    212 #ifdef ANDROID_INSTRUMENT
    213 {
    214     android::TimeCounter::start(android::TimeCounter::JavaScriptParseTimeCounter);
    215     v8::Handle<v8::Script> script = compileScriptInternal(code, fileName, scriptStartPosition, scriptData);
    216     android::TimeCounter::record(android::TimeCounter::JavaScriptParseTimeCounter, __FUNCTION__);
    217     return script;
    218 }
    219 
    220 v8::Handle<v8::Script> V8Proxy::compileScriptInternal(v8::Handle<v8::String> code, const String& fileName, const TextPosition0& scriptStartPosition, v8::ScriptData* scriptData)
    221 #endif
    222 {
    223     const uint16_t* fileNameString = fromWebCoreString(fileName);
    224     v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length());
    225     v8::Handle<v8::Integer> line = v8::Integer::New(scriptStartPosition.m_line.zeroBasedInt());
    226     v8::Handle<v8::Integer> column = v8::Integer::New(scriptStartPosition.m_column.zeroBasedInt());
    227     v8::ScriptOrigin origin(name, line, column);
    228     v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin, scriptData);
    229     return script;
    230 }
    231 
    232 bool V8Proxy::handleOutOfMemory()
    233 {
    234     v8::Local<v8::Context> context = v8::Context::GetCurrent();
    235 
    236     if (!context->HasOutOfMemoryException())
    237         return false;
    238 
    239     // Warning, error, disable JS for this frame?
    240     Frame* frame = V8Proxy::retrieveFrame(context);
    241 
    242     V8Proxy* proxy = V8Proxy::retrieve(frame);
    243     if (proxy) {
    244         // Clean m_context, and event handlers.
    245         proxy->clearForClose();
    246 
    247         proxy->windowShell()->destroyGlobal();
    248     }
    249 
    250 #if PLATFORM(CHROMIUM)
    251     PlatformBridge::notifyJSOutOfMemory(frame);
    252 #endif
    253 
    254     // Disable JS.
    255     Settings* settings = frame->settings();
    256     ASSERT(settings);
    257     settings->setJavaScriptEnabled(false);
    258 
    259     return true;
    260 }
    261 
    262 void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup)
    263 {
    264     // FIXME: This will need to get reorganized once we have a windowShell for the isolated world.
    265     windowShell()->initContextIfNeeded();
    266 
    267     v8::HandleScope handleScope;
    268     V8IsolatedContext* isolatedContext = 0;
    269 
    270     if (worldID > 0) {
    271         IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
    272         if (iter != m_isolatedWorlds.end()) {
    273             isolatedContext = iter->second;
    274         } else {
    275             isolatedContext = new V8IsolatedContext(this, extensionGroup);
    276             if (isolatedContext->context().IsEmpty()) {
    277                 delete isolatedContext;
    278                 return;
    279             }
    280 
    281             // FIXME: We should change this to using window shells to match JSC.
    282             m_isolatedWorlds.set(worldID, isolatedContext);
    283 
    284             // Setup context id for JS debugger.
    285             if (!setInjectedScriptContextDebugId(isolatedContext->context())) {
    286                 m_isolatedWorlds.take(worldID);
    287                 delete isolatedContext;
    288                 return;
    289             }
    290         }
    291     } else {
    292         isolatedContext = new V8IsolatedContext(this, extensionGroup);
    293         if (isolatedContext->context().IsEmpty()) {
    294             delete isolatedContext;
    295             return;
    296         }
    297     }
    298 
    299     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolatedContext->context());
    300     v8::Context::Scope context_scope(context);
    301     for (size_t i = 0; i < sources.size(); ++i)
    302       evaluate(sources[i], 0);
    303 
    304     if (worldID == 0)
    305       isolatedContext->destroy();
    306 }
    307 
    308 bool V8Proxy::setInjectedScriptContextDebugId(v8::Handle<v8::Context> targetContext)
    309 {
    310     // Setup context id for JS debugger.
    311     v8::Context::Scope contextScope(targetContext);
    312     v8::Handle<v8::Context> context = windowShell()->context();
    313     if (context.IsEmpty())
    314         return false;
    315     int debugId = contextDebugId(context);
    316 
    317     char buffer[32];
    318     if (debugId == -1)
    319         snprintf(buffer, sizeof(buffer), "injected");
    320     else
    321         snprintf(buffer, sizeof(buffer), "injected,%d", debugId);
    322     targetContext->SetData(v8::String::New(buffer));
    323 
    324     return true;
    325 }
    326 
    327 PassOwnPtr<v8::ScriptData> V8Proxy::precompileScript(v8::Handle<v8::String> code, CachedScript* cachedScript)
    328 {
    329     // A pseudo-randomly chosen ID used to store and retrieve V8 ScriptData from
    330     // the CachedScript. If the format changes, this ID should be changed too.
    331     static const unsigned dataTypeID = 0xECC13BD7;
    332 
    333     // Very small scripts are not worth the effort to preparse.
    334     static const int minPreparseLength = 1024;
    335 
    336     if (!cachedScript || code->Length() < minPreparseLength)
    337         return 0;
    338 
    339     CachedMetadata* cachedMetadata = cachedScript->cachedMetadata(dataTypeID);
    340     if (cachedMetadata)
    341         return v8::ScriptData::New(cachedMetadata->data(), cachedMetadata->size());
    342 
    343     OwnPtr<v8::ScriptData> scriptData(v8::ScriptData::PreCompile(code));
    344     cachedScript->setCachedMetadata(dataTypeID, scriptData->Data(), scriptData->Length());
    345 
    346     return scriptData.release();
    347 }
    348 
    349 bool V8Proxy::executingScript() const
    350 {
    351     return m_recursion;
    352 }
    353 
    354 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node)
    355 {
    356     ASSERT(v8::Context::InContext());
    357 
    358     V8GCController::checkMemoryUsage();
    359 
    360     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, source.url().isNull() ? String() : source.url().string(), source.startLine());
    361 
    362     v8::Local<v8::Value> result;
    363     {
    364         // Isolate exceptions that occur when compiling and executing
    365         // the code. These exceptions should not interfere with
    366         // javascript code we might evaluate from C++ when returning
    367         // from here.
    368         v8::TryCatch tryCatch;
    369         tryCatch.SetVerbose(true);
    370 
    371         // Compile the script.
    372         v8::Local<v8::String> code = v8ExternalString(source.source());
    373 #if PLATFORM(CHROMIUM)
    374         PlatformBridge::traceEventBegin("v8.compile", node, "");
    375 #endif
    376         OwnPtr<v8::ScriptData> scriptData = precompileScript(code, source.cachedScript());
    377 
    378         // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
    379         // 1, whereas v8 starts at 0.
    380         v8::Handle<v8::Script> script = compileScript(code, source.url(), WTF::toZeroBasedTextPosition(source.startPosition()), scriptData.get());
    381 #if PLATFORM(CHROMIUM)
    382         PlatformBridge::traceEventEnd("v8.compile", node, "");
    383 
    384         PlatformBridge::traceEventBegin("v8.run", node, "");
    385 #endif
    386         // Set inlineCode to true for <a href="javascript:doSomething()">
    387         // and false for <script>doSomething</script>. We make a rough guess at
    388         // this based on whether the script source has a URL.
    389         result = runScript(script, source.url().string().isNull());
    390     }
    391 #if PLATFORM(CHROMIUM)
    392     PlatformBridge::traceEventEnd("v8.run", node, "");
    393 #endif
    394 
    395     InspectorInstrumentation::didEvaluateScript(cookie);
    396 
    397     return result;
    398 }
    399 
    400 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode)
    401 #ifdef ANDROID_INSTRUMENT
    402 {
    403     android::TimeCounter::start(android::TimeCounter::JavaScriptExecuteTimeCounter);
    404     v8::Local<v8::Value> result = runScriptInternal(script, isInlineCode);
    405     android::TimeCounter::record(android::TimeCounter::JavaScriptExecuteTimeCounter, __FUNCTION__);
    406     return result;
    407 }
    408 
    409 v8::Local<v8::Value> V8Proxy::runScriptInternal(v8::Handle<v8::Script> script, bool isInlineCode)
    410 #endif
    411 {
    412     if (script.IsEmpty())
    413         return notHandledByInterceptor();
    414 
    415     V8GCController::checkMemoryUsage();
    416     // Compute the source string and prevent against infinite recursion.
    417     if (m_recursion >= kMaxRecursionDepth) {
    418         v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')");
    419         // FIXME: Ideally, we should be able to re-use the origin of the
    420         // script passed to us as the argument instead of using an empty string
    421         // and 0 baseLine.
    422         script = compileScript(code, "", TextPosition0::minimumPosition());
    423     }
    424 
    425     if (handleOutOfMemory())
    426         ASSERT(script.IsEmpty());
    427 
    428     if (script.IsEmpty())
    429         return notHandledByInterceptor();
    430 
    431     // Save the previous value of the inlineCode flag and update the flag for
    432     // the duration of the script invocation.
    433     bool previousInlineCode = inlineCode();
    434     setInlineCode(isInlineCode);
    435 
    436     // Run the script and keep track of the current recursion depth.
    437     v8::Local<v8::Value> result;
    438     v8::TryCatch tryCatch;
    439     tryCatch.SetVerbose(true);
    440     {
    441         // See comment in V8Proxy::callFunction.
    442         m_frame->keepAlive();
    443 
    444         m_recursion++;
    445         result = script->Run();
    446         m_recursion--;
    447     }
    448 
    449     // Release the storage mutex if applicable.
    450     didLeaveScriptContext();
    451 
    452     if (handleOutOfMemory())
    453         ASSERT(result.IsEmpty());
    454 
    455     // Handle V8 internal error situation (Out-of-memory).
    456     if (tryCatch.HasCaught()) {
    457         ASSERT(result.IsEmpty());
    458         return notHandledByInterceptor();
    459     }
    460 
    461     if (result.IsEmpty())
    462         return notHandledByInterceptor();
    463 
    464     // Restore inlineCode flag.
    465     setInlineCode(previousInlineCode);
    466 
    467     if (v8::V8::IsDead())
    468         handleFatalErrorInV8();
    469 
    470     return result;
    471 }
    472 
    473 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
    474 {
    475 #ifdef ANDROID_INSTRUMENT
    476     android::TimeCounter::start(android::TimeCounter::JavaScriptExecuteTimeCounter);
    477 #endif
    478     V8GCController::checkMemoryUsage();
    479     v8::Local<v8::Value> result;
    480     {
    481         if (m_recursion >= kMaxRecursionDepth) {
    482             v8::Local<v8::String> code = v8::String::New("throw new RangeError('Maximum call stack size exceeded.')");
    483             if (code.IsEmpty())
    484                 return result;
    485             v8::Local<v8::Script> script = v8::Script::Compile(code);
    486             if (script.IsEmpty())
    487                 return result;
    488             script->Run();
    489             return result;
    490         }
    491 
    492         // Evaluating the JavaScript could cause the frame to be deallocated,
    493         // so we start the keep alive timer here.
    494         // Frame::keepAlive method adds the ref count of the frame and sets a
    495         // timer to decrease the ref count. It assumes that the current JavaScript
    496         // execution finishs before firing the timer.
    497         m_frame->keepAlive();
    498 
    499         InspectorInstrumentationCookie cookie;
    500         if (InspectorInstrumentation::hasFrontends()) {
    501             v8::ScriptOrigin origin = function->GetScriptOrigin();
    502             String resourceName("undefined");
    503             int lineNumber = 1;
    504             if (!origin.ResourceName().IsEmpty()) {
    505                 resourceName = toWebCoreString(origin.ResourceName());
    506                 lineNumber = function->GetScriptLineNumber() + 1;
    507             }
    508             cookie = InspectorInstrumentation::willCallFunction(m_frame, resourceName, lineNumber);
    509         }
    510 
    511         m_recursion++;
    512         result = function->Call(receiver, argc, args);
    513         m_recursion--;
    514 
    515         InspectorInstrumentation::didCallFunction(cookie);
    516     }
    517 
    518     // Release the storage mutex if applicable.
    519     didLeaveScriptContext();
    520 
    521     if (v8::V8::IsDead())
    522         handleFatalErrorInV8();
    523 
    524 #ifdef ANDROID_INSTRUMENT
    525     android::TimeCounter::record(android::TimeCounter::JavaScriptExecuteTimeCounter, __FUNCTION__);
    526 #endif
    527     return result;
    528 }
    529 
    530 v8::Local<v8::Value> V8Proxy::callFunctionWithoutFrame(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
    531 {
    532     V8GCController::checkMemoryUsage();
    533     v8::Local<v8::Value> result = function->Call(receiver, argc, args);
    534 
    535     if (v8::V8::IsDead())
    536         handleFatalErrorInV8();
    537 
    538     return result;
    539 }
    540 
    541 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
    542 {
    543     // No artificial limitations on the depth of recursion, see comment in
    544     // V8Proxy::callFunction.
    545     v8::Local<v8::Value> result;
    546     {
    547         // See comment in V8Proxy::callFunction.
    548         m_frame->keepAlive();
    549 
    550         result = constructor->NewInstance(argc, args);
    551     }
    552 
    553     if (v8::V8::IsDead())
    554         handleFatalErrorInV8();
    555 
    556     return result;
    557 }
    558 
    559 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
    560 {
    561     v8::Handle<v8::Object> global = context->Global();
    562     ASSERT(!global.IsEmpty());
    563     global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global);
    564     ASSERT(!global.IsEmpty());
    565     return V8DOMWindow::toNative(global);
    566 }
    567 
    568 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
    569 {
    570     DOMWindow* window = retrieveWindow(context);
    571     Frame* frame = window->frame();
    572     if (frame && frame->domWindow() == window)
    573         return frame;
    574     // We return 0 here because |context| is detached from the Frame.  If we
    575     // did return |frame| we could get in trouble because the frame could be
    576     // navigated to another security origin.
    577     return 0;
    578 }
    579 
    580 Frame* V8Proxy::retrieveFrameForEnteredContext()
    581 {
    582     v8::Handle<v8::Context> context = v8::Context::GetEntered();
    583     if (context.IsEmpty())
    584         return 0;
    585     return retrieveFrame(context);
    586 }
    587 
    588 Frame* V8Proxy::retrieveFrameForCurrentContext()
    589 {
    590     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
    591     if (context.IsEmpty())
    592         return 0;
    593     return retrieveFrame(context);
    594 }
    595 
    596 Frame* V8Proxy::retrieveFrameForCallingContext()
    597 {
    598     v8::Handle<v8::Context> context = v8::Context::GetCalling();
    599     if (context.IsEmpty())
    600         return 0;
    601     return retrieveFrame(context);
    602 }
    603 
    604 V8Proxy* V8Proxy::retrieve()
    605 {
    606     DOMWindow* window = retrieveWindow(currentContext());
    607     ASSERT(window);
    608     return retrieve(window->frame());
    609 }
    610 
    611 V8Proxy* V8Proxy::retrieve(Frame* frame)
    612 {
    613     if (!frame)
    614         return 0;
    615     return frame->script()->canExecuteScripts(NotAboutToExecuteScript) ? frame->script()->proxy() : 0;
    616 }
    617 
    618 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
    619 {
    620     if (!context || !context->isDocument())
    621         return 0;
    622     return retrieve(static_cast<Document*>(context)->frame());
    623 }
    624 
    625 void V8Proxy::disconnectFrame()
    626 {
    627 }
    628 
    629 void V8Proxy::didLeaveScriptContext()
    630 {
    631     Page* page = m_frame->page();
    632     if (!page)
    633         return;
    634 #if ENABLE(INDEXED_DATABASE)
    635     // If we've just left a script context and indexed database has been
    636     // instantiated, we must let its transaction coordinator know so it can terminate
    637     // any not-yet-started transactions.
    638     IDBPendingTransactionMonitor::abortPendingTransactions();
    639 #endif // ENABLE(INDEXED_DATABASE)
    640     // If we've just left a top level script context and local storage has been
    641     // instantiated, we must ensure that any storage locks have been freed.
    642     // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex
    643     if (m_recursion != 0)
    644         return;
    645     if (page->group().hasLocalStorage())
    646         page->group().localStorage()->unlock();
    647 }
    648 
    649 void V8Proxy::resetIsolatedWorlds()
    650 {
    651     for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin();
    652          iter != m_isolatedWorlds.end(); ++iter) {
    653         iter->second->destroy();
    654     }
    655     m_isolatedWorlds.clear();
    656 }
    657 
    658 void V8Proxy::clearForClose()
    659 {
    660     resetIsolatedWorlds();
    661     windowShell()->clearForClose();
    662 }
    663 
    664 void V8Proxy::clearForNavigation()
    665 {
    666     resetIsolatedWorlds();
    667     windowShell()->clearForNavigation();
    668 }
    669 
    670 void V8Proxy::setDOMException(int exceptionCode)
    671 {
    672     if (exceptionCode <= 0)
    673         return;
    674 
    675     ExceptionCodeDescription description;
    676     getExceptionCodeDescription(exceptionCode, description);
    677 
    678     v8::Handle<v8::Value> exception;
    679     switch (description.type) {
    680     case DOMExceptionType:
    681         exception = toV8(DOMCoreException::create(description));
    682         break;
    683     case RangeExceptionType:
    684         exception = toV8(RangeException::create(description));
    685         break;
    686     case EventExceptionType:
    687         exception = toV8(EventException::create(description));
    688         break;
    689     case XMLHttpRequestExceptionType:
    690         exception = toV8(XMLHttpRequestException::create(description));
    691         break;
    692 #if ENABLE(SVG)
    693     case SVGExceptionType:
    694         exception = toV8(SVGException::create(description));
    695         break;
    696 #endif
    697 #if ENABLE(XPATH)
    698     case XPathExceptionType:
    699         exception = toV8(XPathException::create(description));
    700         break;
    701 #endif
    702 #if ENABLE(DATABASE)
    703     case SQLExceptionType:
    704         exception = toV8(SQLException::create(description));
    705         break;
    706 #endif
    707 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
    708     case FileExceptionType:
    709         exception = toV8(FileException::create(description));
    710         break;
    711 #endif
    712 #if ENABLE(INDEXED_DATABASE)
    713     case IDBDatabaseExceptionType:
    714         exception = toV8(IDBDatabaseException::create(description));
    715         break;
    716 #endif
    717     default:
    718         ASSERT_NOT_REACHED();
    719     }
    720 
    721     if (!exception.IsEmpty())
    722         v8::ThrowException(exception);
    723 }
    724 
    725 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message)
    726 {
    727     switch (type) {
    728     case RangeError:
    729         return v8::ThrowException(v8::Exception::RangeError(v8String(message)));
    730     case ReferenceError:
    731         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message)));
    732     case SyntaxError:
    733         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message)));
    734     case TypeError:
    735         return v8::ThrowException(v8::Exception::TypeError(v8String(message)));
    736     case GeneralError:
    737         return v8::ThrowException(v8::Exception::Error(v8String(message)));
    738     default:
    739         ASSERT_NOT_REACHED();
    740         return notHandledByInterceptor();
    741     }
    742 }
    743 
    744 v8::Handle<v8::Value> V8Proxy::throwTypeError()
    745 {
    746     return throwError(TypeError, "Type error");
    747 }
    748 
    749 v8::Handle<v8::Value> V8Proxy::throwSyntaxError()
    750 {
    751     return throwError(SyntaxError, "Syntax error");
    752 }
    753 
    754 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
    755 {
    756     v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame);
    757     if (context.IsEmpty())
    758         return v8::Local<v8::Context>();
    759 
    760     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
    761         context = v8::Local<v8::Context>::New(isolatedContext->context());
    762         if (frame != V8Proxy::retrieveFrame(context))
    763             return v8::Local<v8::Context>();
    764     }
    765 
    766     return context;
    767 }
    768 
    769 v8::Local<v8::Context> V8Proxy::context()
    770 {
    771     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
    772         RefPtr<SharedPersistent<v8::Context> > context = isolatedContext->sharedContext();
    773         if (m_frame != V8Proxy::retrieveFrame(context->get()))
    774             return v8::Local<v8::Context>();
    775         return v8::Local<v8::Context>::New(context->get());
    776     }
    777     return mainWorldContext();
    778 }
    779 
    780 v8::Local<v8::Context> V8Proxy::mainWorldContext()
    781 {
    782     windowShell()->initContextIfNeeded();
    783     return v8::Local<v8::Context>::New(windowShell()->context());
    784 }
    785 
    786 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame)
    787 {
    788     V8Proxy* proxy = retrieve(frame);
    789     if (!proxy)
    790         return v8::Local<v8::Context>();
    791 
    792     return proxy->mainWorldContext();
    793 }
    794 
    795 v8::Local<v8::Context> V8Proxy::currentContext()
    796 {
    797     return v8::Context::GetCurrent();
    798 }
    799 
    800 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
    801 {
    802     if (!AllowAllocation::m_current)
    803         return throwError(TypeError, "Illegal constructor");
    804 
    805     return args.This();
    806 }
    807 
    808 void V8Proxy::registerExtensionWithV8(v8::Extension* extension)
    809 {
    810     // If the extension exists in our list, it was already registered with V8.
    811     if (!registeredExtensionWithV8(extension))
    812         v8::RegisterExtension(extension);
    813 }
    814 
    815 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension)
    816 {
    817     for (size_t i = 0; i < m_extensions.size(); ++i) {
    818         if (m_extensions[i] == extension)
    819             return true;
    820     }
    821 
    822     return false;
    823 }
    824 
    825 void V8Proxy::registerExtension(v8::Extension* extension)
    826 {
    827     registerExtensionWithV8(extension);
    828     m_extensions.append(extension);
    829 }
    830 
    831 bool V8Proxy::setContextDebugId(int debugId)
    832 {
    833     ASSERT(debugId > 0);
    834     v8::HandleScope scope;
    835     v8::Handle<v8::Context> context = windowShell()->context();
    836     if (context.IsEmpty())
    837         return false;
    838     if (!context->GetData()->IsUndefined())
    839         return false;
    840 
    841     v8::Context::Scope contextScope(context);
    842 
    843     char buffer[32];
    844     snprintf(buffer, sizeof(buffer), "page,%d", debugId);
    845     context->SetData(v8::String::New(buffer));
    846 
    847     return true;
    848 }
    849 
    850 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
    851 {
    852     v8::HandleScope scope;
    853     if (!context->GetData()->IsString())
    854         return -1;
    855     v8::String::AsciiValue ascii(context->GetData());
    856     char* comma = strnstr(*ascii, ",", ascii.length());
    857     if (!comma)
    858         return -1;
    859     return atoi(comma + 1);
    860 }
    861 
    862 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, const WorldContextHandle& worldContext)
    863 {
    864     if (context->isDocument()) {
    865         if (V8Proxy* proxy = V8Proxy::retrieve(context))
    866             return worldContext.adjustedContext(proxy);
    867 #if ENABLE(WORKERS)
    868     } else if (context->isWorkerContext()) {
    869         if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy())
    870             return proxy->context();
    871 #endif
    872     }
    873     return v8::Local<v8::Context>();
    874 }
    875 
    876 }  // namespace WebCore
    877