Bug 1392554 - Port (Async)StatementParams to WebIDL bindings. r=asuth,qdot
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 24 Aug 2017 10:52:52 +0200
changeset 426053 df5b4f5fe775d341647f85abcf9a0ca0aa573a67
parent 426050 82c496b0a12890a834582aaae46422d545c4ce35
child 426054 7288fbce6f160bf8c03b30116c97bb8011290933
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, qdot
bugs1392554
milestone57.0a1
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
Bug 1392554 - Port (Async)StatementParams to WebIDL bindings. r=asuth,qdot
dom/bindings/Bindings.conf
dom/webidl/MozStorageAsyncStatementParams.webidl
dom/webidl/MozStorageStatementParams.webidl
dom/webidl/moz.build
storage/moz.build
storage/mozIStorageStatementParams.idl
storage/mozStorageAsyncStatement.h
storage/mozStorageAsyncStatementJSHelper.cpp
storage/mozStorageAsyncStatementJSHelper.h
storage/mozStorageAsyncStatementParams.cpp
storage/mozStorageAsyncStatementParams.h
storage/mozStorageStatement.h
storage/mozStorageStatementJSHelper.cpp
storage/mozStorageStatementJSHelper.h
storage/mozStorageStatementParams.cpp
storage/mozStorageStatementParams.h
storage/test/unit/test_js_helpers.js
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -621,16 +621,26 @@ DOMInterfaces = {
 'MozWakeLock': {
     'nativeType': 'mozilla::dom::WakeLock',
 },
 
 'MozTimeManager': {
     'nativeType': 'mozilla::dom::time::TimeManager',
 },
 
+'MozStorageAsyncStatementParams': {
+    'headerFile': 'mozilla/storage/mozStorageAsyncStatementParams.h',
+    'nativeType': 'mozilla::storage::AsyncStatementParams',
+},
+
+'MozStorageStatementParams': {
+    'headerFile': 'mozilla/storage/mozStorageStatementParams.h',
+    'nativeType': 'mozilla::storage::StatementParams',
+},
+
 'MozStorageStatementRow': {
     'headerFile': 'mozilla/storage/mozStorageStatementRow.h',
     'nativeType': 'mozilla::storage::StatementRow',
 },
 
 'MutationObserver': {
     'nativeType': 'nsDOMMutationObserver',
 },
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozStorageAsyncStatementParams.webidl
@@ -0,0 +1,22 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+[ChromeOnly]
+interface MozStorageAsyncStatementParams
+{
+  readonly attribute unsigned long length;
+
+  [Throws]
+  getter any(unsigned long index);
+
+  [Throws]
+  getter any(DOMString name);
+
+  [Throws]
+  setter creator void(unsigned long index, any arg);
+
+  [Throws]
+  setter creator void(DOMString name, any arg);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozStorageStatementParams.webidl
@@ -0,0 +1,22 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+[ChromeOnly]
+interface MozStorageStatementParams
+{
+  readonly attribute unsigned long length;
+
+  [Throws]
+  getter any(unsigned long index);
+
+  [Throws]
+  getter any(DOMString name);
+
+  [Throws]
+  setter creator void(unsigned long index, any arg);
+
+  [Throws]
+  setter creator void(DOMString name, any arg);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -694,16 +694,18 @@ WEBIDL_FILES = [
     'MessageChannel.webidl',
     'MessageEvent.webidl',
     'MessagePort.webidl',
     'MimeType.webidl',
     'MimeTypeArray.webidl',
     'MouseEvent.webidl',
     'MouseScrollEvent.webidl',
     'MozSelfSupport.webidl',
+    'MozStorageAsyncStatementParams.webidl',
+    'MozStorageStatementParams.webidl',
     'MozStorageStatementRow.webidl',
     'MozTimeManager.webidl',
     'MozWakeLock.webidl',
     'MutationEvent.webidl',
     'MutationObserver.webidl',
     'NamedNodeMap.webidl',
     'NativeOSFileInternals.webidl',
     'NetDashboard.webidl',
--- a/storage/moz.build
+++ b/storage/moz.build
@@ -24,17 +24,16 @@ XPIDL_SOURCES += [
     'mozIStorageFunction.idl',
     'mozIStoragePendingStatement.idl',
     'mozIStorageProgressHandler.idl',
     'mozIStorageResultSet.idl',
     'mozIStorageRow.idl',
     'mozIStorageService.idl',
     'mozIStorageStatement.idl',
     'mozIStorageStatementCallback.idl',
-    'mozIStorageStatementParams.idl',
     'mozIStorageVacuumParticipant.idl',
     'mozIStorageValueArray.idl',
 ]
 
 XPIDL_MODULE = 'storage'
 
 EXPORTS += [
     'mozStorageHelper.h',
@@ -42,16 +41,18 @@ EXPORTS += [
 
 EXPORTS.mozilla += [
     'storage.h',
 ]
 
 # NOTE When adding something to this list, you probably need to add it to the
 #      storage.h file too.
 EXPORTS.mozilla.storage += [
+    'mozStorageAsyncStatementParams.h',
+    'mozStorageStatementParams.h',
     'mozStorageStatementRow.h',
     'StatementCache.h',
     'Variant.h',
     'Variant_inl.h',
 ]
 # SEE ABOVE NOTE!
 
 UNIFIED_SOURCES += [
deleted file mode 100644
--- a/storage/mozIStorageStatementParams.idl
+++ /dev/null
@@ -1,11 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-[scriptable, uuid(e65fe6e2-2643-463c-97e2-27665efe2386)]
-interface mozIStorageStatementParams : nsISupports {
-  // Magic interface for parameter setting that implements nsIXPCScriptable.
-};
--- a/storage/mozStorageAsyncStatement.h
+++ b/storage/mozStorageAsyncStatement.h
@@ -13,22 +13,21 @@
 #include "nsTArray.h"
 
 #include "mozStorageBindingParamsArray.h"
 #include "mozStorageStatementData.h"
 #include "mozIStorageAsyncStatement.h"
 #include "StorageBaseStatementInternal.h"
 #include "mozilla/Attributes.h"
 
-class nsIXPConnectJSObjectHolder;
-
 namespace mozilla {
 namespace storage {
 
 class AsyncStatementJSHelper;
+class AsyncStatementParamsHolder;
 class Connection;
 
 class AsyncStatement final : public mozIStorageAsyncStatement
                            , public StorageBaseStatementInternal
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZISTORAGEASYNCSTATEMENT
@@ -82,17 +81,17 @@ private:
    * Holds the array of parameters to bind to this statement when we execute
    * it asynchronously.
    */
   RefPtr<BindingParamsArray> mParamsArray;
 
   /**
    * Caches the JS 'params' helper for this statement.
    */
-  nsMainThreadPtrHandle<nsIXPConnectJSObjectHolder> mStatementParamsHolder;
+  nsMainThreadPtrHandle<AsyncStatementParamsHolder> mStatementParamsHolder;
 
   /**
    * Have we been explicitly finalized by the user?
    */
   bool mFinalized;
 
   /**
    * Required for access to private mStatementParamsHolder field by
--- a/storage/mozStorageAsyncStatementJSHelper.cpp
+++ b/storage/mozStorageAsyncStatementJSHelper.cpp
@@ -28,51 +28,50 @@ namespace storage {
 
 nsresult
 AsyncStatementJSHelper::getParams(AsyncStatement *aStatement,
                                   JSContext *aCtx,
                                   JSObject *aScopeObj,
                                   JS::Value *_params)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsresult rv;
 
 #ifdef DEBUG
   int32_t state;
   (void)aStatement->GetState(&state);
   NS_ASSERTION(state == mozIStorageAsyncStatement::MOZ_STORAGE_STATEMENT_READY,
                "Invalid state to get the params object - all calls will fail!");
 #endif
 
+  JS::RootedObject scope(aCtx, aScopeObj);
+
   if (!aStatement->mStatementParamsHolder) {
-    nsCOMPtr<mozIStorageStatementParams> params =
-      new AsyncStatementParams(aStatement);
+    dom::GlobalObject global(aCtx, scope);
+    if (global.Failed()) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
+
+    RefPtr<AsyncStatementParams> params(new AsyncStatementParams(window, aStatement));
     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);
 
-    JS::RootedObject scope(aCtx, aScopeObj);
-    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsCOMPtr<nsIXPConnect> xpc(Service::getXPConnect());
-    rv = xpc->WrapNativeHolder(
-      aCtx,
-      ::JS_GetGlobalForObject(aCtx, scope),
-      params,
-      NS_GET_IID(mozIStorageStatementParams),
-      getter_AddRefs(holder)
-    );
-    NS_ENSURE_SUCCESS(rv, rv);
-    RefPtr<AsyncStatementParamsHolder> paramsHolder =
-      new AsyncStatementParamsHolder(holder);
+    RefPtr<AsyncStatementParamsHolder> paramsHolder = new AsyncStatementParamsHolder(params);
+    NS_ENSURE_TRUE(paramsHolder, NS_ERROR_OUT_OF_MEMORY);
+
     aStatement->mStatementParamsHolder =
-      new nsMainThreadPtrHolder<nsIXPConnectJSObjectHolder>(
-        "AsyncStatement::mStatementParamsHolder", paramsHolder);
+      new nsMainThreadPtrHolder<AsyncStatementParamsHolder>(
+        "Statement::mStatementParamsHolder", paramsHolder);
   }
 
-  JS::Rooted<JSObject*> obj(aCtx);
-  obj = aStatement->mStatementParamsHolder->GetJSObject();
-  NS_ENSURE_STATE(obj);
+  RefPtr<AsyncStatementParams> params(aStatement->mStatementParamsHolder->Get());
+  JSObject* obj = params->WrapObject(aCtx, nullptr);
+  if (!obj) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
   _params->setObject(*obj);
   return NS_OK;
 }
 
 NS_IMETHODIMP_(MozExternalRefCountType) AsyncStatementJSHelper::AddRef() { return 2; }
 NS_IMETHODIMP_(MozExternalRefCountType) AsyncStatementJSHelper::Release() { return 1; }
 NS_INTERFACE_MAP_BEGIN(AsyncStatementJSHelper)
@@ -125,36 +124,20 @@ AsyncStatementJSHelper::Resolve(nsIXPCon
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncStatementParamsHolder
 
-NS_IMPL_ISUPPORTS(AsyncStatementParamsHolder, nsIXPConnectJSObjectHolder);
-
-JSObject*
-AsyncStatementParamsHolder::GetJSObject()
-{
-  return mHolder->GetJSObject();
-}
-
-AsyncStatementParamsHolder::AsyncStatementParamsHolder(nsIXPConnectJSObjectHolder* aHolder)
-  : mHolder(aHolder)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mHolder);
-}
+NS_IMPL_ISUPPORTS0(AsyncStatementParamsHolder);
 
 AsyncStatementParamsHolder::~AsyncStatementParamsHolder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   // We are considered dead at this point, so any wrappers for row or params
   // need to lose their reference to the statement.
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(mHolder);
-  nsCOMPtr<mozIStorageStatementParams> iObj = do_QueryWrappedNative(wrapper);
-  AsyncStatementParams *obj = static_cast<AsyncStatementParams *>(iObj.get());
-  obj->mStatement = nullptr;
+  mParams->mStatement = nullptr;
 }
 
 } // namespace storage
 } // namespace mozilla
--- a/storage/mozStorageAsyncStatementJSHelper.h
+++ b/storage/mozStorageAsyncStatementJSHelper.h
@@ -5,21 +5,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_storage_mozStorageAsyncStatementJSHelper_h_
 #define mozilla_storage_mozStorageAsyncStatementJSHelper_h_
 
 #include "nsIXPCScriptable.h"
 #include "nsIXPConnect.h"
 
-class AsyncStatement;
-
 namespace mozilla {
 namespace storage {
 
+class AsyncStatement;
+class AsyncStatementParams;
+
 /**
  * A modified version of StatementJSHelper that only exposes the async-specific
  * 'params' helper.  We do not expose 'row' or 'step' as they do not apply to
  * us.
  */
 class AsyncStatementJSHelper : public nsIXPCScriptable
 {
 public:
@@ -30,25 +31,32 @@ private:
   nsresult getParams(AsyncStatement *, JSContext *, JSObject *, JS::Value *);
 };
 
 /**
  * Wrapper used to clean up the references JS helpers hold to the statement.
  * For cycle-avoidance reasons they do not hold reference-counted references,
  * so it is important we do this.
  */
-class AsyncStatementParamsHolder final : public nsIXPConnectJSObjectHolder
-{
+class AsyncStatementParamsHolder final : public nsISupports {
 public:
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
 
-  explicit AsyncStatementParamsHolder(nsIXPConnectJSObjectHolder* aHolder);
+  explicit AsyncStatementParamsHolder(AsyncStatementParams* aParams)
+    : mParams(aParams)
+  {
+  }
+
+  AsyncStatementParams* Get() const {
+    MOZ_ASSERT(mParams);
+    return mParams;
+  }
 
 private:
   virtual ~AsyncStatementParamsHolder();
-  nsCOMPtr<nsIXPConnectJSObjectHolder> mHolder;
+
+  RefPtr<AsyncStatementParams> mParams;
 };
 
 } // namespace storage
 } // namespace mozilla
 
 #endif // mozilla_storage_mozStorageAsyncStatementJSHelper_h_
--- a/storage/mozStorageAsyncStatementParams.cpp
+++ b/storage/mozStorageAsyncStatementParams.cpp
@@ -1,131 +1,128 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "nsJSUtils.h"
 #include "nsMemory.h"
 #include "nsString.h"
-#include "nsCOMPtr.h"
-#include "nsJSUtils.h"
 
 #include "jsapi.h"
 
+#include "mozilla/dom/MozStorageAsyncStatementParamsBinding.h"
 #include "mozStoragePrivateHelpers.h"
-#include "mozStorageAsyncStatement.h"
-#include "mozStorageAsyncStatementParams.h"
-#include "mozIStorageStatement.h"
-
-#include "xpc_make_class.h"
 
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncStatementParams
 
-AsyncStatementParams::AsyncStatementParams(AsyncStatement *aStatement)
-: mStatement(aStatement)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AsyncStatementParams, mWindow)
+
+NS_INTERFACE_TABLE_HEAD(AsyncStatementParams)
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
+  NS_INTERFACE_TABLE(AsyncStatementParams, nsISupports)
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(AsyncStatementParams)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncStatementParams)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncStatementParams)
+
+AsyncStatementParams::AsyncStatementParams(nsPIDOMWindowInner* aWindow, AsyncStatement *aStatement)
+: mWindow(aWindow),
+  mStatement(aStatement)
 {
   NS_ASSERTION(mStatement != nullptr, "mStatement is null");
 }
 
-NS_IMPL_ISUPPORTS(
-  AsyncStatementParams
-, mozIStorageStatementParams
-, nsIXPCScriptable
-)
-
-////////////////////////////////////////////////////////////////////////////////
-//// nsIXPCScriptable
+JSObject*
+AsyncStatementParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return dom::MozStorageAsyncStatementParamsBinding::Wrap(aCx, this, aGivenProto);
+}
 
-#define XPC_MAP_CLASSNAME         AsyncStatementParams
-#define XPC_MAP_QUOTED_CLASSNAME "AsyncStatementParams"
-#define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_SETPROPERTY | \
-                       XPC_SCRIPTABLE_WANT_RESOLVE | \
-                       XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
-#include "xpc_map_end.h"
-
-NS_IMETHODIMP
-AsyncStatementParams::SetProperty(
-  nsIXPConnectWrappedNative *aWrapper,
-  JSContext *aCtx,
-  JSObject *aScopeObj,
-  jsid aId,
-  JS::Value *_vp,
-  bool *_retval
-)
+void
+AsyncStatementParams::NamedGetter(JSContext* aCx,
+                                  const nsAString& aName,
+                                  bool& aFound,
+                                  JS::MutableHandle<JS::Value> aResult,
+                                  mozilla::ErrorResult& aRv)
 {
-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
-
-  if (JSID_IS_INT(aId)) {
-    int idx = JSID_TO_INT(aId);
-
-    nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
-    NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
-    nsresult rv = mStatement->BindByIndex(idx, variant);
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
   }
-  else if (JSID_IS_STRING(aId)) {
-    JSString *str = JSID_TO_STRING(aId);
-    nsAutoJSString autoStr;
-    if (!autoStr.init(aCtx, str)) {
-      return NS_ERROR_FAILURE;
-    }
+
+  // Unfortunately there's no API that lets us return the parameter value.
+  aFound = false;
+}
 
-    NS_ConvertUTF16toUTF8 name(autoStr);
+void
+AsyncStatementParams::NamedSetter(JSContext* aCx,
+                                  const nsAString& aName,
+                                  JS::Handle<JS::Value> aValue,
+                                  mozilla::ErrorResult& aRv)
+{
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
+  }
 
-    nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
-    NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
-    nsresult rv = mStatement->BindByName(name, variant);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    return NS_ERROR_INVALID_ARG;
+  NS_ConvertUTF16toUTF8 name(aName);
+
+  nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCx, aValue));
+  if (!variant) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
   }
 
-  *_retval = true;
-  return NS_OK;
+  aRv = mStatement->BindByName(name, variant);
+}
+
+void
+AsyncStatementParams::GetSupportedNames(nsTArray<nsString>& aNames)
+{
+  // We don't know how many params there are, so we can't implement this for
+  // AsyncStatementParams.
 }
 
-NS_IMETHODIMP
-AsyncStatementParams::Resolve(nsIXPConnectWrappedNative *aWrapper,
-                              JSContext *aCtx,
-                              JSObject *aScopeObj,
-                              jsid aId,
-                              bool *aResolvedp,
-                              bool *_retval)
+void
+AsyncStatementParams::IndexedGetter(JSContext* aCx,
+                                    uint32_t aIndex,
+                                    bool& aFound,
+                                    JS::MutableHandle<JS::Value> aResult,
+                                    mozilla::ErrorResult& aRv)
 {
-  JS::Rooted<JSObject*> scopeObj(aCtx, aScopeObj);
-
-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
-  // We do not throw at any point after this because we want to allow the
-  // prototype chain to be checked for the property.
-
-  bool resolved = false;
-  bool ok = true;
-  if (JSID_IS_INT(aId)) {
-    uint32_t idx = JSID_TO_INT(aId);
-    // All indexes are good because we don't know how many parameters there
-    // really are.
-    ok = ::JS_DefineElement(aCtx, scopeObj, idx, JS::UndefinedHandleValue,
-                            JSPROP_RESOLVING);
-    resolved = true;
-  }
-  else if (JSID_IS_STRING(aId)) {
-    // We are unable to tell if there's a parameter with this name and so
-    // we must assume that there is.  This screws the rest of the prototype
-    // chain, but people really shouldn't be depending on this anyways.
-    JS::Rooted<jsid> id(aCtx, aId);
-    ok = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue,
-                                 JSPROP_RESOLVING);
-    resolved = true;
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
   }
 
-  *_retval = ok;
-  *aResolvedp = resolved && ok;
-  return NS_OK;
+  // Unfortunately there's no API that lets us return the parameter value.
+  aFound = false;
+}
+
+void
+AsyncStatementParams::IndexedSetter(JSContext* aCx,
+                                    uint32_t aIndex,
+                                    JS::Handle<JS::Value> aValue,
+                                    mozilla::ErrorResult& aRv)
+{
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
+  }
+
+  nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCx, aValue));
+  if (!variant) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  aRv = mStatement->BindByIndex(aIndex, variant);
 }
 
 } // namespace storage
 } // namespace mozilla
