Bug 949325 - C++ wrapper to support DataStore API on the worker (part 1, C++ stubs for DataStore and DataStoreCursor). r=baku,ehsan
authorGene Lian <clian@mozilla.com>
Fri, 20 Dec 2013 16:17:49 +0800
changeset 191037 6f7f23f8828d64853e51e0fd53ee615eb505fdc8
parent 191036 85324eec2367adc5448add8a4f3893523564784f
child 191038 80fb95ebee38fb31cfa3af186cd3e46576eff2ed
push id5832
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:43:22 +0000
treeherdermozilla-aurora@4974d9da2f7d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, ehsan
bugs949325
milestone31.0a1
Bug 949325 - C++ wrapper to support DataStore API on the worker (part 1, C++ stubs for DataStore and DataStoreCursor). r=baku,ehsan
dom/bindings/Bindings.conf
dom/datastore/DataStore.cpp
dom/datastore/DataStore.h
dom/datastore/DataStore.jsm
dom/datastore/DataStoreCursor.cpp
dom/datastore/DataStoreCursor.h
dom/datastore/DataStoreCursor.jsm
dom/datastore/DataStoreCursorImpl.jsm
dom/datastore/DataStoreImpl.jsm
dom/datastore/DataStoreService.js
dom/datastore/moz.build
dom/webidl/DataStore.webidl
dom/webidl/DataStoreImpl.webidl
dom/webidl/moz.build
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -283,16 +283,20 @@ DOMInterfaces = {
 'CSSValueList': {
     'nativeType': 'nsDOMCSSValueList'
 },
 
 'DataChannel': {
     'nativeType': 'nsDOMDataChannel',
 },
 
+'DataStoreCursor': {
+    'wrapperCache': False,
+},
+
 'DedicatedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'workers': True,
 },
 
 'DelayNode': {
     'resultNotAddRefed': [ 'delayTime' ],
 },
