IndexedDB: Use ScriptValue instead of SerializedScriptValue when possible
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Sep 2012 23:20:22 +0000 (23:20 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Sep 2012 23:20:22 +0000 (23:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=94023

Patch by Alec Flett <alecflett@chromium.org> on 2012-09-12
Reviewed by Kentaro Hara.

Transition the put/add/update methods to accept direct ScriptValue
objects rather than SerializedScriptValues, to eliminate lots of
redundant deserialization/serialization steps while storing
values.

Also see https://bugs.webkit.org/show_bug.cgi?id=95409 for
followup get/openCursor work, following this.

No new tests, this is a performance refactor of core IDB
functionality. Most existing tests cover correctness. Tests that
might fail include:

storage/indexeddb/objectstore-basics.html
storage/indexeddb/keypath-basics.html
storage/indexeddb/index-basics.html

* Modules/indexeddb/IDBCursor.cpp:
(WebCore::IDBCursor::update):
* Modules/indexeddb/IDBCursor.h:
(IDBCursor):
* Modules/indexeddb/IDBCursor.idl:
* Modules/indexeddb/IDBObjectStore.cpp:
(WebCore::generateIndexKeysForValue):
(WebCore::IDBObjectStore::add):
(WebCore::IDBObjectStore::put):
(WebCore):
* Modules/indexeddb/IDBObjectStore.h:
(WebCore::IDBObjectStore::add):
(WebCore::IDBObjectStore::put):
(IDBObjectStore):
* Modules/indexeddb/IDBObjectStore.idl:
* bindings/v8/IDBBindingUtilities.cpp:
(WebCore):
(WebCore::createIDBKeyFromScriptValueAndKeyPath):
(WebCore::deserializeIDBValue):
(WebCore::canInjectIDBKeyIntoScriptValue):
* bindings/v8/IDBBindingUtilities.h:
(WebCore):

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

Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBCursor.cpp
Source/WebCore/Modules/indexeddb/IDBCursor.h
Source/WebCore/Modules/indexeddb/IDBCursor.idl
Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp
Source/WebCore/Modules/indexeddb/IDBObjectStore.h
Source/WebCore/Modules/indexeddb/IDBObjectStore.idl
Source/WebCore/bindings/v8/IDBBindingUtilities.cpp
Source/WebCore/bindings/v8/IDBBindingUtilities.h

index 32cf92c..967f490 100644 (file)
@@ -1,3 +1,49 @@
+2012-09-12  Alec Flett  <alecflett@chromium.org>
+
+        IndexedDB: Use ScriptValue instead of SerializedScriptValue when possible
+        https://bugs.webkit.org/show_bug.cgi?id=94023
+
+        Reviewed by Kentaro Hara.
+
+        Transition the put/add/update methods to accept direct ScriptValue
+        objects rather than SerializedScriptValues, to eliminate lots of
+        redundant deserialization/serialization steps while storing
+        values.
+
+        Also see https://bugs.webkit.org/show_bug.cgi?id=95409 for
+        followup get/openCursor work, following this.
+
+        No new tests, this is a performance refactor of core IDB
+        functionality. Most existing tests cover correctness. Tests that
+        might fail include:
+
+        storage/indexeddb/objectstore-basics.html
+        storage/indexeddb/keypath-basics.html
+        storage/indexeddb/index-basics.html
+
+        * Modules/indexeddb/IDBCursor.cpp:
+        (WebCore::IDBCursor::update):
+        * Modules/indexeddb/IDBCursor.h:
+        (IDBCursor):
+        * Modules/indexeddb/IDBCursor.idl:
+        * Modules/indexeddb/IDBObjectStore.cpp:
+        (WebCore::generateIndexKeysForValue):
+        (WebCore::IDBObjectStore::add):
+        (WebCore::IDBObjectStore::put):
+        (WebCore):
+        * Modules/indexeddb/IDBObjectStore.h:
+        (WebCore::IDBObjectStore::add):
+        (WebCore::IDBObjectStore::put):
+        (IDBObjectStore):
+        * Modules/indexeddb/IDBObjectStore.idl:
+        * bindings/v8/IDBBindingUtilities.cpp:
+        (WebCore):
+        (WebCore::createIDBKeyFromScriptValueAndKeyPath):
+        (WebCore::deserializeIDBValue):
+        (WebCore::canInjectIDBKeyIntoScriptValue):
+        * bindings/v8/IDBBindingUtilities.h:
+        (WebCore):
+
 2012-09-12  Chris Fleizach  <cfleizach@apple.com>
 
         AX: svg:image not accessible
index 903dab5..96fe82f 100644 (file)
@@ -125,10 +125,9 @@ IDBAny* IDBCursor::source() const
     return m_source.get();
 }
 
-PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, ExceptionCode& ec)
+PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, ScriptValue& value, ExceptionCode& ec)
 {
     IDB_TRACE("IDBCursor::update");
-    RefPtr<SerializedScriptValue> value = prpValue;
 
     if (!m_gotValue || isKeyCursor()) {
         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
@@ -142,17 +141,12 @@ PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRe
         ec = IDBDatabaseException::READ_ONLY_ERR;
         return 0;
     }
-    if (value->blobURLs().size() > 0) {
-        // FIXME: Add Blob/File/FileList support
-        ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
-        return 0;
-    }
 
     RefPtr<IDBObjectStore> objectStore = effectiveObjectStore();
     const IDBKeyPath& keyPath = objectStore->metadata().keyPath;
     const bool usesInLineKeys = !keyPath.isNull();
     if (usesInLineKeys) {
-        RefPtr<IDBKey> keyPathKey = createIDBKeyFromSerializedValueAndKeyPath(value, keyPath);
+        RefPtr<IDBKey> keyPathKey = createIDBKeyFromScriptValueAndKeyPath(value, keyPath);
         if (!keyPathKey || !keyPathKey->isEqual(m_currentPrimaryKey.get())) {
             ec = IDBDatabaseException::DATA_ERR;
             return 0;
index 5908288..1b61935 100644 (file)
@@ -75,7 +75,7 @@ public:
     PassRefPtr<IDBAny> value();
     IDBAny* source() const;
 
-    PassRefPtr<IDBRequest> update(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, ExceptionCode&);
+    PassRefPtr<IDBRequest> update(ScriptExecutionContext*, ScriptValue&, ExceptionCode&);
     void advance(unsigned long, ExceptionCode&);
     void continueFunction(PassRefPtr<IDBKey>, ExceptionCode&);
     PassRefPtr<IDBRequest> deleteFunction(ScriptExecutionContext*, ExceptionCode&);
index d73d146..516ce1b 100644 (file)
@@ -39,7 +39,7 @@ module storage {
         readonly attribute IDBKey primaryKey;
         readonly attribute IDBAny source;
 
-        [CallWith=ScriptExecutionContext] IDBRequest update(in SerializedScriptValue value)
+        [CallWith=ScriptExecutionContext] IDBRequest update(in any value)
             raises (IDBDatabaseException);
         void advance(in unsigned long count)
             raises (IDBDatabaseException);
index a7aa8a3..5ffc1cb 100644 (file)
@@ -105,11 +105,11 @@ PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, Pass
 }
 
 static void generateIndexKeysForValue(const IDBIndexMetadata& indexMetadata,
-                                      PassRefPtr<SerializedScriptValue> objectValue,
+                                      const ScriptValue& objectValue,
                                       IDBObjectStore::IndexKeys* indexKeys)
 {
     ASSERT(indexKeys);
-    RefPtr<IDBKey> indexKey = createIDBKeyFromSerializedValueAndKeyPath(objectValue, indexMetadata.keyPath);
+    RefPtr<IDBKey> indexKey = createIDBKeyFromScriptValueAndKeyPath(objectValue, indexMetadata.keyPath);
 
     if (!indexKey)
         return;
@@ -129,22 +129,21 @@ static void generateIndexKeysForValue(const IDBIndexMetadata& indexMetadata,
     }
 }
 
-PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, ScriptValue& value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
 {
     IDB_TRACE("IDBObjectStore::add");
     return put(IDBObjectStoreBackendInterface::AddOnly, IDBAny::create(this), context, value, key, ec);
 }
 
-PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, ScriptValue& value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
 {
     IDB_TRACE("IDBObjectStore::put");
     return put(IDBObjectStoreBackendInterface::AddOrUpdate, IDBAny::create(this), context, value, key, ec);
 }
 
-PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMode putMode, PassRefPtr<IDBAny> source, ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, ExceptionCode& ec)
+PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMode putMode, PassRefPtr<IDBAny> source, ScriptExecutionContext* context, ScriptValue& value, PassRefPtr<IDBKey> prpKey, ExceptionCode& ec)
 {
     IDB_TRACE("IDBObjectStore::put");
-    RefPtr<SerializedScriptValue> value = prpValue;
     RefPtr<IDBKey> key = prpKey;
     if (m_deleted) {
         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
@@ -158,7 +157,15 @@ PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMo
         ec = IDBDatabaseException::READ_ONLY_ERR;
         return 0;
     }
-    if (value->blobURLs().size() > 0) {
+
+    ScriptState* state = ScriptState::current();
+    RefPtr<SerializedScriptValue> serializedValue = value.serialize(state);
+    if (state->hadException()) {
+        ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
+        return 0;
+    }
+
+    if (serializedValue->blobURLs().size() > 0) {
         // FIXME: Add Blob/File/FileList support
         ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
         return 0;
@@ -177,7 +184,7 @@ PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMo
         return 0;
     }
     if (usesInLineKeys) {
-        RefPtr<IDBKey> keyPathKey = createIDBKeyFromSerializedValueAndKeyPath(value, keyPath);
+        RefPtr<IDBKey> keyPathKey = createIDBKeyFromScriptValueAndKeyPath(value, keyPath);
         if (keyPathKey && !keyPathKey->isValid()) {
             ec = IDBDatabaseException::DATA_ERR;
             return 0;
@@ -187,9 +194,7 @@ PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMo
             return 0;
         }
         if (hasKeyGenerator && !keyPathKey) {
-            RefPtr<IDBKey> dummyKey = IDBKey::createNumber(-1);
-            RefPtr<SerializedScriptValue> valueAfterInjection = injectIDBKeyIntoSerializedValue(dummyKey, value, keyPath);
-            if (!valueAfterInjection) {
+            if (!canInjectIDBKeyIntoScriptValue(value, keyPath)) {
                 ec = IDBDatabaseException::DATA_ERR;
                 return 0;
             }
@@ -213,7 +218,7 @@ PassRefPtr<IDBRequest> IDBObjectStore::put(IDBObjectStoreBackendInterface::PutMo
     ASSERT(indexKeys.size() == indexNames.size());
 
     RefPtr<IDBRequest> request = IDBRequest::create(context, source, m_transaction.get());
-    m_backend->putWithIndexKeys(value.release(), key.release(), putMode, request, m_transaction->backend(), indexNames, indexKeys, ec);
+    m_backend->putWithIndexKeys(serializedValue.release(), key.release(), putMode, request, m_transaction->backend(), indexNames, indexKeys, ec);
     if (ec) {
         request->markEarlyDeath();
         return 0;
@@ -313,7 +318,7 @@ private:
     {
     }
 
-    virtual void handleEvent(ScriptExecutionContext*, Event* event)
+    virtual void handleEvent(ScriptExecutionContext* context, Event* event)
     {
         ASSERT(event->type() == eventNames().successEvent);
         EventTarget* target = event->target();
@@ -336,7 +341,8 @@ private:
             RefPtr<IDBAny> valueAny = cursor->value();
 
             ASSERT(valueAny->type() == IDBAny::SerializedScriptValueType);
-            RefPtr<SerializedScriptValue> value = valueAny->serializedScriptValue();
+            RefPtr<SerializedScriptValue> serializedValue = valueAny->serializedScriptValue();
+            ScriptValue value(deserializeIDBValue(context, serializedValue));
 
             IDBObjectStore::IndexKeys indexKeys;
             generateIndexKeysForValue(m_indexMetadata, value, &indexKeys);
index c05332a..487563d 100644 (file)
@@ -64,8 +64,8 @@ public:
     PassRefPtr<IDBTransaction> transaction() const { return m_transaction; }
     bool autoIncrement() const { return m_metadata.autoIncrement; }
 
-    PassRefPtr<IDBRequest> add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return add(context, value, 0, ec);  }
-    PassRefPtr<IDBRequest> put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return put(context, value, 0, ec);  }
+    PassRefPtr<IDBRequest> add(ScriptExecutionContext* context, ScriptValue& value, ExceptionCode& ec) { return add(context, value, 0, ec);  }
+    PassRefPtr<IDBRequest> put(ScriptExecutionContext* context, ScriptValue& value, ExceptionCode& ec) { return put(context, value, 0, ec);  }
     PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, static_cast<IDBKeyRange*>(0), ec); } 
     PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec) { return openCursor(context, keyRange, IDBCursor::directionNext(), ec); } 
     PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec) { return openCursor(context, key, IDBCursor::directionNext(), ec); } 
@@ -77,8 +77,8 @@ public:
 
     PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
     PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, ExceptionCode&);
-    PassRefPtr<IDBRequest> add(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
-    PassRefPtr<IDBRequest> put(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
+    PassRefPtr<IDBRequest> add(ScriptExecutionContext*, ScriptValue&, PassRefPtr<IDBKey>, ExceptionCode&);
+    PassRefPtr<IDBRequest> put(ScriptExecutionContext*, ScriptValue&, PassRefPtr<IDBKey>, ExceptionCode&);
     PassRefPtr<IDBRequest> deleteFunction(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, ExceptionCode&);
     PassRefPtr<IDBRequest> deleteFunction(ScriptExecutionContext*, PassRefPtr<IDBKey> key, ExceptionCode&);
     PassRefPtr<IDBRequest> clear(ScriptExecutionContext*, ExceptionCode&);
@@ -97,7 +97,7 @@ public:
     PassRefPtr<IDBRequest> count(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, ExceptionCode&);
     PassRefPtr<IDBRequest> count(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
 
-    PassRefPtr<IDBRequest> put(IDBObjectStoreBackendInterface::PutMode, PassRefPtr<IDBAny> source, ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
+    PassRefPtr<IDBRequest> put(IDBObjectStoreBackendInterface::PutMode, PassRefPtr<IDBAny> source, ScriptExecutionContext*, ScriptValue&, PassRefPtr<IDBKey>, ExceptionCode&);
     void markDeleted() { m_deleted = true; }
     void transactionFinished();
 
index 99d8684..32885a8 100644 (file)
@@ -34,9 +34,9 @@ module storage {
         readonly attribute IDBTransaction transaction;
         readonly attribute boolean autoIncrement;
 
-        [CallWith=ScriptExecutionContext] IDBRequest put(in SerializedScriptValue value, in [Optional] IDBKey key)
+        [CallWith=ScriptExecutionContext] IDBRequest put(in any value, in [Optional] IDBKey key)
             raises (IDBDatabaseException);
-        [CallWith=ScriptExecutionContext] IDBRequest add(in SerializedScriptValue value, in [Optional] IDBKey key)
+        [CallWith=ScriptExecutionContext] IDBRequest add(in any value, in [Optional] IDBKey key)
             raises (IDBDatabaseException);
         [CallWith=ScriptExecutionContext, ImplementedAs=deleteFunction] IDBRequest delete(in IDBKeyRange? keyRange)
             raises (IDBDatabaseException);
index ca62b33..4174b70 100644 (file)
@@ -35,6 +35,7 @@
 #include "SerializedScriptValue.h"
 #include "V8Binding.h"
 #include "V8IDBKey.h"
+#include "WorldContextHandle.h"
 #include <wtf/MathExtras.h>
 #include <wtf/Vector.h>
 
@@ -85,10 +86,8 @@ PassRefPtr<IDBKey> createIDBKeyFromValue(v8::Handle<v8::Value> value)
     return IDBKey::createInvalid();
 }
 
-namespace {
-
 template<typename T>
-bool getValueFrom(T indexOrName, v8::Handle<v8::Value>& v8Value)
+static bool getValueFrom(T indexOrName, v8::Handle<v8::Value>& v8Value)
 {
     v8::Local<v8::Object> object = v8Value->ToObject();
     if (!object->Has(indexOrName))
@@ -98,41 +97,64 @@ bool getValueFrom(T indexOrName, v8::Handle<v8::Value>& v8Value)
 }
 
 template<typename T>
-bool setValue(v8::Handle<v8::Value>& v8Object, T indexOrName, const v8::Handle<v8::Value>& v8Value)
+static bool setValue(v8::Handle<v8::Value>& v8Object, T indexOrName, const v8::Handle<v8::Value>& v8Value)
 {
     v8::Local<v8::Object> object = v8Object->ToObject();
     return object->Set(indexOrName, v8Value);
 }
 
-bool get(v8::Handle<v8::Value>& object, const String& keyPathElement)
+static bool get(v8::Handle<v8::Value>& object, const String& keyPathElement, v8::Handle<v8::Value>& result)
 {
     if (object->IsString() && keyPathElement == "length") {
         int32_t length = v8::Handle<v8::String>::Cast(object)->Length();
-        object = v8::Number::New(length);
+        result = v8::Number::New(length);
         return true;
     }
-    return object->IsObject() && getValueFrom(v8String(keyPathElement), object);
+    return object->IsObject() && getValueFrom(v8String(keyPathElement), result);
 }
 
-bool set(v8::Handle<v8::Value>& object, const String& keyPathElement, const v8::Handle<v8::Value>& v8Value)
+static bool canSet(v8::Handle<v8::Value>& object, const String& keyPathElement)
 {
-    return object->IsObject() && setValue(object, v8String(keyPathElement), v8Value);
+    return object->IsObject();
 }
 
-v8::Handle<v8::Value> getNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index)
+static bool set(v8::Handle<v8::Value>& object, const String& keyPathElement, const v8::Handle<v8::Value>& v8Value)
 {
-    v8::Handle<v8::Value> currentValue(rootValue);
+    return canSet(object, keyPathElement) && setValue(object, v8String(keyPathElement), v8Value);
+}
 
+static v8::Handle<v8::Value> getNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index)
+{
+    v8::Handle<v8::Value> currentValue(rootValue);
     ASSERT(index <= keyPathElements.size());
     for (size_t i = 0; i < index; ++i) {
-        if (!get(currentValue, keyPathElements[i]))
+        v8::Handle<v8::Value> parentValue(currentValue);
+        if (!get(parentValue, keyPathElements[i], currentValue))
             return v8Undefined();
     }
 
     return currentValue;
 }
 
-v8::Handle<v8::Value> ensureNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index)
+static bool canInjectNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index)
+{
+    if (!rootValue->IsObject())
+        return false;
+
+    v8::Handle<v8::Value> currentValue(rootValue);
+
+    ASSERT(index <= keyPathElements.size());
+    for (size_t i = 0; i < index; ++i) {
+        v8::Handle<v8::Value> parentValue(currentValue);
+        const String& keyPathElement = keyPathElements[i];
+        if (!get(parentValue, keyPathElement, currentValue))
+            return canSet(parentValue, keyPathElement);
+    }
+    return true;
+}
+
+
+static v8::Handle<v8::Value> ensureNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index)
 {
     v8::Handle<v8::Value> currentValue(rootValue);
 
@@ -140,7 +162,7 @@ v8::Handle<v8::Value> ensureNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue,
     for (size_t i = 0; i < index; ++i) {
         v8::Handle<v8::Value> parentValue(currentValue);
         const String& keyPathElement = keyPathElements[i];
-        if (!get(currentValue, keyPathElement)) {
+        if (!get(parentValue, keyPathElement, currentValue)) {
             v8::Handle<v8::Object> object = v8::Object::New();
             if (!set(parentValue, keyPathElement, object))
                 return v8Undefined();
@@ -151,7 +173,41 @@ v8::Handle<v8::Value> ensureNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue,
     return currentValue;
 }
 
-} // anonymous namespace
+static PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(const ScriptValue& value, const String& keyPath)
+{
+    Vector<String> keyPathElements;
+    IDBKeyPathParseError error;
+    IDBParseKeyPath(keyPath, keyPathElements, error);
+    ASSERT(error == IDBKeyPathParseErrorNone);
+
+    v8::Handle<v8::Value> v8Value(value.v8Value());
+    v8::Handle<v8::Value> v8Key(getNthValueOnKeyPath(v8Value, keyPathElements, keyPathElements.size()));
+    if (v8Key.IsEmpty())
+        return 0;
+    return createIDBKeyFromValue(v8Key);
+}
+
+PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(const ScriptValue& value, const IDBKeyPath& keyPath)
+{
+    IDB_TRACE("createIDBKeyFromScriptValueAndKeyPath");
+    ASSERT(!keyPath.isNull());
+
+    v8::HandleScope scope;
+    if (keyPath.type() == IDBKeyPath::ArrayType) {
+        IDBKey::KeyArray result;
+        const Vector<String>& array = keyPath.array();
+        for (size_t i = 0; i < array.size(); ++i) {
+            RefPtr<IDBKey> key = createIDBKeyFromScriptValueAndKeyPath(value, array[i]);
+            if (!key)
+                return 0;
+            result.append(key);
+        }
+        return IDBKey::createArray(result);
+    }
+
+    ASSERT(keyPath.type() == IDBKeyPath::StringType);
+    return createIDBKeyFromScriptValueAndKeyPath(value, keyPath.string());
+}
 
 static PassRefPtr<IDBKey> createIDBKeyFromSerializedValueAndKeyPath(PassRefPtr<SerializedScriptValue> prpValue, const String& keyPath)
 {
@@ -172,6 +228,13 @@ static PassRefPtr<IDBKey> createIDBKeyFromSerializedValueAndKeyPath(PassRefPtr<S
     return createIDBKeyFromValue(v8Key);
 }
 
+// FIXME: The only reason this exists is because we need a v8::Context and scope inside a timer. Is there a better / more general way to do this?
+ScriptValue deserializeIDBValue(ScriptExecutionContext* scriptContext, PassRefPtr<SerializedScriptValue> prpValue)
+{
+    v8::HandleScope handleScope;
+    v8::Context::Scope contextScope(toV8Context(scriptContext, UseCurrentWorld));
+    return ScriptValue(prpValue->deserialize());
+}
 
 PassRefPtr<IDBKey> createIDBKeyFromSerializedValueAndKeyPath(PassRefPtr<SerializedScriptValue> prpValue, const IDBKeyPath& keyPath)
 {
@@ -223,6 +286,22 @@ PassRefPtr<SerializedScriptValue> injectIDBKeyIntoSerializedValue(PassRefPtr<IDB
     return SerializedScriptValue::create(v8Value);
 }
 
+bool canInjectIDBKeyIntoScriptValue(const ScriptValue& scriptValue, const IDBKeyPath& keyPath)
+{
+    IDB_TRACE("canInjectIDBKeyIntoScriptValue");
+    ASSERT(keyPath.type() == IDBKeyPath::StringType);
+    Vector<String> keyPathElements;
+    IDBKeyPathParseError error;
+    IDBParseKeyPath(keyPath.string(), keyPathElements, error);
+    ASSERT(error == IDBKeyPathParseErrorNone);
+
+    if (!keyPathElements.size())
+        return false;
+
+    v8::Handle<v8::Value> v8Value(scriptValue.v8Value());
+    return canInjectNthValueOnKeyPath(v8Value, keyPathElements, keyPathElements.size() - 1);
+}
+
 } // namespace WebCore
 
 #endif
index 30eed42..b2b629f 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "ScriptValue.h"
 #include <v8.h>
 #include <wtf/Forward.h>
 
@@ -38,9 +39,15 @@ class IDBKeyPath;
 class SerializedScriptValue;
 
 PassRefPtr<IDBKey> createIDBKeyFromValue(v8::Handle<v8::Value>);
+
+// FIXME: remove the SerializedValue versions when their use is finally removed in https://bugs.webkit.org/show_bug.cgi?id=95409.
 PassRefPtr<IDBKey> createIDBKeyFromSerializedValueAndKeyPath(PassRefPtr<SerializedScriptValue>, const IDBKeyPath&);
 PassRefPtr<SerializedScriptValue> injectIDBKeyIntoSerializedValue(PassRefPtr<IDBKey>, PassRefPtr<SerializedScriptValue>, const IDBKeyPath&);
 
+PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(const ScriptValue&, const IDBKeyPath&);
+bool canInjectIDBKeyIntoScriptValue(const ScriptValue&, const IDBKeyPath&);
+ScriptValue deserializeIDBValue(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>);
+
 }
 
 #endif // ENABLE(INDEXED_DATABASE)