--- a/storage/mozStorageAsyncStatementParams.h
+++ b/storage/mozStorageAsyncStatementParams.h
@@ -2,44 +2,78 @@
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_storage_mozStorageAsyncStatementParams_h_
 #define mozilla_storage_mozStorageAsyncStatementParams_h_
 
-#include "mozIStorageStatementParams.h"
-#include "nsIXPCScriptable.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "nsPIDOMWindow.h"
+#include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace storage {
 
 class AsyncStatement;
 
-/*
- * Since mozIStorageStatementParams is just a tagging interface we do not have
- * an async variant.
- */
-class AsyncStatementParams final : public mozIStorageStatementParams
-                                 , public nsIXPCScriptable
+class AsyncStatementParams final : public nsISupports
+                                 , public nsWrapperCache
 {
 public:
-  explicit AsyncStatementParams(AsyncStatement *aStatement);
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AsyncStatementParams)
+
+  explicit AsyncStatementParams(nsPIDOMWindowInner* aWindow, AsyncStatement* aStatement);
+
+  void NamedGetter(JSContext* aCx,
+                   const nsAString& aName,
+                   bool& aFound,
+                   JS::MutableHandle<JS::Value> aResult,
+                   mozilla::ErrorResult& aRv);
+
+  void NamedSetter(JSContext* aCx,
+                   const nsAString& aName,
+                   JS::Handle<JS::Value> aValue,
+                   mozilla::ErrorResult& aRv);
 
