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