This commit is contained in:
Kyle Huey 2011-06-29 16:37:41 -07:00
Родитель 16eb63ac90 4b550d704d
Коммит 48cb17ffa2
5 изменённых файлов: 96 добавлений и 87 удалений

Просмотреть файл

@ -43,6 +43,7 @@
#include "nsIVariant.h" #include "nsIVariant.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jsclone.h"
#include "mozilla/storage.h" #include "mozilla/storage.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDOMClassInfo.h" #include "nsDOMClassInfo.h"
@ -75,9 +76,10 @@ public:
JSAutoStructuredCloneBuffer& aCloneBuffer, JSAutoStructuredCloneBuffer& aCloneBuffer,
const Key& aKey, const Key& aKey,
bool aOverwrite, bool aOverwrite,
nsTArray<IndexUpdateInfo>& aIndexUpdateInfo) nsTArray<IndexUpdateInfo>& aIndexUpdateInfo,
PRUint64 aOffsetToKeyProp)
: AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore), : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
mKey(aKey), mOverwrite(aOverwrite) mKey(aKey), mOverwrite(aOverwrite), mOffsetToKeyProp(aOffsetToKeyProp)
{ {
mCloneBuffer.swap(aCloneBuffer); mCloneBuffer.swap(aCloneBuffer);
mIndexUpdateInfo.SwapElements(aIndexUpdateInfo); mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
@ -111,6 +113,7 @@ private:
Key mKey; Key mKey;
const bool mOverwrite; const bool mOverwrite;
nsTArray<IndexUpdateInfo> mIndexUpdateInfo; nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
PRUint64 mOffsetToKeyProp;
}; };
class GetHelper : public AsyncConnectionHelper class GetHelper : public AsyncConnectionHelper
@ -423,6 +426,41 @@ GenerateRequest(IDBObjectStore* aObjectStore)
database->Owner(), aObjectStore->Transaction()); database->Owner(), aObjectStore->Transaction());
} }
JSClass gDummyPropClass = {
"dummy", 0,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSBool
StructuredCloneWriteDummyProp(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JSObject* aObj,
void* aClosure)
{
if (JS_GET_CLASS(aCx, aObj) == &gDummyPropClass) {
PRUint64* closure = reinterpret_cast<PRUint64*>(aClosure);
NS_ASSERTION(*closure == 0, "We should not have been here before!");
*closure = js_GetSCOffset(aWriter);
PRUint64 value = 0;
return JS_WriteBytes(aWriter, &value, sizeof(value));
}
// try using the runtime callbacks
const JSStructuredCloneCallbacks* runtimeCallbacks =
aCx->runtime->structuredCloneCallbacks;
if (runtimeCallbacks) {
return runtimeCallbacks->write(aCx, aWriter, aObj, nsnull);
}
return JS_FALSE;
}
} // anonymous namespace } // anonymous namespace
// static // static
@ -840,7 +878,9 @@ IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
bool bool
IDBObjectStore::DeserializeValue(JSContext* aCx, IDBObjectStore::DeserializeValue(JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer, JSAutoStructuredCloneBuffer& aBuffer,
jsval* aValue) jsval* aValue,
JSStructuredCloneCallbacks* aCallbacks,
void* aClosure)
{ {
NS_ASSERTION(NS_IsMainThread(), NS_ASSERTION(NS_IsMainThread(),
"Should only be deserializing on the main thread!"); "Should only be deserializing on the main thread!");
@ -853,14 +893,16 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
JSAutoRequest ar(aCx); JSAutoRequest ar(aCx);
return aBuffer.read(aValue, aCx, nsnull); return aBuffer.read(aValue, aCx, aCallbacks, aClosure);
} }
// static // static
bool bool
IDBObjectStore::SerializeValue(JSContext* aCx, IDBObjectStore::SerializeValue(JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer, JSAutoStructuredCloneBuffer& aBuffer,
jsval aValue) jsval aValue,
JSStructuredCloneCallbacks* aCallbacks,
void* aClosure)
{ {
NS_ASSERTION(NS_IsMainThread(), NS_ASSERTION(NS_IsMainThread(),
"Should only be serializing on the main thread!"); "Should only be serializing on the main thread!");
@ -868,7 +910,7 @@ IDBObjectStore::SerializeValue(JSContext* aCx,
JSAutoRequest ar(aCx); JSAutoRequest ar(aCx);
return aBuffer.write(aCx, aValue, nsnull); return aBuffer.write(aCx, aValue, aCallbacks, aClosure);
} }
static inline jsdouble static inline jsdouble
@ -890,24 +932,12 @@ SwapBytes(PRUint64 u)
nsresult nsresult
IDBObjectStore::ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer, IDBObjectStore::ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer,
Key& aKey) Key& aKey,
PRUint64 aOffsetToKeyProp)
{ {
NS_ASSERTION(IsAutoIncrement() && KeyPath().IsEmpty() && aKey.IsInt(), NS_ASSERTION(IsAutoIncrement() && KeyPath().IsEmpty() && aKey.IsInt(),
"Don't call me!"); "Don't call me!");
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread"); NS_ASSERTION(!NS_IsMainThread(), "Wrong thread");
NS_ASSERTION(mKeyPathSerializationOffset, "How did this happen?");
// The minus 8 dangling off the end here is to account for the null entry
// that terminates the buffer
const PRUint32 keyPropLen = mKeyPathSerialization.nbytes() -
mKeyPathSerializationOffset - sizeof(PRUint64);
const char* location = nsCRT::memmem((char*)aBuffer.data(),
aBuffer.nbytes(),
(char*)mKeyPathSerialization.data() +
mKeyPathSerializationOffset,
keyPropLen);
NS_ASSERTION(location, "How did this happen?");
// This is a duplicate of the js engine's byte munging here // This is a duplicate of the js engine's byte munging here
union { union {
@ -917,16 +947,13 @@ IDBObjectStore::ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer,
pun.d = SwapBytes(aKey.IntValue()); pun.d = SwapBytes(aKey.IntValue());
memcpy(const_cast<char*>(location) + keyPropLen - memcpy((char*)aBuffer.data() + aOffsetToKeyProp, &pun.u, sizeof(PRUint64));
sizeof(pun.u), // We're overwriting the last 8 bytes
&pun.u, sizeof(PRUint64));
return NS_OK; return NS_OK;
} }
IDBObjectStore::IDBObjectStore() IDBObjectStore::IDBObjectStore()
: mId(LL_MININT), : mId(LL_MININT),
mAutoIncrement(PR_FALSE), mAutoIncrement(PR_FALSE)
mKeyPathSerializationOffset(0)
{ {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
} }
@ -942,7 +969,8 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
jsval aKeyVal, jsval aKeyVal,
JSAutoStructuredCloneBuffer& aCloneBuffer, JSAutoStructuredCloneBuffer& aCloneBuffer,
Key& aKey, Key& aKey,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray) nsTArray<IndexUpdateInfo>& aUpdateInfoArray,
PRUint64* aOffsetToKeyProp)
{ {
nsresult rv; nsresult rv;
@ -993,9 +1021,10 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
if (!mKeyPath.IsEmpty() && aKey.IsUnset()) { if (!mKeyPath.IsEmpty() && aKey.IsUnset()) {
NS_ASSERTION(mAutoIncrement, "Should have bailed earlier!"); NS_ASSERTION(mAutoIncrement, "Should have bailed earlier!");
jsval key; JSObject* obj = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
ok = JS_NewNumberValue(aCx, kTotallyRandomNumber, &key); NS_ENSURE_TRUE(obj, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
jsval key = OBJECT_TO_JSVAL(obj);
ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars, ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
keyPathLen, key, nsnull, nsnull, keyPathLen, key, nsnull, nsnull,
@ -1003,13 +1032,20 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
// From this point on we have to try to remove the property. // From this point on we have to try to remove the property.
rv = EnsureKeyPathSerializationData(aCx);
} }
JSStructuredCloneCallbacks callbacks = {
nsnull,
StructuredCloneWriteDummyProp,
nsnull
};
*aOffsetToKeyProp = 0;
// We guard on rv being a success because we need to run the property // We guard on rv being a success because we need to run the property
// deletion code below even if we should not be serializing the value // deletion code below even if we should not be serializing the value
if (NS_SUCCEEDED(rv) && if (NS_SUCCEEDED(rv) &&
!IDBObjectStore::SerializeValue(aCx, aCloneBuffer, aValue)) { !IDBObjectStore::SerializeValue(aCx, aCloneBuffer, aValue, &callbacks,
aOffsetToKeyProp)) {
rv = NS_ERROR_DOM_DATA_CLONE_ERR; rv = NS_ERROR_DOM_DATA_CLONE_ERR;
} }
@ -1051,8 +1087,10 @@ IDBObjectStore::AddOrPut(const jsval& aValue,
JSAutoStructuredCloneBuffer cloneBuffer; JSAutoStructuredCloneBuffer cloneBuffer;
Key key; Key key;
nsTArray<IndexUpdateInfo> updateInfo; nsTArray<IndexUpdateInfo> updateInfo;
PRUint64 offset;
nsresult rv = GetAddInfo(aCx, aValue, keyval, cloneBuffer, key, updateInfo); nsresult rv =
GetAddInfo(aCx, aValue, keyval, cloneBuffer, key, updateInfo, &offset);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
@ -1067,7 +1105,7 @@ IDBObjectStore::AddOrPut(const jsval& aValue,
nsRefPtr<AddHelper> helper = nsRefPtr<AddHelper> helper =
new AddHelper(mTransaction, request, this, cloneBuffer, key, aOverwrite, new AddHelper(mTransaction, request, this, cloneBuffer, key, aOverwrite,
updateInfo); updateInfo, offset);
rv = helper->DispatchToTransactionPool(); rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -1076,46 +1114,6 @@ IDBObjectStore::AddOrPut(const jsval& aValue,
return NS_OK; return NS_OK;
} }
nsresult
IDBObjectStore::EnsureKeyPathSerializationData(JSContext* aCx)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
if (!mKeyPathSerializationOffset) {
JSBool ok;
JSAutoStructuredCloneBuffer emptyObjectBuffer;
JSAutoStructuredCloneBuffer fakeObjectBuffer;
const jschar* keyPathChars =
reinterpret_cast<const jschar*>(mKeyPath.get());
const size_t keyPathLen = mKeyPath.Length();
JSObject* object = JS_NewObject(aCx, nsnull, nsnull, nsnull);
NS_ENSURE_TRUE(object, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
ok = emptyObjectBuffer.write(aCx, OBJECT_TO_JSVAL(object));
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
jsval key;
// This is just to give us some random marker in the byte stream
ok = JS_NewNumberValue(aCx, kTotallyRandomNumber, &key);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
ok = JS_DefineUCProperty(aCx, object, keyPathChars, keyPathLen,
key, nsnull, nsnull, JSPROP_ENUMERATE);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
ok = fakeObjectBuffer.write(aCx, OBJECT_TO_JSVAL(object));
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
mKeyPathSerialization.swap(fakeObjectBuffer);
mKeyPathSerializationOffset = emptyObjectBuffer.nbytes();
}
return NS_OK;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
@ -1850,7 +1848,8 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
// Special case where someone put an object into an autoIncrement'ing // Special case where someone put an object into an autoIncrement'ing
// objectStore with no key in its keyPath set. We needed to figure out // objectStore with no key in its keyPath set. We needed to figure out
// which row id we would get above before we could set that properly. // which row id we would get above before we could set that properly.
rv = mObjectStore->ModifyValueForNewKey(mCloneBuffer, mKey); rv = mObjectStore->ModifyValueForNewKey(mCloneBuffer, mKey,
mOffsetToKeyProp);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
scoper.Abandon(); scoper.Abandon();

Просмотреть файл

@ -119,12 +119,16 @@ public:
static bool static bool
DeserializeValue(JSContext* aCx, DeserializeValue(JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer, JSAutoStructuredCloneBuffer& aBuffer,
jsval* aValue); jsval* aValue,
JSStructuredCloneCallbacks* aCallbacks = nsnull,
void* aClosure = nsnull);
static bool static bool
SerializeValue(JSContext* aCx, SerializeValue(JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer, JSAutoStructuredCloneBuffer& aBuffer,
jsval aValue); jsval aValue,
JSStructuredCloneCallbacks* aCallbacks = nsnull,
void* aClosure = nsnull);
const nsString& Name() const const nsString& Name() const
{ {
@ -158,7 +162,8 @@ public:
} }
nsresult ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer, nsresult ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer,
Key& aKey); Key& aKey,
PRUint64 aOffsetToKeyProp);
protected: protected:
IDBObjectStore(); IDBObjectStore();
@ -169,7 +174,8 @@ protected:
jsval aKeyVal, jsval aKeyVal,
JSAutoStructuredCloneBuffer& aCloneBuffer, JSAutoStructuredCloneBuffer& aCloneBuffer,
Key& aKey, Key& aKey,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray); nsTArray<IndexUpdateInfo>& aUpdateInfoArray,
PRUint64* aOffsetToKeyProp);
nsresult AddOrPut(const jsval& aValue, nsresult AddOrPut(const jsval& aValue,
const jsval& aKey, const jsval& aKey,
@ -178,8 +184,6 @@ protected:
nsIIDBRequest** _retval, nsIIDBRequest** _retval,
bool aOverwrite); bool aOverwrite);
nsresult EnsureKeyPathSerializationData(JSContext* aCx);
private: private:
nsRefPtr<IDBTransaction> mTransaction; nsRefPtr<IDBTransaction> mTransaction;
@ -193,13 +197,7 @@ private:
PRUint32 mDatabaseId; PRUint32 mDatabaseId;
PRUint32 mStructuredCloneVersion; PRUint32 mStructuredCloneVersion;
// Used to store a serialized representation of the fake property
// entry used to handle autoincrement with keypaths.
JSAutoStructuredCloneBuffer mKeyPathSerialization;
PRUint32 mKeyPathSerializationOffset;
nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes; nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes;
}; };
END_INDEXEDDB_NAMESPACE END_INDEXEDDB_NAMESPACE