new file mode 100644
--- /dev/null
+++ b/dom/datastore/DataStore.cpp
@@ -0,0 +1,188 @@
+/* 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 "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreCursor.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/DataStoreImplBinding.h"
+#include "mozilla/dom/Navigator.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/Preferences.h"
+#include "AccessCheck.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_ADDREF_INHERITED(DataStore, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(DataStore, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DataStore)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_CYCLE_COLLECTION_1(DataStore, mStore)
+
+DataStore::DataStore(nsPIDOMWindow* aWindow)
+  : DOMEventTargetHelper(aWindow)
+{
+}
+
+already_AddRefed<DataStore>
+DataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!window) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DataStore> store = new DataStore(window);
+  return store.forget();
+}
+
+JSObject*
+DataStore::WrapObject(JSContext* aCx)
+{
+  return DataStoreBinding::Wrap(aCx, this);
+}
+
+/*static*/ bool
+DataStore::EnabledForScope(JSContext* aCx, JS::Handle<JSObject*> aObj)
+{
+  // Only expose the interface when it is:
+  // 1. enabled by the preference and
+  // 2. accessed by the chrome codes in Gecko.
+  return (Navigator::HasDataStoreSupport(aCx, aObj) &&
+          nsContentUtils::ThreadsafeIsCallerChrome());
+}
+
+void
+DataStore::GetName(nsAString& aName, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  nsAutoString name;
+  mStore->GetName(name, aRv);
+  aName.Assign(name);
+}
+
+void
+DataStore::GetOwner(nsAString& aOwner, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  nsAutoString owner;
+  mStore->GetOwner(owner, aRv);
+  aOwner.Assign(owner);
+}
+
+bool
+DataStore::GetReadOnly(ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->GetReadOnly(aRv);
+}
+
+already_AddRefed<Promise>
+DataStore::Get(const Sequence<OwningStringOrUnsignedLong>& aId,
+               ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->Get(aId, aRv);
+}
+
+already_AddRefed<Promise>
+DataStore::Put(JSContext* aCx,
+               JS::Handle<JS::Value> aObj,
+               const StringOrUnsignedLong& aId,
+               const nsAString& aRevisionId,
+               ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->Put(aObj, aId, aRevisionId, aRv);
+}
+
+already_AddRefed<Promise>
+DataStore::Add(JSContext* aCx,
+               JS::Handle<JS::Value> aObj,
+               const Optional<StringOrUnsignedLong>& aId,
+               const nsAString& aRevisionId,
+               ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->Add(aObj, aId, aRevisionId, aRv);
+}
+
+already_AddRefed<Promise>
+DataStore::Remove(const StringOrUnsignedLong& aId,
+                  const nsAString& aRevisionId,
+                  ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->Remove(aId, aRevisionId, aRv);
+}
+
+already_AddRefed<Promise>
+DataStore::Clear(const nsAString& aRevisionId, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->Clear(aRevisionId, aRv);
+}
+
+void
+DataStore::GetRevisionId(nsAString& aRevisionId, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  nsAutoString revisionId;
+  mStore->GetRevisionId(revisionId, aRv);
+  aRevisionId.Assign(revisionId);
+}
+
+already_AddRefed<Promise>
+DataStore::GetLength(ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->GetLength(aRv);
+}
+
+already_AddRefed<DataStoreCursor>
+DataStore::Sync(const nsAString& aRevisionId, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStore);
+
+  return mStore->Sync(aRevisionId, aRv);
+}
+
+void
+DataStore::SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mStore);
+
+  mStore = &aStore;
+  mStore->SetEventTarget(*this, aRv);
+}
+
+} //namespace dom
+} //namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/datastore/DataStore.h
@@ -0,0 +1,95 @@
+/* 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_dom_DataStore_h
+#define mozilla_dom_DataStore_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class Promise;
+class DataStoreCursor;
+class DataStoreImpl;
+class StringOrUnsignedLong;
+class OwningStringOrUnsignedLong;
+
+class DataStore MOZ_FINAL : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DataStore,
+                                           DOMEventTargetHelper)
+
+  explicit DataStore(nsPIDOMWindow* aWindow);
+
+  // WebIDL (internal functions)
+
+  static already_AddRefed<DataStore> Constructor(GlobalObject& aGlobal,
+                                                 ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
+
+  static bool EnabledForScope(JSContext* aCx, JS::Handle<JSObject*> aObj);
+
+  // WebIDL (public APIs)
+
+  void GetName(nsAString& aName, ErrorResult& aRv);
+
+  void GetOwner(nsAString& aOwner, ErrorResult& aRv);
+
+  bool GetReadOnly(ErrorResult& aRv);
+
+  already_AddRefed<Promise> Get(const Sequence<OwningStringOrUnsignedLong>& aId,
+                                ErrorResult& aRv);
+
+  already_AddRefed<Promise> Put(JSContext* aCx,
+                                JS::Handle<JS::Value> aObj,
+                                const StringOrUnsignedLong& aId,
+                                const nsAString& aRevisionId,
+                                ErrorResult& aRv);
+
+  already_AddRefed<Promise> Add(JSContext* aCx,
+                                JS::Handle<JS::Value> aObj,
+                                const Optional<StringOrUnsignedLong>& aId,
+                                const nsAString& aRevisionId,
+                                ErrorResult& aRv);
+
+  already_AddRefed<Promise> Remove(const StringOrUnsignedLong& aId,
+                                   const nsAString& aRevisionId,
+                                   ErrorResult& aRv);
+
+  already_AddRefed<Promise> Clear(const nsAString& aRevisionId,
+                                  ErrorResult& aRv);
+
+  void GetRevisionId(nsAString& aRevisionId, ErrorResult& aRv);
+
+  already_AddRefed<Promise> GetLength(ErrorResult& aRv);
+
+  already_AddRefed<DataStoreCursor> Sync(const nsAString& aRevisionId,
+                                         ErrorResult& aRv);
+
+  IMPL_EVENT_HANDLER(change)
+
+  // This internal function (ChromeOnly) is aimed to make the DataStore keep a
+  // reference to the DataStoreImpl which really implements the API's logic in
+  // JS. We also need to let the DataStoreImpl implementation keep the event
+  // target of DataStore, so that it can know where to fire the events.
+  void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv);
+
+protected:
+  virtual ~DataStore() {}
+
+private:
+  nsRefPtr<DataStoreImpl> mStore;
+};
+
+} //namespace dom
+} //namespace mozilla
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/datastore/DataStoreCursor.cpp
@@ -0,0 +1,71 @@
+/* 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 "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreCursor.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/DataStoreImplBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/ErrorResult.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DataStoreCursor, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DataStoreCursor, Release)
+
+NS_IMPL_CYCLE_COLLECTION_1(DataStoreCursor, mCursor)
+
+already_AddRefed<DataStoreCursor>
+DataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsRefPtr<DataStoreCursor> cursor = new DataStoreCursor();
+  return cursor.forget();
+}
+
+JSObject*
+DataStoreCursor::WrapObject(JSContext* aCx)
+{
+  return DataStoreCursorBinding::Wrap(aCx, this);
+}
+
+already_AddRefed<DataStore>
+DataStoreCursor::GetStore(ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mCursor);
+
+  return mCursor->GetStore(aRv);
+}
+
+already_AddRefed<Promise>
+DataStoreCursor::Next(ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mCursor);
+
+  return mCursor->Next(aRv);
+}
+
+void
+DataStoreCursor::Close(ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mCursor);
+
+  mCursor->Close(aRv);
+}
+
+void
+DataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mCursor);
+
+  mCursor = &aCursor;
+}
+
+} //namespace dom
+} //namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/datastore/DataStoreCursor.h
@@ -0,0 +1,61 @@
+/* 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_dom_DataStoreCursor_h
+#define mozilla_dom_DataStoreCursor_h
+
+#include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsPIDOMWindow;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class Promise;
+class DataStore;
+class GlobalObject;
+class DataStoreCursorImpl;
+
+class DataStoreCursor MOZ_FINAL
+{
+public:
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DataStoreCursor)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(DataStoreCursor)
+
+  // WebIDL (internal functions)
+
+  static already_AddRefed<DataStoreCursor> Constructor(GlobalObject& aGlobal,
+                                                       ErrorResult& aRv);
+
+  JSObject* WrapObject(JSContext *aCx);
+
+  // WebIDL (public APIs)
+
+  already_AddRefed<DataStore> GetStore(ErrorResult& aRv);
+
+  already_AddRefed<Promise> Next(ErrorResult& aRv);
+
+  void Close(ErrorResult& aRv);
+
+  // This internal function (ChromeOnly) is aimed to make the DataStoreCursor
+  // keep a reference to the DataStoreCursorImpl which really implements the
+  // API's logic in JS.
+  void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor);
+
+protected:
+  virtual ~DataStoreCursor() {}
+
+private:
+  nsRefPtr<DataStoreCursorImpl> mCursor;
+};
+
+} //namespace dom
+} //namespace mozilla
+
+#endif
\ No newline at end of file
rename from dom/datastore/DataStoreCursor.jsm
rename to dom/datastore/DataStoreCursorImpl.jsm
--- a/dom/datastore/DataStoreCursor.jsm
+++ b/dom/datastore/DataStoreCursorImpl.jsm
@@ -72,23 +72,24 @@ Cu.import('resource://gre/modules/XPCOMU
 
 /* Helper functions */
 function createDOMError(aWindow, aEvent) {
   return new aWindow.DOMError(aEvent.target.error.name);
 }
 
 /* DataStoreCursor object */
 this.DataStoreCursor = function(aWindow, aDataStore, aRevisionId) {
+  debug("DataStoreCursor created");
   this.init(aWindow, aDataStore, aRevisionId);
 }
 
 this.DataStoreCursor.prototype = {
   classDescription: 'DataStoreCursor XPCOM Component',
   classID: Components.ID('{b6d14349-1eab-46b8-8513-584a7328a26b}'),
-  contractID: '@mozilla.org/dom/datastore-cursor;1',
+  contractID: '@mozilla.org/dom/datastore-cursor-impl;1',
   QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
 
   _window: null,
   _dataStore: null,
   _revisionId: null,
   _revision: null,
   _revisionsList: null,
   _objectId: 0,
rename from dom/datastore/DataStore.jsm
rename to dom/datastore/DataStoreImpl.jsm
--- a/dom/datastore/DataStore.jsm
+++ b/dom/datastore/DataStoreImpl.jsm
@@ -18,17 +18,17 @@ const REVISION_ADDED = "added";
 const REVISION_UPDATED = "updated";
 const REVISION_REMOVED = "removed";
 const REVISION_VOID = "void";
 
 // This value has to be tuned a bit. Currently it's just a guess
 // and yet we don't know if it's too low or too high.
 const MAX_REQUESTS = 25;
 
-Cu.import("resource://gre/modules/DataStoreCursor.jsm");
+Cu.import("resource://gre/modules/DataStoreCursorImpl.jsm");
 Cu.import("resource://gre/modules/DataStoreDB.jsm");
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.importGlobalProperties(["indexedDB"]);
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
@@ -62,30 +62,31 @@ function validateId(aId) {
 this.DataStore = function(aWindow, aName, aOwner, aReadOnly) {
   debug("DataStore created");
   this.init(aWindow, aName, aOwner, aReadOnly);
 }
 
 this.DataStore.prototype = {
   classDescription: "DataStore XPCOM Component",
   classID: Components.ID("{db5c9602-030f-4bff-a3de-881a8de370f2}"),
-  contractID: "@mozilla.org/dom/datastore;1",
+  contractID: "@mozilla.org/dom/datastore-impl;1",
   QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports,
                                          Components.interfaces.nsIObserver]),
 
   callbacks: [],
 
   _window: null,
   _name: null,
   _owner: null,
   _readOnly: null,
   _revisionId: null,
   _exposedObject: null,
   _cursor: null,
   _shuttingdown: false,
+  _eventTarget: null,
 
   init: function(aWindow, aName, aOwner, aReadOnly) {
     debug("DataStore init");
 
     this._window = aWindow;
     this._name = aName;
     this._owner = aOwner;
     this._readOnly = aReadOnly;
@@ -111,16 +112,20 @@ this.DataStore.prototype = {
 
       cpmm.removeMessageListener("DataStore:Changed:Return:OK", this);
       cpmm.sendAsyncMessage("DataStore:UnregisterForMessages");
       this._shuttingdown = true;
       this._db.close();
     }
   },
 
+  setEventTarget: function(aEventTarget) {
+    this._eventTarget = aEventTarget;
+  },
+
   newDBPromise: function(aTxnType, aFunction) {
     let self = this;
     return new this._window.Promise(function(aResolve, aReject) {
       debug("DBPromise started");
       self._db.txn(
         aTxnType,
         function(aTxn, aStore, aRevisionStore) {
           debug("DBPromise success");
@@ -360,17 +365,17 @@ this.DataStore.prototype = {
 
         // If we have an active cursor we don't emit events.
         if (self._cursor) {
           return;
         }
 
         let event = new self._window.DataStoreChangeEvent('change',
                                                           aMessage.data.message);
-        self.__DOM_IMPL__.dispatchEvent(event);
+        self._eventTarget.dispatchEvent(event);
       }
     );
   },
 
   get exposedObject() {
     debug("get exposedObject");
     return this._exposedObject;
   },
@@ -514,24 +519,20 @@ this.DataStore.prototype = {
     // Promise<int>
     return this.newDBPromise("readonly",
       function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
         self.getLengthInternal(aResolve, aStore);
       }
     );
   },
 
-  set onchange(aCallback) {
-    debug("Set OnChange");
-    this.__DOM_IMPL__.setEventHandler("onchange", aCallback);
-  },
-
-  get onchange() {
-    debug("Get OnChange");
-    return this.__DOM_IMPL__.getEventHandler("onchange");
-  },
-
   sync: function(aRevisionId) {
     debug("Sync");
     this._cursor = new DataStoreCursor(this._window, this, aRevisionId);
-    return this._window.DataStoreCursor._create(this._window, this._cursor);
+
+    let cursorImpl = this._window.DataStoreCursorImpl.
+                                  _create(this._window, this._cursor);
+
+    let exposedCursor = new this._window.DataStoreCursor();
+    exposedCursor.setDataStoreCursorImpl(cursorImpl);
+    return exposedCursor;
   }
 };
--- a/dom/datastore/DataStoreService.js
+++ b/dom/datastore/DataStoreService.js
@@ -11,17 +11,17 @@
 function debug(s) {
   //dump('DEBUG DataStoreService: ' + s + '\n');
 }
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
-Cu.import('resource://gre/modules/DataStore.jsm');
+Cu.import('resource://gre/modules/DataStoreImpl.jsm');
 Cu.import("resource://gre/modules/DataStoreDB.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
@@ -347,20 +347,25 @@ DataStoreService.prototype = {
     if (!callbackPending) {
       aResolve(results);
       return;
     }
 
     for (let i = 0; i < aStores.length; ++i) {
       let obj = new DataStore(aWindow, aStores[i].name,
                               aStores[i].owner, aStores[i].readOnly);
-      let exposedObj = aWindow.DataStore._create(aWindow, obj);
-      obj.exposedObject = exposedObj;
+
+      let storeImpl = aWindow.DataStoreImpl._create(aWindow, obj);
 
-      results.push(exposedObj);
+      let exposedStore = new aWindow.DataStore();
+      exposedStore.setDataStoreImpl(storeImpl);
+
+      obj.exposedObject = exposedStore;
+
+      results.push(exposedStore);
 
       obj.retrieveRevisionId(
         function() {
           --callbackPending;
           if (!callbackPending) {
             aResolve(results);
           }
         }
--- a/dom/datastore/moz.build
+++ b/dom/datastore/moz.build
@@ -5,22 +5,38 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDataStoreService.idl',
 ]
 
 XPIDL_MODULE = 'dom_datastore'
 
+EXPORTS.mozilla.dom += [
+    'DataStore.h',
+    'DataStoreCursor.h',
+]
+
+SOURCES += [
+    'DataStore.cpp',
+    'DataStoreCursor.cpp',
+]
+
+LOCAL_INCLUDES += [
+    '/js/xpconnect/wrappers',
+]
+
 EXTRA_COMPONENTS += [
     'DataStore.manifest',
     'DataStoreService.js',
 ]
 
 EXTRA_JS_MODULES += [
-    'DataStore.jsm',
     'DataStoreChangeNotifier.jsm',
-    'DataStoreCursor.jsm',
+    'DataStoreCursorImpl.jsm',
     'DataStoreDB.jsm',
+    'DataStoreImpl.jsm',
     'DataStoreServiceInternal.jsm',
 ]
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
+
+FINAL_LIBRARY = 'xul'
--- a/dom/webidl/DataStore.webidl
+++ b/dom/webidl/DataStore.webidl
@@ -1,68 +1,101 @@
 /* -*- 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/.
  */
 
 typedef (DOMString or unsigned long) DataStoreKey;
 
+// TODO Bug 957086 - The constructor and the setDataStoreImpl(...) will be
+//                   removed once the DataStore API is fully rewritten in C++,
+//                   which currently plays a role of C++ proxy directing to the
+//                   JS codes implemented by the DataStoreImpl WebIDL.
+
 [Func="Navigator::HasDataStoreSupport",
- JSImplementation="@mozilla.org/dom/datastore;1"]
+ ChromeConstructor]
 interface DataStore : EventTarget {
   // Returns the label of the DataSource.
+  [GetterThrows]
   readonly attribute DOMString name;
 
   // Returns the origin of the DataSource (e.g., 'facebook.com').
   // This value is the manifest URL of the owner app.
+  [GetterThrows]
   readonly attribute DOMString owner;
 
   // is readOnly a F(current_app, datastore) function? yes
+  [GetterThrows]
   readonly attribute boolean readOnly;
 
   // Promise<any>
+  [Throws]
   Promise get(DataStoreKey... id);
 
   // Promise<void>
+  [Throws]
   Promise put(any obj, DataStoreKey id, optional DOMString revisionId = "");
 
   // Promise<DataStoreKey>
+  [Throws]
   Promise add(any obj, optional DataStoreKey id,
               optional DOMString revisionId = "");
 
   // Promise<boolean>
+  [Throws]
   Promise remove(DataStoreKey id, optional DOMString revisionId = "");
 
   // Promise<void>
+  [Throws]
   Promise clear(optional DOMString revisionId = "");
 
+  [GetterThrows]
   readonly attribute DOMString revisionId;
 
   attribute EventHandler onchange;
 
   // Promise<unsigned long>
+  [Throws]
   Promise getLength();
 
+  [NewObject, Throws]
   DataStoreCursor sync(optional DOMString revisionId = "");
 };
 
+partial interface DataStore {
+  [ChromeOnly, Throws]
+  void setDataStoreImpl(DataStoreImpl store);
+};
+
+// TODO Bug 957086 - The constructor and the setDataStoreCursorImpl(...) will be
+//                   removed once the DataStore API is fully rewritten in C++,
+//                   which currently plays a role of C++ proxy directing to the
+//                   JS codes implemented by the DataStoreCursorImpl WebIDL.
+
 [Pref="dom.datastore.enabled",
- JSImplementation="@mozilla.org/dom/datastore-cursor;1"]
+ ChromeConstructor]
 interface DataStoreCursor {
-
   // the DataStore
+  [GetterThrows]
   readonly attribute DataStore store;
 
   // Promise<DataStoreTask>
+  [Throws]
   Promise next();
 
+  [Throws]
   void close();
 };
 
+partial interface DataStoreCursor {
+  [ChromeOnly]
+  void setDataStoreCursorImpl(DataStoreCursorImpl cursor);
+};
+
 enum DataStoreOperation {
   "add",
   "update",
   "remove",
   "clear",
   "done"
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DataStoreImpl.webidl
@@ -0,0 +1,68 @@
+/* -*- 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/.
+ */
+
+// TODO Bug 957086 - The DataStoreImpl WebIDL will be removed once the
+//                   DataStore API is fully rewritten in C++ (i.e. should be
+//                   directly implemented by the DataStore WebIDL).
+
+[HeaderFile="mozilla/dom/DataStore.h",
+ Func="mozilla::dom::DataStore::EnabledForScope",
+ JSImplementation="@mozilla.org/dom/datastore-impl;1"]
+interface DataStoreImpl {
+  void setEventTarget(EventTarget eventTarget);
+
+  // Returns the label of the DataSource.
+  readonly attribute DOMString name;
+
+  // Returns the origin of the DataSource (e.g., 'facebook.com').
+  // This value is the manifest URL of the owner app.
+  readonly attribute DOMString owner;
+
+  // is readOnly a F(current_app, datastore) function? yes
+  readonly attribute boolean readOnly;
+
+  // Promise<any>
+  Promise get(DataStoreKey... id);
+
+  // Promise<void>
+  Promise put(any obj, DataStoreKey id, optional DOMString revisionId = "");
+
+  // Promise<DataStoreKey>
+  Promise add(any obj, optional DataStoreKey id,
+              optional DOMString revisionId = "");
+
+  // Promise<boolean>
+  Promise remove(DataStoreKey id, optional DOMString revisionId = "");
+
+  // Promise<void>
+  Promise clear(optional DOMString revisionId = "");
+
+  readonly attribute DOMString revisionId;
+
+  // Promise<unsigned long>
+  Promise getLength();
+
+  [NewObject]
+  DataStoreCursor sync(optional DOMString revisionId = "");
+};
+
+
+// TODO Bug 957086 - The DataStoreCursorImpl WebIDL will be removed once the
+//                   DataStore API is fully rewritten in C++ (i.e. should be
+//                   directly implemented by the DataStoreCursor WebIDL).
+
+[HeaderFile="mozilla/dom/DataStore.h",
+ Func="mozilla::dom::DataStore::EnabledForScope",
+ JSImplementation="@mozilla.org/dom/datastore-cursor-impl;1"]
+interface DataStoreCursorImpl {
+  // the DataStore
+  readonly attribute DataStore store;
+
+  // Promise<DataStoreTask>
+  Promise next();
+
+  void close();
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -63,16 +63,17 @@ WEBIDL_FILES = [
     'CSS.webidl',
     'CSSPrimitiveValue.webidl',
     'CSSStyleDeclaration.webidl',
     'CSSStyleSheet.webidl',
     'CSSValue.webidl',
     'CSSValueList.webidl',
     'DataContainerEvent.webidl',
     'DataStore.webidl',
+    'DataStoreImpl.webidl',
     'DataTransfer.webidl',
     'DedicatedWorkerGlobalScope.webidl',
     'DelayNode.webidl',
     'DesktopNotification.webidl',
     'DeviceMotionEvent.webidl',
     'DeviceStorage.webidl',
     'Directory.webidl',
     'Document.webidl',