Title: [192798] trunk
Revision
192798
Author
beid...@apple.com
Date
2015-11-30 10:11:34 -0800 (Mon, 30 Nov 2015)

Log Message

Modern IDB: Support keyPath injection into object store records.
https://bugs.webkit.org/show_bug.cgi?id=151640

Reviewed by Andy Estes.

Source/WebCore:

No new tests (At least one existing failure now passes and is unskipped,
while many other existing failures are now closer to passing).

* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord): Use the new UniqueIDBDatabase VM/ExecState.
(WebCore::IDBServer::MemoryObjectStore::populateIndexWithExistingRecords): Ditto
(WebCore::IDBServer::indexVM): Deleted.
(WebCore::IDBServer::indexGlobalExec): Deleted.

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::databaseThreadVM):
(WebCore::IDBServer::UniqueIDBDatabase::databaseThreadExecState):
(WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): If appropriate, inject the key that will be used into
  the value before storing the record.
* Modules/indexeddb/server/UniqueIDBDatabase.h:

Add modern JSValue/ExecState& version of some binding utilities, for use today and in preparation of getting
rid of the DOMRequestState and Deprecated::ScriptValue versions later:
* bindings/js/IDBBindingUtilities.cpp:
(WebCore::idbKeyToJSValue):
(WebCore::injectIDBKeyIntoScriptValue):
(WebCore::deserializeIDBValueData):
(WebCore::deserializeIDBValueDataToJSValue):
* bindings/js/IDBBindingUtilities.h:

LayoutTests:

* platform/mac-wk1/TestExpectations:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (192797 => 192798)


--- trunk/LayoutTests/ChangeLog	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/LayoutTests/ChangeLog	2015-11-30 18:11:34 UTC (rev 192798)
@@ -1,3 +1,12 @@
+2015-11-30  Brady Eidson  <beid...@apple.com>
+
+        Modern IDB: Support keyPath injection into object store records.
+        https://bugs.webkit.org/show_bug.cgi?id=151640
+
+        Reviewed by Andy Estes.
+
+        * platform/mac-wk1/TestExpectations:
+
 2015-11-29  Antoine Quint  <grao...@apple.com>
 
         Browser does not fall back to SVG attribute value when CSS style value is invalid or not supported

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (192797 => 192798)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2015-11-30 18:11:34 UTC (rev 192798)
@@ -73,6 +73,7 @@
 # But Modern IndexedDB is.
 storage/indexeddb/modern [ Pass ]
 storage/indexeddb/mozilla/add-twice-failure.html [ Pass ]
+storage/indexeddb/mozilla/autoincrement-indexes.html [ Pass ]
 storage/indexeddb/mozilla/bad-keypath.html [ Pass ]
 storage/indexeddb/mozilla/create-index-unique.html [ Pass ]
 storage/indexeddb/mozilla/create-index-with-integer-keys.html [ Pass ]

Modified: trunk/Source/WebCore/ChangeLog (192797 => 192798)


--- trunk/Source/WebCore/ChangeLog	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/Source/WebCore/ChangeLog	2015-11-30 18:11:34 UTC (rev 192798)
@@ -1,3 +1,35 @@
+2015-11-30  Brady Eidson  <beid...@apple.com>
+
+        Modern IDB: Support keyPath injection into object store records.
+        https://bugs.webkit.org/show_bug.cgi?id=151640
+
+        Reviewed by Andy Estes.
+
+        No new tests (At least one existing failure now passes and is unskipped,
+        while many other existing failures are now closer to passing).
+
+        * Modules/indexeddb/server/MemoryObjectStore.cpp:
+        (WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord): Use the new UniqueIDBDatabase VM/ExecState.
+        (WebCore::IDBServer::MemoryObjectStore::populateIndexWithExistingRecords): Ditto
+        (WebCore::IDBServer::indexVM): Deleted.
+        (WebCore::IDBServer::indexGlobalExec): Deleted.
+        
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::databaseThreadVM):
+        (WebCore::IDBServer::UniqueIDBDatabase::databaseThreadExecState):
+        (WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): If appropriate, inject the key that will be used into
+          the value before storing the record.
+        * Modules/indexeddb/server/UniqueIDBDatabase.h:
+
+        Add modern JSValue/ExecState& version of some binding utilities, for use today and in preparation of getting 
+        rid of the DOMRequestState and Deprecated::ScriptValue versions later:
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::idbKeyToJSValue):
+        (WebCore::injectIDBKeyIntoScriptValue):
+        (WebCore::deserializeIDBValueData):
+        (WebCore::deserializeIDBValueDataToJSValue):
+        * bindings/js/IDBBindingUtilities.h:
+
 2015-11-25  Andy Estes  <aes...@apple.com>
 
         [Content Filtering] Avoid creating a ContentFilter when loading the empty document

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp (192797 => 192798)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp	2015-11-30 18:11:34 UTC (rev 192798)
@@ -35,6 +35,7 @@
 #include "IndexKey.h"
 #include "Logging.h"
 #include "MemoryBackingStoreTransaction.h"