-  // interfaces
-  NS_DECL_ISUPPORTS
-  NS_DECL_MOZISTORAGESTATEMENTPARAMS
-  NS_DECL_NSIXPCSCRIPTABLE
+  uint32_t Length() const {
+    // WebIDL requires a .length property when there's an indexed getter.
+    // Unfortunately we don't know how many params there are in the async case,
+    // so we have to lie.
+    return UINT16_MAX;
+  }
+
+  void IndexedGetter(JSContext* aCx,
+                     uint32_t aIndex,
+                     bool& aFound,
+                     JS::MutableHandle<JS::Value> aResult,
+                     mozilla::ErrorResult& aRv);
 
-protected:
+  void IndexedSetter(JSContext* aCx,
+                     uint32_t aIndex,
+                     JS::Handle<JS::Value> aValue,
+                     mozilla::ErrorResult& aRv);
+
+  void GetSupportedNames(nsTArray<nsString>& aNames);
+
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  nsPIDOMWindowInner* GetParentObject() const
+  {
+    return mWindow;
+  }
+
+private:
   virtual ~AsyncStatementParams() {}
 
-  AsyncStatement *mStatement;
+  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  AsyncStatement* mStatement;
 
   friend class AsyncStatementParamsHolder;
 };
 
 } // namespace storage
 } // namespace mozilla
 
 #endif // mozilla_storage_mozStorageAsyncStatementParams_h_
