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