Backout eb32aca6d54d, b5c0bfd03fcf and 5675bf2c7930 (bug 692669 and bug 692669) for failing to build on all platforms
authorEd Morley <bmo@edmorley.co.uk>
Thu, 03 Nov 2011 01:57:48 +0000
changeset 79647 72042cd154b915c2aa3d3ae042cfcfd7a3e9902a
parent 79646 5675bf2c79309802372d33ff6f4d190c93147f18
child 79648 12744c5b688ddc3087a5f056a1e09c82d70ddb02
push id21418
push usermak77@bonardo.net
push dateThu, 03 Nov 2011 14:57:14 +0000
treeherdermozilla-central@6cbeabc07c59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs692669
milestone10.0a1
backs outeb32aca6d54da877fed264274d69b4354ff03044
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout eb32aca6d54d, b5c0bfd03fcf and 5675bf2c7930 (bug 692669 and bug 692669) for failing to build on all platforms
content/base/public/nsINode.h
dom/indexedDB/DatabaseInfo.h
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBKeyRange.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/Key.h
dom/indexedDB/Makefile.in
dom/indexedDB/nsIIDBCursor.idl
dom/indexedDB/nsIIDBCursorWithValue.idl
dom/indexedDB/nsIIDBDatabase.idl
dom/indexedDB/nsIIDBDatabaseException.idl
dom/indexedDB/nsIIDBFactory.idl
dom/indexedDB/nsIIDBIndex.idl
dom/indexedDB/nsIIDBKeyRange.idl
dom/indexedDB/nsIIDBObjectStore.idl
dom/indexedDB/nsIIDBOpenDBRequest.idl
dom/indexedDB/nsIIDBRequest.idl
dom/indexedDB/nsIIDBTransaction.idl
dom/indexedDB/nsIIDBVersionChangeEvent.idl
dom/indexedDB/nsIIndexedDatabaseManager.idl
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/test_count.html
dom/indexedDB/test/test_object_identity.html
js/xpconnect/public/nsAutoJSValHolder.h
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -46,23 +46,16 @@
 #include "nsCOMPtr.h"
 #include "nsWrapperCache.h"
 #include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
 #include "nsDOMError.h"
 #include "nsDOMString.h"
 #include "jspubtd.h"
 #include "nsDOMMemoryReporter.h"
 
-// Including 'windows.h' will #define GetClassInfo to something else.
-#ifdef XP_WIN
-#ifdef GetClassInfo
-#undef GetClassInfo
-#endif
-#endif
-
 class nsIContent;
 class nsIDocument;
 class nsIDOMEvent;
 class nsIDOMNode;
 class nsIDOMElement;
 class nsIDOMNodeList;
 class nsINodeList;
 class nsIPresShell;
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -38,17 +38,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_databaseinfo_h__
 #define mozilla_dom_indexeddb_databaseinfo_h__
 
 // Only meant to be included in IndexedDB source files, not exported.
 #include "IndexedDatabase.h"
 
-#include "Key.h"
 #include "IDBObjectStore.h"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   DatabaseInfo();
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -34,16 +34,18 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBCursor.h"
 
+#include "nsIVariant.h"
+
 #include "jscntxt.h"
 #include "mozilla/storage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
@@ -268,20 +270,18 @@ IDBCursor::CreateCommon(IDBRequest* aReq
   cursor->mRangeKey = aRangeKey;
 
   return cursor.forget();
 }
 
 IDBCursor::IDBCursor()
 : mType(OBJECTSTORE),
   mDirection(nsIIDBCursor::NEXT),
-  mCachedKey(JSVAL_VOID),
   mCachedPrimaryKey(JSVAL_VOID),
   mCachedValue(JSVAL_VOID),
-  mHaveCachedKey(false),
   mHaveCachedPrimaryKey(false),
   mHaveCachedValue(false),
   mRooted(false),
   mContinueCalled(false),
   mHaveValue(true)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
@@ -306,45 +306,37 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
                                                        nsIDOMEventTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIndex)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
-  NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
-               "Should have a cached key");
   NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
                JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
                "Should have a cached primary key");
   NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
                "Should have a cached value");
-  if (JSVAL_IS_GCTHING(tmp->mCachedKey)) {
-    void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedKey);
-    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedKey")
+  if (JSVAL_IS_GCTHING(tmp->mCachedValue)) {
+    void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedValue);
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedValue")
   }
   if (JSVAL_IS_GCTHING(tmp->mCachedPrimaryKey)) {
     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedPrimaryKey);
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedPrimaryKey")
   }