--- a/storage/mozStorageStatement.h
+++ b/storage/mozStorageStatement.h
@@ -21,16 +21,17 @@
 
 class nsIXPConnectJSObjectHolder;
 struct sqlite3_stmt;
 
 namespace mozilla {
 namespace storage {
 class StatementJSHelper;
 class Connection;
+class StatementParamsHolder;
 class StatementRowHolder;
 
 class Statement final : public mozIStorageStatement
                       , public mozIStorageValueArray
                       , public StorageBaseStatementInternal
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
@@ -92,17 +93,17 @@ private:
      * it asynchronously.
      */
     RefPtr<BindingParamsArray> mParamsArray;
 
     /**
      * The following two members are only used with the JS helper.  They cache
      * the row and params objects.
      */
-    nsMainThreadPtrHandle<nsIXPConnectJSObjectHolder> mStatementParamsHolder;
+    nsMainThreadPtrHandle<StatementParamsHolder> mStatementParamsHolder;
     nsMainThreadPtrHandle<StatementRowHolder> mStatementRowHolder;
 
   /**
    * Internal version of finalize that allows us to tell it if it is being
    * called from the destructor so it can know not to dispatch events that
    * require a reference to us.
    *
    * @param aDestructing
--- a/storage/mozStorageStatementJSHelper.cpp
+++ b/storage/mozStorageStatementJSHelper.cpp
@@ -128,51 +128,50 @@ StatementJSHelper::getRow(Statement *aSt
 
 nsresult
 StatementJSHelper::getParams(Statement *aStatement,
                              JSContext *aCtx,
                              JSObject *aScopeObj,
                              JS::Value *_params)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsresult rv;
 
 #ifdef DEBUG
   int32_t state;
   (void)aStatement->GetState(&state);
   NS_ASSERTION(state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_READY,
                "Invalid state to get the params object - all calls will fail!");
 #endif
 
+  JS::RootedObject scope(aCtx, aScopeObj);
+
   if (!aStatement->mStatementParamsHolder) {
-    JS::RootedObject scope(aCtx, aScopeObj);
-    nsCOMPtr<mozIStorageStatementParams> params =
-      new StatementParams(aStatement);
+    dom::GlobalObject global(aCtx, scope);
+    if (global.Failed()) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
+
+    RefPtr<StatementParams> params(new StatementParams(window, aStatement));
     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);
 
-    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsCOMPtr<nsIXPConnect> xpc(Service::getXPConnect());
-    rv = xpc->WrapNativeHolder(
-      aCtx,
-      ::JS_GetGlobalForObject(aCtx, scope),
-      params,
-      NS_GET_IID(mozIStorageStatementParams),
-      getter_AddRefs(holder)
-    );
-    NS_ENSURE_SUCCESS(rv, rv);
-    RefPtr<StatementParamsHolder> paramsHolder =
-      new StatementParamsHolder(holder);
+    RefPtr<StatementParamsHolder> paramsHolder = new StatementParamsHolder(params);
+    NS_ENSURE_TRUE(paramsHolder, NS_ERROR_OUT_OF_MEMORY);
+
     aStatement->mStatementParamsHolder =
-      new nsMainThreadPtrHolder<nsIXPConnectJSObjectHolder>(
+      new nsMainThreadPtrHolder<StatementParamsHolder>(
         "Statement::mStatementParamsHolder", paramsHolder);
   }
 
-  JS::Rooted<JSObject*> obj(aCtx);
-  obj = aStatement->mStatementParamsHolder->GetJSObject();
-  NS_ENSURE_STATE(obj);
+  RefPtr<StatementParams> params(aStatement->mStatementParamsHolder->Get());
+  JSObject* obj = params->WrapObject(aCtx, nullptr);
+  if (!obj) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
   _params->setObject(*obj);
   return NS_OK;
 }
 
 NS_IMETHODIMP_(MozExternalRefCountType) StatementJSHelper::AddRef() { return 2; }
 NS_IMETHODIMP_(MozExternalRefCountType) StatementJSHelper::Release() { return 1; }
 NS_INTERFACE_MAP_BEGIN(StatementJSHelper)
@@ -237,43 +236,24 @@ StatementJSHelper::Resolve(nsIXPConnectW
     *_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING);
     *aResolvedp = true;
     return NS_OK;
   }
 
   return NS_OK;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-//// StatementJSObjectHolder
-
-NS_IMPL_ISUPPORTS(StatementJSObjectHolder, nsIXPConnectJSObjectHolder);
-
-JSObject*
-StatementJSObjectHolder::GetJSObject()
-{
-  return mHolder->GetJSObject();
-}
-
-StatementJSObjectHolder::StatementJSObjectHolder(nsIXPConnectJSObjectHolder* aHolder)
-  : mHolder(aHolder)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mHolder);
-}
+NS_IMPL_ISUPPORTS0(StatementParamsHolder);
 
 StatementParamsHolder::~StatementParamsHolder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   // We are considered dead at this point, so any wrappers for row or params
   // need to lose their reference to the statement.
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(mHolder);
-  nsCOMPtr<mozIStorageStatementParams> iObj = do_QueryWrappedNative(wrapper);
-  StatementParams *obj = static_cast<StatementParams *>(iObj.get());
-  obj->mStatement = nullptr;
+  mParams->mStatement = nullptr;
 }
 
 NS_IMPL_ISUPPORTS0(StatementRowHolder);
 
 StatementRowHolder::~StatementRowHolder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   // We are considered dead at this point, so any wrappers for row or params
--- a/storage/mozStorageStatementJSHelper.h
+++ b/storage/mozStorageStatementJSHelper.h
@@ -10,16 +10,17 @@
 #include "nsIXPCScriptable.h"
 #include "nsIXPConnect.h"
 
 class Statement;
 
 namespace mozilla {
 namespace storage {
 
+class StatementParams;
 class StatementRow;
 
 class StatementJSHelper : public nsIXPCScriptable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIXPCSCRIPTABLE
 
@@ -28,37 +29,35 @@ private:
   nsresult getParams(Statement *, JSContext *, JSObject *, JS::Value *);
 };
 
 /**
  * Wrappers used to clean up the references JS helpers hold to the statement.
  * For cycle-avoidance reasons they do not hold reference-counted references,
  * so it is important we do this.
  */
-class StatementJSObjectHolder : public nsIXPConnectJSObjectHolder
-{
+
+class StatementParamsHolder final: public nsISupports {
 public:
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
-
-  explicit StatementJSObjectHolder(nsIXPConnectJSObjectHolder* aHolder);
 
-protected:
-  virtual ~StatementJSObjectHolder() {};
-  nsCOMPtr<nsIXPConnectJSObjectHolder> mHolder;
-};
+  explicit StatementParamsHolder(StatementParams* aParams)
+    : mParams(aParams)
+  {
+  }
 
-class StatementParamsHolder final: public StatementJSObjectHolder {
-public:
-  explicit StatementParamsHolder(nsIXPConnectJSObjectHolder* aHolder)
-    : StatementJSObjectHolder(aHolder) {
+  StatementParams* Get() const {
+    MOZ_ASSERT(mParams);
+    return mParams;
   }
 
 private:
   virtual ~StatementParamsHolder();
+
+  RefPtr<StatementParams> mParams;
 };
 
 class StatementRowHolder final: public nsISupports {
 public:
   NS_DECL_ISUPPORTS
 
   explicit StatementRowHolder(StatementRow* aRow)
     : mRow(aRow)
--- a/storage/mozStorageStatementParams.cpp
+++ b/storage/mozStorageStatementParams.cpp
@@ -5,178 +5,141 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsJSUtils.h"
 #include "nsMemory.h"
 #include "nsString.h"
 
 #include "jsapi.h"
 
+#include "mozilla/dom/MozStorageStatementParamsBinding.h"
 #include "mozStoragePrivateHelpers.h"
-#include "mozStorageStatementParams.h"
-#include "mozIStorageStatement.h"
 
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// StatementParams
 
-StatementParams::StatementParams(mozIStorageStatement *aStatement) :
-    mStatement(aStatement),
-    mParamCount(0)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StatementParams, mWindow)
+
+NS_INTERFACE_TABLE_HEAD(StatementParams)
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
+  NS_INTERFACE_TABLE(StatementParams, nsISupports)
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(StatementParams)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(StatementParams)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(StatementParams)
+
+StatementParams::StatementParams(nsPIDOMWindowInner* aWindow, Statement *aStatement)
+: mWindow(aWindow),
+  mStatement(aStatement),
+  mParamCount(0)
 {
   NS_ASSERTION(mStatement != nullptr, "mStatement is null");
   (void)mStatement->GetParameterCount(&mParamCount);
 }
 
-NS_IMPL_ISUPPORTS(
-  StatementParams,
-  mozIStorageStatementParams,
-  nsIXPCScriptable
-)
-
-////////////////////////////////////////////////////////////////////////////////
-//// nsIXPCScriptable
-
-#define XPC_MAP_CLASSNAME         StatementParams
-#define XPC_MAP_QUOTED_CLASSNAME "StatementParams"
-#define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_SETPROPERTY | \
-                       XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
-                       XPC_SCRIPTABLE_WANT_RESOLVE | \
-                       XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
-#include "xpc_map_end.h"
-
-NS_IMETHODIMP
-StatementParams::SetProperty(nsIXPConnectWrappedNative *aWrapper,
-                             JSContext *aCtx,
-                             JSObject *aScopeObj,
-                             jsid aId,
-                             JS::Value *_vp,
-                             bool *_retval)
+JSObject*
+StatementParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
-
-  if (JSID_IS_INT(aId)) {
-    int idx = JSID_TO_INT(aId);
+  return dom::MozStorageStatementParamsBinding::Wrap(aCx, this, aGivenProto);
+}
 
-    nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
-    NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
-    nsresult rv = mStatement->BindByIndex(idx, variant);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else if (JSID_IS_STRING(aId)) {
-    JSString *str = JSID_TO_STRING(aId);
-    nsAutoJSString autoStr;
-    if (!autoStr.init(aCtx, str)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    NS_ConvertUTF16toUTF8 name(autoStr);
-
-    // check to see if there's a parameter with this name
-    nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp));
-    NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED);
-    nsresult rv = mStatement->BindByName(name, variant);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    return NS_ERROR_INVALID_ARG;
+void
+StatementParams::NamedGetter(JSContext* aCx,
+                             const nsAString& aName,
+                             bool& aFound,
+                             JS::MutableHandle<JS::Value> aResult,
+                             mozilla::ErrorResult& aRv)
+{
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
   }
 
-  *_retval = true;
-  return NS_OK;
+  // Unfortunately there's no API that lets us return the parameter value.
+  aFound = false;
 }
 
-NS_IMETHODIMP
-StatementParams::NewEnumerate(nsIXPConnectWrappedNative *aWrapper,
-                              JSContext *aCtx,
-                              JSObject *aScopeObj,
-                              JS::AutoIdVector &aProperties,
-                              bool *_retval)
+void
+StatementParams::NamedSetter(JSContext* aCx,
+                             const nsAString& aName,
+                             JS::Handle<JS::Value> aValue,
+                             mozilla::ErrorResult& aRv)
 {
-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
-  JS::RootedObject scope(aCtx, aScopeObj);
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
+  }
+
+  NS_ConvertUTF16toUTF8 name(aName);
 
-  if (!aProperties.reserve(mParamCount)) {
-    *_retval = false;
-    return NS_OK;
+  // Check to see if there's a parameter with this name.
+  nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCx, aValue));
+  if (!variant) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  aRv = mStatement->BindByName(name, variant);
+}
+
+void
+StatementParams::GetSupportedNames(nsTArray<nsString>& aNames)
+{
+  if (!mStatement) {
+    return;
   }
 
   for (uint32_t i = 0; i < mParamCount; i++) {
     // Get the name of our parameter.
     nsAutoCString name;
     nsresult rv = mStatement->GetParameterName(i, name);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
 
     // But drop the first character, which is going to be a ':'.
-    JS::RootedString jsname(aCtx, ::JS_NewStringCopyN(aCtx, &(name.get()[1]),
-                                                      name.Length() - 1));
-    NS_ENSURE_TRUE(jsname, NS_ERROR_OUT_OF_MEMORY);
-
-    // Set our name.
-    JS::Rooted<jsid> id(aCtx);
-    if (!::JS_StringToId(aCtx, jsname, &id)) {
-      *_retval = false;
-      return NS_OK;
-    }
-
-    aProperties.infallibleAppend(id);
+    name = Substring(name, 1);
+    aNames.AppendElement(NS_ConvertUTF8toUTF16(name));
   }
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-StatementParams::Resolve(nsIXPConnectWrappedNative *aWrapper,
-                         JSContext *aCtx,
-                         JSObject *aScopeObj,
-                         jsid aId,
-                         bool *resolvedp,
-                         bool *_retval)
+void
+StatementParams::IndexedGetter(JSContext* aCx,
+                               uint32_t aIndex,
+                               bool& aFound,
+                               JS::MutableHandle<JS::Value> aResult,
+                               mozilla::ErrorResult& aRv)
 {
-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
-  // We do not throw at any point after this unless our index is out of range
-  // because we want to allow the prototype chain to be checked for the
-  // property.
-
-  JS::RootedObject scope(aCtx, aScopeObj);
-  JS::RootedId id(aCtx, aId);
-  bool resolved = false;
-  bool ok = true;
-  if (JSID_IS_INT(id)) {
-    uint32_t idx = JSID_TO_INT(id);
-
-    // Ensure that our index is within range.  We do not care about the
-    // prototype chain being checked here.
-    if (idx >= mParamCount)
-      return NS_ERROR_INVALID_ARG;
-
-    ok = ::JS_DefineElement(aCtx, scope, idx, JS::UndefinedHandleValue,
-                            JSPROP_ENUMERATE | JSPROP_RESOLVING);
-    resolved = true;
-  }
-  else if (JSID_IS_STRING(id)) {
-    JSString *str = JSID_TO_STRING(id);
-    nsAutoJSString autoStr;
-    if (!autoStr.init(aCtx, str)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    // Check to see if there's a parameter with this name, and if not, let
-    // the rest of the prototype chain be checked.
-    NS_ConvertUTF16toUTF8 name(autoStr);
-    uint32_t idx;
-    nsresult rv = mStatement->GetParameterIndex(name, &idx);
-    if (NS_SUCCEEDED(rv)) {
-      ok = ::JS_DefinePropertyById(aCtx, scope, id, JS::UndefinedHandleValue,
-                                   JSPROP_ENUMERATE | JSPROP_RESOLVING);
-      resolved = true;
-    }
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
   }
 
-  *_retval = ok;
-  *resolvedp = resolved && ok;
-  return NS_OK;
+  // Unfortunately there's no API that lets us return the parameter value.
+  aFound = false;
+}
+
+void
+StatementParams::IndexedSetter(JSContext* aCx,
+                               uint32_t aIndex,
+                               JS::Handle<JS::Value> aValue,
+                               mozilla::ErrorResult& aRv)
+{
+  if (!mStatement) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
+  }
+
+  nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCx, aValue));
+  if (!variant) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  aRv = mStatement->BindByIndex(aIndex, variant);
 }
 
 } // namespace storage
 } // namespace mozilla
