696128429bac636250767ad9743bc1e663488d8f
[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 "CachedMetadata.h"
35 #include "DateExtension.h"
36 #include "Document.h"
37 #include "DocumentLoader.h"
38 #include "ExceptionHeaders.h"
39 #include "ExceptionInterfaces.h"
40 #include "Frame.h"
41 #include "FrameLoaderClient.h"
42 #include "IDBFactoryBackendInterface.h"
43 #include "InspectorInstrumentation.h"
44 #include "PlatformSupport.h"
45 #include "ScriptCallStack.h"
46 #include "ScriptCallStackFactory.h"
47 #include "ScriptSourceCode.h"
48 #include "SecurityOrigin.h"
49 #include "Settings.h"
50 #include "StylePropertySet.h"
51 #include "V8Binding.h"
52 #include "V8BindingState.h"
53 #include "V8Collection.h"
54 #include "V8DOMCoreException.h"
55 #include "V8DOMMap.h"
56 #include "V8DOMWindow.h"
57 #include "V8HiddenPropertyName.h"
58 #include "V8IsolatedContext.h"
59 #include "V8RecursionScope.h"
60 #include "WorkerContext.h"
61 #include "WorkerContextExecutionProxy.h"
62
63 #include <algorithm>
64 #include <stdio.h>
65 #include <utility>
66 #include <wtf/Assertions.h>
67 #include <wtf/OwnArrayPtr.h>
68 #include <wtf/OwnPtr.h>
69 #include <wtf/StdLibExtras.h>
70 #include <wtf/StringExtras.h>
71 #include <wtf/UnusedParam.h>
72 #include <wtf/text/WTFString.h>
73
74 #if PLATFORM(CHROMIUM)
75 #include "TraceEvent.h"
76 #endif
77
78 namespace WebCore {
79
80 static V8Extensions& staticExtensionsList()
81 {
82     DEFINE_STATIC_LOCAL(V8Extensions, extensions, ());
83     return extensions;
84 }
85
86 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance, 
87                               v8::Handle<v8::ObjectTemplate> proto, 
88                               const BatchedAttribute* attributes, 
89                               size_t attributeCount)
90 {
91     for (size_t i = 0; i < attributeCount; ++i)
92         configureAttribute(instance, proto, attributes[i]);
93 }
94
95 void batchConfigureCallbacks(v8::Handle<v8::ObjectTemplate> proto, 
96                              v8::Handle<v8::Signature> signature, 
97                              v8::PropertyAttribute attributes,
98                              const BatchedCallback* callbacks,
99                              size_t callbackCount)
100 {
101     for (size_t i = 0; i < callbackCount; ++i) {
102         proto->Set(v8::String::New(callbacks[i].name),
103                    v8::FunctionTemplate::New(callbacks[i].callback, 
104                                              v8::Handle<v8::Value>(),
105                                              signature),
106                    attributes);
107     }
108 }
109
110 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor,
111                              v8::Handle<v8::ObjectTemplate> proto,
112                              const BatchedConstant* constants,
113                              size_t constantCount)
114 {
115     for (size_t i = 0; i < constantCount; ++i) {
116         const BatchedConstant* constant = &constants[i];
117         functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
118         proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
119     }
120 }
121
122 typedef HashMap<Node*, v8::Object*> DOMNodeMap;
123 typedef HashMap<void*, v8::Object*> DOMObjectMap;
124 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
125
126 void V8Proxy::reportUnsafeAccessTo(Frame* target)
127 {
128     ASSERT(target);
129     Document* targetDocument = target->document();
130     if (!targetDocument)
131         return;
132
133     Frame* source = V8Proxy::retrieveFrameForEnteredContext();
134     if (!source)
135         return;
136
137     Document* sourceDocument = source->document();
138     if (!sourceDocument)
139         return; // Ignore error if the source document is gone.
140
141     // FIXME: This error message should contain more specifics of why the same
142     // origin check has failed.
143     String str = "Unsafe JavaScript attempt to access frame with URL " + targetDocument->url().string() +
144                  " from frame with URL " + sourceDocument->url().string() + ". Domains, protocols and ports must match.\n";
145
146     RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
147
148     // NOTE: Safari prints the message in the target page, but it seems like
149     // it should be in the source page. Even for delayed messages, we put it in
150     // the source page.
151     sourceDocument->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, str, stackTrace.release());
152 }
153
154 static void handleFatalErrorInV8()
155 {
156     // FIXME: We temporarily deal with V8 internal error situations
157     // such as out-of-memory by crashing the renderer.
158     CRASH();
159 }
160
161 static v8::Local<v8::Value> handleMaxRecursionDepthExceeded()
162 {
163     throwError("Maximum call stack size exceeded.", V8Proxy::RangeError);
164     return v8::Local<v8::Value>();
165 }
166
167 V8Proxy::V8Proxy(Frame* frame)
168     : m_frame(frame)
169     , m_windowShell(V8DOMWindowShell::create(frame))
170 {
171 }
172
173 V8Proxy::~V8Proxy()
174 {
175     clearForClose();
176     windowShell()->destroyGlobal();
177 }
178
179 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition& scriptStartPosition, v8::ScriptData* scriptData)
180 {
181     const uint16_t* fileNameString = fromWebCoreString(fileName);
182     v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length());
183     v8::Handle<v8::Integer> line = v8::Integer::New(scriptStartPosition.m_line.zeroBasedInt());
184     v8::Handle<v8::Integer> column = v8::Integer::New(scriptStartPosition.m_column.zeroBasedInt());
185     v8::ScriptOrigin origin(name, line, column);
186     v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin, scriptData);
187     return script;
188 }
189
190 bool V8Proxy::handleOutOfMemory()
191 {
192     v8::Local<v8::Context> context = v8::Context::GetCurrent();
193
194     if (!context->HasOutOfMemoryException())
195         return false;
196
197     // Warning, error, disable JS for this frame?
198     Frame* frame = V8Proxy::retrieveFrame(context);
199
200     V8Proxy* proxy = V8Proxy::retrieve(frame);
201     if (proxy) {
202         // Clean m_context, and event handlers.
203         proxy->clearForClose();
204
205         proxy->windowShell()->destroyGlobal();
206     }
207
208 #if PLATFORM(CHROMIUM)
209     PlatformSupport::notifyJSOutOfMemory(frame);
210 #endif
211
212     // Disable JS.
213     Settings* settings = frame->settings();
214     ASSERT(settings);
215     settings->setScriptEnabled(false);
216
217     return true;
218 }
219
220 void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup, WTF::Vector<v8::Local<v8::Value> >* results)
221 {
222     // FIXME: This will need to get reorganized once we have a windowShell for the isolated world.
223     if (!windowShell()->initContextIfNeeded())
224         return;
225
226     v8::HandleScope handleScope;
227     V8IsolatedContext* isolatedContext = 0;
228
229     if (worldID > 0) {
230         IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
231         if (iter != m_isolatedWorlds.end()) {
232             isolatedContext = iter->second;
233         } else {
234             isolatedContext = new V8IsolatedContext(this, extensionGroup, worldID);
235             if (isolatedContext->context().IsEmpty()) {
236                 delete isolatedContext;
237                 return;
238             }
239
240             // FIXME: We should change this to using window shells to match JSC.
241             m_isolatedWorlds.set(worldID, isolatedContext);
242         }
243
244         IsolatedWorldSecurityOriginMap::iterator securityOriginIter = m_isolatedWorldSecurityOrigins.find(worldID);
245         if (securityOriginIter != m_isolatedWorldSecurityOrigins.end())
246             isolatedContext->setSecurityOrigin(securityOriginIter->second);
247     } else {
248         isolatedContext = new V8IsolatedContext(this, extensionGroup, worldID);
249         if (isolatedContext->context().IsEmpty()) {
250             delete isolatedContext;
251             return;
252         }
253     }
254
255     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolatedContext->context());
256     v8::Context::Scope context_scope(context);
257
258     if (results) {
259         for (size_t i = 0; i < sources.size(); ++i)
260             results->append(evaluate(sources[i], 0));
261     } else {
262         for (size_t i = 0; i < sources.size(); ++i)
263             evaluate(sources[i], 0);
264     }
265
266     if (worldID == 0)
267         isolatedContext->destroy();
268 }
269
270 void V8Proxy::setIsolatedWorldSecurityOrigin(int worldID, PassRefPtr<SecurityOrigin> prpSecurityOriginIn)
271 {
272     ASSERT(worldID);
273     RefPtr<SecurityOrigin> securityOrigin = prpSecurityOriginIn;
274     m_isolatedWorldSecurityOrigins.set(worldID, securityOrigin);
275     IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
276     if (iter != m_isolatedWorlds.end())
277         iter->second->setSecurityOrigin(securityOrigin);
278 }
279
280 PassOwnPtr<v8::ScriptData> V8Proxy::precompileScript(v8::Handle<v8::String> code, CachedScript* cachedScript)
281 {
282     // A pseudo-randomly chosen ID used to store and retrieve V8 ScriptData from
283     // the CachedScript. If the format changes, this ID should be changed too.
284     static const unsigned dataTypeID = 0xECC13BD7;
285
286     // Very small scripts are not worth the effort to preparse.
287     static const int minPreparseLength = 1024;
288
289     if (!cachedScript || code->Length() < minPreparseLength)
290         return nullptr;
291
292     CachedMetadata* cachedMetadata = cachedScript->cachedMetadata(dataTypeID);
293     if (cachedMetadata)
294         return adoptPtr(v8::ScriptData::New(cachedMetadata->data(), cachedMetadata->size()));
295
296     OwnPtr<v8::ScriptData> scriptData = adoptPtr(v8::ScriptData::PreCompile(code));
297     cachedScript->setCachedMetadata(dataTypeID, scriptData->Data(), scriptData->Length());
298
299     return scriptData.release();
300 }
301
302 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node)
303 {
304     ASSERT(v8::Context::InContext());
305
306     V8GCController::checkMemoryUsage();
307
308     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, source.url().isNull() ? String() : source.url().string(), source.startLine());
309
310     v8::Local<v8::Value> result;
311     {
312         // Isolate exceptions that occur when compiling and executing
313         // the code. These exceptions should not interfere with
314         // javascript code we might evaluate from C++ when returning
315         // from here.
316         v8::TryCatch tryCatch;
317         tryCatch.SetVerbose(true);
318
319         // Compile the script.
320         v8::Local<v8::String> code = v8ExternalString(source.source());
321 #if PLATFORM(CHROMIUM)
322         TRACE_EVENT_BEGIN0("v8", "v8.compile");
323 #endif
324         OwnPtr<v8::ScriptData> scriptData = precompileScript(code, source.cachedScript());
325
326         // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
327         // 1, whereas v8 starts at 0.
328         v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startPosition(), scriptData.get());
329 #if PLATFORM(CHROMIUM)
330         TRACE_EVENT_END0("v8", "v8.compile");
331         TRACE_EVENT0("v8", "v8.run");
332 #endif
333         result = runScript(script);
334     }
335
336     InspectorInstrumentation::didEvaluateScript(cookie);
337
338     return result;
339 }
340
341 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script)
342 {
343     if (script.IsEmpty())
344         return notHandledByInterceptor();
345
346     V8GCController::checkMemoryUsage();
347     if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
348         return handleMaxRecursionDepthExceeded();
349
350     if (handleOutOfMemory())
351         ASSERT(script.IsEmpty());
352
353     // Keep Frame (and therefore ScriptController and V8Proxy) alive.
354     RefPtr<Frame> protect(frame());
355
356     // Run the script and keep track of the current recursion depth.
357     v8::Local<v8::Value> result;
358     v8::TryCatch tryCatch;
359     tryCatch.SetVerbose(true);
360     {
361         V8RecursionScope recursionScope(frame()->document());
362         result = script->Run();
363     }
364
365     if (handleOutOfMemory())
366         ASSERT(result.IsEmpty());
367
368     // Handle V8 internal error situation (Out-of-memory).
369     if (tryCatch.HasCaught()) {
370         ASSERT(result.IsEmpty());
371         return notHandledByInterceptor();
372     }
373
374     if (result.IsEmpty())
375         return notHandledByInterceptor();
376
377     if (v8::V8::IsDead())
378         handleFatalErrorInV8();
379
380     return result;
381 }
382
383 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
384 {
385     // Keep Frame (and therefore ScriptController and V8Proxy) alive.
386     RefPtr<Frame> protect(frame());
387     return V8Proxy::instrumentedCallFunction(frame(), function, receiver, argc, args);
388 }
389
390 v8::Local<v8::Value> V8Proxy::instrumentedCallFunction(Frame* frame, v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
391 {
392     V8GCController::checkMemoryUsage();
393
394     if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
395         return handleMaxRecursionDepthExceeded();
396
397     ScriptExecutionContext* context = frame ? frame->document() : 0;
398
399     InspectorInstrumentationCookie cookie;
400     if (InspectorInstrumentation::hasFrontends() && context) {
401         String resourceName("undefined");
402         int lineNumber = 1;
403         v8::ScriptOrigin origin = function->GetScriptOrigin();
404         if (!origin.ResourceName().IsEmpty()) {
405             resourceName = toWebCoreString(origin.ResourceName());
406             lineNumber = function->GetScriptLineNumber() + 1;
407         }
408         cookie = InspectorInstrumentation::willCallFunction(context, resourceName, lineNumber);
409     }
410
411     v8::Local<v8::Value> result;
412     {
413 #if PLATFORM(CHROMIUM)
414         TRACE_EVENT0("v8", "v8.callFunction");
415 #endif
416         V8RecursionScope recursionScope(context);
417         result = function->Call(receiver, argc, args);
418     }
419
420     InspectorInstrumentation::didCallFunction(cookie);
421
422     if (v8::V8::IsDead())
423         handleFatalErrorInV8();
424
425     return result;
426 }
427
428 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
429 {
430 #if PLATFORM(CHROMIUM)
431     TRACE_EVENT0("v8", "v8.newInstance");
432 #endif
433
434     // No artificial limitations on the depth of recursion, see comment in
435     // V8Proxy::callFunction.
436     v8::Local<v8::Value> result;
437     {
438         result = constructor->NewInstance(argc, args);
439     }
440
441     if (v8::V8::IsDead())
442         handleFatalErrorInV8();
443
444     return result;
445 }
446
447 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
448 {
449     v8::Handle<v8::Object> global = context->Global();
450     ASSERT(!global.IsEmpty());
451     global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global);
452     ASSERT(!global.IsEmpty());
453     return V8DOMWindow::toNative(global);
454 }
455
456 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
457 {
458     DOMWindow* window = retrieveWindow(context);
459     Frame* frame = window->frame();
460     if (frame && frame->domWindow() == window)
461         return frame;
462     // We return 0 here because |context| is detached from the Frame.  If we
463     // did return |frame| we could get in trouble because the frame could be
464     // navigated to another security origin.
465     return 0;
466 }
467
468 Frame* V8Proxy::retrieveFrameForEnteredContext()
469 {
470     v8::Handle<v8::Context> context = v8::Context::GetEntered();
471     if (context.IsEmpty())
472         return 0;
473     return retrieveFrame(context);
474 }
475
476 Frame* V8Proxy::retrieveFrameForCurrentContext()
477 {
478     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
479     if (context.IsEmpty())
480         return 0;
481     return retrieveFrame(context);
482 }
483
484 DOMWindow* V8Proxy::retrieveWindowForCallingContext()
485 {
486     v8::Handle<v8::Context> context = v8::Context::GetCalling();
487     if (context.IsEmpty())
488         return 0;
489     return retrieveWindow(context);
490 }
491
492 Frame* V8Proxy::retrieveFrameForCallingContext()
493 {
494     v8::Handle<v8::Context> context = v8::Context::GetCalling();
495     if (context.IsEmpty())
496         return 0;
497     return retrieveFrame(context);
498 }
499
500 V8Proxy* V8Proxy::retrieve()
501 {
502     DOMWindow* window = retrieveWindow(currentContext());
503     ASSERT(window);
504     return retrieve(window->frame());
505 }
506
507 V8Proxy* V8Proxy::retrieve(Frame* frame)
508 {
509     return frame ? frame->script()->proxy() : 0;
510 }
511
512 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
513 {
514     if (!context || !context->isDocument())
515         return 0;
516     return retrieve(static_cast<Document*>(context)->frame());
517 }
518
519 V8BindingPerContextData* V8Proxy::retrievePerContextData(Frame* frame)
520 {
521     V8IsolatedContext* isolatedContext;
522     if (UNLIKELY(!!(isolatedContext = V8IsolatedContext::getEntered())))
523         return isolatedContext->perContextData();
524     return V8Proxy::retrieve(frame)->windowShell()->perContextData();
525 }
526
527 void V8Proxy::resetIsolatedWorlds()
528 {
529     for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin();
530          iter != m_isolatedWorlds.end(); ++iter) {
531         iter->second->destroy();
532     }
533     m_isolatedWorlds.clear();
534     m_isolatedWorldSecurityOrigins.clear();
535 }
536
537 void V8Proxy::clearForClose()
538 {
539     resetIsolatedWorlds();
540     windowShell()->clearForClose();
541 }
542
543 void V8Proxy::clearForNavigation()
544 {
545     resetIsolatedWorlds();
546     windowShell()->clearForNavigation();
547 }
548
549 #define TRY_TO_CREATE_EXCEPTION(interfaceName) \
550     case interfaceName##Type: \
551         exception = toV8(interfaceName::create(description), isolate); \
552         break;
553
554 void V8Proxy::setDOMException(int ec, v8::Isolate* isolate)
555 {
556     if (ec <= 0)
557         return;
558
559     ExceptionCodeDescription description(ec);
560
561     v8::Handle<v8::Value> exception;
562     switch (description.type) {
563         DOM_EXCEPTION_INTERFACES_FOR_EACH(TRY_TO_CREATE_EXCEPTION)
564     }
565
566     if (!exception.IsEmpty())
567         v8::ThrowException(exception);
568 }
569
570 #undef TRY_TO_CREATE_EXCEPTION
571
572 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message, v8::Isolate* isolate)
573 {
574     switch (type) {
575     case RangeError:
576         return v8::ThrowException(v8::Exception::RangeError(v8String(message, isolate)));
577     case ReferenceError:
578         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message, isolate)));
579     case SyntaxError:
580         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message, isolate)));
581     case TypeError:
582         return v8::ThrowException(v8::Exception::TypeError(v8String(message, isolate)));
583     case GeneralError:
584         return v8::ThrowException(v8::Exception::Error(v8String(message, isolate)));
585     default:
586         ASSERT_NOT_REACHED();
587         return notHandledByInterceptor();
588     }
589 }
590
591 v8::Handle<v8::Value> V8Proxy::throwTypeError()
592 {
593     return throwError(TypeError, "Type error");
594 }
595
596 v8::Handle<v8::Value> V8Proxy::throwSyntaxError()
597 {
598     return throwError(SyntaxError, "Syntax error");
599 }
600
601 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
602 {
603     v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame);
604     if (context.IsEmpty())
605         return v8::Local<v8::Context>();
606
607     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
608         context = v8::Local<v8::Context>::New(isolatedContext->context());
609         if (frame != V8Proxy::retrieveFrame(context))
610             return v8::Local<v8::Context>();
611     }
612
613     return context;
614 }
615
616 v8::Local<v8::Context> V8Proxy::context()
617 {
618     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
619         RefPtr<SharedPersistent<v8::Context> > context = isolatedContext->sharedContext();
620         if (m_frame != V8Proxy::retrieveFrame(context->get()))
621             return v8::Local<v8::Context>();
622         return v8::Local<v8::Context>::New(context->get());
623     }
624     return mainWorldContext();
625 }
626
627 v8::Local<v8::Context> V8Proxy::mainWorldContext()
628 {
629     windowShell()->initContextIfNeeded();
630     return v8::Local<v8::Context>::New(windowShell()->context());
631 }
632
633 bool V8Proxy::matchesCurrentContext()
634 {
635     v8::Handle<v8::Context> context;
636     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
637         context = isolatedContext->sharedContext()->get();
638         if (m_frame != V8Proxy::retrieveFrame(context))
639             return false;
640     } else {
641         windowShell()->initContextIfNeeded();
642         context = windowShell()->context();
643     }
644     return context == context->GetCurrent();
645 }
646
647 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame)
648 {
649     V8Proxy* proxy = retrieve(frame);
650     if (!proxy)
651         return v8::Local<v8::Context>();
652
653     return proxy->mainWorldContext();
654 }
655
656 v8::Local<v8::Context> V8Proxy::currentContext()
657 {
658     return v8::Context::GetCurrent();
659 }
660
661 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
662 {
663     if (ConstructorMode::current() == ConstructorMode::CreateNewObject)
664         return throwError(TypeError, "Illegal constructor");
665
666     return args.This();
667 }
668
669 void V8Proxy::registerExtensionWithV8(v8::Extension* extension)
670 {
671     // If the extension exists in our list, it was already registered with V8.
672     if (!registeredExtensionWithV8(extension))
673         v8::RegisterExtension(extension);
674 }
675
676 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension)
677 {
678     const V8Extensions& registeredExtensions = extensions();
679     for (size_t i = 0; i < registeredExtensions.size(); ++i) {
680         if (registeredExtensions[i] == extension)
681             return true;
682     }
683
684     return false;
685 }
686
687 void V8Proxy::registerExtension(v8::Extension* extension)
688 {
689     registerExtensionWithV8(extension);
690     staticExtensionsList().append(extension);
691 }
692
693 const V8Extensions& V8Proxy::extensions()
694 {
695     return staticExtensionsList();
696 }
697
698 bool V8Proxy::setContextDebugId(int debugId)
699 {
700     ASSERT(debugId > 0);
701     v8::HandleScope scope;
702     v8::Handle<v8::Context> context = windowShell()->context();
703     if (context.IsEmpty())
704         return false;
705     if (!context->GetData()->IsUndefined())
706         return false;
707
708     v8::Context::Scope contextScope(context);
709
710     char buffer[32];
711     snprintf(buffer, sizeof(buffer), "page,%d", debugId);
712     context->SetData(v8::String::New(buffer));
713
714     return true;
715 }
716
717 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
718 {
719     v8::HandleScope scope;
720     if (!context->GetData()->IsString())
721         return -1;
722     v8::String::AsciiValue ascii(context->GetData());
723     char* comma = strnstr(*ascii, ",", ascii.length());
724     if (!comma)
725         return -1;
726     return atoi(comma + 1);
727 }
728
729 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, const WorldContextHandle& worldContext)
730 {
731     if (context->isDocument()) {
732         if (V8Proxy* proxy = V8Proxy::retrieve(context))
733             return worldContext.adjustedContext(proxy);
734 #if ENABLE(WORKERS)
735     } else if (context->isWorkerContext()) {
736         if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy())
737             return proxy->context();
738 #endif
739     }
740     return v8::Local<v8::Context>();
741 }
742
743 }  // namespace WebCore