-  if (JSVAL_IS_GCTHING(tmp->mCachedValue)) {
-    void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedValue);
-    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedValue")
-  }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
   // Don't unlink mObjectStore, mIndex, or mTransaction!
   if (tmp->mRooted) {
     NS_DROP_JS_OBJECTS(tmp, IDBCursor);
-    tmp->mCachedKey = JSVAL_VOID;
     tmp->mCachedPrimaryKey = JSVAL_VOID;
     tmp->mCachedValue = JSVAL_VOID;
-    tmp->mHaveCachedKey = false;
     tmp->mHaveCachedPrimaryKey = false;
     tmp->mHaveCachedValue = false;
     tmp->mRooted = false;
     tmp->mHaveValue = false;
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
@@ -381,43 +373,53 @@ IDBCursor::GetSource(nsISupports** aSour
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   return mType == OBJECTSTORE ?
          CallQueryInterface(mObjectStore, aSource) :
          CallQueryInterface(mIndex, aSource);
 }
 
 NS_IMETHODIMP
-IDBCursor::GetKey(JSContext* aCx,
-                  jsval* aKey)
+IDBCursor::GetKey(nsIVariant** aKey)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
+  if (!mCachedKey) {
+    nsresult rv;
+    nsCOMPtr<nsIWritableVariant> variant =
+      do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
 
-  if (!mHaveValue) {
-    *aKey = JSVAL_VOID;
-    return NS_OK;
+    if (!mHaveValue) {
+      rv = variant->SetAsVoid();
+    }
+    else if (mKey.IsString()) {
+      rv = variant->SetAsAString(mKey.StringValue());
+    }
+    else if (mKey.IsInt()) {
+      rv = variant->SetAsInt64(mKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Huh?!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = variant->SetWritable(false);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    nsIWritableVariant* result;
+    variant.forget(&result);
+
+    mCachedKey = dont_AddRef(static_cast<nsIVariant*>(result));
   }
 
-  if (!mHaveCachedKey) {
-    if (!mRooted) {
-      NS_HOLD_JS_OBJECTS(this, IDBCursor);
-      mRooted = true;
-    }
-
-    JSAutoRequest ar(aCx);
-
-    nsresult rv = mKey.ToJSVal(aCx, &mCachedKey);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mHaveCachedKey = true;
-  }
-
-  *aKey = mCachedKey;
+  nsCOMPtr<nsIVariant> result(mCachedKey);
+  result.forget(aKey);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBCursor::GetPrimaryKey(JSContext* aCx,
                          jsval* aValue)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -433,19 +435,19 @@ IDBCursor::GetPrimaryKey(JSContext* aCx,
       mRooted = true;
     }
 
     JSAutoRequest ar(aCx);
 
     NS_ASSERTION(mType == OBJECTSTORE ? !mKey.IsUnset() :
                                         !mObjectKey.IsUnset(), "Bad key!");
 
-    const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
-
-    nsresult rv = key.ToJSVal(aCx, &mCachedPrimaryKey);
+    nsresult rv =
+      IDBObjectStore::GetJSValFromKey(mType == OBJECTSTORE ? mKey : mObjectKey,
+                                      aCx, &mCachedPrimaryKey);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mHaveCachedPrimaryKey = true;
   }
 
   *aValue = mCachedPrimaryKey;
   return NS_OK;
 }
@@ -491,17 +493,17 @@ IDBCursor::Continue(const jsval &aKey,
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   if (!mHaveValue || mContinueCalled) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   Key key;
-  nsresult rv = key.SetFromJSVal(aCx, aKey);
+  nsresult rv = IDBObjectStore::GetKeyFromJSVal(aKey, aCx, key);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!key.IsUnset()) {
     switch (mDirection) {
       case nsIIDBCursor::NEXT:
       case nsIIDBCursor::NEXT_NO_DUPLICATE:
         if (key <= mKey) {
           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
@@ -581,17 +583,17 @@ IDBCursor::Update(const jsval& aValue,
   NS_ASSERTION(mObjectStore, "This cannot be null!");
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
   NS_ASSERTION(mType != INDEXOBJECT || !mObjectKey.IsUnset(), "Bad key!");
 
   nsresult rv;
 
   JSAutoRequest ar(aCx);
 
-  Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
+  const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
   if (!mObjectStore->KeyPath().IsEmpty()) {
     // This has to be an object.
     if (JSVAL_IS_PRIMITIVE(aValue)) {
       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
 
     // Make sure the object given has the correct keyPath value set on it.
@@ -599,30 +601,30 @@ IDBCursor::Update(const jsval& aValue,
 
     jsval prop;
     JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(aValue),
                                  reinterpret_cast<const jschar*>(keyPath.get()),
                                  keyPath.Length(), &prop);
     NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     Key key;
-    rv = key.SetFromJSVal(aCx, prop);
+    rv = IDBObjectStore::GetKeyFromJSVal(prop, aCx, key);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (key != objectKey) {
       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
 
     return mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, _retval);
   }
 
   jsval keyVal;
-  rv = objectKey.ToJSVal(aCx, &keyVal);
+  rv = IDBObjectStore::GetJSValFromKey(objectKey, aCx, &keyVal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return mObjectStore->Put(aValue, keyVal, aCx, 1, _retval);
 }
 
 NS_IMETHODIMP
 IDBCursor::Delete(JSContext* aCx,
                   nsIIDBRequest** _retval)
@@ -639,20 +641,20 @@ IDBCursor::Delete(JSContext* aCx,
 
   if (!mHaveValue || mType == INDEXKEY) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   NS_ASSERTION(mObjectStore, "This cannot be null!");
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
 
-  Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
+  const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
   jsval key;
-  nsresult rv = objectKey.ToJSVal(aCx, &key);
+  nsresult rv = IDBObjectStore::GetJSValFromKey(objectKey, aCx, &key);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return mObjectStore->Delete(key, aCx, _retval);
 }
 
 nsresult
 ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
@@ -681,47 +683,46 @@ ContinueHelper::DoDatabaseWork(mozIStora
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
     rv = GatherResultsFromStatement(stmt);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
-    mKey.Unset();
+    mKey = Key::UNSETKEY;
   }
 
   return NS_OK;
 }
 
 nsresult
 ContinueHelper::GetSuccessResult(JSContext* aCx,
                                  jsval* aVal)
 {
   // Remove cached stuff from last time.
-  mCursor->mCachedKey = JSVAL_VOID;
-  mCursor->mCachedPrimaryKey = JSVAL_VOID;
+  mCursor->mCachedKey = nsnull;
   mCursor->mCachedValue = JSVAL_VOID;
-  mCursor->mHaveCachedKey = false;
+  mCursor->mCachedPrimaryKey = JSVAL_VOID;
+  mCursor->mHaveCachedValue = false;
   mCursor->mHaveCachedPrimaryKey = false;
-  mCursor->mHaveCachedValue = false;
   mCursor->mContinueCalled = false;
 
   if (mKey.IsUnset()) {
     mCursor->mHaveValue = false;
     *aVal = JSVAL_VOID;
   }
   else {
     NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
                  !mObjectKey.IsUnset(), "Bad key!");
 
     // Set new values.
     mCursor->mKey = mKey;
     mCursor->mObjectKey = mObjectKey;
-    mCursor->mContinueToKey.Unset();
+    mCursor->mContinueToKey = Key::UNSETKEY;
 
     mCursor->mCloneBuffer.swap(mCloneBuffer);
     mCloneBuffer.clear();
 
     nsresult rv = WrapNative(aCx, mCursor, aVal);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
@@ -740,37 +741,65 @@ ContinueObjectStoreHelper::BindArguments
   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
 
   // Bind current key.
   const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
                           mCursor->mKey :
                           mCursor->mContinueToKey;
 
-  rv = currentKey.BindToStatement(aStatement, currentKeyName);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (currentKey.IsString()) {
+    rv = aStatement->BindStringByName(currentKeyName, currentKey.StringValue());
+  }
+  else if (currentKey.IsInt()) {
+    rv = aStatement->BindInt64ByName(currentKeyName, currentKey.IntValue());
+  }
+  else {
+    NS_NOTREACHED("Bad key!");
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Bind range key if it is specified.
   const Key& rangeKey = mCursor->mRangeKey;
 
   if (!rangeKey.IsUnset()) {
-    rv = rangeKey.BindToStatement(aStatement, rangeKeyName);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rangeKey.IsString()) {
+      rv = aStatement->BindStringByName(rangeKeyName, rangeKey.StringValue());
+    }
+    else if (rangeKey.IsInt()) {
+      rv = aStatement->BindInt64ByName(rangeKeyName, rangeKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   return NS_OK;
 }
 
 nsresult
 ContinueObjectStoreHelper::GatherResultsFromStatement(
                                                mozIStorageStatement* aStatement)
 {
   // Figure out what kind of key we have next.
-  nsresult rv = mKey.SetFromStatement(aStatement, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 keyType;
+  nsresult rv = aStatement->GetTypeOfIndex(0, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mKey = aStatement->AsInt64(0);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = aStatement->GetString(0, mKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
 
   rv = IDBObjectStore::GetStructuredCloneDataFromStatement(aStatement, 1,
                                                            mCloneBuffer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
@@ -784,62 +813,152 @@ ContinueIndexHelper::BindArgumentsToStat
 
   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
 
   // Bind current key.
   const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
                           mCursor->mKey :
                           mCursor->mContinueToKey;
 
-  rv = currentKey.BindToStatement(aStatement, currentKeyName);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (currentKey.IsString()) {
+    rv = aStatement->BindStringByName(currentKeyName, currentKey.StringValue());
+  }
+  else if (currentKey.IsInt()) {
+    rv = aStatement->BindInt64ByName(currentKeyName, currentKey.IntValue());
+  }
+  else {
+    NS_NOTREACHED("Bad key!");
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Bind range key if it is specified.
   if (!mCursor->mRangeKey.IsUnset()) {
     NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
-    rv = mCursor->mRangeKey.BindToStatement(aStatement, rangeKeyName);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (mCursor->mRangeKey.IsString()) {
+      rv = aStatement->BindStringByName(rangeKeyName,
+                                        mCursor->mRangeKey.StringValue());
+    }
+    else if (mCursor->mRangeKey.IsInt()) {
+      rv = aStatement->BindInt64ByName(rangeKeyName,
+                                       mCursor->mRangeKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   // Bind object key if duplicates are allowed and we're not continuing to a
   // specific key.
   if ((mCursor->mDirection == nsIIDBCursor::NEXT ||
        mCursor->mDirection == nsIIDBCursor::PREV) &&
        mCursor->mContinueToKey.IsUnset()) {
     NS_ASSERTION(!mCursor->mObjectKey.IsUnset(), "Bad key!");
 
     NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
-    rv = mCursor->mObjectKey.BindToStatement(aStatement, objectKeyName);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (mCursor->mObjectKey.IsString()) {
+      rv = aStatement->BindStringByName(objectKeyName,
+                                        mCursor->mObjectKey.StringValue());
+    }
+    else if (mCursor->mObjectKey.IsInt()) {
+      rv = aStatement->BindInt64ByName(objectKeyName,
+                                       mCursor->mObjectKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   return NS_OK;
 }
 
 nsresult
 ContinueIndexHelper::GatherResultsFromStatement(
                                                mozIStorageStatement* aStatement)
 {
-  nsresult rv = mKey.SetFromStatement(aStatement, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 keyType;
+  nsresult rv = aStatement->GetTypeOfIndex(0, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
 
-  rv = mObjectKey.SetFromStatement(aStatement, 1);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mKey = aStatement->AsInt64(0);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = aStatement->GetString(0, mKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
+
+  rv = aStatement->GetTypeOfIndex(1, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
+
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mObjectKey = aStatement->AsInt64(1);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = aStatement->GetString(1, mObjectKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
 
   return NS_OK;
 }
 
 nsresult
 ContinueIndexObjectHelper::GatherResultsFromStatement(
                                                mozIStorageStatement* aStatement)
 {
-  nsresult rv = mKey.SetFromStatement(aStatement, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 keyType;
+  nsresult rv = aStatement->GetTypeOfIndex(0, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
 
-  rv = mObjectKey.SetFromStatement(aStatement, 1);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mKey = aStatement->AsInt64(0);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = aStatement->GetString(0, mKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
+
+  rv = aStatement->GetTypeOfIndex(1, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
+
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mObjectKey = aStatement->AsInt64(1);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = aStatement->GetString(1, mObjectKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
 
   rv = IDBObjectStore::GetStructuredCloneDataFromStatement(aStatement, 2,
                                                            mCloneBuffer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -37,17 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbcursor_h__
 #define mozilla_dom_indexeddb_idbcursor_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
-#include "mozilla/dom/indexedDB/Key.h"
 
 #include "nsIIDBCursorWithValue.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class nsIRunnable;
 class nsIScriptContext;
 class nsPIDOMWindow;
@@ -146,34 +145,35 @@ protected:
   nsRefPtr<IDBRequest> mRequest;
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBIndex> mIndex;
 
   nsCOMPtr<nsIScriptContext> mScriptContext;
   nsCOMPtr<nsPIDOMWindow> mOwner;
 
+  // Not cycle-collected, this is guaranteed to be primitive!
+  nsCOMPtr<nsIVariant> mCachedKey;
+
   Type mType;
   PRUint16 mDirection;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
 
   // These are cycle-collected!
-  jsval mCachedKey;
   jsval mCachedPrimaryKey;
   jsval mCachedValue;
 
   Key mRangeKey;
 
   Key mKey;
   Key mObjectKey;
   JSAutoStructuredCloneBuffer mCloneBuffer;
   Key mContinueToKey;
 
-  bool mHaveCachedKey;
   bool mHaveCachedPrimaryKey;
   bool mHaveCachedValue;
   bool mRooted;
   bool mContinueCalled;
   bool mHaveValue;
 };
 
 END_INDEXEDDB_NAMESPACE
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -123,16 +123,26 @@ public:
   }
 
 private:
   // In-params.
   PRInt64 mObjectStoreId;
 };
 
 NS_STACK_CLASS
+class AutoFree
+{
+public:
+  AutoFree(void* aPtr) : mPtr(aPtr) { }
+  ~AutoFree() { NS_Free(mPtr); }
+private:
+  void* mPtr;
+};
+
+NS_STACK_CLASS
 class AutoRemoveObjectStore
 {
 public:
   AutoRemoveObjectStore(nsIAtom* aId, const nsAString& aName)
   : mId(aId), mName(aName)
   { }
 
   ~AutoRemoveObjectStore()
@@ -147,16 +157,85 @@ public:
     mId = 0;
   }
 
 private:
   nsCOMPtr<nsIAtom> mId;
   nsString mName;
 };
 
+inline
+nsresult
+ConvertVariantToStringArray(nsIVariant* aVariant,
+                            nsTArray<nsString>& aStringArray)
+{
+#ifdef DEBUG
+  PRUint16 type;
+  NS_ASSERTION(NS_SUCCEEDED(aVariant->GetDataType(&type)) &&
+               type == nsIDataType::VTYPE_ARRAY, "Bad arg!");
+#endif
+
+  PRUint16 valueType;
+  nsIID iid;
+  PRUint32 valueCount;
+  void* rawArray;
+
+  nsresult rv = aVariant->GetAsArray(&valueType, &iid, &valueCount, &rawArray);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  AutoFree af(rawArray);
+
+  // Just delete anything that we don't expect and return.
+  if (valueType != nsIDataType::VTYPE_WCHAR_STR) {
+    switch (valueType) {
+      case nsIDataType::VTYPE_ID:
+      case nsIDataType::VTYPE_CHAR_STR: {
+        char** charArray = reinterpret_cast<char**>(rawArray);
+        for (PRUint32 index = 0; index < valueCount; index++) {
+          if (charArray[index]) {
+            NS_Free(charArray[index]);
+          }
+        }
+      } break;
+
+      case nsIDataType::VTYPE_INTERFACE:
+      case nsIDataType::VTYPE_INTERFACE_IS: {
+        nsISupports** supportsArray = reinterpret_cast<nsISupports**>(rawArray);
+        for (PRUint32 index = 0; index < valueCount; index++) {
+          NS_IF_RELEASE(supportsArray[index]);
+        }
+      } break;
+
+      default: {
+        // The other types are primitives that do not need to be freed.
+      }
+    }
+
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  PRUnichar** strings = reinterpret_cast<PRUnichar**>(rawArray);
+
+  for (PRUint32 index = 0; index < valueCount; index++) {
+    nsString* newString = aStringArray.AppendElement();
+
+    if (!newString) {
+      NS_ERROR("Out of memory?");
+      for (; index < valueCount; index++) {
+        NS_Free(strings[index]);
+      }
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    newString->Adopt(strings[index], -1);
+  }
+
+  return NS_OK;
+}
+
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBDatabase>
 IDBDatabase::Create(nsIScriptContext* aScriptContext,
                     nsPIDOMWindow* aOwner,
                     DatabaseInfo* aDatabaseInfo,
                     const nsACString& aASCIIOrigin)
@@ -610,147 +689,147 @@ IDBDatabase::DeleteObjectStore(const nsA
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   ObjectStoreInfo::Remove(mDatabaseId, aName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBDatabase::Transaction(const jsval& aStoreNames,
+IDBDatabase::Transaction(nsIVariant* aStoreNames,
                          PRUint16 aMode,
+                         PRUint32 aTimeout,
                          JSContext* aCx,
                          PRUint8 aOptionalArgCount,
                          nsIIDBTransaction** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (IndexedDatabaseManager::IsShuttingDown()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (mClosed) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
-  DatabaseInfo* info;
-  if (!DatabaseInfo::Get(mDatabaseId, &info)) {
-    NS_ERROR("This should never fail!");
-  }
-
-  if (info->runningVersionChange) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
-  }
-
   if (aOptionalArgCount) {
     if (aMode != nsIIDBTransaction::READ_WRITE &&
         aMode != nsIIDBTransaction::READ_ONLY) {
       return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     }
   }
   else {
     aMode = nsIIDBTransaction::READ_ONLY;
   }
 
-  nsresult rv;
+  if (aOptionalArgCount <= 1) {
+    aTimeout = kDefaultDatabaseTimeoutSeconds;
+  }
+
+  PRUint16 type;
+  nsresult rv = aStoreNames->GetDataType(&type);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  DatabaseInfo* info;
+  if (!DatabaseInfo::Get(mDatabaseId, &info)) {
+    NS_ERROR("This should never fail!");
+  }
+
+  if (info->runningVersionChange) {
+    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+  }
+
   nsTArray<nsString> storesToOpen;
 
-  if (!JSVAL_IS_PRIMITIVE(aStoreNames)) {
-    JSObject* obj = JSVAL_TO_OBJECT(aStoreNames);
-
-    // See if this is a JS array.
-    if (JS_IsArrayObject(aCx, obj)) {
-      jsuint length;
-      if (!JS_GetArrayLength(aCx, obj, &length)) {
+  switch (type) {
+    case nsIDataType::VTYPE_VOID:
+    case nsIDataType::VTYPE_EMPTY:
+    case nsIDataType::VTYPE_EMPTY_ARRAY: {
+      // Empty, request all object stores
+      if (!info->GetObjectStoreNames(storesToOpen)) {
+        NS_WARNING("Out of memory?");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
+    } break;
 
-      if (!length) {
-        return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+    case nsIDataType::VTYPE_WSTRING_SIZE_IS: {
+      // Single name
+      nsString name;
+      rv = aStoreNames->GetAsAString(name);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      if (!info->ContainsStoreName(name)) {
+        return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
       }
 
-      storesToOpen.SetCapacity(length);
-
-      for (jsuint index = 0; index < length; index++) {
-        jsval val;
-        JSString* jsstr;
-        nsDependentJSString str;
-        if (!JS_GetElement(aCx, obj, index, &val) ||
-            !(jsstr = JS_ValueToString(aCx, val)) ||
-            !str.init(aCx, jsstr)) {
-          return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-        }
+      if (!storesToOpen.AppendElement(name)) {
+        NS_WARNING("Out of memory?");
+        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+      }
+    } break;
 
-        storesToOpen.AppendElement(str);
-      }
-
-      NS_ASSERTION(!storesToOpen.IsEmpty(),
-                   "Must have something here or else code below will "
-                   "misbehave!");
-    }
-    else {
-      // Perhaps some kind of wrapped object?
-      nsIXPConnect* xpc = nsContentUtils::XPConnect();
-      NS_ASSERTION(xpc, "This should never be null!");
-
-      nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-      rv = xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrapper));
+    case nsIDataType::VTYPE_ARRAY: {
+      nsTArray<nsString> names;
+      rv = ConvertVariantToStringArray(aStoreNames, names);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-      if (wrapper) {
-        nsISupports* wrappedObject = wrapper->Native();
-        NS_ENSURE_TRUE(wrappedObject, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-        // We only accept DOMStringList.
-        nsCOMPtr<nsIDOMDOMStringList> list = do_QueryInterface(wrappedObject);
-        if (list) {
-          PRUint32 length;
-          rv = list->GetLength(&length);
-          NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      PRUint32 nameCount = names.Length();
+      for (PRUint32 nameIndex = 0; nameIndex < nameCount; nameIndex++) {
+        nsString& name = names[nameIndex];
 
-          if (!length) {
-            return NS_ERROR_DOM_INVALID_ACCESS_ERR;
-          }
-
-          storesToOpen.SetCapacity(length);
+        if (!info->ContainsStoreName(name)) {
+          return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
+        }
 
-          for (PRUint32 index = 0; index < length; index++) {
-            nsString* item = storesToOpen.AppendElement();
-            NS_ASSERTION(item, "This should never fail!");
-
-            rv = list->Item(index, *item);
-            NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-          }
-
-          NS_ASSERTION(!storesToOpen.IsEmpty(),
-                       "Must have something here or else code below will "
-                       "misbehave!");
+        if (!storesToOpen.AppendElement(name)) {
+          NS_WARNING("Out of memory?");
+          return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
       }
-    }
-  }
+      NS_ASSERTION(nameCount == storesToOpen.Length(), "Should have bailed!");
+    } break;
+
+    case nsIDataType::VTYPE_INTERFACE:
+    case nsIDataType::VTYPE_INTERFACE_IS: {
+      nsCOMPtr<nsISupports> supports;
+      nsID *iid;
+      rv = aStoreNames->GetAsInterface(&iid, getter_AddRefs(supports));
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      NS_Free(iid);
+
+      nsCOMPtr<nsIDOMDOMStringList> stringList(do_QueryInterface(supports));
+      if (!stringList) {
+        // We don't support anything other than nsIDOMDOMStringList.
+        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
+      }
 
-  // If our list is empty here then the argument must have been an object that
-  // we don't support or a primitive. Either way we convert to a string.
-  if (storesToOpen.IsEmpty()) {
-    JSString* jsstr;
-    nsDependentJSString str;
-    if (!(jsstr = JS_ValueToString(aCx, aStoreNames)) ||
-        !str.init(aCx, jsstr)) {
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
+      PRUint32 stringCount;
+      rv = stringList->GetLength(&stringCount);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      for (PRUint32 stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+        nsString name;
+        rv = stringList->Item(stringIndex, name);
+        NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    storesToOpen.AppendElement(str);
-  }
+        if (!info->ContainsStoreName(name)) {
+          return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
+        }
 
-  // Now check to make sure the object store names we collected actually exist.
-  for (PRUint32 index = 0; index < storesToOpen.Length(); index++) {
-    if (!info->ContainsStoreName(storesToOpen[index])) {
-      return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
-    }
+        if (!storesToOpen.AppendElement(name)) {
+          NS_WARNING("Out of memory?");
+          return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+        }
+      }
+    } break;
+
+    default:
+      return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
   }
 
   nsRefPtr<IDBTransaction> transaction =
     IDBTransaction::Create(this, storesToOpen, aMode,
                            kDefaultDatabaseTimeoutSeconds);
   NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   transaction.forget(_retval);
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -47,17 +47,16 @@
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsThreadUtils.h"
 #include "mozilla/storage.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
-#include "IDBKeyRange.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
@@ -163,118 +162,102 @@ protected:
 };
 
 class OpenKeyCursorHelper : public AsyncConnectionHelper
 {
 public:
   OpenKeyCursorHelper(IDBTransaction* aTransaction,
                       IDBRequest* aRequest,
                       IDBIndex* aIndex,
-                      IDBKeyRange* aKeyRange,
+                      const Key& aLowerKey,
+                      const Key& aUpperKey,
+                      bool aLowerOpen,
+                      bool aUpperOpen,
                       PRUint16 aDirection)
   : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange), mDirection(aDirection)
+    mLowerKey(aLowerKey), mUpperKey(aUpperKey), mLowerOpen(aLowerOpen),
+    mUpperOpen(aUpperOpen), mDirection(aDirection)
   { }
 
   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   nsresult GetSuccessResult(JSContext* aCx,
                             jsval* aVal);
 
   void ReleaseMainThreadObjects()
   {
     mIndex = nsnull;
-    mKeyRange = nsnull;
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
-  nsRefPtr<IDBKeyRange> mKeyRange;
+  const Key mLowerKey;
+  const Key mUpperKey;
+  const bool mLowerOpen;
+  const bool mUpperOpen;
   const PRUint16 mDirection;
 
   // Out-params.
   Key mKey;
   Key mObjectKey;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
 };
 
 class OpenCursorHelper : public AsyncConnectionHelper
 {
 public:
   OpenCursorHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBIndex* aIndex,
-                   IDBKeyRange* aKeyRange,
+                   const Key& aLowerKey,
+                   const Key& aUpperKey,
+                   bool aLowerOpen,
+                   bool aUpperOpen,
                    PRUint16 aDirection)
   : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange), mDirection(aDirection)
+    mLowerKey(aLowerKey), mUpperKey(aUpperKey), mLowerOpen(aLowerOpen),
+    mUpperOpen(aUpperOpen), mDirection(aDirection)
   { }
 
   ~OpenCursorHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
   }
 
   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   nsresult GetSuccessResult(JSContext* aCx,
                             jsval* aVal);
 
   void ReleaseMainThreadObjects()
   {
     mIndex = nsnull;
-    mKeyRange = nsnull;
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
-  nsRefPtr<IDBKeyRange> mKeyRange;
+  const Key mLowerKey;
+  const Key mUpperKey;
+  const bool mLowerOpen;
+  const bool mUpperOpen;
   const PRUint16 mDirection;
 
   // Out-params.
   Key mKey;
   Key mObjectKey;
   JSAutoStructuredCloneBuffer mCloneBuffer;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
 };
 
-class CountHelper : public AsyncConnectionHelper
-{
-public:
-  CountHelper(IDBTransaction* aTransaction,
-              IDBRequest* aRequest,
-              IDBIndex* aIndex,
-              IDBKeyRange* aKeyRange)
-  : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange), mCount(0)
-  { }
-
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mIndex = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
-
-private:
-  nsRefPtr<IDBIndex> mIndex;
-  nsRefPtr<IDBKeyRange> mKeyRange;
-  PRUint64 mCount;
-};
-
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBIndex* aIndex)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   IDBTransaction* transaction = aIndex->ObjectStore()->Transaction();
   IDBDatabase* database = transaction->Database();
   return IDBRequest::Create(aIndex, database->ScriptContext(),
@@ -283,17 +266,17 @@ GenerateRequest(IDBIndex* aIndex)
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBIndex>
 IDBIndex::Create(IDBObjectStore* aObjectStore,
                  const IndexInfo* aIndexInfo)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(aIndexInfo, "Null pointer!");
 
   IDBDatabase* database = aObjectStore->Transaction()->Database();
 
   nsRefPtr<IDBIndex> index = new IDBIndex();
 
   index->mScriptContext = database->ScriptContext();
@@ -309,22 +292,22 @@ IDBIndex::Create(IDBObjectStore* aObject
   return index.forget();
 }
 
 IDBIndex::IDBIndex()
 : mId(LL_MININT),
   mUnique(false),
   mAutoIncrement(false)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBIndex::~IDBIndex()
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
@@ -345,174 +328,193 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex)
 
 DOMCI_DATA(IDBIndex, IDBIndex)
 
 NS_IMETHODIMP
 IDBIndex::GetName(nsAString& aName)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   aName.Assign(mName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetStoreName(nsAString& aStoreName)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   return mObjectStore->GetName(aStoreName);
 }
 
 NS_IMETHODIMP
 IDBIndex::GetKeyPath(nsAString& aKeyPath)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   aKeyPath.Assign(mKeyPath);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetUnique(bool* aUnique)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   *aUnique = mUnique;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetObjectStore(nsIIDBObjectStore** aObjectStore)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIIDBObjectStore> objectStore(mObjectStore);
   objectStore.forget(aObjectStore);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::Get(const jsval& aKey,
-              JSContext* aCx,
+IDBIndex::Get(nsIVariant* aKey,
               nsIIDBRequest** _retval)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   Key key;
-  nsresult rv = key.SetFromJSVal(aCx, aKey);
+  nsresult rv = IDBObjectStore::GetKeyFromVariant(aKey, key);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  if (key.IsUnset()) {
+    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  }
+
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  nsRefPtr<GetHelper> helper =
-    new GetHelper(transaction, request, this, key);
+  nsRefPtr<GetHelper> helper = new GetHelper(transaction, request, this, key);
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::GetKey(const jsval& aKey,
-                 JSContext* aCx,
+IDBIndex::GetKey(nsIVariant* aKey,
                  nsIIDBRequest** _retval)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   Key key;
-  nsresult rv = key.SetFromJSVal(aCx, aKey);
+  nsresult rv = IDBObjectStore::GetKeyFromVariant(aKey, key);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  if (key.IsUnset()) {
+    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  }
+
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetKeyHelper> helper =
     new GetKeyHelper(transaction, request, this, key);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::GetAll(const jsval& aKey,
+IDBIndex::GetAll(nsIVariant* aKey,
                  PRUint32 aLimit,
-                 JSContext* aCx,
                  PRUint8 aOptionalArgCount,
                  nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
+  nsresult rv;
+
   Key key;
-  if (aOptionalArgCount && NS_FAILED(key.SetFromJSVal(aCx, aKey))) {
-    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  if (aOptionalArgCount &&
+      NS_FAILED(IDBObjectStore::GetKeyFromVariant(aKey, key))) {
+    PRUint16 type;
+    rv = aKey->GetDataType(&type);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (type != nsIDataType::VTYPE_EMPTY) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    }
   }
 
   if (aOptionalArgCount < 2) {
     aLimit = PR_UINT32_MAX;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetAllHelper> helper =
     new GetAllHelper(transaction, request, this, key, aLimit);
 
-  nsresult rv = helper->DispatchToTransactionPool();
+  rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::GetAllKeys(const jsval& aKey,
+IDBIndex::GetAllKeys(nsIVariant* aKey,
                      PRUint32 aLimit,
-                     JSContext* aCx,
                      PRUint8 aOptionalArgCount,
                      nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
 
   Key key;
-  if (aOptionalArgCount && NS_FAILED(key.SetFromJSVal(aCx, aKey))) {
-    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  if (aOptionalArgCount &&
+      NS_FAILED(IDBObjectStore::GetKeyFromVariant(aKey, key))) {
+    PRUint16 type;
+    rv = aKey->GetDataType(&type);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (type != nsIDataType::VTYPE_EMPTY) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    }
   }
 
   if (aOptionalArgCount < 2) {
     aLimit = PR_UINT32_MAX;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -523,133 +525,144 @@ IDBIndex::GetAllKeys(const jsval& aKey,
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::OpenCursor(const jsval& aKey,
+IDBIndex::OpenCursor(nsIIDBKeyRange* aKeyRange,
                      PRUint16 aDirection,
-                     JSContext* aCx,
                      PRUint8 aOptionalArgCount,
                      nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
+  Key lowerKey, upperKey;
+  bool lowerOpen = false, upperOpen = false;
 
-  nsRefPtr<IDBKeyRange> keyRange;
-  if (aOptionalArgCount) {
-    rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (aKeyRange) {
+    nsCOMPtr<nsIVariant> variant;
+    rv = aKeyRange->GetLower(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = IDBObjectStore::GetKeyFromVariant(variant, lowerKey);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    rv = aKeyRange->GetUpper(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    if (aOptionalArgCount >= 2) {
-      if (aDirection != nsIIDBCursor::NEXT &&
-          aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
-          aDirection != nsIIDBCursor::PREV &&
-          aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
-        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
-      }
+    rv = IDBObjectStore::GetKeyFromVariant(variant, upperKey);
+    if (NS_FAILED(rv)) {
+      return rv;
     }
-    else {
-      aDirection = nsIIDBCursor::NEXT;
+
+    rv = aKeyRange->GetLowerOpen(&lowerOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = aKeyRange->GetUpperOpen(&upperOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (aOptionalArgCount >= 2) {
+    if (aDirection != nsIIDBCursor::NEXT &&
+        aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
+        aDirection != nsIIDBCursor::PREV &&
+        aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
+      return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     }
   }
+  else {
+    aDirection = nsIIDBCursor::NEXT;
+  }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
-    new OpenCursorHelper(transaction, request, this, keyRange, aDirection);
+    new OpenCursorHelper(transaction, request, this, lowerKey, upperKey,
+                         lowerOpen, upperOpen, aDirection);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::OpenKeyCursor(const jsval& aKey,
+IDBIndex::OpenKeyCursor(nsIIDBKeyRange* aKeyRange,
                         PRUint16 aDirection,
-                        JSContext* aCx,
                         PRUint8 aOptionalArgCount,
                         nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
+  Key lowerKey, upperKey;
+  bool lowerOpen = false, upperOpen = false;
 
-  nsRefPtr<IDBKeyRange> keyRange;
-  if (aOptionalArgCount) {
-    rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (aKeyRange) {
+    nsCOMPtr<nsIVariant> variant;
+    rv = aKeyRange->GetLower(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = IDBObjectStore::GetKeyFromVariant(variant, lowerKey);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    rv = aKeyRange->GetUpper(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    if (aOptionalArgCount >= 2) {
-      if (aDirection != nsIIDBCursor::NEXT &&
-          aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
-          aDirection != nsIIDBCursor::PREV &&
-          aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
-        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
-      }
+    rv = IDBObjectStore::GetKeyFromVariant(variant, upperKey);
+    if (NS_FAILED(rv)) {
+      return rv;
     }
-    else {
-      aDirection = nsIIDBCursor::NEXT;
+
+    rv = aKeyRange->GetLowerOpen(&lowerOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = aKeyRange->GetUpperOpen(&upperOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (aOptionalArgCount >= 2) {
+    if (aDirection != nsIIDBCursor::NEXT &&
+        aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
+        aDirection != nsIIDBCursor::PREV &&
+        aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
+      return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     }
   }
+  else {
+    aDirection = nsIIDBCursor::NEXT;
+  }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenKeyCursorHelper> helper =
-    new OpenKeyCursorHelper(transaction, request, this, keyRange, aDirection);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  request.forget(_retval);
-  return NS_OK;
-}
+    new OpenKeyCursorHelper(transaction, request, this, lowerKey, upperKey,
+                            lowerOpen, upperOpen, aDirection);
 
-NS_IMETHODIMP
-IDBIndex::Count(const jsval& aKey,
-                JSContext* aCx,
-                PRUint8 aOptionalArgCount,
-                nsIIDBRequest** _retval)
-{
-  IDBTransaction* transaction = mObjectStore->Transaction();
-  if (!transaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
-  }
-
-  nsresult rv;
-
-  nsRefPtr<IDBKeyRange> keyRange;
-  if (aOptionalArgCount) {
-    rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<CountHelper> helper =
-    new CountHelper(transaction, request, this, keyRange);
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
@@ -665,39 +678,63 @@ GetKeyHelper::DoDatabaseWork(mozIStorage
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_NAMED_LITERAL_CSTRING(value, "value");
 
-  rv = mKey.BindToStatement(stmt, value);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (mKey.IsInt()) {
+    rv = stmt->BindInt64ByName(value, mKey.IntValue());
+  }
+  else if (mKey.IsString()) {
+    rv = stmt->BindStringByName(value, mKey.StringValue());
+  }
+  else {
+    NS_NOTREACHED("Bad key type!");
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  mKey.Unset();
+  mKey = Key::UNSETKEY;
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
-    rv = mKey.SetFromStatement(stmt, 0);
-    NS_ENSURE_SUCCESS(rv, rv);
+    PRInt32 keyType;
+    rv = stmt->GetTypeOfIndex(0, &keyType);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+                 keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+                 "Bad key type!");
+
+    if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+      mKey = stmt->AsInt64(0);
+    }
+    else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+      rv = stmt->GetString(0, mKey.ToString());
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    }
+    else {
+      NS_NOTREACHED("Bad SQLite type!");
+    }
   }
 
   return NS_OK;
 }
 
 nsresult
 GetKeyHelper::GetSuccessResult(JSContext* aCx,
                                jsval* aVal)
 {
   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
-  return mKey.ToJSVal(aCx, aVal);
+  return IDBObjectStore::GetJSValFromKey(mKey, aCx, aVal);
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
   nsCOMPtr<mozIStorageStatement> stmt =
@@ -708,20 +745,28 @@ GetHelper::DoDatabaseWork(mozIStorageCon
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
                                       mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_NAMED_LITERAL_CSTRING(value, "value");
 
-  rv = mKey.BindToStatement(stmt, value);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (mKey.IsInt()) {
+    rv = stmt->BindInt64ByName(value, mKey.IntValue());
+  }
+  else if (mKey.IsString()) {
+    rv = stmt->BindStringByName(value, mKey.StringValue());
+  }
+  else {
+    NS_NOTREACHED("Bad key type!");
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  mKey.Unset();
+  mKey = Key::UNSETKEY;
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
     rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0,
                                                              mCloneBuffer);
@@ -800,31 +845,58 @@ GetAllKeysHelper::DoDatabaseWork(mozISto
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!mKey.IsUnset()) {
-    rv = mKey.BindToStatement(stmt, value);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (mKey.IsInt()) {
+      rv = stmt->BindInt64ByName(value, mKey.IntValue());
+    }
+    else if (mKey.IsString()) {
+      rv = stmt->BindStringByName(value, mKey.StringValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key type!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   bool hasResult;
   while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
     if (mKeys.Capacity() == mKeys.Length()) {
-      mKeys.SetCapacity(mKeys.Capacity() * 2);
+      if (!mKeys.SetCapacity(mKeys.Capacity() * 2)) {
+        NS_ERROR("Out of memory!");
+        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+      }
     }
 
     Key* key = mKeys.AppendElement();
     NS_ASSERTION(key, "This shouldn't fail!");
 
-    rv = key->SetFromStatement(stmt, 0);
-    NS_ENSURE_SUCCESS(rv, rv);
+    PRInt32 keyType;
+    rv = stmt->GetTypeOfIndex(0, &keyType);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+                 keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+                 "Bad key type!");
+
+    if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+      *key = stmt->AsInt64(0);
+    }
+    else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+      rv = stmt->GetString(0, key->ToString());
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    }
+    else {
+      NS_NOTREACHED("Bad SQLite type!");
+    }
   }
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
@@ -852,17 +924,17 @@ GetAllKeysHelper::GetSuccessResult(JSCon
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32 index = 0, count = keys.Length(); index < count; index++) {
       const Key& key = keys[index];
       NS_ASSERTION(!key.IsUnset(), "Bad key!");
 
       jsval value;
-      nsresult rv = key.ToJSVal(aCx, &value);
+      nsresult rv = IDBObjectStore::GetJSValFromKey(key, aCx, &value);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to get jsval for key!");
         return rv;
       }
 
       if (!JS_SetElement(aCx, array, index, &value)) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -937,18 +1009,26 @@ GetAllHelper::DoDatabaseWork(mozIStorage
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!mKey.IsUnset()) {
-    rv = mKey.BindToStatement(stmt, value);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (mKey.IsInt()) {
+      rv = stmt->BindInt64ByName(value, mKey.IntValue());
+    }
+    else if (mKey.IsString()) {
+      rv = stmt->BindStringByName(value, mKey.StringValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key type!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   bool hasResult;
   while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
     if (mCloneBuffers.Capacity() == mCloneBuffers.Length()) {
       if (!mCloneBuffers.SetCapacity(mCloneBuffers.Capacity() * 2)) {
         NS_ERROR("Out of memory!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -1011,25 +1091,23 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
 
   NS_NAMED_LITERAL_CSTRING(id, "id");
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   NS_NAMED_LITERAL_CSTRING(value, "value");
 
   nsCAutoString keyRangeClause;
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      AppendConditionClause(value, lowerKeyName, false,
-                            !mKeyRange->IsLowerOpen(), keyRangeClause);
-    }
-    if (!mKeyRange->Upper().IsUnset()) {
-      AppendConditionClause(value, upperKeyName, true,
-                            !mKeyRange->IsUpperOpen(), keyRangeClause);
-    }
+  if (!mLowerKey.IsUnset()) {
+    AppendConditionClause(value, lowerKeyName, false, !mLowerOpen,
+                          keyRangeClause);
+  }
+  if (!mUpperKey.IsUnset()) {
+    AppendConditionClause(value, upperKeyName, true, !mUpperOpen,
+                          keyRangeClause);
   }
 
   nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value;
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
       directionClause.AppendLiteral(" ASC");
       break;
@@ -1055,103 +1133,145 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
     mTransaction->GetCachedStatement(firstQuery);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+  if (!mLowerKey.IsUnset()) {
+    if (mLowerKey.IsString()) {
+      rv = stmt->BindStringByName(lowerKeyName, mLowerKey.StringValue());
+    }
+    else if (mLowerKey.IsInt()) {
+      rv = stmt->BindInt64ByName(lowerKeyName, mLowerKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
     }
-    if (!mKeyRange->Upper().IsUnset()) {
-      rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (!mUpperKey.IsUnset()) {
+    if (mUpperKey.IsString()) {
+      rv = stmt->BindStringByName(upperKeyName, mUpperKey.StringValue());
     }
+    else if (mUpperKey.IsInt()) {
+      rv = stmt->BindInt64ByName(upperKeyName, mUpperKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
-    mKey.Unset();
+    mKey = Key::UNSETKEY;
     return NS_OK;
   }
 
-  rv = mKey.SetFromStatement(stmt, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 keyType;
+  rv = stmt->GetTypeOfIndex(0, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
 
-  rv = mObjectKey.SetFromStatement(stmt, 1);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mKey = stmt->AsInt64(0);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = stmt->GetString(0, mKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
+
+  rv = stmt->GetTypeOfIndex(1, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
+
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mObjectKey = stmt->AsInt64(1);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = stmt->GetString(1, mObjectKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
 
   // Now we need to make the query to get the next match.
   nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, ") + keyColumn +
                              NS_LITERAL_CSTRING(" FROM ") + table +
                              NS_LITERAL_CSTRING(" WHERE index_id = :") + id;
 
   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
   NS_NAMED_LITERAL_CSTRING(objectKey, "object_key");
 
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
-      if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
-        AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Upper();
+      if (!mUpperKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, true, !mUpperOpen, queryStart);
+        mRangeKey = mUpperKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ( ( value = :") +
                        currentKey + NS_LITERAL_CSTRING(" AND ") + keyColumn +
                        NS_LITERAL_CSTRING(" > :") + objectKey +
                        NS_LITERAL_CSTRING(" ) OR ( value > :") + currentKey +
                        NS_LITERAL_CSTRING(" ) )") + directionClause +
                        NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
                          currentKey + NS_LITERAL_CSTRING(" LIMIT 1");
       break;
 
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
-      if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
-        AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Upper();
+      if (!mUpperKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, true, !mUpperOpen, queryStart);
+        mRangeKey = mUpperKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value > :") +
                        currentKey + directionClause +
                        NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
                          currentKey + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
       break;
 
     case nsIIDBCursor::PREV:
-      if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
-        AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Lower();
+      if (!mLowerKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, false, !mLowerOpen, queryStart);
+        mRangeKey = mLowerKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ( ( value = :") +
                        currentKey + NS_LITERAL_CSTRING(" AND ") + keyColumn +
                        NS_LITERAL_CSTRING(" < :") + objectKey +
                        NS_LITERAL_CSTRING(" ) OR ( value < :") + currentKey +
                        NS_LITERAL_CSTRING(" ) )") + directionClause +
                        NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
                          currentKey + NS_LITERAL_CSTRING(" LIMIT 1");
       break;
 
     case nsIIDBCursor::PREV_NO_DUPLICATE:
-      if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
-        AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Lower();
+      if (!mLowerKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, false, !mLowerOpen, queryStart);
+        mRangeKey = mLowerKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value < :") +
                        currentKey + directionClause +
                        NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
                          currentKey + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
       break;
@@ -1217,25 +1337,23 @@ OpenCursorHelper::DoDatabaseWork(mozISto
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsCString value = indexTable + NS_LITERAL_CSTRING(".value");
   nsCString data = objectTable + NS_LITERAL_CSTRING(".data");
   nsCString keyValue = objectTable + NS_LITERAL_CSTRING(".") + keyValueColumn;
 
   nsCAutoString keyRangeClause;
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      AppendConditionClause(value, lowerKeyName, false,
-                            !mKeyRange->IsLowerOpen(), keyRangeClause);
-    }
-    if (!mKeyRange->Upper().IsUnset()) {
-      AppendConditionClause(value, upperKeyName, true,
-                            !mKeyRange->IsUpperOpen(), keyRangeClause);
-    }
+  if (!mLowerKey.IsUnset()) {
+    AppendConditionClause(value, lowerKeyName, false, !mLowerOpen,
+                          keyRangeClause);
+  }
+  if (!mUpperKey.IsUnset()) {
+    AppendConditionClause(value, upperKeyName, true, !mUpperOpen,
+                          keyRangeClause);
   }
 
   nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value;
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
       directionClause.AppendLiteral(" ASC");
       break;
@@ -1268,41 +1386,87 @@ OpenCursorHelper::DoDatabaseWork(mozISto
     mTransaction->GetCachedStatement(firstQuery);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+  if (!mLowerKey.IsUnset()) {
+    if (mLowerKey.IsString()) {
+      rv = stmt->BindStringByName(lowerKeyName, mLowerKey.StringValue());
+    }
+    else if (mLowerKey.IsInt()) {
+      rv = stmt->BindInt64ByName(lowerKeyName, mLowerKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
     }
-    if (!mKeyRange->Upper().IsUnset()) {
-      rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (!mUpperKey.IsUnset()) {
+    if (mUpperKey.IsString()) {
+      rv = stmt->BindStringByName(upperKeyName, mUpperKey.StringValue());
     }
+    else if (mUpperKey.IsInt()) {
+      rv = stmt->BindInt64ByName(upperKeyName, mUpperKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
-    mKey.Unset();
+    mKey = Key::UNSETKEY;
     return NS_OK;
   }
 
-  rv = mKey.SetFromStatement(stmt, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 keyType;
+  rv = stmt->GetTypeOfIndex(0, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
 
-  rv = mObjectKey.SetFromStatement(stmt, 1);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mKey = stmt->AsInt64(0);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = stmt->GetString(0, mKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
+
+  rv = stmt->GetTypeOfIndex(1, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(keyType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
+               keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
+               "Bad key type!");
+
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mObjectKey = stmt->AsInt64(1);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = stmt->GetString(1, mObjectKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
 
   rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 2,
                                                            mCloneBuffer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now we need to make the query to get the next match.
   nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT ") + value +
                              NS_LITERAL_CSTRING(", ") + keyValue +
@@ -1316,74 +1480,70 @@ OpenCursorHelper::DoDatabaseWork(mozISto
                              NS_LITERAL_CSTRING(".index_id = :id");
 
   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
   NS_NAMED_LITERAL_CSTRING(objectKey, "object_key");
 
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
-      if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
-        AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Upper();
+      if (!mUpperKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, true, !mUpperOpen, queryStart);
+        mRangeKey = mUpperKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ( ( ") +
                        value + NS_LITERAL_CSTRING(" = :") + currentKey +
                        NS_LITERAL_CSTRING(" AND ") + keyValue +
                        NS_LITERAL_CSTRING(" > :") + objectKey +
                        NS_LITERAL_CSTRING(" ) OR ( ") + value +
                        NS_LITERAL_CSTRING(" > :") + currentKey +
                        NS_LITERAL_CSTRING(" ) )") + directionClause +
                        NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value +
                          NS_LITERAL_CSTRING(" >= :") +
                          currentKey + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
       break;
 
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
-      if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
-        AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Upper();
+      if (!mUpperKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, true, !mUpperOpen, queryStart);
+        mRangeKey = mUpperKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value +
                        NS_LITERAL_CSTRING(" > :") + currentKey +
                        directionClause + NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value +
                          NS_LITERAL_CSTRING(" >= :") + currentKey +
                          directionClause + NS_LITERAL_CSTRING(" LIMIT 1");
       break;
 
     case nsIIDBCursor::PREV:
-      if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
-        AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Lower();
+      if (!mLowerKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, false, !mLowerOpen, queryStart);
+        mRangeKey = mLowerKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ( ( ") +
                        value + NS_LITERAL_CSTRING(" = :") + currentKey +
                        NS_LITERAL_CSTRING(" AND ") + keyValue +
                        NS_LITERAL_CSTRING(" < :") + objectKey +
                        NS_LITERAL_CSTRING(" ) OR ( ") + value +
                        NS_LITERAL_CSTRING(" < :") + currentKey +
                        NS_LITERAL_CSTRING(" ) )") + directionClause +
                        NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value +
                          NS_LITERAL_CSTRING(" <= :") +
                          currentKey + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
       break;
 
     case nsIIDBCursor::PREV_NO_DUPLICATE:
-      if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
-        AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
-                              queryStart);
-        mRangeKey = mKeyRange->Lower();
+      if (!mLowerKey.IsUnset()) {
+        AppendConditionClause(value, rangeKey, false, !mLowerOpen, queryStart);
+        mRangeKey = mLowerKey;
       }
       mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value +
                        NS_LITERAL_CSTRING(" < :") + currentKey +
                        directionClause + NS_LITERAL_CSTRING(" LIMIT 1");
       mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND ") + value +
                          NS_LITERAL_CSTRING(" <= :") + currentKey +
                          directionClause + NS_LITERAL_CSTRING(" LIMIT 1");
       break;
@@ -1409,87 +1569,8 @@ OpenCursorHelper::GetSuccessResult(JSCon
                       mContinueQuery, mContinueToQuery, mKey, mObjectKey,
                       mCloneBuffer);
   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneBuffer.data(), "Should have swapped!");
 
   return WrapNative(aCx, cursor, aVal);
 }
-
-nsresult
-CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
-{
-  nsCString table;
-
-  if (mIndex->IsAutoIncrement()) {
-    if (mIndex->IsUnique()) {
-      table.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      table.AssignLiteral("ai_index_data");
-    }
-  }
-  else {
-    if (mIndex->IsUnique()) {
-      table.AssignLiteral("unique_index_data");
-    }
-    else {
-      table.AssignLiteral("index_data");
-    }
-  }
-
-  NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
-  NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
-  NS_NAMED_LITERAL_CSTRING(value, "value");
-
-  nsCAutoString keyRangeClause;
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      AppendConditionClause(value, lowerKeyName, false,
-                            !mKeyRange->IsLowerOpen(), keyRangeClause);
-    }
-    if (!mKeyRange->Upper().IsUnset()) {
-      AppendConditionClause(value, upperKeyName, true,
-                            !mKeyRange->IsUpperOpen(), keyRangeClause);
-    }
-  }
-
-  NS_NAMED_LITERAL_CSTRING(id, "id");
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE index_id = :") + id +
-                    keyRangeClause;
-
-  nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  mozStorageStatementScoper scoper(stmt);
-
-  nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    if (!mKeyRange->Upper().IsUnset()) {
-      rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-
-  bool hasResult;
-  rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  NS_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  mCount = stmt->AsInt64(0);
-  return NS_OK;
-}
-
-nsresult
-CountHelper::GetSuccessResult(JSContext* aCx,
-                              jsval* aVal)
-{
-  return JS_NewNumberValue(aCx, static_cast<jsdouble>(mCount), aVal);
-}
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -37,206 +37,230 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBKeyRange.h"
 
 #include "nsIXPConnect.h"
 
 #include "jscntxt.h"
-#include "nsDOMClassInfo.h"
+#include "nsDOMClassInfoID.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 
 #include "Key.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 inline
-bool
+JSBool
+ConvertArguments(JSContext* aCx,
+                 uintN aArgc,
+                 jsval* aVp,
+                 const char* aMethodName,
+                 nsTArray<nsCOMPtr<nsIVariant> >& aKeys)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aCx, "Null pointer!");
+  NS_ASSERTION(aVp, "Null pointer!");
+  NS_ASSERTION(aMethodName, "Null pointer!");
+  NS_ASSERTION(aKeys.Capacity(), "Need guaranteed capacity!");
+  NS_ASSERTION(aKeys.IsEmpty(), "Not an empty array!");
+
+  if (aArgc < aKeys.Capacity()) {
+    nsCString num;
+    num.AppendInt(aKeys.Length());
+    JS_ReportErrorNumberUC(aCx, js_GetErrorMessage, nsnull,
+                           JSMSG_MORE_ARGS_NEEDED, aMethodName, num.get(),
+                           aKeys.Capacity() == 1 ? "" : "s");
+    return JS_FALSE;
+  }
+
+  for (uintN i = 0; i < aKeys.Capacity(); i++) {
+    jsval& arg = JS_ARGV(aCx, aVp)[i];
+    if (JSVAL_IS_VOID(arg) || JSVAL_IS_NULL(arg) ||
+        !Key::CanBeConstructedFromJSVal(arg)) {
+      JS_ReportError(aCx, "Argument is not a supported key type.");
+      return JS_FALSE;
+    }
+
+    nsIXPConnect* xpc = nsContentUtils::XPConnect();
+    NS_ASSERTION(xpc, "This should never be null!");
+
+    nsCOMPtr<nsIVariant>* key = aKeys.AppendElement();
+    NS_ASSERTION(key, "This should never fail!");
+
+    if (NS_FAILED(xpc->JSValToVariant(aCx, &arg, getter_AddRefs(*key)))) {
+      JS_ReportError(aCx, "Could not convert argument to variant.");
+      return JS_FALSE;
+    }
+  }
+
+  return JS_TRUE;
+}
+
+inline
+JSBool
 ReturnKeyRange(JSContext* aCx,
                jsval* aVp,
                IDBKeyRange* aKeyRange)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aCx, "Null pointer!");
   NS_ASSERTION(aVp, "Null pointer!");
   NS_ASSERTION(aKeyRange, "Null pointer!");
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   NS_ASSERTION(xpc, "This should never be null!");
 
   JSObject* global = JS_GetGlobalForScopeChain(aCx);
-  if (!global) {
-    NS_WARNING("Couldn't get global object!");
-    return false;
-  }
+  NS_ENSURE_TRUE(global, JS_FALSE);
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   if (NS_FAILED(xpc->WrapNative(aCx, global, aKeyRange,
                                 NS_GET_IID(nsIIDBKeyRange),
                                 getter_AddRefs(holder)))) {
     JS_ReportError(aCx, "Couldn't wrap IDBKeyRange object.");
-    return false;
+    return JS_FALSE;
   }
 
   JSObject* result;
   if (NS_FAILED(holder->GetJSObject(&result))) {
     JS_ReportError(aCx, "Couldn't get JSObject from wrapper.");
-    return false;
+    return JS_FALSE;
   }
 
   JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(result));
-  return true;
-}
-
-inline
-nsresult
-GetKeyFromJSVal(JSContext* aCx,
-                jsval aVal,
-                Key& aKey,
-                bool aAllowUnset = false)
-{
-  nsresult rv = aKey.SetFromJSVal(aCx, aVal);
-  if (NS_FAILED(rv)) {
-    NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB,
-                 "Bad error code!");
-    return rv;
-  }
-
-  if (aKey.IsUnset() && !aAllowUnset) {
-    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-  }
-
-  return NS_OK;
-}
-
-inline
-void
-ThrowException(JSContext* aCx,
-               nsresult aErrorCode)
-{
-  NS_ASSERTION(NS_FAILED(aErrorCode), "Not an error code!");
-  if (!JS_IsExceptionPending(aCx)) {
-    nsDOMClassInfo::ThrowJSException(aCx, aErrorCode);
-  }
-}
-
-inline
-bool
-GetKeyFromJSValOrThrow(JSContext* aCx,
-                       jsval aVal,
-                       Key& aKey)
-{
-  nsresult rv = GetKeyFromJSVal(aCx, aVal, aKey);
-  if (NS_FAILED(rv)) {
-    ThrowException(aCx, rv);
-    return false;
-  }
-  return true;
+  return JS_TRUE;
 }
 
 JSBool
 MakeOnlyKeyRange(JSContext* aCx,
                  uintN aArgc,
                  jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval val;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &val)) {
-    return false;
+  nsAutoTArray<nsCOMPtr<nsIVariant>, 1> keys;
+  if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.only", keys)) {
+    return JS_FALSE;
+  }
+  NS_ASSERTION(keys.Length() == 1, "Didn't set all keys!");
+
+  nsRefPtr<IDBKeyRange> range =
+    IDBKeyRange::Create(keys[0], keys[0], false, false);
+  NS_ASSERTION(range, "Out of memory?");
+
+  if (!ReturnKeyRange(aCx, aVp, range)) {
+    return JS_FALSE;
   }
 
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(false, false, true);
-
-  if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
-    return false;
-  }
-
-  return ReturnKeyRange(aCx, aVp, keyRange);
+  return JS_TRUE;
 }
 
 JSBool
 MakeLowerBoundKeyRange(JSContext* aCx,
                        uintN aArgc,
                        jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval val;
-  JSBool open = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", &val, &open)) {
-    return false;
+  nsAutoTArray<nsCOMPtr<nsIVariant>, 1> keys;
+  if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.lowerBound", keys)) {
+    return JS_FALSE;
+  }
+  NS_ASSERTION(keys.Length() == 1, "Didn't set all keys!");
+
+  JSBool open = JS_FALSE;
+  if (aArgc > 1 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[1], &open)) {
+    JS_ReportError(aCx, "Couldn't convert argument 2 to boolean.");
+    return JS_FALSE;
   }
 
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(open, true, false);
+  nsRefPtr<IDBKeyRange> range =
+    IDBKeyRange::Create(keys[0], nsnull, !!open, true);
+  NS_ASSERTION(range, "Out of memory?");
 
-  if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
-    return false;
+  if (!ReturnKeyRange(aCx, aVp, range)) {
+    return JS_FALSE;
   }
 
-  return ReturnKeyRange(aCx, aVp, keyRange);
+  return JS_TRUE;
 }
 
 JSBool
 MakeUpperBoundKeyRange(JSContext* aCx,
                        uintN aArgc,
                        jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval val;
-  JSBool open = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", &val, &open)) {
-    return false;
+  nsAutoTArray<nsCOMPtr<nsIVariant>, 1> keys;
+  if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.upperBound", keys)) {
+    return JS_FALSE;
+  }
+  NS_ASSERTION(keys.Length() == 1, "Didn't set all keys!");
+
+  JSBool open = JS_FALSE;
+  if (aArgc > 1 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[1], &open)) {
+    JS_ReportError(aCx, "Couldn't convert argument 2 to boolean.");
+    return JS_FALSE;
   }
 
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(true, open, false);
+  nsRefPtr<IDBKeyRange> range =
+    IDBKeyRange::Create(nsnull, keys[0], true, !!open);
+  NS_ASSERTION(range, "Out of memory?");
 
-  if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Upper())) {
-    return false;
+  if (!ReturnKeyRange(aCx, aVp, range)) {
+    return JS_FALSE;
   }
 
-  return ReturnKeyRange(aCx, aVp, keyRange);
+  return JS_TRUE;
 }
 
 JSBool
 MakeBoundKeyRange(JSContext* aCx,
                   uintN aArgc,
                   jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval lowerVal, upperVal;
-  JSBool lowerOpen = false, upperOpen = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "vv/bb", &lowerVal,
-                           &upperVal, &lowerOpen, &upperOpen)) {
-    return false;
+  nsAutoTArray<nsCOMPtr<nsIVariant>, 2> keys;
+  if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.bound", keys)) {
+    return JS_FALSE;
+  }
+  NS_ASSERTION(keys.Length() == 2, "Didn't set all keys!");
+
+  JSBool lowerOpen = JS_FALSE;
+  if (aArgc > 2 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[2], &lowerOpen)) {
+    JS_ReportError(aCx, "Couldn't convert argument 3 to boolean.");
+    return JS_FALSE;
   }
 
-  nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(lowerOpen, upperOpen, false);
-
-  if (!GetKeyFromJSValOrThrow(aCx, lowerVal, keyRange->Lower()) ||
-      !GetKeyFromJSValOrThrow(aCx, upperVal, keyRange->Upper())) {
-    return false;
+  JSBool upperOpen = JS_FALSE;
+  if (aArgc > 3 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[3], &upperOpen)) {
+    JS_ReportError(aCx, "Couldn't convert argument 3 to boolean.");
+    return JS_FALSE;
   }
 
-  if (keyRange->Lower() > keyRange->Upper() ||
-      (keyRange->Lower() == keyRange->Upper() && (lowerOpen || upperOpen))) {
-    ThrowException(aCx, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
-    return false;
+  nsRefPtr<IDBKeyRange> range =
+    IDBKeyRange::Create(keys[0], keys[1], lowerOpen, upperOpen);
+  NS_ASSERTION(range, "Out of memory?");
+
+  if (!ReturnKeyRange(aCx, aVp, range)) {
+    return JS_FALSE;
   }
 
-  return ReturnKeyRange(aCx, aVp, keyRange);
+  return JS_TRUE;
 }
 
+
 #define KEYRANGE_FUNCTION_FLAGS (JSPROP_ENUMERATE | JSPROP_PERMANENT)
 
 const JSFunctionSpec gKeyRangeConstructors[] = {
   JS_FN("only", MakeOnlyKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
   JS_FN("lowerBound", MakeLowerBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
   JS_FN("upperBound", MakeUpperBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
   JS_FN("bound", MakeBoundKeyRange, 2, KEYRANGE_FUNCTION_FLAGS),
   JS_FS_END
@@ -256,152 +280,72 @@ IDBKeyRange::DefineConstructors(JSContex
   NS_ASSERTION(aObject, "Null pointer!");
 
   // Add the constructor methods for key ranges.
   return JS_DefineFunctions(aCx, aObject,
                             const_cast<JSFunctionSpec*>(gKeyRangeConstructors));
 }
 
 // static
-nsresult
-IDBKeyRange::FromJSVal(JSContext* aCx,
-                       const jsval& aVal,
-                       IDBKeyRange** aKeyRange)
+already_AddRefed<IDBKeyRange>
+IDBKeyRange::Create(nsIVariant* aLower,
+                    nsIVariant* aUpper,
+                    bool aLowerOpen,
+                    bool aUpperOpen)
 {
-  nsresult rv;
-  nsRefPtr<IDBKeyRange> keyRange;
-
-  if (JSVAL_IS_VOID(aVal) || JSVAL_IS_NULL(aVal)) {
-    // undefined and null returns no IDBKeyRange.
-  }
-  else if (JSVAL_IS_PRIMITIVE(aVal)) {
-    // A valid key returns an 'only' IDBKeyRange.
-    keyRange = new IDBKeyRange(false, false, true);
+  nsRefPtr<IDBKeyRange> keyRange(new IDBKeyRange());
+  keyRange->mLower = aLower;
+  keyRange->mUpper = aUpper;
+  keyRange->mLowerOpen = aLowerOpen;
+  keyRange->mUpperOpen = aUpperOpen;
 
-    rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  else {
-    // An object is not permitted unless it's another IDBKeyRange.
-    nsIXPConnect* xpc = nsContentUtils::XPConnect();
-    NS_ASSERTION(xpc, "This should never be null!");
-
-    nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-    rv = xpc->GetWrappedNativeOfJSObject(aCx, JSVAL_TO_OBJECT(aVal),
-                                         getter_AddRefs(wrapper));
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    nsCOMPtr<nsIIDBKeyRange> iface;
-    if (!wrapper || !(iface = do_QueryInterface(wrapper->Native()))) {
-      // Some random JS object?
-      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-    }
-
-    keyRange = static_cast<IDBKeyRange*>(iface.get());
-  }
-
-  keyRange.forget(aKeyRange);
-  return NS_OK;
+  return keyRange.forget();
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_ADDREF(IDBKeyRange)
+NS_IMPL_RELEASE(IDBKeyRange)
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
-  if (JSVAL_IS_GCTHING(tmp->mCachedLowerVal)) {
-    void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedLowerVal);
-    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedLowerVal")
-  }
-  if (JSVAL_IS_GCTHING(tmp->mCachedUpperVal)) {
-    void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedUpperVal);
-    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedUpperVal")
-  }
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
-  if (tmp->mRooted) {
-    NS_DROP_JS_OBJECTS(tmp, IDBKeyRange);
-    tmp->mCachedLowerVal = JSVAL_VOID;
-    tmp->mCachedUpperVal = JSVAL_VOID;
-    tmp->mHaveCachedLowerVal = false;
-    tmp->mHaveCachedUpperVal = false;
-    tmp->mRooted = false;
-  }
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_BEGIN(IDBKeyRange)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIDBKeyRange)
   NS_INTERFACE_MAP_ENTRY(nsIIDBKeyRange)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBKeyRange)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
-
 DOMCI_DATA(IDBKeyRange, IDBKeyRange)
 
 NS_IMETHODIMP
-IDBKeyRange::GetLower(JSContext* aCx,
-                      jsval* aLower)
+IDBKeyRange::GetLower(nsIVariant** aLower)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!mHaveCachedLowerVal) {
-    if (!mRooted) {
-      NS_HOLD_JS_OBJECTS(this, IDBKeyRange);
-      mRooted = true;
-    }
-
-    nsresult rv = Lower().ToJSVal(aCx, &mCachedLowerVal);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mHaveCachedLowerVal = true;
-  }
-
-  *aLower = mCachedLowerVal;
+  nsCOMPtr<nsIVariant> result(mLower);
+  result.forget(aLower);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBKeyRange::GetUpper(JSContext* aCx,
-                      jsval* aUpper)
+IDBKeyRange::GetUpper(nsIVariant** aUpper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!mHaveCachedUpperVal) {
-    if (!mRooted) {
-      NS_HOLD_JS_OBJECTS(this, IDBKeyRange);
-      mRooted = true;
-    }
-
-    nsresult rv = Upper().ToJSVal(aCx, &mCachedUpperVal);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mHaveCachedUpperVal = true;
-  }
-
-  *aUpper = mCachedUpperVal;
+  nsCOMPtr<nsIVariant> result(mUpper);
+  result.forget(aUpper);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBKeyRange::GetLowerOpen(bool* aLowerOpen)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  *aLowerOpen = mLowerOpen;
+  *aLowerOpen = mLowerOpen ? true : false;
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 IDBKeyRange::GetUpperOpen(bool* aUpperOpen)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  *aUpperOpen = mUpperOpen;
+  *aUpperOpen = mUpperOpen ? true : false;
   return NS_OK;
 }
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -36,85 +36,45 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbkeyrange_h__
 #define mozilla_dom_indexeddb_idbkeyrange_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
-#include "mozilla/dom/indexedDB/Key.h"
 
 #include "nsIIDBKeyRange.h"
-
-#include "nsCycleCollectionParticipant.h"
+#include "nsIVariant.h"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class IDBKeyRange : public nsIIDBKeyRange
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_ISUPPORTS
   NS_DECL_NSIIDBKEYRANGE
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBKeyRange)
 
   static JSBool DefineConstructors(JSContext* aCx,
                                    JSObject* aObject);
 
   static
-  nsresult FromJSVal(JSContext* aCx,
-                     const jsval& aVal,
-                     IDBKeyRange** aKeyRange);
+  already_AddRefed<IDBKeyRange> Create(nsIVariant* aLower,
+                                       nsIVariant* aUpper,
+                                       bool aLowerOpen,
+                                       bool aUpperOpen);
 
-  IDBKeyRange(bool aLowerOpen, bool aUpperOpen, bool aIsOnly)
-  : mCachedLowerVal(JSVAL_VOID), mCachedUpperVal(JSVAL_VOID),
-    mLowerOpen(aLowerOpen), mUpperOpen(aUpperOpen), mIsOnly(aIsOnly),
-    mHaveCachedLowerVal(false), mHaveCachedUpperVal(false), mRooted(false)
+protected:
+  IDBKeyRange()
+  : mLowerOpen(false), mUpperOpen(false)
   { }
 
-  const Key& Lower() const
-  {
-    return mLower;
-  }
-
-  Key& Lower()
-  {
-    return mLower;
-  }
-
-  const Key& Upper() const
-  {
-    return mIsOnly ? mLower : mUpper;
-  }
-
-  Key& Upper()
-  {
-    return mIsOnly ? mLower : mUpper;
-  }
-
-  bool IsLowerOpen() const
-  {
-    return mLowerOpen;
-  }
-
-  bool IsUpperOpen() const
-  {
-    return mUpperOpen;
-  }
-
-protected:
   ~IDBKeyRange() { }
 
-  Key mLower;
-  Key mUpper;
-  jsval mCachedLowerVal;
-  jsval mCachedUpperVal;
+  nsCOMPtr<nsIVariant> mLower;
+  nsCOMPtr<nsIVariant> mUpper;
   bool mLowerOpen;
   bool mUpperOpen;
-  bool mIsOnly;
-  bool mHaveCachedLowerVal;
-  bool mHaveCachedUpperVal;
-  bool mRooted;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbkeyrange_h__
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -35,17 +35,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBObjectStore.h"
 
 #include "nsIJSContextStack.h"
-
+#include "nsIVariant.h"
+
+#include "jscntxt.h"
 #include "jsclone.h"
 #include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
@@ -57,16 +59,19 @@
 #include "IDBKeyRange.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
+// This is just to give us some random marker in the byte stream
+static const PRUint64 kTotallyRandomNumber = LL_INIT(0x286F258B, 0x177D47A9);
+
 class AddHelper : public AsyncConnectionHelper
 {
 public:
   AddHelper(IDBTransaction* aTransaction,
             IDBRequest* aRequest,
             IDBObjectStore* aObjectStore,
             JSAutoStructuredCloneBuffer& aCloneBuffer,
             const Key& aKey,
@@ -136,17 +141,17 @@ public:
     mObjectStore = nsnull;
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 protected:
   // In-params.
   nsRefPtr<IDBObjectStore> mObjectStore;
-  Key mKey;
+  const Key mKey;
 
 private:
   // Out-params.
   JSAutoStructuredCloneBuffer mCloneBuffer;
 };
 
 class DeleteHelper : public GetHelper
 {
@@ -186,43 +191,49 @@ protected:
 };
 
 class OpenCursorHelper : public AsyncConnectionHelper
 {
 public:
   OpenCursorHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBObjectStore* aObjectStore,
-                   IDBKeyRange* aKeyRange,
+                   const Key& aLowerKey,
+                   const Key& aUpperKey,
+                   bool aLowerOpen,
+                   bool aUpperOpen,
                    PRUint16 aDirection)
   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
-    mKeyRange(aKeyRange), mDirection(aDirection)
+    mLowerKey(aLowerKey), mUpperKey(aUpperKey), mLowerOpen(aLowerOpen),
+    mUpperOpen(aUpperOpen), mDirection(aDirection)
   { }
 
   ~OpenCursorHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
   }
 
   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   nsresult GetSuccessResult(JSContext* aCx,
                             jsval* aVal);
 
   void ReleaseMainThreadObjects()
   {
     mObjectStore = nsnull;
-    mKeyRange = nsnull;
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   // In-params.
   nsRefPtr<IDBObjectStore> mObjectStore;
-  nsRefPtr<IDBKeyRange> mKeyRange;
+  const Key mLowerKey;
+  const Key mUpperKey;
+  const bool mLowerOpen;
+  const bool mUpperOpen;
   const PRUint16 mDirection;
 
   // Out-params.
   Key mKey;
   JSAutoStructuredCloneBuffer mCloneBuffer;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
@@ -257,17 +268,18 @@ private:
   static void DestroyTLSEntry(void* aPtr);
 
   static PRUintn sTLSIndex;
 
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
 };
 
-PRUintn CreateIndexHelper::sTLSIndex = PRUintn(BAD_TLS_INDEX);
+static const PRUintn BAD_TLS_INDEX = (PRUint32)-1;
+PRUintn CreateIndexHelper::sTLSIndex = BAD_TLS_INDEX;
 
 class DeleteIndexHelper : public AsyncConnectionHelper
 {
 public:
   DeleteIndexHelper(IDBTransaction* aTransaction,
                     const nsAString& aName,
                     IDBObjectStore* aObjectStore)
   : AsyncConnectionHelper(aTransaction, nsnull), mName(aName),
@@ -299,84 +311,60 @@ private:
 };
 
 class GetAllHelper : public AsyncConnectionHelper
 {
 public:
   GetAllHelper(IDBTransaction* aTransaction,
                IDBRequest* aRequest,
                IDBObjectStore* aObjectStore,
-               IDBKeyRange* aKeyRange,
+               const Key& aLowerKey,
+               const Key& aUpperKey,
+               const bool aLowerOpen,
+               const bool aUpperOpen,
                const PRUint32 aLimit)
   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
-    mKeyRange(aKeyRange), mLimit(aLimit)
+    mLowerKey(aLowerKey), mUpperKey(aUpperKey), mLowerOpen(aLowerOpen),
+    mUpperOpen(aUpperOpen), mLimit(aLimit)
   { }
 
   ~GetAllHelper()
   {
     for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
       IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
     }
   }
 
   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   nsresult GetSuccessResult(JSContext* aCx,
                             jsval* aVal);
 
   void ReleaseMainThreadObjects()
   {
     mObjectStore = nsnull;
-    mKeyRange = nsnull;
     for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
       IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
     }
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 protected:
   // In-params.
   nsRefPtr<IDBObjectStore> mObjectStore;
-  nsRefPtr<IDBKeyRange> mKeyRange;
+  const Key mLowerKey;
+  const Key mUpperKey;
+  const bool mLowerOpen;
+  const bool mUpperOpen;
   const PRUint32 mLimit;
 
 private:
   // Out-params.
   nsTArray<JSAutoStructuredCloneBuffer> mCloneBuffers;
 };
 
-class CountHelper : public AsyncConnectionHelper
-{
-public:
-  CountHelper(IDBTransaction* aTransaction,
-              IDBRequest* aRequest,
-              IDBObjectStore* aObjectStore,
-              IDBKeyRange* aKeyRange)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
-    mKeyRange(aKeyRange), mCount(0)
-  { }
-
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
-
-protected:
-  nsRefPtr<IDBObjectStore> mObjectStore;
-  nsRefPtr<IDBKeyRange> mKeyRange;
-
-private:
-  PRUint64 mCount;
-};
-
 NS_STACK_CLASS
 class AutoRemoveIndex
 {
 public:
   AutoRemoveIndex(nsIAtom* aDatabaseId,
                   const nsAString& aObjectStoreName,
                   const nsAString& aIndexName)
   : mDatabaseId(aDatabaseId), mObjectStoreName(aObjectStoreName),
@@ -421,17 +409,17 @@ GetKeyFromObject(JSContext* aCx,
 
   const jschar* keyPathChars = reinterpret_cast<const jschar*>(aKeyPath.get());
   const size_t keyPathLen = aKeyPath.Length();
 
   jsval key;
   JSBool ok = JS_GetUCProperty(aCx, aObj, keyPathChars, keyPathLen, &key);
   NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  nsresult rv = aKey.SetFromJSVal(aCx, key);
+  nsresult rv = IDBObjectStore::GetKeyFromJSVal(key, aCx, aKey);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBObjectStore* aObjectStore)
@@ -498,16 +486,117 @@ IDBObjectStore::Create(IDBTransaction* a
   objectStore->mAutoIncrement = aStoreInfo->autoIncrement;
   objectStore->mDatabaseId = aStoreInfo->databaseId;
 
   return objectStore.forget();
 }
 
 // static
 nsresult
+IDBObjectStore::GetKeyFromVariant(nsIVariant* aKeyVariant,
+                                  Key& aKey)
+{
+  if (!aKeyVariant) {
+    aKey = Key::UNSETKEY;
+    return NS_OK;
+  }
+
+  PRUint16 type;
+  nsresult rv = aKeyVariant->GetDataType(&type);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  // See xpcvariant.cpp, these are the only types we should expect.
+  switch (type) {
+    case nsIDataType::VTYPE_VOID:
+      aKey = Key::UNSETKEY;
+      return NS_OK;
+
+    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+      rv = aKeyVariant->GetAsAString(aKey.ToString());
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      return NS_OK;
+
+    case nsIDataType::VTYPE_INT32:
+    case nsIDataType::VTYPE_DOUBLE:
+      rv = aKeyVariant->GetAsInt64(aKey.ToIntPtr());
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+      return NS_OK;
+
+    default:
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  }
+
+  NS_NOTREACHED("Can't get here!");
+  return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+}
+
+// static
+nsresult
+IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal,
+                                JSContext* aCx,
+                                Key& aKey)
+{
+  if (JSVAL_IS_VOID(aKeyVal)) {
+    aKey = Key::UNSETKEY;
+  }
+  else if (JSVAL_IS_STRING(aKeyVal)) {
+    nsDependentJSString depStr;
+    if (!depStr.init(aCx, JSVAL_TO_STRING(aKeyVal))) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    aKey = depStr;
+  }
+  else if (JSVAL_IS_INT(aKeyVal)) {
+    aKey = JSVAL_TO_INT(aKeyVal);
+  }
+  else if (JSVAL_IS_DOUBLE(aKeyVal)) {
+    aKey = JSVAL_TO_DOUBLE(aKeyVal);
+  }
+  else {
+    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  }
+
+  return NS_OK;
+}
+
+// static
+nsresult
+IDBObjectStore::GetJSValFromKey(const Key& aKey,
+                                JSContext* aCx,
+                                jsval* aKeyVal)
+{
+  if (aKey.IsUnset()) {
+    *aKeyVal = JSVAL_VOID;
+    return NS_OK;
+  }
+
+  if (aKey.IsInt()) {
+    JSBool ok = JS_NewNumberValue(aCx, aKey.IntValue(), aKeyVal);
+    NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    return NS_OK;
+  }
+
+  if (aKey.IsString()) {
+    const nsString& keyString = aKey.StringValue();
+    JSString* str =
+      JS_NewUCStringCopyN(aCx,
+                          reinterpret_cast<const jschar*>(keyString.get()),
+                          keyString.Length());
+    NS_ENSURE_TRUE(str, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    *aKeyVal = STRING_TO_JSVAL(str);
+    return NS_OK;
+  }
+
+  NS_NOTREACHED("Unknown key type!");
+  return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+}
+
+// static
+nsresult
 IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
                                                   PRUint32 aDataLength,
                                                   const nsAString& aKeyPath,
                                                   JSContext* aCx,
                                                   Key& aValue)
 {
   NS_ASSERTION(aData, "Null pointer!");
   NS_ASSERTION(aDataLength, "Empty data!");
@@ -520,35 +609,35 @@ IDBObjectStore::GetKeyPathValueFromStruc
   if (!JS_ReadStructuredClone(aCx, reinterpret_cast<const uint64*>(aData),
                               aDataLength, JS_STRUCTURED_CLONE_VERSION,
                               &clone, NULL, NULL)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   if (JSVAL_IS_PRIMITIVE(clone)) {
     // This isn't an object, so just leave the key unset.
-    aValue.Unset();
+    aValue = Key::UNSETKEY;
     return NS_OK;
   }
 
   JSObject* obj = JSVAL_TO_OBJECT(clone);
 
   const jschar* keyPathChars =
     reinterpret_cast<const jschar*>(aKeyPath.BeginReading());
   const size_t keyPathLen = aKeyPath.Length();
 
   jsval keyVal;
   JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &keyVal);
   NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  nsresult rv = aValue.SetFromJSVal(aCx, keyVal);
+  nsresult rv = GetKeyFromJSVal(keyVal, aCx, aValue);
   if (NS_FAILED(rv)) {
     // If the object doesn't have a value that we can use for our index then we
     // leave it unset.
-    aValue.Unset();
+    aValue = Key::UNSETKEY;
   }
 
   return NS_OK;
 }
 
 /* static */
 nsresult
 IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
@@ -575,17 +664,17 @@ IDBObjectStore::GetIndexUpdateInfo(Objec
       const size_t keyPathLen = indexInfo.keyPath.Length();
 
       jsval keyPathValue;
       JSBool ok = JS_GetUCProperty(aCx, cloneObj, keyPathChars, keyPathLen,
                                    &keyPathValue);
       NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
       Key value;
-      nsresult rv = value.SetFromJSVal(aCx, keyPathValue);
+      nsresult rv = GetKeyFromJSVal(keyPathValue, aCx, value);
       if (NS_FAILED(rv) || value.IsUnset()) {
         // Not a value we can do anything with, ignore it.
         continue;
       }
 
       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
       updateInfo->info = indexInfo;
       updateInfo->value = value;
@@ -634,17 +723,27 @@ IDBObjectStore::UpdateIndexes(IDBTransac
 
     mozStorageStatementScoper scoper(stmt);
 
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), aObjectStoreId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ASSERTION(!aObjectStoreKey.IsUnset(), "This shouldn't happen!");
 
-    rv = aObjectStoreKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value"));
+    NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
+
+    if (aObjectStoreKey.IsInt()) {
+      rv = stmt->BindInt64ByName(keyValue, aObjectStoreKey.IntValue());
+    }
+    else if (aObjectStoreKey.IsString()) {
+      rv = stmt->BindStringByName(keyValue, aObjectStoreKey.StringValue());
+    }
+    else {
+      NS_NOTREACHED("Unknown key type!");
+    }
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasResult;
     rv = stmt->ExecuteStep(&hasResult);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!hasResult) {
       NS_ERROR("This is bad, we just added this value! Where'd it go?!");
@@ -670,25 +769,45 @@ IDBObjectStore::UpdateIndexes(IDBTransac
                                updateInfo.info.id);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"),
                                aObjectDataId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!updateInfo.info.autoIncrement) {
-      rv =
-        aObjectStoreKey.BindToStatement(stmt,
-                                        NS_LITERAL_CSTRING("object_data_key"));
+      NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
+
+      if (aObjectStoreKey.IsInt()) {
+        rv = stmt->BindInt64ByName(objectDataKey, aObjectStoreKey.IntValue());
+      }
+      else if (aObjectStoreKey.IsString()) {
+        rv = stmt->BindStringByName(objectDataKey,
+                                    aObjectStoreKey.StringValue());
+      }
+      else {
+        NS_NOTREACHED("Unknown key type!");
+      }
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    rv =
-      updateInfo.value.BindToStatementAllowUnset(stmt,
-                                                 NS_LITERAL_CSTRING("value"));
+    NS_NAMED_LITERAL_CSTRING(value, "value");
+
+    if (updateInfo.value.IsInt()) {
+      rv = stmt->BindInt64ByName(value, updateInfo.value.IntValue());
+    }
+    else if (updateInfo.value.IsString()) {
+      rv = stmt->BindStringByName(value, updateInfo.value.StringValue());
+    }
+    else if (updateInfo.value.IsUnset()) {
+      rv = stmt->BindStringByName(value, updateInfo.value.StringValue());
+    }
+    else {
+      NS_NOTREACHED("Unknown key type!");
+    }
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->Execute();
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
@@ -777,35 +896,36 @@ SwapBytes(PRUint64 u)
            ((u & 0x000000000000ff00LLU) << 40) |
            ((u & 0x0000000000ff0000LLU) << 24) |
             ((u & 0x00000000ff000000LLU) << 8) |
             ((u & 0x000000ff00000000LLU) >> 8) |
            ((u & 0x0000ff0000000000LLU) >> 24) |
            ((u & 0x00ff000000000000LLU) >> 40) |
            ((u & 0xff00000000000000LLU) >> 56);
 #else
-     return jsdouble(u);
+     return u;
 #endif
 }
 
 nsresult
 IDBObjectStore::ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer,
                                      Key& aKey,
                                      PRUint64 aOffsetToKeyProp)
 {
-  NS_ASSERTION(IsAutoIncrement() && aKey.IsInteger(), "Don't call me!");
+  NS_ASSERTION(IsAutoIncrement() && KeyPath().IsEmpty() && aKey.IsInt(),
+               "Don't call me!");
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread");
 
   // This is a duplicate of the js engine's byte munging here
   union {
     jsdouble d;
     PRUint64 u;
   } pun;
 
-  pun.d = SwapBytes(aKey.ToInteger());
+  pun.d = SwapBytes(aKey.IntValue());
 
   memcpy((char*)aBuffer.data() + aOffsetToKeyProp, &pun.u, sizeof(PRUint64));
   return NS_OK;
 }
 
 IDBObjectStore::IDBObjectStore()
 : mId(LL_MININT),
   mAutoIncrement(false)
@@ -834,17 +954,17 @@ IDBObjectStore::GetAddInfo(JSContext* aC
   if (!JSVAL_IS_VOID(aKeyVal) && !mKeyPath.IsEmpty()) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   JSAutoRequest ar(aCx);
 
   if (mKeyPath.IsEmpty()) {
     // Out-of-line keys must be passed in.
-    rv = aKey.SetFromJSVal(aCx, aKeyVal);
+    rv = GetKeyFromJSVal(aKeyVal, aCx, aKey);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     // Inline keys live on the object. Make sure that the value passed in is an
     // object.
     if (JSVAL_IS_PRIMITIVE(aValue)) {
       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
@@ -1048,31 +1168,52 @@ IDBObjectStore::GetIndexNames(nsIDOMDOMS
                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   list.forget(aIndexNames);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBObjectStore::Get(const jsval& aKey,
-                    JSContext* aCx,
+IDBObjectStore::Get(nsIVariant* aKey,
                     nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   Key key;
-  nsresult rv = key.SetFromJSVal(aCx, aKey);
+  nsresult rv = GetKeyFromVariant(aKey, key);
   if (NS_FAILED(rv)) {
-    // Maybe this is a key range.
-    return GetAll(aKey, 0, aCx, 1, _retval);
+    // Check to see if this is a key range.
+    PRUint16 type;
+    rv = aKey->GetDataType(&type);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (type != nsIDataType::VTYPE_INTERFACE &&
+        type != nsIDataType::VTYPE_INTERFACE_IS) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    }
+
+    // XXX I hate this API. Move to jsvals, stat.
+    nsID* iid;
+    nsCOMPtr<nsISupports> supports;
+    rv = aKey->GetAsInterface(&iid, getter_AddRefs(supports));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    NS_Free(iid);
+
+    nsCOMPtr<nsIIDBKeyRange> keyRange = do_QueryInterface(supports);
+    if (!keyRange) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    }
+
+    return GetAll(keyRange, 0, 0, _retval);
   }
 
   if (key.IsUnset()) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -1082,45 +1223,66 @@ IDBObjectStore::Get(const jsval& aKey,
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBObjectStore::GetAll(const jsval& aKey,
+IDBObjectStore::GetAll(nsIIDBKeyRange* aKeyRange,
                        PRUint32 aLimit,
-                       JSContext* aCx,
                        PRUint8 aOptionalArgCount,
                        nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
-  nsresult rv;
-
-  nsRefPtr<IDBKeyRange> keyRange;
-  if (aOptionalArgCount) {
-    rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
   if (aOptionalArgCount < 2) {
     aLimit = PR_UINT32_MAX;
   }
 
+  nsresult rv;
+  Key lowerKey, upperKey;
+  bool lowerOpen = false, upperOpen = false;
+
+  if (aKeyRange) {
+    nsCOMPtr<nsIVariant> variant;
+    rv = aKeyRange->GetLower(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = IDBObjectStore::GetKeyFromVariant(variant, lowerKey);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    rv = aKeyRange->GetUpper(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = IDBObjectStore::GetKeyFromVariant(variant, upperKey);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    rv = aKeyRange->GetLowerOpen(&lowerOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = aKeyRange->GetUpperOpen(&upperOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetAllHelper> helper =
-    new GetAllHelper(mTransaction, request, this, keyRange, aLimit);
+    new GetAllHelper(mTransaction, request, this, lowerKey, upperKey, lowerOpen,
+                     upperOpen, aLimit);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
@@ -1159,17 +1321,17 @@ IDBObjectStore::Delete(const jsval& aKey
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   if (!IsWriteAllowed()) {
     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
   }
 
   Key key;
-  nsresult rv = key.SetFromJSVal(aCx, aKey);
+  nsresult rv = GetKeyFromJSVal(aKey, aCx, key);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (key.IsUnset()) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
@@ -1207,53 +1369,74 @@ IDBObjectStore::Clear(nsIIDBRequest** _r
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBObjectStore::OpenCursor(const jsval& aKey,
+IDBObjectStore::OpenCursor(nsIIDBKeyRange* aKeyRange,
                            PRUint16 aDirection,
-                           JSContext* aCx,
                            PRUint8 aOptionalArgCount,
                            nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
-
-  nsRefPtr<IDBKeyRange> keyRange;
-  if (aOptionalArgCount) {
-    rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (aOptionalArgCount >= 2) {
-      if (aDirection != nsIIDBCursor::NEXT &&
-          aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
-          aDirection != nsIIDBCursor::PREV &&
-          aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
-        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
-      }
+  Key lowerKey, upperKey;
+  bool lowerOpen = false, upperOpen = false;
+
+  if (aKeyRange) {
+    nsCOMPtr<nsIVariant> variant;
+    rv = aKeyRange->GetLower(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = IDBObjectStore::GetKeyFromVariant(variant, lowerKey);
+    if (NS_FAILED(rv)) {
+      return rv;
     }
-    else {
-      aDirection = nsIIDBCursor::NEXT;
+
+    rv = aKeyRange->GetUpper(getter_AddRefs(variant));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = IDBObjectStore::GetKeyFromVariant(variant, upperKey);
+    if (NS_FAILED(rv)) {
+      return rv;
     }
+
+    rv = aKeyRange->GetLowerOpen(&lowerOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    rv = aKeyRange->GetUpperOpen(&upperOpen);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (aOptionalArgCount >= 2) {
+    if (aDirection != nsIIDBCursor::NEXT &&
+        aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
+        aDirection != nsIIDBCursor::PREV &&
+        aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
+      return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
+    }
+  }
+  else {
+    aDirection = nsIIDBCursor::NEXT;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
-    new OpenCursorHelper(mTransaction, request, this, keyRange, aDirection);
+    new OpenCursorHelper(mTransaction, request, this, lowerKey, upperKey,
+                         lowerOpen, upperOpen, aDirection);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
@@ -1485,46 +1668,16 @@ IDBObjectStore::DeleteIndex(const nsAStr
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   info->indexes.RemoveElementAt(index);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBObjectStore::Count(const jsval& aKey,
-                      JSContext* aCx,
-                      PRUint8 aOptionalArgCount,
-                      nsIIDBRequest** _retval)
-{
-  if (!mTransaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
-  }
-
-  nsresult rv;
-
-  nsRefPtr<IDBKeyRange> keyRange;
-  if (aOptionalArgCount) {
-    rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<CountHelper> helper =
-    new CountHelper(mTransaction, request, this, keyRange);
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  request.forget(_retval);
-  return NS_OK;
-}
-
 nsresult
 AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
   nsresult rv;
   bool mayOverwrite = mOverwrite;
   bool unsetKey = mKey.IsUnset();
@@ -1550,18 +1703,28 @@ AddHelper::DoDatabaseWork(mozIStorageCon
     stmt = mTransaction->GetStatement(autoIncrement);
     NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     mozStorageStatementScoper scoper(stmt);
 
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    rv = mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("id"));
-    NS_ENSURE_SUCCESS(rv, rv);
+    NS_NAMED_LITERAL_CSTRING(id, "id");
+
+    if (mKey.IsInt()) {
+      rv = stmt->BindInt64ByName(id, mKey.IntValue());
+    }
+    else if (mKey.IsString()) {
+      rv = stmt->BindStringByName(id, mKey.StringValue());
+    }
+    else {
+      NS_NOTREACHED("Unknown key type!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     bool hasResult;
     rv = stmt->ExecuteStep(&hasResult);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (hasResult) {
       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     }
@@ -1576,18 +1739,26 @@ AddHelper::DoDatabaseWork(mozIStorageCon
   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
 
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!autoIncrement || mayOverwrite) {
     NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!");
 
-    rv = mKey.BindToStatement(stmt, keyValue);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (mKey.IsInt()) {
+      rv = stmt->BindInt64ByName(keyValue, mKey.IntValue());
+    }
+    else if (mKey.IsString()) {
+      rv = stmt->BindStringByName(keyValue, mKey.StringValue());
+    }
+    else {
+      NS_NOTREACHED("Unknown key type!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   const PRUint8* buffer = reinterpret_cast<const PRUint8*>(mCloneBuffer.data());
   size_t bufferLength = mCloneBuffer.nbytes();
 
   rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), buffer, bufferLength);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -1604,48 +1775,52 @@ AddHelper::DoDatabaseWork(mozIStorageCon
 
       mozStorageStatementScoper scoper2(stmt);
 
       rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!");
 
-      rv = mKey.BindToStatement(stmt, keyValue);
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (mKey.IsInt()) {
+        rv = stmt->BindInt64ByName(keyValue, mKey.IntValue());
+      }
+      else if (mKey.IsString()) {
+        rv = stmt->BindStringByName(keyValue, mKey.StringValue());
+      }
+      else {
+        NS_NOTREACHED("Unknown key type!");
+      }
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), buffer,
                                 bufferLength);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = stmt->Execute();
     }
 
     if (NS_FAILED(rv)) {
       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     }
   }
 
   // If we are supposed to generate a key, get the new id.
   if (autoIncrement && !mOverwrite) {
 #ifdef DEBUG
-    PRInt64 oldKey = unsetKey ? 0 : mKey.ToInteger();
+    PRInt64 oldKey = unsetKey ? 0 : mKey.IntValue();
 #endif
 
-    PRInt64 newIntKey;
-    rv = aConnection->GetLastInsertRowID(&newIntKey);
+    rv = aConnection->GetLastInsertRowID(mKey.ToIntPtr());
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    rv = mKey.SetFromInteger(newIntKey);
-    NS_ENSURE_SUCCESS(rv, rv);
-
 #ifdef DEBUG
-    NS_ASSERTION(mKey.IsInteger(), "Bad key value!");
+    NS_ASSERTION(mKey.IsInt(), "Bad key value!");
     if (!unsetKey) {
-      NS_ASSERTION(mKey.ToInteger() == oldKey, "Something went haywire!");
+      NS_ASSERTION(mKey.IntValue() == oldKey, "Something went haywire!");
     }
 #endif
 
     if (!keyPath.IsEmpty() && unsetKey) {
       // Special case where someone put an object into an autoIncrement'ing
       // 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.
       rv = mObjectStore->ModifyValueForNewKey(mCloneBuffer, mKey,
@@ -1659,34 +1834,34 @@ AddHelper::DoDatabaseWork(mozIStorageCon
       stmt = mTransaction->AddStatement(false, true, true);
       NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       mozStorageStatementScoper scoper2(stmt);
 
       rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-      rv = mKey.BindToStatement(stmt, keyValue);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = stmt->BindInt64ByName(keyValue, mKey.IntValue());
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       buffer = reinterpret_cast<const PRUint8*>(mCloneBuffer.data());
       bufferLength = mCloneBuffer.nbytes();
 
       rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), buffer,
                                 bufferLength);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
   }
 
   // Update our indexes if needed.
   if (!mIndexUpdateInfo.IsEmpty()) {
-    PRInt64 objectDataId = autoIncrement ? mKey.ToInteger() : LL_MININT;
+    PRInt64 objectDataId = autoIncrement ? mKey.IntValue() : LL_MININT;
     rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey,
                                        autoIncrement, mOverwrite,
                                        objectDataId, mIndexUpdateInfo);
     if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     }
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
@@ -1697,17 +1872,17 @@ AddHelper::DoDatabaseWork(mozIStorageCon
 nsresult
 AddHelper::GetSuccessResult(JSContext* aCx,
                             jsval* aVal)
 {
   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
 
   mCloneBuffer.clear();
 
-  return mKey.ToJSVal(aCx, aVal);
+  return IDBObjectStore::GetJSValFromKey(mKey, aCx, aVal);
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
   nsCOMPtr<mozIStorageStatement> stmt =
@@ -1717,18 +1892,28 @@ GetHelper::DoDatabaseWork(mozIStorageCon
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mKey.IsUnset(), "Must have a key here!");
 
-  rv = mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("id"));
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_NAMED_LITERAL_CSTRING(id, "id");
+
+  if (mKey.IsInt()) {
+    rv = stmt->BindInt64ByName(id, mKey.IntValue());
+  }
+  else if (mKey.IsString()) {
+    rv = stmt->BindStringByName(id, mKey.StringValue());
+  }
+  else {
+    NS_NOTREACHED("Unknown key type!");
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Search for it!
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (hasResult) {
     rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0,
@@ -1763,31 +1948,41 @@ DeleteHelper::DoDatabaseWork(mozIStorage
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mKey.IsUnset(), "Must have a key here!");
 
-  rv = mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value"));
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_NAMED_LITERAL_CSTRING(key_value, "key_value");
+
+  if (mKey.IsInt()) {
+    rv = stmt->BindInt64ByName(key_value, mKey.IntValue());
+  }
+  else if (mKey.IsString()) {
+    rv = stmt->BindStringByName(key_value, mKey.StringValue());
+  }
+  else {
+    NS_NOTREACHED("Unknown key type!");
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::GetSuccessResult(JSContext* aCx,
                                jsval* aVal)
 {
   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
-  return mKey.ToJSVal(aCx, aVal);
+  return IDBObjectStore::GetJSValFromKey(mKey, aCx, aVal);
 }
 
 nsresult
 ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
   nsCString table;
@@ -1831,25 +2026,23 @@ OpenCursorHelper::DoDatabaseWork(mozISto
     keyColumn.AssignLiteral("key_value");
   }
 
   NS_NAMED_LITERAL_CSTRING(id, "id");
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsCAutoString keyRangeClause;
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      AppendConditionClause(keyColumn, lowerKeyName, false,
-                            !mKeyRange->IsLowerOpen(), keyRangeClause);
-    }
-    if (!mKeyRange->Upper().IsUnset()) {
-      AppendConditionClause(keyColumn, upperKeyName, true,
-                            !mKeyRange->IsUpperOpen(), keyRangeClause);
-    }
+  if (!mLowerKey.IsUnset()) {
+    AppendConditionClause(keyColumn, lowerKeyName, false, !mLowerOpen,
+                          keyRangeClause);
+  }
+  if (!mUpperKey.IsUnset()) {
+    AppendConditionClause(keyColumn, upperKeyName, true, !mUpperOpen,
+                          keyRangeClause);
   }
 
   nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyColumn;
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
       directionClause += NS_LITERAL_CSTRING(" ASC");
       break;
@@ -1872,38 +2065,65 @@ OpenCursorHelper::DoDatabaseWork(mozISto
     mTransaction->GetCachedStatement(firstQuery);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+  if (!mLowerKey.IsUnset()) {
+    if (mLowerKey.IsString()) {
+      rv = stmt->BindStringByName(lowerKeyName, mLowerKey.StringValue());
+    }
+    else if (mLowerKey.IsInt()) {
+      rv = stmt->BindInt64ByName(lowerKeyName, mLowerKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
     }
-    if (!mKeyRange->Upper().IsUnset()) {
-      rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (!mUpperKey.IsUnset()) {
+    if (mUpperKey.IsString()) {
+      rv = stmt->BindStringByName(upperKeyName, mUpperKey.StringValue());
     }
+    else if (mUpperKey.IsInt()) {
+      rv = stmt->BindInt64ByName(upperKeyName, mUpperKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (!hasResult) {
-    mKey.Unset();
+    mKey = Key::UNSETKEY;
     return NS_OK;
   }
 
-  rv = mKey.SetFromStatement(stmt, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 keyType;
+  rv = stmt->GetTypeOfIndex(0, &keyType);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+    mKey = stmt->AsInt64(0);
+  }
+  else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+    rv = stmt->GetString(0, mKey.ToString());
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_NOTREACHED("Bad SQLite type!");
+  }
 
   rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 1,
                                                            mCloneBuffer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now we need to make the query to get the next match.
   keyRangeClause.Truncate();
   nsCAutoString continueToKeyRangeClause;
@@ -1913,38 +2133,36 @@ OpenCursorHelper::DoDatabaseWork(mozISto
 
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
       AppendConditionClause(keyColumn, currentKey, false, false,
                             keyRangeClause);
       AppendConditionClause(keyColumn, currentKey, false, true,
                             continueToKeyRangeClause);
-      if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
-        AppendConditionClause(keyColumn, rangeKey, true,
-                              !mKeyRange->IsUpperOpen(), keyRangeClause);
-        AppendConditionClause(keyColumn, rangeKey, true,
-                              !mKeyRange->IsUpperOpen(),
+      if (!mUpperKey.IsUnset()) {
+        AppendConditionClause(keyColumn, rangeKey, true, !mUpperOpen,
+                              keyRangeClause);
+        AppendConditionClause(keyColumn, rangeKey, true, !mUpperOpen,
                               continueToKeyRangeClause);
-        mRangeKey = mKeyRange->Upper();
+        mRangeKey = mUpperKey;
       }
       break;
 
     case nsIIDBCursor::PREV:
     case nsIIDBCursor::PREV_NO_DUPLICATE:
       AppendConditionClause(keyColumn, currentKey, true, false, keyRangeClause);
       AppendConditionClause(keyColumn, currentKey, true, true,
                            continueToKeyRangeClause);
-      if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
-        AppendConditionClause(keyColumn, rangeKey, false,
-                              !mKeyRange->IsLowerOpen(), keyRangeClause);
-        AppendConditionClause(keyColumn, rangeKey, false,
-                              !mKeyRange->IsLowerOpen(),
+      if (!mLowerKey.IsUnset()) {
+        AppendConditionClause(keyColumn, rangeKey, false, !mLowerOpen,
+                              keyRangeClause);
+        AppendConditionClause(keyColumn, rangeKey, false, !mLowerOpen,
                               continueToKeyRangeClause);
-        mRangeKey = mKeyRange->Lower();
+        mRangeKey = mLowerKey;
       }
       break;
 
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
   mContinueQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
@@ -2169,23 +2387,34 @@ CreateIndexHelper::InsertDataFromObjectS
 
     rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"),
                                      stmt->AsInt64(0));
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (!mIndex->IsAutoIncrement()) {
       NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
 
-      Key key;
-      rv = key.SetFromStatement(stmt, 2);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv =
-        key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("object_data_key"));
-      NS_ENSURE_SUCCESS(rv, rv);
+      PRInt32 keyType;
+      rv = stmt->GetTypeOfIndex(2, &keyType);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+        rv = insertStmt->BindInt64ByName(objectDataKey, stmt->AsInt64(2));
+      }
+      else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+        nsString stringKey;
+        rv = stmt->GetString(2, stringKey);
+        NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+        rv = insertStmt->BindStringByName(objectDataKey, stringKey);
+      }
+      else {
+        NS_NOTREACHED("Bad SQLite type!");
+      }
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     const PRUint8* data;
     PRUint32 dataLength;
     rv = stmt->GetSharedBlob(1, &dataLength, &data);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -2198,26 +2427,34 @@ CreateIndexHelper::InsertDataFromObjectS
       NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       PR_SetThreadPrivate(sTLSIndex, tlsEntry);
     }
 
     Key key;
     rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
                                                            mIndex->KeyPath(),
-                                                           tlsEntry->Context(),
-                                                           key);
+                                                           tlsEntry->Context(), key);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (key.IsUnset()) {
       continue;
     }
 
-    rv = key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("value"));
-    NS_ENSURE_SUCCESS(rv, rv);
+    NS_NAMED_LITERAL_CSTRING(value, "value");
+    if (key.IsInt()) {
+      rv = insertStmt->BindInt64ByName(value, key.IntValue());
+    }
+    else if (key.IsString()) {
+      rv = insertStmt->BindStringByName(value, key.StringValue());
+    }
+    else {
+      return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     rv = insertStmt->Execute();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   return NS_OK;
 }
 
@@ -2260,70 +2497,86 @@ GetAllHelper::DoDatabaseWork(mozIStorage
     keyColumn.AssignLiteral("key_value");
   }
 
   NS_NAMED_LITERAL_CSTRING(osid, "osid");
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsCAutoString keyRangeClause;
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn;
-      if (mKeyRange->IsLowerOpen()) {
-        keyRangeClause.AppendLiteral(" > :");
-      }
-      else {
-        keyRangeClause.AppendLiteral(" >= :");
-      }
-      keyRangeClause.Append(lowerKeyName);
+  if (!mLowerKey.IsUnset()) {
+    keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn;
+    if (mLowerOpen) {
+      keyRangeClause.AppendLiteral(" > :");
+    }
+    else {
+      keyRangeClause.AppendLiteral(" >= :");
     }
-
-    if (!mKeyRange->Upper().IsUnset()) {
-      keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn;
-      if (mKeyRange->IsUpperOpen()) {
-        keyRangeClause.AppendLiteral(" < :");
-      }
-      else {
-        keyRangeClause.AppendLiteral(" <= :");
-      }
-      keyRangeClause.Append(upperKeyName);
+    keyRangeClause.Append(lowerKeyName);
+  }
+
+  if (!mUpperKey.IsUnset()) {
+    keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn;
+    if (mUpperOpen) {
+      keyRangeClause.AppendLiteral(" < :");
     }
+    else {
+      keyRangeClause.AppendLiteral(" <= :");
+    }
+    keyRangeClause.Append(upperKeyName);
   }
 
   nsCAutoString limitClause;
   if (mLimit != PR_UINT32_MAX) {
     limitClause.AssignLiteral(" LIMIT ");
     limitClause.AppendInt(mLimit);
   }
 
   nsCString query = NS_LITERAL_CSTRING("SELECT data FROM ") + table +
                     NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid +
                     keyRangeClause + NS_LITERAL_CSTRING(" ORDER BY ") +
                     keyColumn + NS_LITERAL_CSTRING(" ASC") + limitClause;
 
-  mCloneBuffers.SetCapacity(50);
+  if (!mCloneBuffers.SetCapacity(50)) {
+    NS_ERROR("Out of memory!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+  if (!mLowerKey.IsUnset()) {
+    if (mLowerKey.IsString()) {
+      rv = stmt->BindStringByName(lowerKeyName, mLowerKey.StringValue());
+    }
+    else if (mLowerKey.IsInt()) {
+      rv = stmt->BindInt64ByName(lowerKeyName, mLowerKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
     }
-    if (!mKeyRange->Upper().IsUnset()) {
-      rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  if (!mUpperKey.IsUnset()) {
+    if (mUpperKey.IsString()) {
+      rv = stmt->BindStringByName(upperKeyName, mUpperKey.StringValue());
     }
+    else if (mUpperKey.IsInt()) {
+      rv = stmt->BindInt64ByName(upperKeyName, mUpperKey.IntValue());
+    }
+    else {
+      NS_NOTREACHED("Bad key!");
+    }
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   bool hasResult;
   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
     if (mCloneBuffers.Capacity() == mCloneBuffers.Length()) {
       if (!mCloneBuffers.SetCapacity(mCloneBuffers.Capacity() * 2)) {
         NS_ERROR("Out of memory!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -2351,91 +2604,8 @@ GetAllHelper::GetSuccessResult(JSContext
 
   for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
     mCloneBuffers[index].clear();
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
-
-nsresult
-CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
-{
-  nsCString table;
-  nsCString keyColumn;
-
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    keyColumn.AssignLiteral("id");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    keyColumn.AssignLiteral("key_value");
-  }
-
-  NS_NAMED_LITERAL_CSTRING(osid, "osid");
-  NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
-  NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
-
-  nsCAutoString keyRangeClause;
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn;
-      if (mKeyRange->IsLowerOpen()) {
-        keyRangeClause.AppendLiteral(" > :");
-      }
-      else {
-        keyRangeClause.AppendLiteral(" >= :");
-      }
-      keyRangeClause.Append(lowerKeyName);
-    }
-
-    if (!mKeyRange->Upper().IsUnset()) {
-      keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn;
-      if (mKeyRange->IsUpperOpen()) {
-        keyRangeClause.AppendLiteral(" < :");
-      }
-      else {
-        keyRangeClause.AppendLiteral(" <= :");
-      }
-      keyRangeClause.Append(upperKeyName);
-    }
-  }
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid +
-                    keyRangeClause;
-
-  nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  mozStorageStatementScoper scoper(stmt);
-
-  nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  if (mKeyRange) {
-    if (!mKeyRange->Lower().IsUnset()) {
-      rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    if (!mKeyRange->Upper().IsUnset()) {
-      rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-
-  bool hasResult;
-  rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  NS_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  mCount = stmt->AsInt64(0);
-  return NS_OK;
-}
-
-nsresult
-CountHelper::GetSuccessResult(JSContext* aCx,
-                              jsval* aVal)
-{
-  return JS_NewNumberValue(aCx, static_cast<jsdouble>(mCount), aVal);
-}
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -37,29 +37,29 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbobjectstore_h__
 #define mozilla_dom_indexeddb_idbobjectstore_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 #include "mozilla/dom/indexedDB/IDBTransaction.h"
+#include "mozilla/dom/indexedDB/Key.h"
 
 #include "nsIIDBObjectStore.h"
 #include "nsIIDBTransaction.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
-class Key;
 
 struct ObjectStoreInfo;
 struct IndexInfo;
 struct IndexUpdateInfo;
 
 class IDBObjectStore : public nsIIDBObjectStore
 {
 public:
@@ -68,16 +68,30 @@ public:
 
   NS_DECL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
 
   static already_AddRefed<IDBObjectStore>
   Create(IDBTransaction* aTransaction,
          const ObjectStoreInfo* aInfo);
 
   static nsresult
+  GetKeyFromVariant(nsIVariant* aKeyVariant,
+                    Key& aKey);
+
+  static nsresult
+  GetKeyFromJSVal(jsval aKeyVal,
+                  JSContext* aCx,
+                  Key& aKey);
+
+  static nsresult
+  GetJSValFromKey(const Key& aKey,
+                  JSContext* aCx,
+                  jsval* aKeyVal);
+
+  static nsresult
   GetKeyPathValueFromStructuredData(const PRUint8* aData,
                                     PRUint32 aDataLength,
                                     const nsAString& aKeyPath,
                                     JSContext* aCx,
                                     Key& aValue);
 
   static nsresult
   GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -36,16 +36,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBRequest.h"
 
 #include "nsIScriptContext.h"
+#include "nsIVariant.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsPIDOMWindow.h"
 #include "nsStringGlue.h"
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -37,88 +37,119 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_key_h__
 #define mozilla_dom_indexeddb_key_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
-#include "mozIStorageStatement.h"
-
-#include "xpcprivate.h"
-#include "XPCQuickStubs.h"
-
 BEGIN_INDEXEDDB_NAMESPACE
 
 class Key
 {
 public:
+  enum Type { UNSETKEY, STRINGKEY, INTKEY };
+
   Key()
+  : mType(UNSETKEY), mInt(0)
+  { }
+
+  Key(const Key& aOther)
+  {
+    *this = aOther;
+  }
+
+  Key& operator=(const Key& aOther)
   {
-    Unset();
+    if (this != &aOther) {
+      mType = aOther.mType;
+      mString = aOther.mString;
+      mInt = aOther.mInt;
+    }
+    return *this;
+  }
+
+  Key& operator=(Type aType)
+  {
+    NS_ASSERTION(aType == UNSETKEY ,
+                 "Use one of the other operators to assign your value!");
+    mType = aType;
+    mString.Truncate();
+    mInt = 0;
+    return *this;
   }
 
   Key& operator=(const nsAString& aString)
   {
-    SetFromString(aString);
+    mType = STRINGKEY;
+    mString = aString;
+    mInt = 0;
     return *this;
   }
 
   Key& operator=(PRInt64 aInt)
   {
-    SetFromInteger(aInt);
+    mType = INTKEY;
+    mString.Truncate();
+    mInt = aInt;
     return *this;
   }
 
   bool operator==(const Key& aOther) const
   {
-     NS_ASSERTION(mType != KEYTYPE_VOID && aOther.mType != KEYTYPE_VOID,
-                 "Don't compare unset keys!");
-
     if (mType == aOther.mType) {
       switch (mType) {
-        case KEYTYPE_STRING:
-          return ToString() == aOther.ToString();
+        case UNSETKEY:
+          return true;
 
-        case KEYTYPE_INTEGER:
-          return ToInteger() == aOther.ToInteger();
+        case STRINGKEY:
+          return mString == aOther.mString;
+
+        case INTKEY:
+          return mInt == aOther.mInt;
 
         default:
           NS_NOTREACHED("Unknown type!");
       }
     }
     return false;
   }
 
   bool operator!=(const Key& aOther) const
   {
     return !(*this == aOther);
   }
 
   bool operator<(const Key& aOther) const
   {
-    NS_ASSERTION(mType != KEYTYPE_VOID && aOther.mType != KEYTYPE_VOID,
-                 "Don't compare unset keys!");
+    switch (mType) {
+      case UNSETKEY:
+        if (aOther.mType == UNSETKEY) {
+          return false;
+        }
+        return true;
 
-    switch (mType) {
-      case KEYTYPE_STRING: {
-        if (aOther.mType == KEYTYPE_INTEGER) {
+      case STRINGKEY:
+        if (aOther.mType == UNSETKEY ||
+            aOther.mType == INTKEY) {
           return false;
         }
-        NS_ASSERTION(aOther.mType == KEYTYPE_STRING, "Unknown type!");
-        return ToString() < aOther.ToString();
-      }
+        NS_ASSERTION(aOther.mType == STRINGKEY, "Unknown type!");
+        return mString < aOther.mString;
 
-      case KEYTYPE_INTEGER:
-        if (aOther.mType == KEYTYPE_STRING) {
+      case INTKEY:
+        if (aOther.mType == UNSETKEY) {
+          return false;
+        }
+        if (aOther.mType == STRINGKEY) {
           return true;
         }
-        NS_ASSERTION(aOther.mType == KEYTYPE_INTEGER, "Unknown type!");
-        return ToInteger() < aOther.ToInteger();
+        NS_ASSERTION(aOther.mType == INTKEY, "Unknown type!");
+        return mInt < aOther.mInt;
 
       default:
         NS_NOTREACHED("Unknown type!");
     }
     return false;
   }
 
   bool operator>(const Key& aOther) const
@@ -131,195 +162,49 @@ public:
     return (*this == aOther || *this < aOther);
   }
 
   bool operator>=(const Key& aOther) const
   {
     return (*this == aOther || !(*this < aOther));
   }
 
-  void
-  Unset()
-  {
-    mType = KEYTYPE_VOID;
-    mStringKey.SetIsVoid(true);
-    mIntKey = 0;
-  }
-
-  bool IsUnset() const { return mType == KEYTYPE_VOID; }
-  bool IsString() const { return mType == KEYTYPE_STRING; }
-  bool IsInteger() const { return mType == KEYTYPE_INTEGER; }
-
-  nsresult SetFromString(const nsAString& aString)
-  {
-    mType = KEYTYPE_STRING;
-    mStringKey = aString;
-    mIntKey = 0;
-    return NS_OK;
-  }
-
-  nsresult SetFromInteger(PRInt64 aInt)
-  {
-    mType = KEYTYPE_INTEGER;
-    mStringKey.SetIsVoid(true);
-    mIntKey = aInt;
-    return NS_OK;
-  }
+  bool IsUnset() const { return mType == UNSETKEY; }
+  bool IsString() const { return mType == STRINGKEY; }
+  bool IsInt() const { return mType == INTKEY; }
 
-  nsresult SetFromJSVal(JSContext* aCx,
-                        jsval aVal)
-  {
-    if (JSVAL_IS_STRING(aVal)) {
-      jsval tempRoot = JSVAL_VOID;
-      SetFromString(xpc_qsAString(aCx, aVal, &tempRoot));
-      return NS_OK;
-    }
-
-    if (JSVAL_IS_INT(aVal)) {
-      SetFromInteger(JSVAL_TO_INT(aVal));
-      return NS_OK;
-    }
-
-    if (JSVAL_IS_DOUBLE(aVal)) {
-      jsdouble doubleActual = JSVAL_TO_DOUBLE(aVal);
-      int64 doubleAsInt = static_cast<int64>(doubleActual);
-      if (doubleActual == doubleAsInt) {
-        SetFromInteger(doubleAsInt);
-        return NS_OK;
-      }
-    }
-
-    if (JSVAL_IS_NULL(aVal) || JSVAL_IS_VOID(aVal)) {
-      Unset();
-      return NS_OK;
-    }
-
-    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+  const nsString& StringValue() const {
+    NS_ASSERTION(IsString(), "Wrong type!");
+    return mString;
   }
 
-  nsresult ToJSVal(JSContext* aCx,
-                   jsval* aVal) const
-  {
-    if (IsString()) {
-      nsString stringKey = ToString();
-      if (!xpc_qsStringToJsval(aCx, stringKey, aVal)) {
-        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-      }
-    }
-    else if (IsInteger()) {
-      if (!JS_NewNumberValue(aCx, static_cast<jsdouble>(ToInteger()), aVal)) {
-        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-      }
-    }
-    else if (IsUnset()) {
-      *aVal = JSVAL_VOID;
-    }
-    else {
-      NS_NOTREACHED("Unknown key type!");
-    }
-    return NS_OK;
-  }
-
-  PRInt64 ToInteger() const
-  {
-    NS_ASSERTION(IsInteger(), "Don't call me!");
-    return mIntKey;
-  }
-
-  const nsAString& ToString() const
-  {
-    NS_ASSERTION(IsString(), "Don't call me!");
-    return mStringKey;
+  PRInt64 IntValue() const {
+    NS_ASSERTION(IsInt(), "Wrong type!");
+    return mInt;
   }
 
-  nsresult BindToStatement(mozIStorageStatement* aStatement,
-                           const nsACString& aParamName) const
-  {
-    nsresult rv;
-
-    if (IsString()) {
-      rv = aStatement->BindStringByName(aParamName, ToString());
-    }
-    else if (IsInteger()) {
-      rv = aStatement->BindInt64ByName(aParamName, ToInteger());
-    }
-    else {
-      NS_NOTREACHED("Bad key!");
-    }
-
-    return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  nsresult BindToStatementAllowUnset(mozIStorageStatement* aStatement,
-                                     const nsACString& aParamName) const
-  {
-    nsresult rv;
-
-    if (IsUnset()) {
-      rv = aStatement->BindStringByName(aParamName, EmptyString());
-      return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    return BindToStatement(aStatement, aParamName);
+  nsAString& ToString() {
+    mType = STRINGKEY;
+    mInt = 0;
+    return mString;
   }
 
-  nsresult SetFromStatement(mozIStorageStatement* aStatement,
-                            PRUint32 aIndex)
-  {
-    PRInt32 columnType;
-    nsresult rv = aStatement->GetTypeOfIndex(aIndex, &columnType);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    NS_ASSERTION(columnType == mozIStorageStatement::VALUE_TYPE_INTEGER ||
-                 columnType == mozIStorageStatement::VALUE_TYPE_TEXT,
-                 "Unsupported column type!");
-
-    return SetFromStatement(aStatement, aIndex, columnType);
-  }
-
-  nsresult SetFromStatement(mozIStorageStatement* aStatement,
-                            PRUint32 aIndex,
-                            PRInt32 aColumnType)
-  {
-    if (aColumnType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
-      return SetFromInteger(aStatement->AsInt64(aIndex));
-    }
-
-    if (aColumnType == mozIStorageStatement::VALUE_TYPE_TEXT) {
-      nsString keyString;
-      nsresult rv = aStatement->GetString(aIndex, keyString);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      return SetFromString(keyString);
-    }
-
-    NS_NOTREACHED("Unsupported column type!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  PRInt64* ToIntPtr() {
+    mType = INTKEY;
+    mString.Truncate();
+    return &mInt;
   }
 
   static
-  bool CanBeConstructedFromJSVal(jsval aVal)
-  {
-    return JSVAL_IS_INT(aVal) || JSVAL_IS_DOUBLE(aVal) || JSVAL_IS_STRING(aVal);
+  JSBool CanBeConstructedFromJSVal(jsval aVal) {
+    return JSVAL_IS_VOID(aVal) || JSVAL_IS_NULL(aVal) || JSVAL_IS_INT(aVal) ||
+           JSVAL_IS_DOUBLE(aVal) || JSVAL_IS_STRING(aVal);
   }
 
 private:
-  // Wish we could use JSType here but we will end up supporting types like Date
-  // which JSType can't really identify. Rolling our own for now.
-  enum Type {
-    KEYTYPE_VOID,
-    KEYTYPE_STRING,
-    KEYTYPE_INTEGER
-  };
-
-  // Type of value in mJSVal.
   Type mType;
-
-  // The string if mType is KEYTYPE_STRING, otherwise a void string.
-  nsString mStringKey;
-
-  // The integer value if mType is KEYTYPE_INTEGER, otherwise 0.
-  int64 mIntKey;
+  nsString mString;
+  PRInt64 mInt;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif /* mozilla_dom_indexeddb_key_h__ */
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -88,17 +88,16 @@ EXPORTS_mozilla/dom/indexedDB = \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/xpcom/build \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/src/storage \
   -I$(topsrcdir)/content/base/src \
   -I$(topsrcdir)/content/events/src \
-  -I$(topsrcdir)/js/xpconnect/src \
   $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
 # Make sure to quickstub as much as possible here! See
 # js/xpconnect/src/dom_quickstubs.qsconf.
 XPIDLSRCS = \
   nsIIDBCursor.idl \
--- a/dom/indexedDB/nsIIDBCursor.idl
+++ b/dom/indexedDB/nsIIDBCursor.idl
@@ -35,35 +35,35 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIIDBRequest;
+interface nsIVariant;
 
 /**
  * IDBCursor interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBCursor for more
  * information.
  */
-[scriptable, builtinclass, uuid(462a3607-b2d6-4f4b-9dd7-8ca0b26d3414)]
+[scriptable, uuid(adee4085-68cd-4568-9d74-e3d32b6dc5c5)]
 interface nsIIDBCursor : nsISupports
 {
   const unsigned short NEXT = 0;
   const unsigned short NEXT_NO_DUPLICATE = 1;
   const unsigned short PREV = 2;
   const unsigned short PREV_NO_DUPLICATE = 3;
   readonly attribute unsigned short direction;
 
   readonly attribute nsISupports source;
 
-  [implicit_jscontext]
-  readonly attribute jsval key;
+  readonly attribute nsIVariant key;
 
   [implicit_jscontext]
   readonly attribute jsval primaryKey;
 
   // Calling continue means that the same onsuccess function will be called
   // again with the new key/value (or null if no more matches).
   [implicit_jscontext]
   void continue([optional /* undefined */] in jsval key);
--- a/dom/indexedDB/nsIIDBCursorWithValue.idl
+++ b/dom/indexedDB/nsIIDBCursorWithValue.idl
@@ -34,19 +34,23 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIIDBCursor.idl"
 
+%{C++
+#include "jsapi.h"
+%}
+
 /**
  * IDBCursor interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBCursor for more
  * information.
  */
-[scriptable, builtinclass, uuid(b6b7e08a-4379-4441-a176-447c5c96df69)]
+[scriptable, uuid(b6b7e08a-4379-4441-a176-447c5c96df69)]
 interface nsIIDBCursorWithValue : nsIIDBCursor
 {
   [implicit_jscontext]
   readonly attribute jsval value;
 };
--- a/dom/indexedDB/nsIIDBDatabase.idl
+++ b/dom/indexedDB/nsIIDBDatabase.idl
@@ -34,28 +34,29 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
+interface nsIVariant;
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 interface nsIDOMEventListener;
 
 /**
  * IDBDatabase interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
  * for more information.
  */
-[scriptable, builtinclass, uuid(ddc9dd43-704f-45da-bb91-20f4b3103117)]
+[scriptable, uuid(ac14faa5-261c-4a84-9616-a700fd606f83)]
 interface nsIIDBDatabase : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute unsigned long long version;
 
   readonly attribute nsIDOMDOMStringList objectStoreNames;
 
@@ -72,18 +73,19 @@ interface nsIIDBDatabase : nsISupports
   createObjectStore(in AString name,
                     [optional /* none */] in jsval options);
 
   void
   deleteObjectStore(in AString name);
 
   [optional_argc, implicit_jscontext]
   nsIIDBTransaction
-  transaction(in jsval storeNames, // js array of strings
-              [optional /* READ_ONLY */] in unsigned short mode);
+  transaction(in nsIVariant storeNames, // js array of strings
+              [optional /* READ_ONLY */] in unsigned short mode,
+              [optional /* 5000ms */] in unsigned long timeout);
 
   void
   close();
 
   attribute nsIDOMEventListener onerror;
 
   attribute nsIDOMEventListener onversionchange;
 };
--- a/dom/indexedDB/nsIIDBDatabaseException.idl
+++ b/dom/indexedDB/nsIIDBDatabaseException.idl
@@ -34,17 +34,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, builtinclass, uuid(7aad2542-a5cb-4a57-b20c-c7d16b8582ab)]
+[scriptable, uuid(7aad2542-a5cb-4a57-b20c-c7d16b8582ab)]
 interface nsIIDBDatabaseException : nsISupports
 {
   // const unsigned short NO_ERR = 0;
   const unsigned short UNKNOWN_ERR = 1;
   const unsigned short NON_TRANSIENT_ERR = 2;
   const unsigned short NOT_FOUND_ERR = 3;
   const unsigned short CONSTRAINT_ERR = 4;
   const unsigned short DATA_ERR = 5;
--- a/dom/indexedDB/nsIIDBFactory.idl
+++ b/dom/indexedDB/nsIIDBFactory.idl
@@ -37,22 +37,23 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIIDBKeyRange;
 interface nsIIDBOpenDBRequest;
+interface nsIVariant;
 
 /**
  * Interface that defines the indexedDB property on a window.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
  * for more information.
  */
-[scriptable, builtinclass, uuid(d2889b8f-662a-42d3-8a8f-ac5179b9d5b0)]
+[scriptable, uuid(d2889b8f-662a-42d3-8a8f-ac5179b9d5b0)]
 interface nsIIDBFactory : nsISupports
 {
   [implicit_jscontext, optional_argc]
   nsIIDBOpenDBRequest
   open(in AString name,
        [optional] in long long version);
 };
--- a/dom/indexedDB/nsIIDBIndex.idl
+++ b/dom/indexedDB/nsIIDBIndex.idl
@@ -34,62 +34,57 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
+interface nsIIDBKeyRange;
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
+interface nsIVariant;
 
 /**
  * IDBIndex interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBIndex for more
  * information.
  */
-[scriptable, builtinclass, uuid(1da60889-3db4-4f66-9fd7-b78c1e7969b7)]
+[scriptable, uuid(9df1ac24-06cf-47d1-9159-3b3d65975b80)]
 interface nsIIDBIndex : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString storeName;
 
   readonly attribute DOMString keyPath;
 
   readonly attribute boolean unique;
 
   readonly attribute nsIIDBObjectStore objectStore;
 
-  [implicit_jscontext]
   nsIIDBRequest
-  get(in jsval key);
+  get(in nsIVariant key);
 
-  [implicit_jscontext]
   nsIIDBRequest
-  getKey(in jsval key);
+  getKey(in nsIVariant key);
 
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIIDBRequest
-  getAll([optional /* null */] in jsval key,
+  getAll([optional /* null */] in nsIVariant key,
          [optional /* unlimited */] in unsigned long limit);
 
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIIDBRequest
-  getAllKeys([optional /* null */] in jsval key,
+  getAllKeys([optional /* null */] in nsIVariant key,
              [optional /* unlimited */] in unsigned long limit);
 
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIIDBRequest
-  openCursor([optional /* null */] in jsval key,
+  openCursor([optional /* null */] in nsIIDBKeyRange range,
              [optional /* nsIIDBCursor::NEXT */] in unsigned short direction);
 
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIIDBRequest
-  openKeyCursor([optional /* null */] in jsval key,
+  openKeyCursor([optional /* null */] in nsIIDBKeyRange range,
                 [optional /* nsIIDBCursor::NEXT */] in unsigned short direction);
-
-  // Accepts null, a key value, or a nsIIDBKeyRange object.
-  [implicit_jscontext, optional_argc]
-  nsIIDBRequest
-  count([optional] in jsval key);
 };
--- a/dom/indexedDB/nsIIDBKeyRange.idl
+++ b/dom/indexedDB/nsIIDBKeyRange.idl
@@ -34,25 +34,23 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
+interface nsIVariant;
+
 /**
  * IDBKeyRange interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBKeyRange for more
  * information.
  */
-[scriptable, builtinclass, uuid(8aeb8660-76b3-4651-b8c2-9894ae6dfe68)]
+[scriptable, uuid(a1505e41-7e48-4542-9fa5-3f2c98233567)]
 interface nsIIDBKeyRange : nsISupports
 {
-  [implicit_jscontext]
-  readonly attribute jsval lower;
-
-  [implicit_jscontext]
-  readonly attribute jsval upper;
-
+  readonly attribute nsIVariant lower;
+  readonly attribute nsIVariant upper;
   readonly attribute boolean lowerOpen;
   readonly attribute boolean upperOpen;
 };
--- a/dom/indexedDB/nsIIDBObjectStore.idl
+++ b/dom/indexedDB/nsIIDBObjectStore.idl
@@ -38,43 +38,43 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIIDBIndex;
 interface nsIIDBKeyRange;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
+interface nsIVariant;
 interface nsIDOMDOMStringList;
 
 /**
  * nsIIDBObjectStore interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
  * for more information.
  */
-[scriptable, builtinclass, uuid(d25dff2f-81ad-4531-bcbe-e85c8a19f11a)]
+[scriptable, uuid(6a65dc92-66e3-407a-a370-590a6c54664a)]
 interface nsIIDBObjectStore : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString keyPath;
 
   readonly attribute nsIDOMDOMStringList indexNames;
 
   readonly attribute nsIIDBTransaction transaction;
 
   // Success fires IDBTransactionEvent, result == value for key
-  [implicit_jscontext]
   nsIIDBRequest
-  get(in jsval key);
+  get(in nsIVariant key);
 
   // Success fires IDBTransactionEvent, result == array of values for given keys
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIIDBRequest
-  getAll([optional /* null */] in jsval key,
+  getAll([optional /* null */] in nsIIDBKeyRange key,
          [optional /* unlimited */] in unsigned long limit);
 
   // Success fires IDBTransactionEvent, result == key
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   add(in jsval value,
       [optional /* undefined */] in jsval key);
 
@@ -90,19 +90,19 @@ interface nsIIDBObjectStore : nsISupport
   delete(in jsval key);
 
   // Success fires IDBTransactionEvent, result == null
   nsIIDBRequest
   clear();
 
   // Success fires IDBTransactionEvent, result == IDBCursor or result == null if
   // no match.
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIIDBRequest
-  openCursor([optional /* null */] in jsval range,
+  openCursor([optional /* null */] in nsIIDBKeyRange range,
              [optional /* NEXT */] in unsigned short direction);
 
   /**
    * Optional arguments:
    *   - unique (boolean):
    *       Specifies whether values in the index must be unique. Defaults to
    *       false.
    */
@@ -113,14 +113,9 @@ interface nsIIDBObjectStore : nsISupport
               [optional /* none */] in jsval options);
 
   // Returns object immediately
   nsIIDBIndex
   index(in AString name);
 
   void
   deleteIndex(in AString name);
-
-  // Accepts null, a key value, or a nsIIDBKeyRange object.
-  [implicit_jscontext, optional_argc]
-  nsIIDBRequest
-  count([optional] in jsval key);
 };
--- a/dom/indexedDB/nsIIDBOpenDBRequest.idl
+++ b/dom/indexedDB/nsIIDBOpenDBRequest.idl
@@ -42,14 +42,14 @@
 
 interface nsIDOMEventListener;
 
 /**
  * IDBOpenDBRequest interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
  * for more information.
  */
-[scriptable, builtinclass, uuid(91010fbe-1dfb-435d-852e-288d2804c0a7)]
+[scriptable, uuid(91010fbe-1dfb-435d-852e-288d2804c0a7)]
 interface nsIIDBOpenDBRequest : nsISupports
 {
   attribute nsIDOMEventListener onblocked;
   attribute nsIDOMEventListener onupgradeneeded;
 };
--- a/dom/indexedDB/nsIIDBRequest.idl
+++ b/dom/indexedDB/nsIIDBRequest.idl
@@ -43,17 +43,17 @@
 interface nsIDOMEventListener;
 interface nsIIDBTransaction;
 
 /**
  * IDBReqeust interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more
  * information.
  */
-[scriptable, builtinclass, uuid(a1e4a0ff-e0b2-431c-89cf-43b078189e27)]
+[scriptable, uuid(a1e4a0ff-e0b2-431c-89cf-43b078189e27)]
 interface nsIIDBRequest : nsISupports
 {
   const unsigned short LOADING = 1;
   const unsigned short DONE = 2;
   readonly attribute unsigned short readyState;
 
   readonly attribute nsISupports source;
 
--- a/dom/indexedDB/nsIIDBTransaction.idl
+++ b/dom/indexedDB/nsIIDBTransaction.idl
@@ -45,17 +45,17 @@ interface nsIIDBRequest;
 interface nsIIDBDatabase;
 interface nsIDOMDOMStringList;
 
 /**
  * IDBDTransaction interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBTransaction
  * for more information.
  */
-[scriptable, builtinclass, uuid(13e551a1-1a58-42ec-b0bd-7102ec0f64d6)]
+[scriptable, uuid(13e551a1-1a58-42ec-b0bd-7102ec0f64d6)]
 interface nsIIDBTransaction : nsISupports
 {
   readonly attribute nsIIDBDatabase db;
 
   const unsigned short INITIAL = 0;
   const unsigned short LOADING = 1;
   const unsigned short COMMITTING = 2;
   const unsigned short DONE = 3;
--- a/dom/indexedDB/nsIIDBVersionChangeEvent.idl
+++ b/dom/indexedDB/nsIIDBVersionChangeEvent.idl
@@ -34,14 +34,14 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEvent.idl"
 
-[scriptable, builtinclass, uuid(2c5159dc-7d71-4fc6-a3b3-884ed7586456)]
+[scriptable, uuid(2c5159dc-7d71-4fc6-a3b3-884ed7586456)]
 interface nsIIDBVersionChangeEvent : nsIDOMEvent
 {
   readonly attribute unsigned long long oldVersion;
   readonly attribute unsigned long long newVersion;
 };
--- a/dom/indexedDB/nsIIndexedDatabaseManager.idl
+++ b/dom/indexedDB/nsIIndexedDatabaseManager.idl
@@ -46,17 +46,17 @@ interface nsIIndexedDatabaseUsageCallbac
 {
   /**
    *
    */
   void onUsageResult(in nsIURI aURI,
                      in unsigned long long aUsage);
 };
 
-[scriptable, builtinclass, uuid(415f5684-6c84-4a8b-b777-d01f5df778f2)]
+[scriptable, uuid(415f5684-6c84-4a8b-b777-d01f5df778f2)]
 interface nsIIndexedDatabaseManager : nsISupports
 {
   /**
    * Schedules an asynchronous callback that will return the total amount of
    * disk space being used by databases for the given origin.
    *
    * @param aURI
    *        The URI whose usage is being queried.
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -52,17 +52,16 @@ TEST_FILES = \
   exceptions_in_success_events_iframe.html \
   helpers.js \
   leaving_page_iframe.html \
   test_add_twice_failure.html \
   test_autoIncrement_indexes.html \
   test_bad_keypath.html \
   test_bfcache.html \
   test_clear.html \
-  test_count.html \
   test_create_index.html \
   test_create_index_with_integer_keys.html \
   test_create_objectStore.html \
   test_cursors.html \
   test_cursor_mutation.html \
   test_cursor_update_updates_indexes.html \
   test_error_events_abort_transactions.html \
   test_event_propagation.html \
deleted file mode 100644
--- a/dom/indexedDB/test/test_count.html
+++ /dev/null
@@ -1,366 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript;version=1.7">
-    function testSteps()
-    {
-      const name = window.location.pathname;
-      const objectStoreName = "People";
-
-      const objectStoreData = [
-        { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
-        { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
-        { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } },
-        { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
-        { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
-        { key: "237-23-7737", value: { name: "Pat", height: 65 } },
-        { key: "237-23-7738", value: { name: "Mel", height: 66, weight: {} } },
-        { key: "237-23-7739", value: { name: "Tom", height: 62, weight: 130 } }
-      ];
-
-      const indexData = {
-        name: "weight",
-        keyPath: "weight",
-        options: { unique: false }
-      };
-
-      const weightSort = [1, 0, 3, 7, 4, 2];
-
-      let request = mozIndexedDB.open(name, 1);
-      request.onerror = errorHandler;
-      request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
-      is(event.type, "upgradeneeded", "Got correct event type");
-
-      let db = event.target.result;
-      db.onerror = errorHandler;
-
-      let objectStore = db.createObjectStore(objectStoreName, { });
-      objectStore.createIndex(indexData.name, indexData.keyPath,
-                              indexData.options);
-
-      for each (let data in objectStoreData) {
-        objectStore.add(data.value, data.key);
-      }
-
-      event = yield;
-
-      is(event.type, "success", "Got correct event type");
-
-      objectStore = db.transaction(db.objectStoreNames)
-                      .objectStore(objectStoreName);
-
-      objectStore.count().onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length,
-         "Correct number of object store entries for all keys");
-
-      objectStore.count(null).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length,
-         "Correct number of object store entries for null key");
-
-      objectStore.count(objectStoreData[2].key).onsuccess =
-        grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 1,
-         "Correct number of object store entries for single existing key");
-
-      objectStore.count("foo").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of object store entries for single non-existing key");
-
-      let keyRange = IDBKeyRange.only(objectStoreData[2].key);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 1,
-         "Correct number of object store entries for existing only keyRange");
-
-      keyRange = IDBKeyRange.only("foo");
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of object store entries for non-existing only keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[2].key);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length - 2,
-         "Correct number of object store entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[2].key, true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length - 3,
-         "Correct number of object store entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound("foo");
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of object store entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[2].key, false);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 3,
-         "Correct number of object store entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[2].key, true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 2,
-         "Correct number of object store entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound("foo", true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length,
-         "Correct number of object store entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[0].key,
-                                   objectStoreData[objectStoreData.length - 1].key);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length,
-         "Correct number of object store entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[0].key,
-                                   objectStoreData[objectStoreData.length - 1].key,
-                                   true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length - 1,
-         "Correct number of object store entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[0].key,
-                                   objectStoreData[objectStoreData.length - 1].key,
-                                   true, true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length - 2,
-         "Correct number of object store entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound("foo", "foopy", true, true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of object store entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[0].key, "foo", true, true);
-      objectStore.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, objectStoreData.length - 1,
-         "Correct number of object store entries for bound keyRange");
-
-      let index = objectStore.index(indexData.name);
-
-      index.count().onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length,
-         "Correct number of index entries for no key");
-
-      index.count(objectStoreData[7].value.weight).onsuccess =
-        grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 2,
-         "Correct number of index entries for duplicate key");
-
-      index.count(objectStoreData[0].value.weight).onsuccess =
-        grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 1,
-         "Correct number of index entries for single key");
-
-      keyRange = IDBKeyRange.only(objectStoreData[0].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 1,
-         "Correct number of index entries for only existing keyRange");
-
-      keyRange = IDBKeyRange.only("foo");
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of index entries for only non-existing keyRange");
-
-      keyRange = IDBKeyRange.only(objectStoreData[7].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 2,
-         "Correct number of index entries for only duplicate keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[0]].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[1]].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length - 1,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[0]].value.weight - 1);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[0]].value.weight,
-                                        true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length - 1,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[weightSort.length - 1]].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 1,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[weightSort.length - 1]].value.weight,
-                                        true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.lowerBound(objectStoreData[weightSort[weightSort.length - 1]].value.weight + 1,
-                                        true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of index entries for lowerBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[weightSort[0]].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 1,
-         "Correct number of index entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[weightSort[0]].value.weight,
-                                        true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of index entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[weightSort[weightSort.length - 1]].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length,
-         "Correct number of index entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[weightSort[weightSort.length - 1]].value.weight,
-                                        true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length - 1,
-         "Correct number of index entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound(objectStoreData[weightSort[weightSort.length - 1]].value.weight,
-                                        true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length - 1,
-         "Correct number of index entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.upperBound("foo");
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length,
-         "Correct number of index entries for upperBound keyRange");
-
-      keyRange = IDBKeyRange.bound("foo", "foopy");
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, 0,
-         "Correct number of index entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[weightSort[0]].value.weight,
-                                   objectStoreData[weightSort[weightSort.length - 1]].value.weight);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length,
-         "Correct number of index entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[weightSort[0]].value.weight,
-                                   objectStoreData[weightSort[weightSort.length - 1]].value.weight,
-                                   true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length - 1,
-         "Correct number of index entries for bound keyRange");
-
-      keyRange = IDBKeyRange.bound(objectStoreData[weightSort[0]].value.weight,
-                                   objectStoreData[weightSort[weightSort.length - 1]].value.weight,
-                                   true, true);
-      index.count(keyRange).onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(event.target.result, weightSort.length - 2,
-         "Correct number of index entries for bound keyRange");
-
-      finishTest();
-      yield;
-    }
-  </script>
-  <script type="text/javascript;version=1.7" src="helpers.js"></script>
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
--- a/dom/indexedDB/test/test_object_identity.html
+++ b/dom/indexedDB/test/test_object_identity.html
@@ -26,17 +26,17 @@
 
       let index1 = objectStore1.createIndex("bar", "key");
       let index2 = objectStore2.index("bar");
       ok(index1 === index2, "Got same indexes");
 
       request.onsuccess = continueToNextStep;
       yield;
 
-      transaction = db.transaction(db.objectStoreNames);
+      transaction = db.transaction("foo");
 
       let objectStore3 = transaction.objectStore("foo");
       let objectStore4 = transaction.objectStore("foo");
       ok(objectStore3 === objectStore4, "Got same objectStores");
 
       ok(objectStore3 !== objectStore1, "Different objectStores");
       ok(objectStore4 !== objectStore2, "Different objectStores");
 
--- a/js/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/xpconnect/public/nsAutoJSValHolder.h
@@ -47,125 +47,118 @@
 /**
  * Simple class that looks and acts like a jsval except that it unroots
  * itself automatically if Root() is ever called. Designed to be rooted on the
  * context or runtime (but not both!).
  */
 class nsAutoJSValHolder
 {
 public:
-  nsAutoJSValHolder() : mVal(JSVAL_NULL), mRt(nsnull)
+
+  nsAutoJSValHolder()
+    : mRt(NULL)
+    , mVal(JSVAL_NULL)
+    , mHeld(JS_FALSE)
   {
     // nothing to do
   }
 
   /**
    * Always release on destruction.
    */
   virtual ~nsAutoJSValHolder() {
     Release();
   }
 
-  nsAutoJSValHolder(const nsAutoJSValHolder& aOther) {
-    *this = aOther;
-  }
-
-  nsAutoJSValHolder& operator=(const nsAutoJSValHolder& aOther) {
-    if (this != &aOther) {
-      if (aOther.IsHeld()) {
-        // XXX No error handling here...
-        this->Hold(aOther.mRt);
-      }
-      else {
-        this->Release();
-      }
-      *this = static_cast<jsval>(aOther);
-    }
-    return *this;
-  }
-
   /**
    * Hold by rooting on the context's runtime.
    */
-  bool Hold(JSContext* aCx) {
+  JSBool Hold(JSContext* aCx) {
     return Hold(JS_GetRuntime(aCx));
   }
 
   /**
    * Hold by rooting on the runtime.
    * Note that mVal may be JSVAL_NULL, which is not a problem.
    */
-  bool Hold(JSRuntime* aRt) {
-    // Do we really care about different runtimes?
-    if (mRt && aRt != mRt) {
-      js_RemoveRoot(mRt, &mVal);
-      mRt = nsnull;
+  JSBool Hold(JSRuntime* aRt) {
+    if (!mHeld) {
+      if (js_AddRootRT(aRt, &mVal, "nsAutoJSValHolder")) {
+        mRt = aRt;
+        mHeld = JS_TRUE;
+      } else {
+        Release(); // out of memory
+      }
     }
-
-    if (!mRt && js_AddRootRT(aRt, &mVal, "nsAutoJSValHolder")) {
-      mRt = aRt;
-    }
-
-    return !!mRt;
+    return mHeld;
   }
 
   /**
    * Manually release, nullifying mVal, and mRt, but returning
    * the original jsval.
    */
   jsval Release() {
+    NS_ASSERTION(!mHeld || mRt, "Bad!");
+
     jsval oldval = mVal;
 
-    if (mRt) {
+    if (mHeld) {
       js_RemoveRoot(mRt, &mVal); // infallible
-      mRt = nsnull;
+      mHeld = JS_FALSE;
     }
 
     mVal = JSVAL_NULL;
+    mRt = NULL;
 
     return oldval;
   }
 
   /**
    * Determine if Hold has been called.
    */
-  bool IsHeld() const {
-    return !!mRt;
+  JSBool IsHeld() {
+    return mHeld;
   }
 
   /**
    * Explicit JSObject* conversion.
    */
   JSObject* ToJSObject() const {
     return JSVAL_IS_OBJECT(mVal)
          ? JSVAL_TO_OBJECT(mVal)
-         : nsnull;
+         : NULL;
   }
 
   jsval* ToJSValPtr() {
     return &mVal;
   }
 
   /**
    * Pretend to be a jsval.
    */
   operator jsval() const { return mVal; }
 
   nsAutoJSValHolder &operator=(JSObject* aOther) {
+#ifdef DEBUG
+    if (aOther) {
+      NS_ASSERTION(mHeld, "Not rooted!");
+    }
+#endif
     return *this = OBJECT_TO_JSVAL(aOther);
   }
 
   nsAutoJSValHolder &operator=(jsval aOther) {
 #ifdef DEBUG
-    if (JSVAL_IS_GCTHING(aOther) && !JSVAL_IS_NULL(aOther)) {
-      NS_ASSERTION(IsHeld(), "Not rooted!");
+    if (JSVAL_IS_OBJECT(aOther) && JSVAL_TO_OBJECT(aOther)) {
+      NS_ASSERTION(mHeld, "Not rooted!");
     }
 #endif
     mVal = aOther;
     return *this;
   }
 
 private:
+  JSRuntime* mRt;
   jsval mVal;
-  JSRuntime* mRt;
+  JSBool mHeld;
 };
 
 #endif /* __NSAUTOJSVALHOLDER_H__ */