OLD | NEW |
1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
2 // All rights reserved. | 2 // 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 22 matching lines...) Expand all Loading... |
33 #include <utility> | 33 #include <utility> |
34 | 34 |
35 #include <v8.h> | 35 #include <v8.h> |
36 #include <v8-debug.h> | 36 #include <v8-debug.h> |
37 | 37 |
38 #include "v8_proxy.h" | 38 #include "v8_proxy.h" |
39 #include "v8_index.h" | 39 #include "v8_index.h" |
40 #include "v8_binding.h" | 40 #include "v8_binding.h" |
41 #include "V8Collection.h" | 41 #include "V8Collection.h" |
42 #include "V8DOMWindow.h" | 42 #include "V8DOMWindow.h" |
| 43 #include "V8IsolatedWorld.h" |
43 | 44 |
44 #include "ChromiumBridge.h" | 45 #include "ChromiumBridge.h" |
45 #include "CSSMutableStyleDeclaration.h" | 46 #include "CSSMutableStyleDeclaration.h" |
46 #include "DOMObjectsInclude.h" | 47 #include "DOMObjectsInclude.h" |
47 #include "DocumentLoader.h" | 48 #include "DocumentLoader.h" |
48 #include "ScriptController.h" | 49 #include "ScriptController.h" |
49 #include "V8CustomBinding.h" | 50 #include "V8CustomBinding.h" |
50 #include "V8DOMMap.h" | 51 #include "V8DOMMap.h" |
51 | 52 |
52 namespace WebCore { | 53 namespace WebCore { |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 proto->Set(v8::String::New(c->name), | 160 proto->Set(v8::String::New(c->name), |
160 v8::Integer::New(c->value), | 161 v8::Integer::New(c->value), |
161 v8::ReadOnly); | 162 v8::ReadOnly); |
162 } | 163 } |
163 } | 164 } |
164 | 165 |
165 typedef HashMap<Node*, v8::Object*> DOMNodeMap; | 166 typedef HashMap<Node*, v8::Object*> DOMNodeMap; |
166 typedef HashMap<void*, v8::Object*> DOMObjectMap; | 167 typedef HashMap<void*, v8::Object*> DOMObjectMap; |
167 | 168 |
168 #ifndef NDEBUG | 169 #ifndef NDEBUG |
| 170 |
169 static void EnumerateDOMObjectMap(DOMObjectMap& wrapper_map) | 171 static void EnumerateDOMObjectMap(DOMObjectMap& wrapper_map) |
170 { | 172 { |
171 for (DOMObjectMap::iterator it = wrapper_map.begin(), end = wrapper_map.end(); | 173 for (DOMObjectMap::iterator it = wrapper_map.begin(), end = wrapper_map.end(); |
172 it != end; ++it) { | 174 it != end; ++it) { |
173 v8::Persistent<v8::Object> wrapper(it->second); | 175 v8::Persistent<v8::Object> wrapper(it->second); |
174 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); | 176 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); |
175 void* obj = it->first; | 177 void* obj = it->first; |
176 USE_VAR(type); | 178 USE_VAR(type); |
177 USE_VAR(obj); | 179 USE_VAR(obj); |
178 } | 180 } |
179 } | 181 } |
180 | 182 |
| 183 class DOMObjectVisitor : public DOMWrapperMap<void>::Visitor { |
| 184 public: |
| 185 void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) { |
| 186 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); |
| 187 USE_VAR(type); |
| 188 USE_VAR(object); |
| 189 } |
| 190 }; |
181 | 191 |
182 static void EnumerateDOMNodeMap(DOMNodeMap& node_map) | 192 class EnsureWeakDOMNodeVisitor : public DOMWrapperMap<Node>::Visitor { |
183 { | 193 public: |
184 for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end(); | 194 void visitDOMWrapper(Node* object, v8::Persistent<v8::Object> wrapper) { |
185 it != end; ++it) { | 195 USE_VAR(object); |
186 Node* node = it->first; | 196 ASSERT(wrapper.IsWeak()); |
187 USE_VAR(node); | |
188 ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak()); | |
189 } | 197 } |
190 } | 198 }; |
| 199 |
191 #endif // NDEBUG | 200 #endif // NDEBUG |
192 | 201 |
193 #if ENABLE(SVG) | 202 #if ENABLE(SVG) |
194 v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( | 203 v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( |
195 SVGElementInstance* instance) | 204 SVGElementInstance* instance) |
196 { | 205 { |
197 if (!instance) | 206 if (!instance) |
198 return v8::Null(); | 207 return v8::Null(); |
199 | 208 |
200 v8::Handle<v8::Object> existing_instance = getDOMSVGElementInstanceMap().get(i
nstance); | 209 v8::Handle<v8::Object> existing_instance = getDOMSVGElementInstanceMap().get(i
nstance); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 if (!dom_object) | 325 if (!dom_object) |
317 return; | 326 return; |
318 if (!gc_protected_map().contains(dom_object)) | 327 if (!gc_protected_map().contains(dom_object)) |
319 return; | 328 return; |
320 | 329 |
321 // Dispose the strong reference. | 330 // Dispose the strong reference. |
322 v8::Persistent<v8::Object> wrapper(gc_protected_map().take(dom_object)); | 331 v8::Persistent<v8::Object> wrapper(gc_protected_map().take(dom_object)); |
323 wrapper.Dispose(); | 332 wrapper.Dispose(); |
324 } | 333 } |
325 | 334 |
326 | 335 class GCPrologueVisitor : public DOMWrapperMap<void>::Visitor { |
327 // Create object groups for DOM tree nodes. | 336 public: |
328 static void GCPrologue() | 337 void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) { |
329 { | |
330 v8::HandleScope scope; | |
331 | |
332 #ifndef NDEBUG | |
333 EnumerateDOMObjectMap(getDOMObjectMap().impl()); | |
334 #endif | |
335 | |
336 // Run through all objects with possible pending activity making their | |
337 // wrappers non weak if there is pending activity. | |
338 DOMObjectMap active_map = getActiveDOMObjectMap().impl(); | |
339 for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); | |
340 it != end; ++it) { | |
341 void* obj = it->first; | |
342 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second); | |
343 ASSERT(wrapper.IsWeak()); | 338 ASSERT(wrapper.IsWeak()); |
344 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); | 339 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); |
345 switch (type) { | 340 switch (type) { |
346 #define MAKE_CASE(TYPE, NAME) \ | 341 #define MAKE_CASE(TYPE, NAME) \ |
347 case V8ClassIndex::TYPE: { \ | 342 case V8ClassIndex::TYPE: { \ |
348 NAME* impl = static_cast<NAME*>(obj); \ | 343 NAME* impl = static_cast<NAME*>(object); \ |
349 if (impl->hasPendingActivity()) \ | 344 if (impl->hasPendingActivity()) \ |
350 wrapper.ClearWeak(); \ | 345 wrapper.ClearWeak(); \ |
351 break; \ | 346 break; \ |
352 } | 347 } |
353 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) | 348 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) |
354 default: | 349 default: |
355 ASSERT(false); | 350 ASSERT(false); |
356 #undef MAKE_CASE | 351 #undef MAKE_CASE |
357 } | 352 } |
358 | 353 |
359 // Additional handling of message port ensuring that entangled ports also | 354 // Additional handling of message port ensuring that entangled ports also |
360 // have their wrappers entangled. This should ideally be handled when the | 355 // have their wrappers entangled. This should ideally be handled when the |
361 // ports are actually entangled in MessagePort::entangle, but to avoid | 356 // ports are actually entangled in MessagePort::entangle, but to avoid |
362 // forking MessagePort.* this is postponed to GC time. Having this postponed | 357 // forking MessagePort.* this is postponed to GC time. Having this postponed |
363 // has the drawback that the wrappers are "entangled/unentangled" for each | 358 // has the drawback that the wrappers are "entangled/unentangled" for each |
364 // GC even though their entnaglement most likely is still the same. | 359 // GC even though their entnaglement most likely is still the same. |
365 if (type == V8ClassIndex::MESSAGEPORT) { | 360 if (type == V8ClassIndex::MESSAGEPORT) { |
366 // Get the port and its entangled port. | 361 // Get the port and its entangled port. |
367 MessagePort* port1 = static_cast<MessagePort*>(obj); | 362 MessagePort* port1 = static_cast<MessagePort*>(object); |
368 MessagePortProxy* port2 = port1->entangledPort(); | 363 MessagePortProxy* port2 = port1->entangledPort(); |
369 if (port2 != NULL) { | 364 if (port2 != NULL) { |
370 // As ports are always entangled in pairs only perform the entanglement | 365 // As ports are always entangled in pairs only perform the entanglement |
371 // once for each pair (see ASSERT in MessagePort::unentangle()). | 366 // once for each pair (see ASSERT in MessagePort::unentangle()). |
372 if (port1 < port2) { | 367 if (port1 < port2) { |
373 v8::Handle<v8::Value> port1_wrapper = | 368 v8::Handle<v8::Value> port1_wrapper = |
374 V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); | 369 V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); |
375 v8::Handle<v8::Value> port2_wrapper = | 370 v8::Handle<v8::Value> port2_wrapper = |
376 V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port2); | 371 V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port2); |
377 ASSERT(port1_wrapper->IsObject()); | 372 ASSERT(port1_wrapper->IsObject()); |
378 v8::Handle<v8::Object>::Cast(port1_wrapper)->SetInternalField( | 373 v8::Handle<v8::Object>::Cast(port1_wrapper)->SetInternalField( |
379 V8Custom::kMessagePortEntangledPortIndex, port2_wrapper); | 374 V8Custom::kMessagePortEntangledPortIndex, port2_wrapper); |
380 ASSERT(port2_wrapper->IsObject()); | 375 ASSERT(port2_wrapper->IsObject()); |
381 v8::Handle<v8::Object>::Cast(port2_wrapper)->SetInternalField( | 376 v8::Handle<v8::Object>::Cast(port2_wrapper)->SetInternalField( |
382 V8Custom::kMessagePortEntangledPortIndex, port1_wrapper); | 377 V8Custom::kMessagePortEntangledPortIndex, port1_wrapper); |
383 } | 378 } |
384 } else { | 379 } else { |
385 // Remove the wrapper entanglement when a port is not entangled. | 380 // Remove the wrapper entanglement when a port is not entangled. |
386 if (V8Proxy::DOMObjectHasJSWrapper(port1)) { | 381 if (V8Proxy::DOMObjectHasJSWrapper(port1)) { |
387 v8::Handle<v8::Value> wrapper = | 382 v8::Handle<v8::Value> wrapper = |
388 V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); | 383 V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); |
389 ASSERT(wrapper->IsObject()); | 384 ASSERT(wrapper->IsObject()); |
390 v8::Handle<v8::Object>::Cast(wrapper)->SetInternalField( | 385 v8::Handle<v8::Object>::Cast(wrapper)->SetInternalField( |
391 V8Custom::kMessagePortEntangledPortIndex, v8::Undefined()); | 386 V8Custom::kMessagePortEntangledPortIndex, v8::Undefined()); |
392 } | 387 } |
393 } | 388 } |
394 } | 389 } |
395 } | 390 } |
| 391 }; |
396 | 392 |
397 // Create object groups. | 393 class GrouperItem { |
398 typedef std::pair<uintptr_t, Node*> GrouperPair; | 394 public: |
399 typedef Vector<GrouperPair> GrouperList; | 395 GrouperItem(uintptr_t group_id, Node* node, v8::Persistent<v8::Object> wrapper
) |
| 396 : group_id_(group_id), node_(node), wrapper_(wrapper) { } |
| 397 |
| 398 uintptr_t group_id() const { return group_id_; } |
| 399 Node* node() const { return node_; } |
| 400 v8::Persistent<v8::Object> wrapper() const { return wrapper_; } |
400 | 401 |
401 DOMNodeMap node_map = getDOMNodeMap().impl(); | 402 private: |
402 GrouperList grouper; | 403 uintptr_t group_id_; |
403 grouper.reserveCapacity(node_map.size()); | 404 Node* node_; |
| 405 v8::Persistent<v8::Object> wrapper_; |
| 406 }; |
404 | 407 |
405 for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end(); | 408 bool operator<(const GrouperItem& a, const GrouperItem& b) { |
406 it != end; ++it) { | 409 return a.group_id() < b.group_id(); |
407 Node* node = it->first; | 410 } |
408 | 411 |
| 412 typedef Vector<GrouperItem> GrouperList; |
| 413 |
| 414 class ObjectGrouperVisitor : public DOMWrapperMap<Node>::Visitor { |
| 415 public: |
| 416 ObjectGrouperVisitor() { |
| 417 // TODO(abarth): grouper_.reserveCapacity(node_map.size()); ? |
| 418 } |
| 419 |
| 420 void visitDOMWrapper(Node* node, v8::Persistent<v8::Object> wrapper) { |
409 // If the node is in document, put it in the ownerDocument's object group. | 421 // If the node is in document, put it in the ownerDocument's object group. |
410 // | 422 // |
411 // If an image element was created by JavaScript "new Image", | 423 // If an image element was created by JavaScript "new Image", |
412 // it is not in a document. However, if the load event has not | 424 // it is not in a document. However, if the load event has not |
413 // been fired (still onloading), it is treated as in the document. | 425 // been fired (still onloading), it is treated as in the document. |
414 // | 426 // |
415 // Otherwise, the node is put in an object group identified by the root | 427 // Otherwise, the node is put in an object group identified by the root |
416 // elment of the tree to which it belongs. | 428 // elment of the tree to which it belongs. |
417 uintptr_t group_id; | 429 uintptr_t group_id; |
418 if (node->inDocument() || | 430 if (node->inDocument() || |
419 (node->hasTagName(HTMLNames::imgTag) && | 431 (node->hasTagName(HTMLNames::imgTag) && |
420 !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) { | 432 !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) { |
421 group_id = reinterpret_cast<uintptr_t>(node->document()); | 433 group_id = reinterpret_cast<uintptr_t>(node->document()); |
422 } else { | 434 } else { |
423 Node* root = node; | 435 Node* root = node; |
424 while (root->parent()) | 436 while (root->parent()) |
425 root = root->parent(); | 437 root = root->parent(); |
426 | 438 |
427 // If the node is alone in its DOM tree (doesn't have a parent or any | 439 // If the node is alone in its DOM tree (doesn't have a parent or any |
428 // children) then the group will be filtered out later anyway. | 440 // children) then the group will be filtered out later anyway. |
429 if (root == node && !node->hasChildNodes()) | 441 if (root == node && !node->hasChildNodes()) |
430 continue; | 442 return; |
431 | 443 |
432 group_id = reinterpret_cast<uintptr_t>(root); | 444 group_id = reinterpret_cast<uintptr_t>(root); |
433 } | 445 } |
434 grouper.append(GrouperPair(group_id, node)); | 446 grouper_.append(GrouperItem(group_id, node, wrapper)); |
435 } | 447 } |
436 | 448 |
437 // Group by sorting by the group id. This will use the std::pair operator<, | 449 void ApplyGrouping() { |
438 // which will really sort by both the group id and the Node*. However the | 450 // Group by sorting by the group id. |
439 // Node* is only involved to sort within a group id, so it will be fine. | 451 std::sort(grouper_.begin(), grouper_.end()); |
440 std::sort(grouper.begin(), grouper.end()); | |
441 | 452 |
442 // TODO(deanm): Should probably work in iterators here, but indexes were | 453 // TODO(deanm): Should probably work in iterators here, but indexes were |
443 // easier for my simple mind. | 454 // easier for my simple mind. |
444 for (size_t i = 0; i < grouper.size(); ) { | 455 for (size_t i = 0; i < grouper_.size(); ) { |
445 // Seek to the next key (or the end of the list). | 456 // Seek to the next key (or the end of the list). |
446 size_t next_key_index = grouper.size(); | 457 size_t next_key_index = grouper_.size(); |
447 for (size_t j = i; j < grouper.size(); ++j) { | 458 for (size_t j = i; j < grouper_.size(); ++j) { |
448 if (grouper[i].first != grouper[j].first) { | 459 if (grouper_[i].group_id() != grouper_[j].group_id()) { |
449 next_key_index = j; | 460 next_key_index = j; |
450 break; | 461 break; |
451 } | |
452 } | |
453 | |
454 ASSERT(next_key_index > i); | |
455 | |
456 // We only care about a group if it has more than one object. If it only | |
457 // has one object, it has nothing else that needs to be kept alive. | |
458 if (next_key_index - i <= 1) { | |
459 i = next_key_index; | |
460 continue; | |
461 } | |
462 | |
463 Vector<v8::Persistent<v8::Value> > group; | |
464 group.reserveCapacity(next_key_index - i); | |
465 for (; i < next_key_index; ++i) { | |
466 Node* node = grouper[i].second; | |
467 v8::Persistent<v8::Value> wrapper = | |
468 getDOMNodeMap().get(node); | |
469 if (!wrapper.IsEmpty()) | |
470 group.append(wrapper); | |
471 // If the node is styled and there is a wrapper for the inline | |
472 // style declaration, we need to keep that style declaration | |
473 // wrapper alive as well, so we add it to the object group. | |
474 if (node->isStyledElement()) { | |
475 StyledElement* element = reinterpret_cast<StyledElement*>(node); | |
476 CSSStyleDeclaration* style = element->inlineStyleDecl(); | |
477 if (style != NULL) { | |
478 wrapper = getDOMObjectMap().get(style); | |
479 if (!wrapper.IsEmpty()) | |
480 group.append(wrapper); | |
481 } | 462 } |
482 } | 463 } |
| 464 |
| 465 ASSERT(next_key_index > i); |
| 466 |
| 467 // We only care about a group if it has more than one object. If it only |
| 468 // has one object, it has nothing else that needs to be kept alive. |
| 469 if (next_key_index - i <= 1) { |
| 470 i = next_key_index; |
| 471 continue; |
| 472 } |
| 473 |
| 474 Vector<v8::Persistent<v8::Value> > group; |
| 475 group.reserveCapacity(next_key_index - i); |
| 476 for (; i < next_key_index; ++i) { |
| 477 Node* node = grouper_[i].node(); |
| 478 v8::Persistent<v8::Value> wrapper = grouper_[i].wrapper(); |
| 479 if (!wrapper.IsEmpty()) |
| 480 group.append(wrapper); |
| 481 /* TODO(abarth): Re-enabled this code to avoid GCing these wrappers! |
| 482 Currently this depends on looking up the wrapper |
| 483 during a GC, but we don't know which isolated world |
| 484 we're in, so it's unclear which map to look in... |
| 485 |
| 486 // If the node is styled and there is a wrapper for the inline |
| 487 // style declaration, we need to keep that style declaration |
| 488 // wrapper alive as well, so we add it to the object group. |
| 489 if (node->isStyledElement()) { |
| 490 StyledElement* element = reinterpret_cast<StyledElement*>(node); |
| 491 CSSStyleDeclaration* style = element->inlineStyleDecl(); |
| 492 if (style != NULL) { |
| 493 wrapper = getDOMObjectMap().get(style); |
| 494 if (!wrapper.IsEmpty()) |
| 495 group.append(wrapper); |
| 496 } |
| 497 } |
| 498 */ |
| 499 } |
| 500 |
| 501 if (group.size() > 1) |
| 502 v8::V8::AddObjectGroup(&group[0], group.size()); |
| 503 |
| 504 ASSERT(i == next_key_index); |
483 } | 505 } |
| 506 } |
| 507 |
| 508 private: |
| 509 GrouperList grouper_; |
| 510 }; |
484 | 511 |
485 if (group.size() > 1) | 512 // Create object groups for DOM tree nodes. |
486 v8::V8::AddObjectGroup(&group[0], group.size()); | 513 static void GCPrologue() |
487 | |
488 ASSERT(i == next_key_index); | |
489 } | |
490 } | |
491 | |
492 | |
493 static void GCEpilogue() | |
494 { | 514 { |
495 v8::HandleScope scope; | 515 v8::HandleScope scope; |
496 | 516 |
497 // Run through all objects with pending activity making their wrappers weak | 517 #ifndef NDEBUG |
498 // again. | 518 DOMObjectVisitor domObjectVisitor; |
499 DOMObjectMap active_map = getActiveDOMObjectMap().impl(); | 519 visitDOMObjectsInCurrentThread(&domObjectVisitor); |
500 for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); | 520 #endif |
501 it != end; ++it) { | 521 |
502 void* obj = it->first; | 522 // Run through all objects with possible pending activity making their |
503 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second); | 523 // wrappers non weak if there is pending activity. |
| 524 GCPrologueVisitor prologueVisitor; |
| 525 visitActiveDOMObjectsInCurrentThread(&prologueVisitor); |
| 526 |
| 527 // Create object groups. |
| 528 ObjectGrouperVisitor objectGrouperVisitor; |
| 529 visitDOMNodesInCurrentThread(&objectGrouperVisitor); |
| 530 objectGrouperVisitor.ApplyGrouping(); |
| 531 } |
| 532 |
| 533 class GCEpilogueVisitor : public DOMWrapperMap<void>::Visitor { |
| 534 public: |
| 535 void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) |
| 536 { |
504 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); | 537 V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); |
505 switch (type) { | 538 switch (type) { |
506 #define MAKE_CASE(TYPE, NAME) \ | 539 #define MAKE_CASE(TYPE, NAME) \ |
507 case V8ClassIndex::TYPE: { \ | 540 case V8ClassIndex::TYPE: { \ |
508 NAME* impl = static_cast<NAME*>(obj); \ | 541 NAME* impl = static_cast<NAME*>(object); \ |
509 if (impl->hasPendingActivity()) { \ | 542 if (impl->hasPendingActivity()) { \ |
510 ASSERT(!wrapper.IsWeak()); \ | 543 ASSERT(!wrapper.IsWeak()); \ |
511 wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \ | 544 wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \ |
512 } \ | 545 } \ |
513 break; \ | 546 break; \ |
514 } | 547 } |
515 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) | 548 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) |
516 default: | 549 default: |
517 ASSERT(false); | 550 ASSERT(false); |
518 #undef MAKE_CASE | 551 #undef MAKE_CASE |
519 } | 552 } |
520 } | 553 } |
| 554 }; |
| 555 |
| 556 static void GCEpilogue() |
| 557 { |
| 558 v8::HandleScope scope; |
| 559 |
| 560 // Run through all objects with pending activity making their wrappers weak |
| 561 // again. |
| 562 GCEpilogueVisitor epilogueVisitor; |
| 563 visitActiveDOMObjectsInCurrentThread(&epilogueVisitor); |
521 | 564 |
522 #ifndef NDEBUG | 565 #ifndef NDEBUG |
523 // Check all survivals are weak. | 566 // Check all survivals are weak. |
524 EnumerateDOMObjectMap(getDOMObjectMap().impl()); | 567 DOMObjectVisitor domObjectVisitor; |
525 EnumerateDOMNodeMap(getDOMNodeMap().impl()); | 568 visitDOMObjectsInCurrentThread(&domObjectVisitor); |
| 569 |
| 570 EnsureWeakDOMNodeVisitor weakDOMNodeVisitor; |
| 571 visitDOMNodesInCurrentThread(&weakDOMNodeVisitor); |
| 572 |
526 EnumerateDOMObjectMap(gc_protected_map()); | 573 EnumerateDOMObjectMap(gc_protected_map()); |
527 EnumerateGlobalHandles(); | 574 EnumerateGlobalHandles(); |
528 #undef USE_VAR | 575 #undef USE_VAR |
529 #endif | 576 #endif |
530 } | 577 } |
531 | 578 |
532 | 579 |
533 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap; | 580 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap; |
534 | 581 |
535 bool AllowAllocation::m_current = false; | 582 bool AllowAllocation::m_current = false; |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
990 ChromiumBridge::notifyJSOutOfMemory(frame); | 1037 ChromiumBridge::notifyJSOutOfMemory(frame); |
991 | 1038 |
992 // Disable JS. | 1039 // Disable JS. |
993 Settings* settings = frame->settings(); | 1040 Settings* settings = frame->settings(); |
994 ASSERT(settings); | 1041 ASSERT(settings); |
995 settings->setJavaScriptEnabled(false); | 1042 settings->setJavaScriptEnabled(false); |
996 | 1043 |
997 return true; | 1044 return true; |
998 } | 1045 } |
999 | 1046 |
| 1047 void V8Proxy::evaluateInNewWorld(const Vector<ScriptSourceCode>& sources) |
| 1048 { |
| 1049 InitContextIfNeeded(); |
| 1050 V8IsolatedWorld::evaluate(sources, this); |
| 1051 } |
| 1052 |
1000 void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources) | 1053 void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources) |
1001 { | 1054 { |
1002 InitContextIfNeeded(); | 1055 InitContextIfNeeded(); |
1003 | 1056 |
1004 v8::HandleScope handleScope; | 1057 v8::HandleScope handleScope; |
1005 | 1058 |
1006 // Set up the DOM window as the prototype of the new global object. | 1059 // Set up the DOM window as the prototype of the new global object. |
1007 v8::Handle<v8::Context> windowContext = m_context; | 1060 v8::Handle<v8::Context> windowContext = m_context; |
1008 v8::Handle<v8::Object> windowGlobal = windowContext->Global(); | 1061 v8::Handle<v8::Object> windowGlobal = windowContext->Global(); |
1009 v8::Handle<v8::Value> windowWrapper = | 1062 v8::Handle<v8::Value> windowWrapper = |
(...skipping 1101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2111 extensionNames[index++] = it->extension->name(); | 2164 extensionNames[index++] = it->extension->name(); |
2112 } | 2165 } |
2113 v8::ExtensionConfiguration extensions(index, extensionNames); | 2166 v8::ExtensionConfiguration extensions(index, extensionNames); |
2114 result = v8::Context::New(&extensions, globalTemplate, global); | 2167 result = v8::Context::New(&extensions, globalTemplate, global); |
2115 delete [] extensionNames; | 2168 delete [] extensionNames; |
2116 extensionNames = 0; | 2169 extensionNames = 0; |
2117 | 2170 |
2118 return result; | 2171 return result; |
2119 } | 2172 } |
2120 | 2173 |
| 2174 bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context, |
| 2175 DOMWindow* window) |
| 2176 { |
| 2177 v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__"); |
| 2178 if (implicit_proto_string.IsEmpty()) |
| 2179 return false; |
| 2180 |
| 2181 // Create a new JS window object and use it as the prototype for the |
| 2182 // shadow global object. |
| 2183 v8::Handle<v8::Function> window_constructor = |
| 2184 GetConstructor(V8ClassIndex::DOMWINDOW); |
| 2185 v8::Local<v8::Object> js_window = |
| 2186 SafeAllocation::NewInstance(window_constructor); |
| 2187 // Bail out if allocation failed. |
| 2188 if (js_window.IsEmpty()) |
| 2189 return false; |
| 2190 |
| 2191 // Wrap the window. |
| 2192 SetDOMWrapper(js_window, |
| 2193 V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), |
| 2194 window); |
| 2195 |
| 2196 window->ref(); |
| 2197 V8Proxy::SetJSWrapperForDOMObject(window, |
| 2198 v8::Persistent<v8::Object>::New(js_window)); |
| 2199 |
| 2200 // Insert the window instance as the prototype of the shadow object. |
| 2201 v8::Handle<v8::Object> v8_global = context->Global(); |
| 2202 v8_global->Set(implicit_proto_string, js_window); |
| 2203 return true; |
| 2204 } |
| 2205 |
2121 // Create a new environment and setup the global object. | 2206 // Create a new environment and setup the global object. |
2122 // | 2207 // |
2123 // The global object corresponds to a DOMWindow instance. However, to | 2208 // The global object corresponds to a DOMWindow instance. However, to |
2124 // allow properties of the JS DOMWindow instance to be shadowed, we | 2209 // allow properties of the JS DOMWindow instance to be shadowed, we |
2125 // use a shadow object as the global object and use the JS DOMWindow | 2210 // use a shadow object as the global object and use the JS DOMWindow |
2126 // instance as the prototype for that shadow object. The JS DOMWindow | 2211 // instance as the prototype for that shadow object. The JS DOMWindow |
2127 // instance is undetectable from javascript code because the __proto__ | 2212 // instance is undetectable from javascript code because the __proto__ |
2128 // accessors skip that object. | 2213 // accessors skip that object. |
2129 // | 2214 // |
2130 // The shadow object and the DOMWindow instance are seen as one object | 2215 // The shadow object and the DOMWindow instance are seen as one object |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2198 return; | 2283 return; |
2199 } | 2284 } |
2200 #ifndef NDEBUG | 2285 #ifndef NDEBUG |
2201 RegisterGlobalHandle(PROXY, this, m_global); | 2286 RegisterGlobalHandle(PROXY, this, m_global); |
2202 #endif | 2287 #endif |
2203 } | 2288 } |
2204 | 2289 |
2205 // Allocate strings used during initialization. | 2290 // Allocate strings used during initialization. |
2206 v8::Handle<v8::String> object_string = v8::String::New("Object"); | 2291 v8::Handle<v8::String> object_string = v8::String::New("Object"); |
2207 v8::Handle<v8::String> prototype_string = v8::String::New("prototype"); | 2292 v8::Handle<v8::String> prototype_string = v8::String::New("prototype"); |
2208 v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__"); | |
2209 // Bail out if allocation failed. | 2293 // Bail out if allocation failed. |
2210 if (object_string.IsEmpty() || | 2294 if (object_string.IsEmpty() || |
2211 prototype_string.IsEmpty() || | 2295 prototype_string.IsEmpty()) { |
2212 implicit_proto_string.IsEmpty()) { | |
2213 DisposeContextHandles(); | 2296 DisposeContextHandles(); |
2214 return; | 2297 return; |
2215 } | 2298 } |
2216 | 2299 |
2217 // Allocate clone cache and pre-allocated objects | 2300 // Allocate clone cache and pre-allocated objects |
2218 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast( | 2301 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast( |
2219 m_global->Get(object_string)); | 2302 m_global->Get(object_string)); |
2220 m_object_prototype = v8::Persistent<v8::Value>::New( | 2303 m_object_prototype = v8::Persistent<v8::Value>::New( |
2221 object->Get(prototype_string)); | 2304 object->Get(prototype_string)); |
2222 m_wrapper_boilerplates = v8::Persistent<v8::Array>::New( | 2305 m_wrapper_boilerplates = v8::Persistent<v8::Array>::New( |
2223 v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT)); | 2306 v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT)); |
2224 // Bail out if allocation failed. | 2307 // Bail out if allocation failed. |
2225 if (m_object_prototype.IsEmpty()) { | 2308 if (m_object_prototype.IsEmpty()) { |
2226 DisposeContextHandles(); | 2309 DisposeContextHandles(); |
2227 return; | 2310 return; |
2228 } | 2311 } |
2229 #ifndef NDEBUG | 2312 #ifndef NDEBUG |
2230 RegisterGlobalHandle(PROXY, this, m_object_prototype); | 2313 RegisterGlobalHandle(PROXY, this, m_object_prototype); |
2231 RegisterGlobalHandle(PROXY, this, m_wrapper_boilerplates); | 2314 RegisterGlobalHandle(PROXY, this, m_wrapper_boilerplates); |
2232 #endif | 2315 #endif |
2233 | 2316 |
2234 // Create a new JS window object and use it as the prototype for the | 2317 if (!installDOMWindow(context, m_frame->domWindow())) |
2235 // shadow global object. | |
2236 v8::Handle<v8::Function> window_constructor = | |
2237 GetConstructor(V8ClassIndex::DOMWINDOW); | |
2238 v8::Local<v8::Object> js_window = | |
2239 SafeAllocation::NewInstance(window_constructor); | |
2240 // Bail out if allocation failed. | |
2241 if (js_window.IsEmpty()) { | |
2242 DisposeContextHandles(); | 2318 DisposeContextHandles(); |
2243 return; | |
2244 } | |
2245 | |
2246 DOMWindow* window = m_frame->domWindow(); | |
2247 | |
2248 // Wrap the window. | |
2249 SetDOMWrapper(js_window, | |
2250 V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), | |
2251 window); | |
2252 | |
2253 window->ref(); | |
2254 V8Proxy::SetJSWrapperForDOMObject(window, | |
2255 v8::Persistent<v8::Object>::New(js_window)); | |
2256 | |
2257 // Insert the window instance as the prototype of the shadow object. | |
2258 v8::Handle<v8::Object> v8_global = context->Global(); | |
2259 v8_global->Set(implicit_proto_string, js_window); | |
2260 | 2319 |
2261 updateDocument(); | 2320 updateDocument(); |
2262 | 2321 |
2263 SetSecurityToken(); | 2322 SetSecurityToken(); |
2264 | 2323 |
2265 m_frame->loader()->dispatchWindowObjectAvailable(); | 2324 m_frame->loader()->dispatchWindowObjectAvailable(); |
2266 } | 2325 } |
2267 | 2326 |
2268 | 2327 |
2269 void V8Proxy::SetDOMException(int exception_code) | 2328 void V8Proxy::SetDOMException(int exception_code) |
(...skipping 1205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3475 v8::HandleScope scope; | 3534 v8::HandleScope scope; |
3476 if (!context->GetData()->IsObject()) { | 3535 if (!context->GetData()->IsObject()) { |
3477 return -1; | 3536 return -1; |
3478 } | 3537 } |
3479 v8::Handle<v8::Value> data = context->GetData()->ToObject()->Get( | 3538 v8::Handle<v8::Value> data = context->GetData()->ToObject()->Get( |
3480 v8::String::New(kContextDebugDataValue)); | 3539 v8::String::New(kContextDebugDataValue)); |
3481 return data->IsInt32() ? data->Int32Value() : -1; | 3540 return data->IsInt32() ? data->Int32Value() : -1; |
3482 } | 3541 } |
3483 | 3542 |
3484 } // namespace WebCore | 3543 } // namespace WebCore |
OLD | NEW |