+#include "UniqueIDBDatabase.h"
 
 #include <wtf/NeverDestroyed.h>
 
@@ -267,27 +268,6 @@
     return error;
 }
 
-static VM& indexVM()
-{
-    ASSERT(!isMainThread());
-    static NeverDestroyed<RefPtr<VM>> vm = VM::create();
-    return *vm.get();
-}
-
-static ExecState& indexGlobalExec()
-{
-    ASSERT(!isMainThread());
-    static NeverDestroyed<Strong<JSGlobalObject>> globalObject;
-    static bool initialized = false;
-    if (!initialized) {
-        globalObject.get().set(indexVM(), JSGlobalObject::create(indexVM(), JSGlobalObject::createStructure(indexVM(), jsNull())));
-        initialized = true;
-    }
-
-    RELEASE_ASSERT(globalObject.get()->globalExec());
-    return *globalObject.get()->globalExec();
-}
-
 void MemoryObjectStore::updateCursorsForPutRecord(std::set<IDBKeyData>::iterator iterator)
 {
     for (auto& cursor : m_cursors.values())
@@ -308,9 +288,9 @@
 
 IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData& key, const ThreadSafeDataBuffer& value)
 {
-    JSLockHolder locker(indexVM());
+    JSLockHolder locker(UniqueIDBDatabase::databaseThreadVM());
 
-    auto jsValue = idbValueDataToJSValue(indexGlobalExec(), value);
+    auto jsValue = idbValueDataToJSValue(UniqueIDBDatabase::databaseThreadExecState(), value);
     if (jsValue.isUndefinedOrNull())
         return { };
 
@@ -319,7 +299,7 @@
 
     for (auto* index : m_indexesByName.values()) {
         IndexKey indexKey;
-        generateIndexKeyForValue(indexGlobalExec(), index->info(), jsValue, indexKey);
+        generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index->info(), jsValue, indexKey);
 
         if (indexKey.isNull())
             continue;
@@ -340,21 +320,20 @@
     return error;
 }
 
-
 IDBError MemoryObjectStore::populateIndexWithExistingRecords(MemoryIndex& index)
 {
     if (!m_keyValueStore)
         return { };
 
-    JSLockHolder locker(indexVM());
+    JSLockHolder locker(UniqueIDBDatabase::databaseThreadVM());
 
     for (auto iterator : *m_keyValueStore) {
-        auto jsValue = idbValueDataToJSValue(indexGlobalExec(), iterator.value);
+        auto jsValue = idbValueDataToJSValue(UniqueIDBDatabase::databaseThreadExecState(), iterator.value);
         if (jsValue.isUndefinedOrNull())
             return { };
 
         IndexKey indexKey;
-        generateIndexKeyForValue(indexGlobalExec(), index.info(), jsValue, indexKey);
+        generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index.info(), jsValue, indexKey);
 
         if (indexKey.isNull())
             continue;

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (192797 => 192798)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2015-11-30 18:11:34 UTC (rev 192798)
@@ -36,8 +36,11 @@
 #include "Logging.h"
 #include "UniqueIDBDatabaseConnection.h"
 #include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/ThreadSafeRefCounted.h>
 
+using namespace JSC;
+
 namespace WebCore {
 namespace IDBServer {
     
@@ -479,9 +482,26 @@
     m_server.postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performPutOrAdd, callbackID, requestData.transactionIdentifier(), requestData.objectStoreIdentifier(), keyData, valueData, overwriteMode));
 }
 
