Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp

Issue 2615213002: Introduce a lifecycle model to WindowProxy (Closed)
Patch Set: temp Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/bindings/core/v8/WindowProxy.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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)'.
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 20 matching lines...) Expand all
265 MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame, 272 MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame,
266 origin); 273 origin);
267 frame->loader().client()->didCreateScriptContext( 274 frame->loader().client()->didCreateScriptContext(
268 context, m_world->extensionGroup(), m_world->worldId()); 275 context, m_world->extensionGroup(), m_world->worldId());
269 } 276 }
270 // If conditional features for window have been queued before the V8 context 277 // If conditional features for window have been queued before the V8 context
271 // was ready, then inject them into the context now 278 // was ready, then inject them into the context now
272 if (m_world->isMainWorld()) { 279 if (m_world->isMainWorld()) {
273 installPendingConditionalFeaturesOnWindow(m_scriptState.get()); 280 installPendingConditionalFeaturesOnWindow(m_scriptState.get());
274 } 281 }
282
283 // TODO(haraken): Currently we cannot enable the following DCHECK because
284 // an already detached window proxy can be re-initialized. This is wrong.
285 // DCHECK(m_lifecycle == Lifecycle::ContextUninitialized);
286 m_lifecycle = Lifecycle::ContextInitialized;
dcheng 2017/01/09 22:10:58 I understand the trybot failures now. It is proble
287 DCHECK(m_scriptState->contextIsValid());
275 } 288 }
276 289
277 void WindowProxy::createContext() { 290 void WindowProxy::createContext() {
278 // Create a new v8::Context with the window object as the global object 291 // Create a new v8::Context with the window object as the global object
279 // (aka the inner global). Reuse the global proxy object (aka the outer 292 // (aka the inner global). Reuse the global proxy object (aka the outer
280 // global) if it already exists. See the comments in 293 // global) if it already exists. See the comments in
281 // setupWindowPrototypeChain for the structure of the prototype chain of 294 // setupWindowPrototypeChain for the structure of the prototype chain of
282 // the global object. 295 // the global object.
283 v8::Local<v8::ObjectTemplate> globalTemplate = 296 v8::Local<v8::ObjectTemplate> globalTemplate =
284 V8Window::domTemplate(m_isolate, *m_world)->InstanceTemplate(); 297 V8Window::domTemplate(m_isolate, *m_world)->InstanceTemplate();
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/bindings/core/v8/WindowProxy.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698