Web Inspector: support stable remote object ids
authoryurys@chromium.org <yurys@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Mar 2013 15:18:54 +0000 (15:18 +0000)
committeryurys@chromium.org <yurys@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Mar 2013 15:18:54 +0000 (15:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=109908

Reviewed by Pavel Feldman.

Source/WebCore:

Introduced a map from javascript object to its id. It guarantees
that object is assined id only once (unless it is explicitely
released). The map is per execution context and is stored in
InjectedScriptManager.

Test: inspector-protocol/persistent-id.html

* bindings/js/JSInjectedScriptHostCustom.cpp:
(WebCore::JSInjectedScriptHost::objectId):
(WebCore):
(WebCore::JSInjectedScriptHost::releaseObjectId):
* bindings/js/ScriptObject.h:
(WTF):
(WTF::ScriptObjectHash::hash):
(WTF::ScriptObjectHash::equal):
(ScriptObjectHash):
* bindings/v8/ScriptObject.h:
(WTF):
(WTF::ScriptObjectHash::hash):
(WTF::ScriptObjectHash::equal):
(ScriptObjectHash):
* bindings/v8/custom/V8InjectedScriptHostCustom.cpp:
(WebCore::V8InjectedScriptHost::objectIdMethodCustom):
(WebCore):
(WebCore::V8InjectedScriptHost::releaseObjectIdMethodCustom):
* inspector/InjectedScriptHost.cpp:
(WebCore::InjectedScriptHost::create):
(WebCore::InjectedScriptHost::InjectedScriptHost):
(WebCore::InjectedScriptHost::disconnect):
(WebCore::InjectedScriptHost::objectId):
(WebCore):
(WebCore::InjectedScriptHost::releaseObjectId):
* inspector/InjectedScriptHost.h:
(WebCore):
(InjectedScriptHost):
* inspector/InjectedScriptHost.idl:
* inspector/InjectedScriptManager.cpp:
(InjectedScriptManager::ObjectIdMap):
(WebCore::InjectedScriptManager::ObjectIdMap::ObjectIdMap):
(WebCore::InjectedScriptManager::ObjectIdMap::objectId):
(WebCore::InjectedScriptManager::ObjectIdMap::releaseObjectId):
(WebCore):
(WebCore::InjectedScriptManager::InjectedScriptManager):
(WebCore::InjectedScriptManager::discardInjectedScripts):
(WebCore::InjectedScriptManager::discardInjectedScriptsFor):
(WebCore::InjectedScriptManager::objectId):
(WebCore::InjectedScriptManager::releaseObjectId):
* inspector/InjectedScriptManager.h:
(InjectedScriptManager):
* inspector/InjectedScriptSource.js:
(.):

LayoutTests:

Test that same object will have same id if requested several times.

* inspector-protocol/persistent-id-expected.txt: Added.
* inspector-protocol/persistent-id.html: Added.
* inspector/console/command-line-api-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@144924 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector-protocol/persistent-id-expected.txt [new file with mode: 0644]
LayoutTests/inspector-protocol/persistent-id.html [new file with mode: 0644]
LayoutTests/inspector/console/command-line-api-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp
Source/WebCore/bindings/js/ScriptObject.h
Source/WebCore/bindings/v8/ScriptObject.h
Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp
Source/WebCore/inspector/InjectedScriptHost.cpp
Source/WebCore/inspector/InjectedScriptHost.h
Source/WebCore/inspector/InjectedScriptHost.idl
Source/WebCore/inspector/InjectedScriptManager.cpp
Source/WebCore/inspector/InjectedScriptManager.h
Source/WebCore/inspector/InjectedScriptSource.js

index a570995..5d6ee7c 100644 (file)
@@ -1,3 +1,16 @@
+2013-03-05  Yury Semikhatsky  <yurys@chromium.org>
+
+        Web Inspector: support stable remote object ids
+        https://bugs.webkit.org/show_bug.cgi?id=109908
+
+        Reviewed by Pavel Feldman.
+
+        Test that same object will have same id if requested several times.
+
+        * inspector-protocol/persistent-id-expected.txt: Added.
+        * inspector-protocol/persistent-id.html: Added.
+        * inspector/console/command-line-api-expected.txt:
+
 2013-03-06  Krzysztof Czech  <k.czech@samsung.com>
 
         Unreviewed EFL gardening.
diff --git a/LayoutTests/inspector-protocol/persistent-id-expected.txt b/LayoutTests/inspector-protocol/persistent-id-expected.txt
new file mode 100644 (file)
index 0000000..f45cf54
--- /dev/null
@@ -0,0 +1,5 @@
+Test that evaluating same object will result in same remote object id.Bug 109908.
+
+ SUCCESS: evaluated to an object with same id
+SUCCESS: evaluated to an object with id different from released one
+
diff --git a/LayoutTests/inspector-protocol/persistent-id.html b/LayoutTests/inspector-protocol/persistent-id.html
new file mode 100644 (file)
index 0000000..c7b0141
--- /dev/null
@@ -0,0 +1,51 @@
+<html>
+<head>
+<script type="text/javascript" src="../http/tests/inspector-protocol/resources/protocol-test.js"></script>
+<script>
+var aGlobalObject = {};
+
+function test()
+{
+
+    InspectorTest.sendCommand("Runtime.evaluate", { "expression": "aGlobalObject" }, didEvaluate1.bind(this));
+
+    function didEvaluate1(messageObject)
+    {
+        var objectId = messageObject.result.result.objectId;
+        InspectorTest.sendCommand("Runtime.evaluate", { "expression": "aGlobalObject" }, didEvaluate2.bind(this, objectId));
+    }
+
+    function didEvaluate2(expectedObjectId, messageObject)
+    {
+        var objectId = messageObject.result.result.objectId;
+        if (expectedObjectId === objectId)
+            InspectorTest.log("SUCCESS: evaluated to an object with same id");
+        else {
+            InspectorTest.log("FAIL: object ids are different, expected " + expectedObjectId + " found " + objectId);
+            return InspectorTest.completeTest();
+        }
+        InspectorTest.sendCommand("Runtime.releaseObject", { "objectId": objectId }, didReleaseObjectId.bind(this, objectId));
+    }
+
+    function didReleaseObjectId(releasedObjectId, messageObject)
+    {
+        InspectorTest.sendCommand("Runtime.evaluate", { "expression": "aGlobalObject" }, didEvaluate3.bind(this, releasedObjectId));
+    }
+    function didEvaluate3(releasedObjectId, messageObject)
+    {
+        var objectId = messageObject.result.result.objectId;
+        if (releasedObjectId === objectId) {
+            InspectorTest.log("FAIL: object id is the same as was released");
+            return InspectorTest.completeTest();
+        } else
+            InspectorTest.log("SUCCESS: evaluated to an object with id different from released one");
+        InspectorTest.completeTest();
+    }
+
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test that evaluating same object will result in same remote object id.<a href="https://bugs.webkit.org/show_bug.cgi?id=109908">Bug 109908.</p>
+</body>
+</html>
index b0ec879..0964e76 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 1182: The console function $() has changed from $=getElementById(id) to $=querySelector(selector). You might try $("#%s")
+CONSOLE MESSAGE: line 1184: The console function $() has changed from $=getElementById(id) to $=querySelector(selector). You might try $("#%s")
 Tests that command line api works.
 
 
index 8cc8876..22b26dc 100644 (file)
@@ -1,3 +1,62 @@
+2013-03-05  Yury Semikhatsky  <yurys@chromium.org>
+
+        Web Inspector: support stable remote object ids
+        https://bugs.webkit.org/show_bug.cgi?id=109908
+
+        Reviewed by Pavel Feldman.
+
+        Introduced a map from javascript object to its id. It guarantees
+        that object is assined id only once (unless it is explicitely
+        released). The map is per execution context and is stored in
+        InjectedScriptManager.
+
+        Test: inspector-protocol/persistent-id.html
+
+        * bindings/js/JSInjectedScriptHostCustom.cpp:
+        (WebCore::JSInjectedScriptHost::objectId):
+        (WebCore):
+        (WebCore::JSInjectedScriptHost::releaseObjectId):
+        * bindings/js/ScriptObject.h:
+        (WTF):
+        (WTF::ScriptObjectHash::hash):
+        (WTF::ScriptObjectHash::equal):
+        (ScriptObjectHash):
+        * bindings/v8/ScriptObject.h:
+        (WTF):
+        (WTF::ScriptObjectHash::hash):
+        (WTF::ScriptObjectHash::equal):
+        (ScriptObjectHash):
+        * bindings/v8/custom/V8InjectedScriptHostCustom.cpp:
+        (WebCore::V8InjectedScriptHost::objectIdMethodCustom):
+        (WebCore):
+        (WebCore::V8InjectedScriptHost::releaseObjectIdMethodCustom):
+        * inspector/InjectedScriptHost.cpp:
+        (WebCore::InjectedScriptHost::create):
+        (WebCore::InjectedScriptHost::InjectedScriptHost):
+        (WebCore::InjectedScriptHost::disconnect):
+        (WebCore::InjectedScriptHost::objectId):
+        (WebCore):
+        (WebCore::InjectedScriptHost::releaseObjectId):
+        * inspector/InjectedScriptHost.h:
+        (WebCore):
+        (InjectedScriptHost):
+        * inspector/InjectedScriptHost.idl:
+        * inspector/InjectedScriptManager.cpp:
+        (InjectedScriptManager::ObjectIdMap):
+        (WebCore::InjectedScriptManager::ObjectIdMap::ObjectIdMap):
+        (WebCore::InjectedScriptManager::ObjectIdMap::objectId):
+        (WebCore::InjectedScriptManager::ObjectIdMap::releaseObjectId):
+        (WebCore):
+        (WebCore::InjectedScriptManager::InjectedScriptManager):
+        (WebCore::InjectedScriptManager::discardInjectedScripts):
+        (WebCore::InjectedScriptManager::discardInjectedScriptsFor):
+        (WebCore::InjectedScriptManager::objectId):
+        (WebCore::InjectedScriptManager::releaseObjectId):
+        * inspector/InjectedScriptManager.h:
+        (InjectedScriptManager):
+        * inspector/InjectedScriptSource.js:
+        (.):
+
 2013-03-06  Marja Hölttä  <marja@chromium.org>
 
         REGRESSION(r144617): Wrong usage of overwritten variable in toDOMWindow (V8Binding.cpp)
index 0f15e4b..f30a7c9 100644 (file)
@@ -263,6 +263,31 @@ JSValue JSInjectedScriptHost::inspect(ExecState* exec)
     return jsUndefined();
 }
 
+JSValue JSInjectedScriptHost::objectId(ExecState* exec)
+{
+    if (exec->argumentCount() < 1)
+        return jsUndefined();
+    JSObject* jsObject = exec->argument(0).getObject();
+    if (!jsObject)
+        return jsUndefined();
+    ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
+    ScriptObject object(globalExec, jsObject);
+    return jsNumber(impl()->objectId(object));
+}
+
+JSValue JSInjectedScriptHost::releaseObjectId(ExecState* exec)
+{
+    if (exec->argumentCount() < 1)
+        return jsUndefined();
+    JSObject* jsObject = exec->argument(0).getObject();
+    if (!jsObject)
+        return jsUndefined();
+    ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
+    ScriptObject object(globalExec, jsObject);
+    impl()->releaseObjectId(object);
+    return jsUndefined();
+}
+
 JSValue JSInjectedScriptHost::databaseId(ExecState* exec)
 {
     if (exec->argumentCount() < 1)
index 09133b7..24d46b1 100644 (file)
@@ -68,4 +68,30 @@ namespace WebCore {
 
 }
 
+namespace WTF {
+
+struct ScriptObjectHash {
+    static unsigned hash(const WebCore::ScriptObject& key)
+    {
+        return DefaultHash<JSC::JSObject*>::Hash::hash(key.jsObject());
+    }
+    static bool equal(const WebCore::ScriptObject& a, const WebCore::ScriptObject& b)
+    {
+        return a == b;
+    }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+template<> struct DefaultHash<WebCore::ScriptObject> {
+    typedef ScriptObjectHash Hash;
+};
+
+template<> struct HashTraits<WebCore::ScriptObject> : GenericHashTraits<WebCore::ScriptObject> {
+    static const bool emptyValueIsZero = true;
+    static const bool needsDestruction = true;
+    static void constructDeletedValue(WebCore::ScriptObject& slot) { new (NotNull, &slot) WebCore::ScriptObject(); }
+    static bool isDeletedValue(WebCore::ScriptObject value) { return value.hasNoValue(); }
+};
+
+}
+
 #endif // ScriptObject_h
index 1c47a60..ea1579c 100644 (file)
@@ -66,4 +66,31 @@ namespace WebCore {
 
 }
 
+namespace WTF {
+
+struct ScriptObjectHash {
+    static unsigned hash(const WebCore::ScriptObject& key)
+    {
+        return key.v8Object()->GetIdentityHash();
+    }
+    static bool equal(const WebCore::ScriptObject& a, const WebCore::ScriptObject& b)
+    {
+        return a == b;
+    }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+template<> struct DefaultHash<WebCore::ScriptObject> {
+    typedef ScriptObjectHash Hash;
+};
+
+template<> struct HashTraits<WebCore::ScriptObject> : GenericHashTraits<WebCore::ScriptObject> {
+    static const bool emptyValueIsZero = true;
+    static const bool needsDestruction = true;
+    static void constructDeletedValue(WebCore::ScriptObject& slot) { new (NotNull, &slot) WebCore::ScriptObject(); }
+    static bool isDeletedValue(WebCore::ScriptObject value) { return value.hasNoValue(); }
+};
+
+}
+
+
 #endif // ScriptObject_h
index e63698f..68cd818 100644 (file)
@@ -282,6 +282,30 @@ v8::Handle<v8::Value> V8InjectedScriptHost::inspectMethodCustom(const v8::Argume
     return v8::Undefined();
 }
 
+v8::Handle<v8::Value> V8InjectedScriptHost::objectIdMethodCustom(const v8::Arguments& args)
+{
+    if (args.Length() < 1)
+        return v8::Undefined();
+    v8::Handle<v8::Object> object = args[0]->ToObject();
+    if (object.IsEmpty())
+        return v8::Undefined();
+    InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
+    unsigned id = host->objectId(ScriptObject(ScriptState::current(), object));
+    return v8::Number::New(id);
+}
+
+v8::Handle<v8::Value> V8InjectedScriptHost::releaseObjectIdMethodCustom(const v8::Arguments& args)
+{
+    if (args.Length() < 1)
+        return v8::Undefined();
+    v8::Handle<v8::Object> object = args[0]->ToObject();
+    if (object.IsEmpty())
+        return v8::Undefined();
+    InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
+    unsigned id = host->releaseObjectId(ScriptObject(ScriptState::current(), object));
+    return v8::Number::New(id);
+}
+
 v8::Handle<v8::Value> V8InjectedScriptHost::databaseIdMethodCustom(const v8::Arguments& args)
 {
     if (args.Length() < 1)
index 2e634d4..14425af 100644 (file)
@@ -64,13 +64,14 @@ using namespace std;
 
 namespace WebCore {
 
-PassRefPtr<InjectedScriptHost> InjectedScriptHost::create()
+PassRefPtr<InjectedScriptHost> InjectedScriptHost::create(InjectedScriptManager* manager)
 {
-    return adoptRef(new InjectedScriptHost());
+    return adoptRef(new InjectedScriptHost(manager));
 }
 
-InjectedScriptHost::InjectedScriptHost()
-    : m_inspectorAgent(0)
+InjectedScriptHost::InjectedScriptHost(InjectedScriptManager* manager)
+    : m_manager(manager)
+    , m_inspectorAgent(0)
     , m_consoleAgent(0)
 #if ENABLE(SQL_DATABASE)
     , m_databaseAgent(0)
@@ -87,6 +88,7 @@ InjectedScriptHost::~InjectedScriptHost()
 
 void InjectedScriptHost::disconnect()
 {
+    m_manager = 0;
     m_inspectorAgent = 0;
     m_consoleAgent = 0;
 #if ENABLE(SQL_DATABASE)
@@ -123,6 +125,20 @@ void InjectedScriptHost::copyText(const String& text)
     Pasteboard::generalPasteboard()->writePlainText(text, Pasteboard::CannotSmartReplace);
 }
 
+unsigned InjectedScriptHost::objectId(const ScriptObject& object)
+{
+    if (!m_manager)
+        return 0;
+    return m_manager->objectId(object);
+}
+
+unsigned InjectedScriptHost::releaseObjectId(const ScriptObject& object)
+{
+    if (!m_manager)
+        return 0;
+    return m_manager->releaseObjectId(object);
+}
+
 ScriptValue InjectedScriptHost::InspectableObject::get(ScriptState*)
 {
     return ScriptValue();
index af66b28..f0aad32 100644 (file)
@@ -40,6 +40,7 @@ namespace WebCore {
 
 class Database;
 class InjectedScript;
+class InjectedScriptManager;
 class InspectorAgent;
 class InspectorConsoleAgent;
 class InspectorDOMAgent;
@@ -59,7 +60,7 @@ struct EventListenerInfo;
 
 class InjectedScriptHost : public RefCounted<InjectedScriptHost> {
 public:
-    static PassRefPtr<InjectedScriptHost> create();
+    static PassRefPtr<InjectedScriptHost> create(InjectedScriptManager*);
     ~InjectedScriptHost();
 
     void init(InspectorAgent* inspectorAgent
@@ -106,6 +107,8 @@ public:
 
     void clearConsoleMessages();
     void copyText(const String& text);
+    unsigned objectId(const ScriptObject&);
+    unsigned releaseObjectId(const ScriptObject&);
 #if ENABLE(SQL_DATABASE)
     String databaseIdImpl(Database*);
 #endif
@@ -116,8 +119,9 @@ public:
 #endif
 
 private:
-    InjectedScriptHost();
+    explicit InjectedScriptHost(InjectedScriptManager*);
 
+    InjectedScriptManager* m_manager;
     InspectorAgent* m_inspectorAgent;
     InspectorConsoleAgent* m_consoleAgent;
 #if ENABLE(SQL_DATABASE)
index bec3485..deaaaa1 100644 (file)
@@ -46,6 +46,8 @@
     [Custom] Array getInternalProperties(in any object);
     [Custom] Array getEventListeners(in Node node);
 
+    [Custom] unsigned int objectId(in any object);
+    [Custom] void releaseObjectId(in any object);
     [Custom] DOMString databaseId(in any database);
     [Custom] DOMString storageId(in any storage);
     [Custom] any evaluate(in DOMString text);
index 9756edf..c6fef54 100644 (file)
 
 namespace WebCore {
 
+class InjectedScriptManager::ObjectIdMap {
+    WTF_MAKE_NONCOPYABLE(ObjectIdMap);
+public:
+    ObjectIdMap() : m_nextId(1) { }
+
+    unsigned objectId(const ScriptObject& object)
+    {
+        Map::AddResult result = m_objectToId.add(object, m_nextId);
+        if (result.isNewEntry)
+            ++m_nextId;
+        return result.iterator->value;
+    }
+
+    unsigned releaseObjectId(const ScriptObject& object)
+    {
+        return m_objectToId.take(object);
+    }
+
+private:
+
+    typedef HashMap<ScriptObject, unsigned> Map;
+    Map m_objectToId;
+    unsigned m_nextId;
+};
+
 PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForPage()
 {
     return adoptPtr(new InjectedScriptManager(&InjectedScriptManager::canAccessInspectedWindow));
@@ -55,7 +80,7 @@ PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForWorker()
 
 InjectedScriptManager::InjectedScriptManager(InspectedStateAccessCheck accessCheck)
     : m_nextInjectedScriptId(1)
-    , m_injectedScriptHost(InjectedScriptHost::create())
+    , m_injectedScriptHost(InjectedScriptHost::create(this))
     , m_inspectedStateAccessCheck(accessCheck)
 {
 }
@@ -113,6 +138,7 @@ void InjectedScriptManager::discardInjectedScripts()
 {
     m_idToInjectedScript.clear();
     m_scriptStateToId.clear();
+    m_scriptStateToObjectIdMap.clear();
 }
 
 void InjectedScriptManager::discardInjectedScriptsFor(DOMWindow* window)
@@ -120,6 +146,16 @@ void InjectedScriptManager::discardInjectedScriptsFor(DOMWindow* window)
     if (m_scriptStateToId.isEmpty())
         return;
 
+    // Destroy object id maps.
+    Vector<ScriptState*> scriptStatesToRemove;
+    for (ScriptStateToObjectIdMap::iterator it = m_scriptStateToObjectIdMap.begin(); it != m_scriptStateToObjectIdMap.end(); ++it) {
+        ScriptState* scriptState = it->key;
+        if (window == domWindowFromScriptState(scriptState))
+            scriptStatesToRemove.append(scriptState);
+    }
+    for (size_t i = 0; i < scriptStatesToRemove.size(); i++)
+        m_scriptStateToObjectIdMap.remove(scriptStatesToRemove[i]);
+
     Vector<long> idsToRemove;
     IdToInjectedScriptMap::iterator end = m_idToInjectedScript.end();
     for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != end; ++it) {
@@ -134,7 +170,7 @@ void InjectedScriptManager::discardInjectedScriptsFor(DOMWindow* window)
         m_idToInjectedScript.remove(idsToRemove[i]);
 
     // Now remove script states that have id but no injected script.
-    Vector<ScriptState*> scriptStatesToRemove;
+    scriptStatesToRemove.clear();
     for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
         ScriptState* scriptState = it->key;
         if (window == domWindowFromScriptState(scriptState))
@@ -155,6 +191,30 @@ void InjectedScriptManager::releaseObjectGroup(const String& objectGroup)
         it->value.releaseObjectGroup(objectGroup);
 }
 
+unsigned InjectedScriptManager::objectId(const ScriptObject& object)
+{
+    if (object.hasNoValue())
+        return 0;
+    ScriptState* state = object.scriptState();
+    ObjectIdMap* map = m_scriptStateToObjectIdMap.get(state);
+    if (!map) {
+        ScriptStateToObjectIdMap::AddResult result = m_scriptStateToObjectIdMap.set(state, adoptPtr(new ObjectIdMap()));
+        map = result.iterator->value.get();
+    }
+    return map->objectId(object);
+}
+
+unsigned InjectedScriptManager::releaseObjectId(const ScriptObject& object)
+{
+    if (object.hasNoValue())
+        return 0;
+    ScriptState* state = object.scriptState();
+    ObjectIdMap* map = m_scriptStateToObjectIdMap.get(state);
+    if (!map)
+        return 0;
+    return map->releaseObjectId(object);
+}
+
 String InjectedScriptManager::injectedScriptSource()
 {
     return String(reinterpret_cast<const char*>(InjectedScriptSource_js), sizeof(InjectedScriptSource_js));
index 17f8f75..24f8e29 100644 (file)
@@ -62,6 +62,9 @@ public:
     void discardInjectedScriptsFor(DOMWindow*);
     void releaseObjectGroup(const String& objectGroup);
 
+    unsigned objectId(const ScriptObject&);
+    unsigned releaseObjectId(const ScriptObject&);
+
     typedef bool (*InspectedStateAccessCheck)(ScriptState*);
     InspectedStateAccessCheck inspectedStateAccessCheck() const { return m_inspectedStateAccessCheck; }
 
@@ -81,6 +84,9 @@ private:
     InspectedStateAccessCheck m_inspectedStateAccessCheck;
     typedef HashMap<ScriptState*, int> ScriptStateToId;
     ScriptStateToId m_scriptStateToId;
+    class ObjectIdMap;
+    typedef HashMap<ScriptState*, OwnPtr<ObjectIdMap> > ScriptStateToObjectIdMap;
+    ScriptStateToObjectIdMap m_scriptStateToObjectIdMap;
 };
 
 } // namespace WebCore
index 8613074..fbf96aa 100644 (file)
@@ -77,7 +77,6 @@ function bind(func, thisObject, var_args)
  */
 var InjectedScript = function()
 {
-    this._lastBoundObjectId = 1;
     this._idToWrappedObject = {};
     this._idToObjectGroupName = {};
     this._objectGroups = {};
@@ -223,7 +222,7 @@ InjectedScript.prototype = {
      */
     _bind: function(object, objectGroupName)
     {
-        var id = this._lastBoundObjectId++;
+        var id = InjectedScriptHost.objectId(object);
         this._idToWrappedObject[id] = object;
         var objectId = "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + "}";
         if (objectGroupName) {
@@ -371,6 +370,9 @@ InjectedScript.prototype = {
      */
     _releaseObject: function(id)
     {
+        var object = this._idToWrappedObject[id];
+        if (object)
+            InjectedScriptHost.releaseObjectId(object);
         delete this._idToWrappedObject[id];
         delete this._idToObjectGroupName[id];
     },