-void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+VM& UniqueIDBDatabase::databaseThreadVM()
 {
     ASSERT(!isMainThread());
+    static VM* vm = &VM::create().leakRef();
+    return *vm;
+}
+
+ExecState& UniqueIDBDatabase::databaseThreadExecState()
+{
+    ASSERT(!isMainThread());
+
+    static NeverDestroyed<Strong<JSGlobalObject>> globalObject(databaseThreadVM(), JSGlobalObject::create(databaseThreadVM(), JSGlobalObject::createStructure(databaseThreadVM(), jsNull())));
+
+    RELEASE_ASSERT(globalObject.get()->globalExec());
+    return *globalObject.get()->globalExec();
+}
+
+void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& originalRecordValue, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
+{
+    ASSERT(!isMainThread());
     LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");
 
     ASSERT(m_backingStore);
@@ -497,6 +517,7 @@
         return;
     }
 
+    bool usedKeyIsGenerated = false;
     if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
         uint64_t keyNumber;
         error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
@@ -506,6 +527,7 @@
         }
         
         usedKey.setNumberValue(keyNumber);
+        usedKeyIsGenerated = true;
     } else
         usedKey = keyData;
 
@@ -521,6 +543,33 @@
         }
     }
 
+    // 3.4.1.2 Object Store Storage Operation
+    // If ObjectStore has a key path and the key is autogenerated, then inject the key into the value
+    // using steps to assign a key to a value using a key path.
+    ThreadSafeDataBuffer injectedRecordValue;
+    if (usedKeyIsGenerated && !objectStoreInfo->keyPath().isNull()) {
+        JSLockHolder locker(databaseThreadVM());
+
+        JSValue value = deserializeIDBValueDataToJSValue(databaseThreadExecState(), originalRecordValue);
+        if (value.isUndefined()) {
+            m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Unable to deserialize record value for record key injection")), usedKey));
+            return;
+        }
+
+        if (!injectIDBKeyIntoScriptValue(databaseThreadExecState(), usedKey, value, objectStoreInfo->keyPath())) {
+            m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Unable to inject record key into record value")), usedKey));
+            return;
+        }
+
+        auto serializedValue = SerializedScriptValue::create(&databaseThreadExecState(), value, nullptr, nullptr);
+        if (databaseThreadExecState().hadException()) {
+            m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Unable to serialize record value after injecting record key")), usedKey));
+            return;
+        }
+
+        injectedRecordValue = ThreadSafeDataBuffer::copyVector(serializedValue->data());
+    }
+
     // 3.4.1 Object Store Storage Operation
     // ...If a record already exists in store ...
     // then remove the record from store using the steps for deleting records from an object store...
@@ -531,7 +580,7 @@
         return;
     }
 
-    error = m_backingStore->addRecord(transactionIdentifier, objectStoreIdentifier, usedKey, valueData);
+    error = m_backingStore->addRecord(transactionIdentifier, objectStoreIdentifier, usedKey, injectedRecordValue.data() ? injectedRecordValue : originalRecordValue);
 
     m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
 }

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h (192797 => 192798)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h	2015-11-30 18:11:34 UTC (rev 192798)
@@ -29,6 +29,7 @@
 #if ENABLE(INDEXED_DATABASE)
 
 #include "IDBBackingStore.h"
+#include "IDBBindingUtilities.h"
 #include "IDBDatabaseIdentifier.h"
 #include "IDBDatabaseInfo.h"
 #include "IDBGetResult.h"
@@ -97,6 +98,9 @@
     void handleDelete(IDBConnectionToClient&, const IDBRequestData&);
     bool deletePending() const { return m_deletePending; }
 
+    static JSC::VM& databaseThreadVM();
+    static JSC::ExecState& databaseThreadExecState();
+
 private:
     UniqueIDBDatabase(IDBServer&, const IDBDatabaseIdentifier&);
     

Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp (192797 => 192798)


--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp	2015-11-30 18:11:34 UTC (rev 192798)
@@ -115,7 +115,7 @@
 
 }
 
-static JSValue idbKeyToJSValue(ExecState* exec, JSDOMGlobalObject* globalObject, IDBKey* key)
+static JSValue idbKeyToJSValue(ExecState* exec, JSGlobalObject* globalObject, IDBKey* key)
 {
     if (!key || !exec) {
         // This should be undefined, not null.
@@ -294,12 +294,40 @@
     if (parent.isUndefined())
         return false;
 
-    if (!set(exec, parent, keyPathElements.last(), idbKeyToJSValue(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), key.get())))
+    if (!set(exec, parent, keyPathElements.last(), idbKeyToJSValue(exec, exec->lexicalGlobalObject(), key.get())))
         return false;
 
     return true;
 }
 