Просмотреть файл

@ -46,6 +46,13 @@
using namespace js; using namespace js;
JS_FRIEND_API(uint64_t)
js_GetSCOffset(JSStructuredCloneWriter* writer)
{
JS_ASSERT(writer);
return writer->output().count() * sizeof(uint64_t);
}
namespace js namespace js
{ {

Просмотреть файл

@ -46,6 +46,9 @@
#include "jsvector.h" #include "jsvector.h"
#include "jsvalue.h" #include "jsvalue.h"
JS_FRIEND_API(uint64_t)
js_GetSCOffset(JSStructuredCloneWriter* writer);
namespace js { namespace js {
bool bool
@ -73,6 +76,8 @@ struct SCOutput {
bool extractBuffer(uint64_t **datap, size_t *sizep); bool extractBuffer(uint64_t **datap, size_t *sizep);
uint64_t count() { return buf.length(); }
private: private:
JSContext *cx; JSContext *cx;
js::Vector<uint64_t> buf; js::Vector<uint64_t> buf;

Просмотреть файл

@ -807,7 +807,7 @@ UPLOAD_FILES= \
$(if $(UPLOAD_EXTRA_FILES), $(foreach f, $(UPLOAD_EXTRA_FILES), $(wildcard $(DIST)/$(f)))) $(if $(UPLOAD_EXTRA_FILES), $(foreach f, $(UPLOAD_EXTRA_FILES), $(wildcard $(DIST)/$(f))))
checksum: checksum:
mkdir -p `dirname $CHECKSUM_FILE` mkdir -p `dirname $(CHECKSUM_FILE)`
@$(PYTHON) $(MOZILLA_DIR)/build/checksums.py \ @$(PYTHON) $(MOZILLA_DIR)/build/checksums.py \
-o $(CHECKSUM_FILE) \ -o $(CHECKSUM_FILE) \
-d $(CHECKSUM_ALGORITHM) \ -d $(CHECKSUM_ALGORITHM) \