OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009, Google Inc. |
| 2 // 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 #include "config.h" |
| 31 #include "DartController.h" |
| 32 |
| 33 #include "DOMWindow.h" |
| 34 #include "DartApplicationLoader.h" |
| 35 #include "DartBuiltinLibrarySource.h" |
| 36 #include "DartClassInfo.h" |
| 37 #include "DartDOMLibrarySource.h" |
| 38 #include "DartDOMWindow.h" |
| 39 #include "DartDOMWrapper.h" |
| 40 #include "DartFlags.h" |
| 41 #include "DartIsolateState.h" |
| 42 #include "DartUtilities.h" |
| 43 #include "Document.h" |
| 44 #include "Frame.h" |
| 45 #include "IDBPendingTransactionMonitor.h" |
| 46 #include "JavaScriptController.h" |
| 47 #include "Page.h" |
| 48 #include "PageGroup.h" |
| 49 #include "ScriptExecutionContext.h" |
| 50 #include "Settings.h" |
| 51 #include "StorageNamespace.h" |
| 52 |
| 53 #include "npruntime_impl.h" |
| 54 #include <bindings/npruntime.h> |
| 55 |
| 56 namespace WebCore { |
| 57 |
| 58 static void initDOMIsolate() |
| 59 { |
| 60 DartApiScope dartApiScope; |
| 61 |
| 62 // Create the dom library. |
| 63 Dart_Handle dom = Dart_LoadLibrary(Dart_NewString(DartUtilities::domLibraryN
ame), Dart_NewString("#library(\"Dom\");")); |
| 64 ASSERT(!Dart_IsError(dom)); |
| 65 Dart_LibraryImportLibrary(dom, Dart_LookupLibrary(Dart_NewString("dart:corei
mpl"))); |
| 66 // FIXME: add return value checks. |
| 67 Dart_LoadSource(dom, Dart_NewString("DOMExtensions"), Dart_NewString(dartDOM
LibrarySource)); |
| 68 Dart_CreateNativeWrapperClass(dom, Dart_NewString("DOMWrapperBase"), DartDOM
Wrapper::wrapperNativeFieldCount()); |
| 69 |
| 70 // Inject builtin library to forward core functionality to dom. |
| 71 // FIXME: We need to provide something for non-DOM isolates as well. |
| 72 Dart_Handle core = Dart_LookupLibrary(Dart_NewString("dart:core")); |
| 73 Dart_LoadSource(core, Dart_NewString("dart:builtin"), Dart_NewString(dartBui
ltinLibrarySource)); |
| 74 Dart_LibraryImportLibrary(core, dom); |
| 75 |
| 76 DartClassInfo::registerClasses(dom); |
| 77 } |
| 78 |
| 79 DartPerScriptState::DartPerScriptState(Document* document, NPObject* layoutTestC
ontroller) |
| 80 : m_dartApplicationLoader(adoptRef(new DartApplicationLoader(document, layou
tTestController))) |
| 81 , m_isolate(DartIsolateState::create(document, m_dartApplicationLoader.get()
)) |
| 82 { |
| 83 initDOMIsolate(); |
| 84 isolateToDartApplicationLoaderMap().set(m_isolate, m_dartApplicationLoader.g
et()); |
| 85 // DartIsolateState::create pushes newly create isolate, undo it. |
| 86 DartIsolateState::pop(); |
| 87 } |
| 88 |
| 89 DartPerScriptState::~DartPerScriptState() |
| 90 { |
| 91 *DartUtilities::recursionForIsolate(m_isolate) = 0; |
| 92 isolateToDartApplicationLoaderMap().remove(m_isolate); |
| 93 DartIsolateState::shutdown(m_isolate); |
| 94 } |
| 95 |
| 96 DartController::DartController(Frame* frame) |
| 97 : m_frame(frame) |
| 98 , m_states() |
| 99 , m_layoutTestController(0) |
| 100 { |
| 101 // The DartController's constructor must be called in the Frame's |
| 102 // constructor, so it can properly maintain the unit of related |
| 103 // browsing contexts. |
| 104 |
| 105 // The DartController must be created after the frame's loader and |
| 106 // tree nodes are initialized. |
| 107 ASSERT(frame->loader()); |
| 108 ASSERT(frame->tree()); |
| 109 } |
| 110 |
| 111 void DartController::clearWindowShell() |
| 112 { |
| 113 m_states.clear(); |
| 114 } |
| 115 |
| 116 class PostMessageTask : public ScriptExecutionContext::Task { |
| 117 public: |
| 118 PostMessageTask(Dart_Isolate destinationIsolate, Dart_Port destinationPort,
Dart_Port replyPort, Dart_Message message) |
| 119 : m_destinationIsolate(destinationIsolate) |
| 120 , m_destinationPort(destinationPort) |
| 121 , m_replyPort(replyPort) |
| 122 , m_message(message) { } |
| 123 |
| 124 ~PostMessageTask() |
| 125 { |
| 126 free(m_message); |
| 127 } |
| 128 |
| 129 virtual void performTask(ScriptExecutionContext* context) |
| 130 { |
| 131 // FIXME: one shouldn't trust isFullDomIsolate as another |
| 132 // isolate with the same address might be allocated. Apparently better |
| 133 // way would be to maintain a way to tell all the tasks that they are |
| 134 // cancelled from now on. For example, we may maintain a list of all |
| 135 // pending tasks and iterate over it. |
| 136 // destinationIsolate might have been shut down before. |
| 137 if (!DartUtilities::isFullDomIsolate(m_destinationIsolate)) |
| 138 return; |
| 139 DartIsolateState::Scope scope(m_destinationIsolate); |
| 140 DartApiScope apiScope; |
| 141 Dart_Handle result = Dart_HandleMessage(m_destinationPort, m_replyPort,
m_message); |
| 142 if (Dart_IsError(result)) |
| 143 DartUtilities::reportProblem(context, result); |
| 144 } |
| 145 |
| 146 private: |
| 147 Dart_Isolate m_destinationIsolate; |
| 148 Dart_Port m_destinationPort; |
| 149 Dart_Port m_replyPort; |
| 150 Dart_Message m_message; |
| 151 }; |
| 152 |
| 153 static bool postMessageCallback(Dart_Isolate destinationIsolate, Dart_Port desti
nationPort, Dart_Port replyPort, Dart_Message message) |
| 154 { |
| 155 ASSERT(DartUtilities::isFullDomIsolate(destinationIsolate)); |
| 156 ScriptExecutionContext* destinationContext = DartUtilities::isolateContext(d
estinationIsolate); |
| 157 destinationContext->postTask(adoptPtr(new PostMessageTask(destinationIsolate
, destinationPort, replyPort, message))); |
| 158 return true; |
| 159 } |
| 160 |
| 161 static void closePortCallback(Dart_Isolate, Dart_Port) |
| 162 { |
| 163 } |
| 164 |
| 165 void DartController::setupDOMEnabledIsolate(ScriptExecutionContext* context) |
| 166 { |
| 167 ASSERT(context); |
| 168 Dart_SetMessageCallbacks(&postMessageCallback, &closePortCallback); |
| 169 DartUtilities::registerIsolateContext(Dart_CurrentIsolate(), context); |
| 170 } |
| 171 |
| 172 bool DartController::initializeIsolateCallback(void* data, char** errorMsg) |
| 173 { |
| 174 Dart_Isolate isolate = Dart_CreateIsolate(0, data, errorMsg); |
| 175 if (!isolate) |
| 176 return false; |
| 177 |
| 178 DartApiScope dartApiScope; |
| 179 |
| 180 // It's safe to reinitialize DOM in all isolates: unless Dart isolate is |
| 181 // registered with DartUtilities::registerIsolatecContext, it's DOM function
ality |
| 182 // will be disabled: we won't be able to resolve top level accessors. |
| 183 initDOMIsolate(); |
| 184 |
| 185 DartApplicationLoader* dartApplicationLoader = reinterpret_cast<DartApplicat
ionLoader*>(data); |
| 186 // FIXME: when DartVM has shutdown callback, we'll be able to deref it. |
| 187 dartApplicationLoader->ref(); |
| 188 |
| 189 ASSERT(!dartApplicationLoader->isLoadingMainIsolate()); |
| 190 dartApplicationLoader->reinjectSources(); |
| 191 |
| 192 return true; |
| 193 } |
| 194 |
| 195 void DartController::initVMIfNeeded() |
| 196 { |
| 197 static bool hasBeenInitialized = false; |
| 198 if (hasBeenInitialized) |
| 199 return; |
| 200 |
| 201 int argc = DartFlags::count(); |
| 202 const char** argv = const_cast<const char**>(DartFlags::flags()); |
| 203 Dart_SetVMFlags(argc, argv); |
| 204 Dart_Initialize(&initializeIsolateCallback); |
| 205 hasBeenInitialized = true; |
| 206 } |
| 207 |
| 208 bool DartController::isScriptTypeSupported(const String& mimeType) |
| 209 { |
| 210 DEFINE_STATIC_LOCAL(HashSet<String>, types, ()); |
| 211 if (types.isEmpty()) { |
| 212 types.add("application/dart"); |
| 213 types.add("application/dart-app"); |
| 214 types.add("application/dart-script"); |
| 215 } |
| 216 return !mimeType.isEmpty() && types.contains(mimeType); |
| 217 } |
| 218 |
| 219 void DartController::evaluate(const ScriptSourceCode& sourceCode) |
| 220 { |
| 221 if (!m_frame->page()->settings()->isDartEnabled()) |
| 222 return; |
| 223 |
| 224 initVMIfNeeded(); |
| 225 |
| 226 // FIXME: it may make sense to ensure that we'll never call evaluate more th
an once for the same script tag. |
| 227 DartPerScriptState* state = new DartPerScriptState(frame()->document(), m_la
youtTestController); |
| 228 ASSERT(state->isolate()); |
| 229 m_states.append(adoptPtr(state)); |
| 230 |
| 231 DartIsolateState::Scope scope(state->isolate()); |
| 232 state->dartApplicationLoader()->load(sourceCode.url(), sourceCode.source()); |
| 233 } |
| 234 |
| 235 void DartController::bindToWindowObject(Frame*, const String& key, NPObject* obj
ect) |
| 236 { |
| 237 // FIXME: production code should not know anything about layoutTestControlle
r. |
| 238 if (key != "layoutTestController") |
| 239 return; |
| 240 |
| 241 // FIXME: proper management of lifetime. |
| 242 ASSERT(m_states.isEmpty()); |
| 243 m_layoutTestController = object; |
| 244 } |
| 245 |
| 246 Dart_Handle DartController::callFunction(Dart_Handle function, int argc, Dart_Ha
ndle* argv) |
| 247 { |
| 248 // FIXME: Introduce Dart variant of V8GCController::checkMemoryUsage(); |
| 249 const int kMaxRecursionDepth = 22; |
| 250 |
| 251 int* recursion = DartUtilities::recursionForCurrentIsolate(); |
| 252 |
| 253 if (*recursion >= kMaxRecursionDepth) |
| 254 return Dart_Error("Maximum call stack size exceeded"); |
| 255 |
| 256 // FIXME: implement InspectorInstrumentationCookie stuff a la v8. |
| 257 (*recursion)++; |
| 258 Dart_Handle result = Dart_InvokeClosure(function, argc, argv); |
| 259 (*recursion)--; |
| 260 |
| 261 // Release the storage mutex if applicable. |
| 262 didLeaveScriptContext(*recursion); |
| 263 |
| 264 // Handle fatal error in Dart VM a la v8. |
| 265 |
| 266 return result; |
| 267 } |
| 268 |
| 269 void DartController::didLeaveScriptContext(int recursion) |
| 270 { |
| 271 // FIXME: common to v8, should be factored out. |
| 272 Page* page = m_frame->page(); |
| 273 if (!page) |
| 274 return; |
| 275 #if ENABLE(INDEXED_DATABASE) |
| 276 // If we've just left a script context and indexed database has been |
| 277 // instantiated, we must let its transaction coordinator know so it can term
inate |
| 278 // any not-yet-started transactions. |
| 279 IDBPendingTransactionMonitor::abortPendingTransactions(); |
| 280 #endif // ENABLE(INDEXED_DATABASE) |
| 281 // If we've just left a top level script context and local storage has been |
| 282 // instantiated, we must ensure that any storage locks have been freed. |
| 283 // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex |
| 284 if (recursion) |
| 285 return; |
| 286 if (page->group().hasLocalStorage()) |
| 287 page->group().localStorage()->unlock(); |
| 288 } |
| 289 |
| 290 DartController* DartController::retrieve(Frame* frame) |
| 291 { |
| 292 if (!frame) |
| 293 return 0; |
| 294 // FIXME: check if can execute Dart scripts. |
| 295 if (!frame->script()->javaScript()->canExecuteScripts(NotAboutToExecuteScrip
t)) |
| 296 return 0; |
| 297 return frame->script()->dart(); |
| 298 } |
| 299 |
| 300 DartController* DartController::retrieve(ScriptExecutionContext* context) |
| 301 { |
| 302 if (!context || !context->isDocument()) |
| 303 return 0; |
| 304 return retrieve(static_cast<Document*>(context)->frame()); |
| 305 } |
| 306 |
| 307 } |
OLD | NEW |