+bool injectIDBKeyIntoScriptValue(JSC::ExecState& exec, const IDBKeyData& keyData, JSC::JSValue value, const IDBKeyPath& keyPath)
+{
+    LOG(IndexedDB, "injectIDBKeyIntoScriptValue");
+
+    ASSERT(keyPath.type() == IndexedDB::KeyPathType::String);
+
+    Vector<String> keyPathElements;
+    IDBKeyPathParseError error;
+    IDBParseKeyPath(keyPath.string(), keyPathElements, error);
+    ASSERT(error == IDBKeyPathParseError::None);
+
+    if (keyPathElements.isEmpty())
+        return false;
+
+    JSValue parent = ensureNthValueOnKeyPath(&exec, value, keyPathElements, keyPathElements.size() - 1);
+    if (parent.isUndefined())
+        return false;
+
+    auto key = keyData.maybeCreateIDBKey();
+    if (!key)
+        return false;
+
+    if (!set(&exec, parent, keyPathElements.last(), idbKeyToJSValue(&exec, exec.lexicalGlobalObject(), key.get())))
+        return false;
+
+    return true;
+}
+
 RefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(ExecState* exec, const Deprecated::ScriptValue& value, const IDBKeyPath& keyPath)
 {
     LOG(StorageAPI, "createIDBKeyFromScriptValueAndKeyPath");
@@ -409,21 +437,26 @@
     if (!execState)
         return Deprecated::ScriptValue();
 
+    return Deprecated::ScriptValue(execState->vm(), deserializeIDBValueDataToJSValue(*execState, valueData));
+}
+
+JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState& exec, const ThreadSafeDataBuffer& valueData)
+{
     if (!valueData.data())
-        return Deprecated::ScriptValue(execState->vm(), jsUndefined());
+        return jsUndefined();
 
     const Vector<uint8_t>& data = ""
     JSValue result;
     if (data.size()) {
         RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(data);
 
-        execState->vm().apiLock().lock();
-        result = serializedValue->deserialize(execState, execState->lexicalGlobalObject(), 0, NonThrowing);
-        execState->vm().apiLock().unlock();
+        exec.vm().apiLock().lock();
+        result = serializedValue->deserialize(&exec, exec.lexicalGlobalObject(), 0, NonThrowing);
+        exec.vm().apiLock().unlock();
     } else
         result = jsNull();
 
-    return Deprecated::ScriptValue(execState->vm(), result);
+    return result;
 }
 
 Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState* requestState, PassRefPtr<SharedBuffer> prpBuffer, bool keyIsDefined)

Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h (192797 => 192798)


--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h	2015-11-30 18:06:23 UTC (rev 192797)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h	2015-11-30 18:11:34 UTC (rev 192798)
@@ -48,6 +48,7 @@
 IDBKeyPath idbKeyPathFromValue(JSC::ExecState*, JSC::JSValue);
 
 bool injectIDBKeyIntoScriptValue(DOMRequestState*, PassRefPtr<IDBKey>, Deprecated::ScriptValue&, const IDBKeyPath&);
+bool injectIDBKeyIntoScriptValue(JSC::ExecState&, const IDBKeyData&, JSC::JSValue, const IDBKeyPath&);
 
 RefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(JSC::ExecState*, const Deprecated::ScriptValue&, const IDBKeyPath&);
 RefPtr<IDBKey> maybeCreateIDBKeyFromScriptValueAndKeyPath(JSC::ExecState&, const Deprecated::ScriptValue&, const IDBKeyPath&);
@@ -61,6 +62,8 @@
 Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState*, PassRefPtr<SharedBuffer>, bool keyIsDefined);
 WEBCORE_EXPORT Deprecated::ScriptValue deserializeIDBValueBuffer(JSC::ExecState*, const Vector<uint8_t>&, bool keyIsDefined);
 
+JSC::JSValue deserializeIDBValueDataToJSValue(JSC::ExecState&, const ThreadSafeDataBuffer& valueData);
+
 Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState*, PassRefPtr<IDBKey>);
 RefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState*, const JSC::JSValue&);
 RefPtr<IDBKey> scriptValueToIDBKey(JSC::ExecState&, const JSC::JSValue&);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to