--- a/storage/mozStorageStatementParams.h
+++ b/storage/mozStorageStatementParams.h
@@ -2,42 +2,76 @@
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZSTORAGESTATEMENTPARAMS_H
 #define MOZSTORAGESTATEMENTPARAMS_H
 
-#include "mozIStorageStatementParams.h"
-#include "nsIXPCScriptable.h"
 #include "mozilla/Attributes.h"
-
-class mozIStorageStatement;
+#include "mozilla/ErrorResult.h"
+#include "nsPIDOMWindow.h"
+#include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace storage {
 
-class StatementParams final : public mozIStorageStatementParams
-                            , public nsIXPCScriptable
+class Statement;
+
+class StatementParams final : public nsISupports
+                            , public nsWrapperCache
 {
 public:
-  explicit StatementParams(mozIStorageStatement *aStatement);
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StatementParams)
+
+  explicit StatementParams(nsPIDOMWindowInner* aWindow, Statement* aStatement);
+
+  void NamedGetter(JSContext* aCx,
+                   const nsAString& aName,
+                   bool& aFound,
+                   JS::MutableHandle<JS::Value> aResult,
+                   mozilla::ErrorResult& aRv);
+
+  void NamedSetter(JSContext* aCx,
+                   const nsAString& aName,
+                   JS::Handle<JS::Value> aValue,
+                   mozilla::ErrorResult& aRv);
+
+  uint32_t Length() const {
+    return mParamCount;
+  }
 
