| 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 |