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