-  // interfaces
-  NS_DECL_ISUPPORTS
-  NS_DECL_MOZISTORAGESTATEMENTPARAMS
-  NS_DECL_NSIXPCSCRIPTABLE
+  void IndexedGetter(JSContext* aCx,
+                     uint32_t aIndex,
+                     bool& aFound,
+                     JS::MutableHandle<JS::Value> aResult,
+                     mozilla::ErrorResult& aRv);
+
+  void IndexedSetter(JSContext* aCx,
+                     uint32_t aIndex,
+                     JS::Handle<JS::Value> aValue,
+                     mozilla::ErrorResult& aRv);
 
-protected:
+  void GetSupportedNames(nsTArray<nsString>& aNames);
+
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  nsPIDOMWindowInner* GetParentObject() const
+  {
+    return mWindow;
+  }
+
+private:
   ~StatementParams() {}
 
-  mozIStorageStatement *mStatement;
+  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  Statement* mStatement;
   uint32_t mParamCount;
 
   friend class StatementParamsHolder;
-  friend class StatementRowHolder;
 };
 
 } // namespace storage
 } // namespace mozilla
 
 #endif /* MOZSTORAGESTATEMENTPARAMS_H */
--- a/storage/test/unit/test_js_helpers.js
+++ b/storage/test/unit/test_js_helpers.js
@@ -12,24 +12,24 @@
 // Test Functions
 
 function test_params_enumerate() {
   let stmt = createStatement(
     "SELECT * FROM test WHERE id IN (:a, :b, :c)"
   );
 
   // Make sure they are right.
-  let expected = ["a", "b", "c"];
+  let expected = [0, 1, 2, "a", "b", "c", "length"];
   let index = 0;
   for (let name in stmt.params) {
     if (name == "QueryInterface")
       continue;
     do_check_eq(name, expected[index++]);
   }
-  do_check_eq(index, 3);
+  do_check_eq(index, 7);
 }
 
 function test_params_prototype() {
   let stmt = createStatement(
     "SELECT * FROM sqlite_master"
   );
 
   // Set a property on the prototype and make sure it exist (will not be a