Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 | 76 |
| 77 WindowProxy* WindowProxy::create(v8::Isolate* isolate, | 77 WindowProxy* WindowProxy::create(v8::Isolate* isolate, |
| 78 Frame* frame, | 78 Frame* frame, |
| 79 DOMWrapperWorld& world) { | 79 DOMWrapperWorld& world) { |
| 80 return new WindowProxy(frame, &world, isolate); | 80 return new WindowProxy(frame, &world, isolate); |
| 81 } | 81 } |
| 82 | 82 |
| 83 WindowProxy::WindowProxy(Frame* frame, | 83 WindowProxy::WindowProxy(Frame* frame, |
| 84 PassRefPtr<DOMWrapperWorld> world, | 84 PassRefPtr<DOMWrapperWorld> world, |
| 85 v8::Isolate* isolate) | 85 v8::Isolate* isolate) |
| 86 : m_frame(frame), m_isolate(isolate), m_world(world) {} | 86 : m_frame(frame), |
| 87 m_isolate(isolate), | |
| 88 m_world(world), | |
| 89 m_lifecycle(Lifecycle::ContextUninitialized) {} | |
| 87 | 90 |
| 88 WindowProxy::~WindowProxy() { | 91 WindowProxy::~WindowProxy() { |
| 89 // clearForClose() or clearForNavigation() must be invoked before destruction | 92 // clearForClose() or clearForNavigation() must be invoked before destruction |
| 90 // starts. | 93 // starts. |
| 91 ASSERT(!isContextInitialized()); | 94 DCHECK(m_lifecycle != Lifecycle::ContextInitialized); |
| 92 } | 95 } |
| 93 | 96 |
| 94 DEFINE_TRACE(WindowProxy) { | 97 DEFINE_TRACE(WindowProxy) { |
| 95 visitor->trace(m_frame); | 98 visitor->trace(m_frame); |
| 96 } | 99 } |
| 97 | 100 |
| 98 void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) { | 101 void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) { |
| 99 if (!isContextInitialized()) | 102 if (m_lifecycle != Lifecycle::ContextInitialized) |
| 100 return; | 103 return; |
| 101 | 104 |
| 102 ScriptState::Scope scope(m_scriptState.get()); | 105 ScriptState::Scope scope(m_scriptState.get()); |
| 103 v8::Local<v8::Context> context = m_scriptState->context(); | 106 v8::Local<v8::Context> context = m_scriptState->context(); |
| 104 if (m_frame->isLocalFrame()) { | 107 if (m_frame->isLocalFrame()) { |
| 105 LocalFrame* frame = toLocalFrame(m_frame); | 108 LocalFrame* frame = toLocalFrame(m_frame); |
| 106 // The embedder could run arbitrary code in response to the | 109 // The embedder could run arbitrary code in response to the |
| 107 // willReleaseScriptContext callback, so all disposing should happen after | 110 // willReleaseScriptContext callback, so all disposing should happen after |
| 108 // it returns. | 111 // it returns. |
| 109 frame->loader().client()->willReleaseScriptContext(context, | 112 frame->loader().client()->willReleaseScriptContext(context, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 126 m_scriptState->detachGlobalObject(); | 129 m_scriptState->detachGlobalObject(); |
| 127 } | 130 } |
| 128 | 131 |
| 129 m_scriptState->disposePerContextData(); | 132 m_scriptState->disposePerContextData(); |
| 130 | 133 |
| 131 // It's likely that disposing the context has created a lot of | 134 // It's likely that disposing the context has created a lot of |
| 132 // garbage. Notify V8 about this so it'll have a chance of cleaning | 135 // garbage. Notify V8 about this so it'll have a chance of cleaning |
| 133 // it up when idle. | 136 // it up when idle. |
| 134 V8GCForContextDispose::instance().notifyContextDisposed( | 137 V8GCForContextDispose::instance().notifyContextDisposed( |
| 135 m_frame->isMainFrame()); | 138 m_frame->isMainFrame()); |
| 139 | |
| 140 DCHECK(m_lifecycle == Lifecycle::ContextInitialized); | |
| 141 m_lifecycle = Lifecycle::ContextDetached; | |
| 136 } | 142 } |
| 137 | 143 |
| 138 void WindowProxy::clearForClose() { | 144 void WindowProxy::clearForClose() { |
| 139 disposeContext(DoNotDetachGlobal); | 145 disposeContext(DoNotDetachGlobal); |
| 140 } | 146 } |
| 141 | 147 |
| 142 void WindowProxy::clearForNavigation() { | 148 void WindowProxy::clearForNavigation() { |
| 143 disposeContext(DetachGlobal); | 149 disposeContext(DetachGlobal); |
| 144 } | 150 } |
| 145 | 151 |
| 146 v8::Local<v8::Object> WindowProxy::globalIfNotDetached() { | 152 v8::Local<v8::Object> WindowProxy::globalIfNotDetached() { |
| 147 if (!isContextInitialized()) | 153 if (m_lifecycle == Lifecycle::ContextInitialized) { |
| 148 return v8::Local<v8::Object>(); | 154 DCHECK(m_scriptState->contextIsValid()); |
| 149 DCHECK(m_scriptState->contextIsValid()); | 155 DCHECK(m_globalProxy == m_scriptState->context()->Global()); |
| 150 DCHECK(m_globalProxy == m_scriptState->context()->Global()); | 156 return m_globalProxy.newLocal(m_isolate); |
| 151 return m_globalProxy.newLocal(m_isolate); | 157 } |
| 158 return v8::Local<v8::Object>(); | |
| 152 } | 159 } |
| 153 | 160 |
| 154 v8::Local<v8::Object> WindowProxy::releaseGlobal() { | 161 v8::Local<v8::Object> WindowProxy::releaseGlobal() { |
| 155 ASSERT(!isContextInitialized()); | 162 DCHECK(m_lifecycle != Lifecycle::ContextInitialized); |
| 156 // If a ScriptState was created, the context was initialized at some point. | |
| 157 // Make sure the global object was detached from the proxy by calling | 163 // Make sure the global object was detached from the proxy by calling |
| 158 // clearForNavigation(). | 164 // clearForNavigation(). |
| 159 if (m_scriptState) | 165 if (m_lifecycle == Lifecycle::ContextDetached) |
| 160 ASSERT(m_scriptState->isGlobalObjectDetached()); | 166 ASSERT(m_scriptState->isGlobalObjectDetached()); |
| 167 | |
| 161 v8::Local<v8::Object> global = m_globalProxy.newLocal(m_isolate); | 168 v8::Local<v8::Object> global = m_globalProxy.newLocal(m_isolate); |
| 162 m_globalProxy.clear(); | 169 m_globalProxy.clear(); |
| 163 return global; | 170 return global; |
| 164 } | 171 } |
| 165 | 172 |
| 166 void WindowProxy::setGlobal(v8::Local<v8::Object> global) { | 173 void WindowProxy::setGlobal(v8::Local<v8::Object> global) { |
| 167 m_globalProxy.set(m_isolate, global); | 174 m_globalProxy.set(m_isolate, global); |
| 168 | 175 |
| 169 // Initialize the window proxy now, to re-establish the connection between | 176 // Initialize the window proxy now, to re-establish the connection between |
| 170 // the global object and the v8::Context. This is really only needed for a | 177 // the global object and the v8::Context. This is really only needed for a |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 // has a security token which is the domain. The outer window cannot | 211 // has a security token which is the domain. The outer window cannot |
| 205 // have its own properties. window.foo = 'x' is delegated to the | 212 // have its own properties. window.foo = 'x' is delegated to the |
| 206 // inner window. | 213 // inner window. |
| 207 // | 214 // |
| 208 // When a frame navigates to a new page, the inner window is cut off | 215 // When a frame navigates to a new page, the inner window is cut off |
| 209 // the outer window, and the outer window identify is preserved for | 216 // the outer window, and the outer window identify is preserved for |
| 210 // the frame. However, a new inner window is created for the new page. | 217 // the frame. However, a new inner window is created for the new page. |
| 211 // If there are JS code holds a closure to the old inner window, | 218 // If there are JS code holds a closure to the old inner window, |
| 212 // it won't be able to reach the outer window via its global object. | 219 // it won't be able to reach the outer window via its global object. |
| 213 void WindowProxy::initializeIfNeeded() { | 220 void WindowProxy::initializeIfNeeded() { |
| 214 if (isContextInitialized()) | 221 // TODO(haraken): It is wrong to re-initialize an already detached window |
| 215 return; | 222 // proxy. This must be 'if(m_lifecycle == Lifecycle::ContextUninitialized)'. |
|
haraken
2017/01/06 10:53:19
If I change the condition to 'if(m_lifecycle == Li
| |
| 216 initialize(); | 223 if (m_lifecycle != Lifecycle::ContextInitialized) { |
| 217 | 224 initialize(); |
| 218 if (m_world->isMainWorld() && m_frame->isLocalFrame()) | 225 if (m_world->isMainWorld() && m_frame->isLocalFrame()) |
| 219 toLocalFrame(m_frame)->loader().dispatchDidClearWindowObjectInMainWorld(); | 226 toLocalFrame(m_frame)->loader().dispatchDidClearWindowObjectInMainWorld(); |
| 227 } | |
| 220 } | 228 } |
| 221 | 229 |
| 222 void WindowProxy::initialize() { | 230 void WindowProxy::initialize() { |
| 223 TRACE_EVENT1("v8", "WindowProxy::initialize", "isMainWindow", | 231 TRACE_EVENT1("v8", "WindowProxy::initialize", "isMainWindow", |
| 224 m_frame->isMainFrame()); | 232 m_frame->isMainFrame()); |
| 225 SCOPED_BLINK_UMA_HISTOGRAM_TIMER( | 233 SCOPED_BLINK_UMA_HISTOGRAM_TIMER( |
| 226 m_frame->isMainFrame() ? "Blink.Binding.InitializeMainWindowProxy" | 234 m_frame->isMainFrame() ? "Blink.Binding.InitializeMainWindowProxy" |
| 227 : "Blink.Binding.InitializeNonMainWindowProxy"); | 235 : "Blink.Binding.InitializeNonMainWindowProxy"); |
| 228 | 236 |
| 229 ScriptForbiddenScope::AllowUserAgentScript allowScript; | 237 ScriptForbiddenScope::AllowUserAgentScript allowScript; |
| 230 | 238 |
| 231 v8::HandleScope handleScope(m_isolate); | 239 v8::HandleScope handleScope(m_isolate); |
| 232 | 240 |
| 233 createContext(); | 241 createContext(); |
| 234 CHECK(isContextInitialized()); | |
| 235 | 242 |
| 236 ScriptState::Scope scope(m_scriptState.get()); | 243 ScriptState::Scope scope(m_scriptState.get()); |
| 237 v8::Local<v8::Context> context = m_scriptState->context(); | 244 v8::Local<v8::Context> context = m_scriptState->context(); |
| 238 if (m_globalProxy.isEmpty()) { | 245 if (m_globalProxy.isEmpty()) { |
| 239 m_globalProxy.set(m_isolate, context->Global()); | 246 m_globalProxy.set(m_isolate, context->Global()); |
| 240 CHECK(!m_globalProxy.isEmpty()); | 247 CHECK(!m_globalProxy.isEmpty()); |
| 241 } | 248 } |
| 242 | 249 |
| 243 setupWindowPrototypeChain(); | 250 setupWindowPrototypeChain(); |
| 244 | 251 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 310 { | 317 { |
| 311 V8PerIsolateData::UseCounterDisabledScope useCounterDisabled( | 318 V8PerIsolateData::UseCounterDisabledScope useCounterDisabled( |
| 312 V8PerIsolateData::from(m_isolate)); | 319 V8PerIsolateData::from(m_isolate)); |
| 313 context = | 320 context = |
| 314 v8::Context::New(m_isolate, &extensionConfiguration, globalTemplate, | 321 v8::Context::New(m_isolate, &extensionConfiguration, globalTemplate, |
| 315 m_globalProxy.newLocal(m_isolate)); | 322 m_globalProxy.newLocal(m_isolate)); |
| 316 } | 323 } |
| 317 CHECK(!context.IsEmpty()); | 324 CHECK(!context.IsEmpty()); |
| 318 | 325 |
| 319 m_scriptState = ScriptState::create(context, m_world); | 326 m_scriptState = ScriptState::create(context, m_world); |
| 327 | |
| 328 // TODO(haraken): Currently we cannot enable the following DCHECK because | |
| 329 // an already detached window proxy can be re-initialized. This is wrong. | |
| 330 // DCHECK(m_lifecycle == Lifecycle::ContextUninitialized); | |
|
haraken
2017/01/06 10:53:19
Ditto.
| |
| 331 m_lifecycle = Lifecycle::ContextInitialized; | |
| 332 DCHECK(m_scriptState->contextIsValid()); | |
| 320 } | 333 } |
| 321 | 334 |
| 322 void WindowProxy::setupWindowPrototypeChain() { | 335 void WindowProxy::setupWindowPrototypeChain() { |
| 323 // Associate the window wrapper object and its prototype chain with the | 336 // Associate the window wrapper object and its prototype chain with the |
| 324 // corresponding native DOMWindow object. | 337 // corresponding native DOMWindow object. |
| 325 // The full structure of the global object's prototype chain is as follows: | 338 // The full structure of the global object's prototype chain is as follows: |
| 326 // | 339 // |
| 327 // global proxy object [1] | 340 // global proxy object [1] |
| 328 // -- has prototype --> global object (window wrapper object) [2] | 341 // -- has prototype --> global object (window wrapper object) [2] |
| 329 // -- has prototype --> Window.prototype | 342 // -- has prototype --> Window.prototype |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 | 471 |
| 459 // NOTE: V8 does identity comparison in fast path, must use a symbol | 472 // NOTE: V8 does identity comparison in fast path, must use a symbol |
| 460 // as the security token. | 473 // as the security token. |
| 461 context->SetSecurityToken(v8AtomicString(m_isolate, token)); | 474 context->SetSecurityToken(v8AtomicString(m_isolate, token)); |
| 462 } | 475 } |
| 463 | 476 |
| 464 void WindowProxy::updateDocument() { | 477 void WindowProxy::updateDocument() { |
| 465 DCHECK(m_world->isMainWorld()); | 478 DCHECK(m_world->isMainWorld()); |
| 466 // For an uninitialized main window proxy, there's nothing we need | 479 // For an uninitialized main window proxy, there's nothing we need |
| 467 // to update. The update is done when the window proxy gets initialized later. | 480 // to update. The update is done when the window proxy gets initialized later. |
| 468 if (!isContextInitialized()) | 481 if (m_lifecycle == Lifecycle::ContextUninitialized) |
| 482 return; | |
| 483 // TODO(yukishiino): Is it okay to not update document when the context | |
| 484 // is detached? It's not trivial to fix this because udpateDocumentProperty | |
| 485 // requires a not-yet-detached context to instantiate a document wrapper. | |
| 486 if (m_lifecycle == Lifecycle::ContextDetached) | |
| 469 return; | 487 return; |
| 470 | 488 |
| 471 updateActivityLogger(); | 489 updateActivityLogger(); |
| 472 updateDocumentProperty(); | 490 updateDocumentProperty(); |
| 473 updateSecurityOrigin(m_frame->securityContext()->getSecurityOrigin()); | 491 updateSecurityOrigin(m_frame->securityContext()->getSecurityOrigin()); |
| 474 } | 492 } |
| 475 | 493 |
| 476 static v8::Local<v8::Value> getNamedProperty( | 494 static v8::Local<v8::Value> getNamedProperty( |
| 477 HTMLDocument* htmlDocument, | 495 HTMLDocument* htmlDocument, |
| 478 const AtomicString& key, | 496 const AtomicString& key, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 if (info.Holder() | 534 if (info.Holder() |
| 517 ->GetRealNamedPropertyInPrototypeChain( | 535 ->GetRealNamedPropertyInPrototypeChain( |
| 518 info.GetIsolate()->GetCurrentContext(), property.As<v8::String>()) | 536 info.GetIsolate()->GetCurrentContext(), property.As<v8::String>()) |
| 519 .ToLocal(&value)) | 537 .ToLocal(&value)) |
| 520 v8SetReturnValue(info, value); | 538 v8SetReturnValue(info, value); |
| 521 } | 539 } |
| 522 | 540 |
| 523 void WindowProxy::namedItemAdded(HTMLDocument* document, | 541 void WindowProxy::namedItemAdded(HTMLDocument* document, |
| 524 const AtomicString& name) { | 542 const AtomicString& name) { |
| 525 DCHECK(m_world->isMainWorld()); | 543 DCHECK(m_world->isMainWorld()); |
| 526 DCHECK(m_scriptState); | 544 |
| 527 if (!isContextInitialized()) | 545 // Context must be initialized before this point. |
| 546 DCHECK(m_lifecycle >= Lifecycle::ContextInitialized); | |
| 547 // TODO(yukishiino): Is it okay to not update named properties | |
| 548 // after the context gets detached? | |
| 549 if (m_lifecycle == Lifecycle::ContextDetached) | |
| 528 return; | 550 return; |
| 529 | 551 |
| 530 ScriptState::Scope scope(m_scriptState.get()); | 552 ScriptState::Scope scope(m_scriptState.get()); |
| 531 v8::Local<v8::Object> documentWrapper = | 553 v8::Local<v8::Object> documentWrapper = |
| 532 m_world->domDataStore().get(document, m_isolate); | 554 m_world->domDataStore().get(document, m_isolate); |
| 533 // TODO(yukishiino,peria): We should check if the own property with the same | 555 // TODO(yukishiino,peria): We should check if the own property with the same |
| 534 // name already exists or not, and if it exists, we shouldn't define a new | 556 // name already exists or not, and if it exists, we shouldn't define a new |
| 535 // accessor property (it fails). | 557 // accessor property (it fails). |
| 536 documentWrapper->SetAccessor(m_isolate->GetCurrentContext(), | 558 documentWrapper->SetAccessor(m_isolate->GetCurrentContext(), |
| 537 v8String(m_isolate, name), getter); | 559 v8String(m_isolate, name), getter); |
| 538 } | 560 } |
| 539 | 561 |
| 540 void WindowProxy::namedItemRemoved(HTMLDocument* document, | 562 void WindowProxy::namedItemRemoved(HTMLDocument* document, |
| 541 const AtomicString& name) { | 563 const AtomicString& name) { |
| 542 DCHECK(m_world->isMainWorld()); | 564 DCHECK(m_world->isMainWorld()); |
| 543 DCHECK(m_scriptState); | 565 |
| 544 if (!isContextInitialized()) | 566 // Context must be initialized before this point. |
| 567 DCHECK(m_lifecycle >= Lifecycle::ContextInitialized); | |
| 568 // TODO(yukishiino): Is it okay to not update named properties | |
| 569 // after the context gets detached? | |
| 570 if (m_lifecycle == Lifecycle::ContextDetached) | |
| 545 return; | 571 return; |
| 572 | |
| 546 if (document->hasNamedItem(name) || document->hasExtraNamedItem(name)) | 573 if (document->hasNamedItem(name) || document->hasExtraNamedItem(name)) |
| 547 return; | 574 return; |
| 548 | |
| 549 ScriptState::Scope scope(m_scriptState.get()); | 575 ScriptState::Scope scope(m_scriptState.get()); |
| 550 v8::Local<v8::Object> documentWrapper = | 576 v8::Local<v8::Object> documentWrapper = |
| 551 m_world->domDataStore().get(document, m_isolate); | 577 m_world->domDataStore().get(document, m_isolate); |
| 552 documentWrapper | 578 documentWrapper |
| 553 ->Delete(m_isolate->GetCurrentContext(), v8String(m_isolate, name)) | 579 ->Delete(m_isolate->GetCurrentContext(), v8String(m_isolate, name)) |
| 554 .ToChecked(); | 580 .ToChecked(); |
| 555 } | 581 } |
| 556 | 582 |
| 557 void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) { | 583 void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) { |
| 558 if (!isContextInitialized()) | 584 // For an uninitialized main window proxy, there's nothing we need |
| 585 // to update. The update is done when the window proxy gets initialized later. | |
| 586 if (m_lifecycle == Lifecycle::ContextUninitialized) | |
| 559 return; | 587 return; |
| 588 // TODO(yukishiino): Is it okay to not update security origin when the context | |
| 589 // is detached? | |
| 590 if (m_lifecycle == Lifecycle::ContextDetached) | |
| 591 return; | |
| 592 | |
| 560 setSecurityToken(origin); | 593 setSecurityToken(origin); |
| 561 } | 594 } |
| 562 | 595 |
| 563 } // namespace blink | 596 } // namespace blink |
| OLD | NEW |