Bug 949325 - C++ wrapper to support DataStore API on the worker (part 2-3, dispatch tasks on the worker to the main thread). r=baku,khuey f=nsm
authorGene Lian <clian@mozilla.com>
Mon, 24 Feb 2014 21:57:15 +0800
changeset 193507 c5624c2a2d2fbc8565be10e41b2830833a6d07fa
parent 193506 a613090760597ae6319056aa080f9167e4afa97d
child 193508 b46eaebe6572d67df2e9c18fa651906808d9523e
push idunknown
push userunknown
push dateunknown
reviewersbaku, khuey
bugs949325
milestone32.0a1
Bug 949325 - C++ wrapper to support DataStore API on the worker (part 2-3, dispatch tasks on the worker to the main thread). r=baku,khuey f=nsm
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/bindings/Bindings.conf
dom/datastore/DataStore.h
dom/datastore/DataStoreCursor.cpp
dom/datastore/DataStoreCursor.h
dom/webidl/WorkerNavigator.webidl
dom/workers/DataStore.cpp
dom/workers/DataStore.h
dom/workers/DataStoreCursor.cpp
dom/workers/DataStoreCursor.h
dom/workers/Navigator.cpp
dom/workers/Navigator.h
dom/workers/moz.build
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1405,38 +1405,46 @@ Navigator::GetBattery(ErrorResult& aRv)
 
     mBatteryManager = new battery::BatteryManager(mWindow);
     mBatteryManager->Init();
   }
 
   return mBatteryManager;
 }
 
-already_AddRefed<Promise>
-Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
+/* static */ already_AddRefed<Promise>
+Navigator::GetDataStores(nsPIDOMWindow* aWindow,
+                         const nsAString& aName,
+                         ErrorResult& aRv)
 {
-  if (!mWindow || !mWindow->GetDocShell()) {
+  if (!aWindow || !aWindow->GetDocShell()) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsCOMPtr<nsIDataStoreService> service =
     do_GetService("@mozilla.org/datastore-service;1");
   if (!service) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> promise;
-  aRv = service->GetDataStores(mWindow, aName, getter_AddRefs(promise));
+  aRv = service->GetDataStores(aWindow, aName, getter_AddRefs(promise));
 
   nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
   return p.forget();
 }
 
+already_AddRefed<Promise>
+Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
+{
+  return GetDataStores(mWindow, aName, aRv);
+}
+
 PowerManager*
 Navigator::GetMozPower(ErrorResult& aRv)
 {
   if (!mPowerManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -151,16 +151,21 @@ public:
                                const nsAString& aTitle, ErrorResult& aRv);
   void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
                               const nsAString& aTitle, ErrorResult& aRv);
   nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
   nsPluginArray* GetPlugins(ErrorResult& aRv);
   // The XPCOM GetDoNotTrack is ok
   Geolocation* GetGeolocation(ErrorResult& aRv);
   battery::BatteryManager* GetBattery(ErrorResult& aRv);
+
+  static already_AddRefed<Promise> GetDataStores(nsPIDOMWindow* aWindow,
+                                                 const nsAString& aName,
+                                                 ErrorResult& aRv);
+
   already_AddRefed<Promise> GetDataStores(const nsAString &aName,
                                           ErrorResult& aRv);
   bool Vibrate(uint32_t aDuration);
   bool Vibrate(const nsTArray<uint32_t>& aDuration);
   uint32_t MaxTouchPoints();
   void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
   {
     aRv = GetAppCodeName(aAppCodeName);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -283,19 +283,34 @@ DOMInterfaces = {
 'CSSValueList': {
     'nativeType': 'nsDOMCSSValueList'
 },
 
 'DataChannel': {
     'nativeType': 'nsDOMDataChannel',
 },
 
-'DataStoreCursor': {
+'DataStore': [{
+    'workers': False
+}, {
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::WorkerDataStore',
+    'implicitJSContext': ['name', 'owner', 'readOnly', 'get', 'remove',
+                          'clear', 'revisionId', 'getLength', 'sync']
+}],
+
+'DataStoreCursor': [{
+    'workers': False,
+    'wrapperCache': False
+}, {
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::WorkerDataStoreCursor',
     'wrapperCache': False,
-},
+    'implicitJSContext': ['store', 'next', 'close']
+}],
 
 'DedicatedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'workers': True,
 },
 
 'DelayNode': {
     'resultNotAddRefed': [ 'delayTime' ],
@@ -1540,16 +1555,17 @@ DOMInterfaces = {
 'WorkerLocation': {
     'headerFile': 'mozilla/dom/workers/bindings/Location.h',
     'workers': True,
 },
 
 'WorkerNavigator': {
     'headerFile': 'mozilla/dom/workers/bindings/Navigator.h',
     'workers': True,
+    'implicitJSContext': ['getDataStores'],
 },
 
 'XMLHttpRequest': [
 {
     'nativeType': 'nsXMLHttpRequest',
     'implicitJSContext': [ 'constructor', ],
     'resultNotAddRefed': [ 'upload', 'responseXML' ]
 },
--- a/dom/datastore/DataStore.h
+++ b/dom/datastore/DataStore.h
@@ -77,19 +77,16 @@ public:
   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
--- a/dom/datastore/DataStoreCursor.cpp
+++ b/dom/datastore/DataStoreCursor.cpp
@@ -8,18 +8,22 @@
 #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_COLLECTING_ADDREF(DataStoreCursor)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DataStoreCursor)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataStoreCursor)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(DataStoreCursor, mCursor)
 
 already_AddRefed<DataStoreCursor>
 DataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
 {
   nsRefPtr<DataStoreCursor> cursor = new DataStoreCursor();
   return cursor.forget();
--- a/dom/datastore/DataStoreCursor.h
+++ b/dom/datastore/DataStoreCursor.h
@@ -17,21 +17,21 @@ class ErrorResult;
 
 namespace dom {
 
 class Promise;
 class DataStore;
 class GlobalObject;
 class DataStoreCursorImpl;
 
-class DataStoreCursor MOZ_FINAL
+class DataStoreCursor MOZ_FINAL : public nsISupports
 {
 public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DataStoreCursor)
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(DataStoreCursor)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DataStoreCursor)
 
   // WebIDL (internal functions)
 
   static already_AddRefed<DataStoreCursor> Constructor(GlobalObject& aGlobal,
                                                        ErrorResult& aRv);
 
   JSObject* WrapObject(JSContext *aCx);
 
@@ -43,19 +43,16 @@ public:
 
   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
--- a/dom/webidl/WorkerNavigator.webidl
+++ b/dom/webidl/WorkerNavigator.webidl
@@ -2,8 +2,9 @@
  * 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/. */
 
 interface WorkerNavigator {
 };
 
 WorkerNavigator implements NavigatorID;
 WorkerNavigator implements NavigatorOnLine;
+WorkerNavigator implements NavigatorDataStore;
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStore.cpp
@@ -0,0 +1,712 @@
+/* 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 "DataStore.h"
+#include "DataStoreCursor.h"
+
+#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/dom/PromiseWorkerProxy.h"
+#include "mozilla/ErrorResult.h"
+
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+#include "WorkerScope.h"
+
+BEGIN_WORKERS_NAMESPACE
+
+NS_IMPL_ADDREF_INHERITED(WorkerDataStore, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(WorkerDataStore, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN(WorkerDataStore)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+WorkerDataStore::WorkerDataStore(WorkerGlobalScope* aScope)
+  : DOMEventTargetHelper(aScope)
+{}
+
+already_AddRefed<WorkerDataStore>
+WorkerDataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  JSContext* cx = aGlobal.GetContext();
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<WorkerDataStore> store =
+    new WorkerDataStore(workerPrivate->GlobalScope());
+  return store.forget();
+}
+
+JSObject*
+WorkerDataStore::WrapObject(JSContext* aCx)
+{
+  return DataStoreBinding_workers::Wrap(aCx, this);
+}
+
+// A WorkerMainThreadRunnable which holds a reference to WorkerDataStore.
+class DataStoreRunnable : public WorkerMainThreadRunnable
+{
+protected:
+  nsMainThreadPtrHandle<DataStore> mBackingStore;
+
+public:
+  DataStoreRunnable(WorkerPrivate* aWorkerPrivate,
+                    const nsMainThreadPtrHandle<DataStore>& aBackingStore)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mBackingStore(aBackingStore)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+};
+
+// A DataStoreRunnable to run:
+//   - DataStore::GetName(...)
+//   - DataStore::GetOwner(...)
+//   - DataStore::GetRevisionId(...)
+// on the main thread.
+class DataStoreGetStringRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  typedef void
+  (DataStore::*FuncType)(nsAString&, ErrorResult&);
+
+  FuncType mFunc;
+  nsAString& mString;
+  ErrorResult& mRv;
+
+public:
+  DataStoreGetStringRunnable(WorkerPrivate* aWorkerPrivate,
+                             const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                             FuncType aFunc,
+                             nsAString& aString,
+                             ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mFunc(aFunc)
+    , mString(aString)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsString string;
+    (mBackingStore.get()->*mFunc)(string, mRv);
+    mString.Assign(string);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::GetReadOnly(...) on the main
+// thread.
+class DataStoreGetReadOnlyRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  ErrorResult& mRv;
+
+public:
+  bool mReadOnly;
+
+public:
+  DataStoreGetReadOnlyRunnable(WorkerPrivate* aWorkerPrivate,
+                               const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                               ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    mReadOnly = mBackingStore->GetReadOnly(mRv);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Get(...) on the main thread.
+class DataStoreGetRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  Sequence<OwningStringOrUnsignedLong> mId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreGetRunnable(WorkerPrivate* aWorkerPrivate,
+                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                       Promise* aWorkerPromise,
+                       const Sequence<OwningStringOrUnsignedLong>& aId,
+                       ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    if (!mId.AppendElements(aId)) {
+      mRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    }
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->Get(mId, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Put(...) on the main thread.
+class DataStorePutRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  JSAutoStructuredCloneBuffer mObjBuffer;
+  const StringOrUnsignedLong& mId;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStorePutRunnable(WorkerPrivate* aWorkerPrivate,
+                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                       Promise* aWorkerPromise,
+                       JSContext* aCx,
+                       JS::Handle<JS::Value> aObj,
+                       const StringOrUnsignedLong& aId,
+                       const nsAString& aRevisionId,
+                       ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mId(aId)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    // This needs to be structured cloned while it's still on the worker thread.
+    if (!mObjBuffer.write(aCx, aObj)) {
+      JS_ClearPendingException(aCx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+    }
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Get the JSContext for the target window
+    nsCOMPtr<nsIScriptGlobalObject> sgo =
+      do_QueryInterface(static_cast<DOMEventTargetHelper*>
+                        (mBackingStore.get())->GetOwner());
+    MOZ_ASSERT(sgo);
+
+    nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
+    AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
+                                       : nsContentUtils::GetSafeJSContext());
+    MOZ_ASSERT(cx);
+
+    JS::Rooted<JS::Value> value(cx);
+    if (!mObjBuffer.read(cx, &value)) {
+      JS_ClearPendingException(cx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+      return true;
+    }
+
+    nsRefPtr<Promise> promise = mBackingStore->Put(cx,
+                                                   value,
+                                                   mId,
+                                                   mRevisionId,
+                                                   mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Add(...) on the main thread.
+class DataStoreAddRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  JSAutoStructuredCloneBuffer mObjBuffer;
+  const Optional<StringOrUnsignedLong>& mId;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreAddRunnable(WorkerPrivate* aWorkerPrivate,
+                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                       Promise* aWorkerPromise,
+                       JSContext* aCx,
+                       JS::Handle<JS::Value> aObj,
+                       const Optional<StringOrUnsignedLong>& aId,
+                       const nsAString& aRevisionId,
+                       ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mId(aId)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    // This needs to be structured cloned while it's still on the worker thread.
+    if (!mObjBuffer.write(aCx, aObj)) {
+      JS_ClearPendingException(aCx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+    }
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Get the JSContext for the target window
+    nsCOMPtr<nsIScriptGlobalObject> sgo =
+      do_QueryInterface(static_cast<DOMEventTargetHelper*>
+                        (mBackingStore.get())->GetOwner());
+    MOZ_ASSERT(sgo);
+
+    nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
+    AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
+                                       : nsContentUtils::GetSafeJSContext());
+    MOZ_ASSERT(cx);
+
+    JS::Rooted<JS::Value> value(cx);
+    if (!mObjBuffer.read(cx, &value)) {
+      JS_ClearPendingException(cx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+      return true;
+    }
+
+    nsRefPtr<Promise> promise = mBackingStore->Add(cx,
+                                                   value,
+                                                   mId,
+                                                   mRevisionId,
+                                                   mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Remove(...) on the main
+// thread.
+class DataStoreRemoveRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  const StringOrUnsignedLong& mId;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreRemoveRunnable(WorkerPrivate* aWorkerPrivate,
+                          const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                          Promise* aWorkerPromise,
+                          const StringOrUnsignedLong& aId,
+                          const nsAString& aRevisionId,
+                          ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mId(aId)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->Remove(mId, mRevisionId, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Sync(...) on the main thread.
+class DataStoreSyncStoreRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  WorkerDataStoreCursor* mWorkerCursor;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreSyncStoreRunnable(WorkerPrivate* aWorkerPrivate,
+                             const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                             WorkerDataStoreCursor* aWorkerCursor,
+                             const nsAString& aRevisionId,
+                             ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mWorkerCursor(aWorkerCursor)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Point WorkerDataStoreCursor to DataStoreCursor.
+    nsRefPtr<DataStoreCursor> cursor = mBackingStore->Sync(mRevisionId, mRv);
+    nsMainThreadPtrHandle<DataStoreCursor> backingCursor =
+      new nsMainThreadPtrHolder<DataStoreCursor>(cursor);
+    mWorkerCursor->SetBackingDataStoreCursor(backingCursor);
+
+    return true;
+  }
+};
+
+void
+WorkerDataStore::GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetStringRunnable> runnable =
+    new DataStoreGetStringRunnable(workerPrivate,
+                                   mBackingStore,
+                                   &DataStore::GetName,
+                                   aName,
+                                   aRv);
+  runnable->Dispatch(aCx);
+}
+
+void
+WorkerDataStore::GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetStringRunnable> runnable =
+    new DataStoreGetStringRunnable(workerPrivate,
+                                   mBackingStore,
+                                   &DataStore::GetOwner,
+                                   aOwner,
+                                   aRv);
+  runnable->Dispatch(aCx);
+}
+
+bool
+WorkerDataStore::GetReadOnly(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetReadOnlyRunnable> runnable =
+    new DataStoreGetReadOnlyRunnable(workerPrivate, mBackingStore, aRv);
+  runnable->Dispatch(aCx);
+
+  return runnable->mReadOnly;
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Get(JSContext* aCx,
+                     const Sequence<OwningStringOrUnsignedLong>& aId,
+                     ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreGetRunnable> runnable =
+    new DataStoreGetRunnable(workerPrivate,
+                             mBackingStore,
+                             promise,
+                             aId,
+                             aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Put(JSContext* aCx,
+                     JS::Handle<JS::Value> aObj,
+                     const StringOrUnsignedLong& aId,
+                     const nsAString& aRevisionId,
+                     ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStorePutRunnable> runnable =
+    new DataStorePutRunnable(workerPrivate,
+                             mBackingStore,
+                             promise,
+                             aCx,
+                             aObj,
+                             aId,
+                             aRevisionId,
+                             aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Add(JSContext* aCx,
+                     JS::Handle<JS::Value> aObj,
+                     const Optional<StringOrUnsignedLong>& aId,
+                     const nsAString& aRevisionId,
+                     ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreAddRunnable> runnable =
+    new DataStoreAddRunnable(workerPrivate,
+                             mBackingStore,
+                             promise,
+                             aCx,
+                             aObj,
+                             aId,
+                             aRevisionId,
+                             aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Remove(JSContext* aCx,
+                        const StringOrUnsignedLong& aId,
+                        const nsAString& aRevisionId,
+                        ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreRemoveRunnable> runnable =
+    new DataStoreRemoveRunnable(workerPrivate,
+                                mBackingStore,
+                                promise,
+                                aId,
+                                aRevisionId,
+                                aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+// A DataStoreRunnable to run DataStore::Clear(...) on the main thread.
+class DataStoreClearRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreClearRunnable(WorkerPrivate* aWorkerPrivate,
+                         const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                         Promise* aWorkerPromise,
+                         const nsAString& aRevisionId,
+                         ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->Clear(mRevisionId, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+already_AddRefed<Promise>
+WorkerDataStore::Clear(JSContext* aCx,
+                       const nsAString& aRevisionId,
+                       ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreClearRunnable> runnable =
+    new DataStoreClearRunnable(workerPrivate,
+                               mBackingStore,
+                               promise,
+                               aRevisionId,
+                               aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+void
+WorkerDataStore::GetRevisionId(JSContext* aCx,
+                               nsAString& aRevisionId,
+                               ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetStringRunnable> runnable =
+    new DataStoreGetStringRunnable(workerPrivate,
+                                   mBackingStore,
+                                   &DataStore::GetRevisionId,
+                                   aRevisionId,
+                                   aRv);
+  runnable->Dispatch(aCx);
+}
+
+// A DataStoreRunnable to run DataStore::GetLength(...) on the main thread.
+class DataStoreGetLengthRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  ErrorResult& mRv;
+
+public:
+  DataStoreGetLengthRunnable(WorkerPrivate* aWorkerPrivate,
+                             const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                             Promise* aWorkerPromise,
+                             ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->GetLength(mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+already_AddRefed<Promise>
+WorkerDataStore::GetLength(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreGetLengthRunnable> runnable =
+    new DataStoreGetLengthRunnable(workerPrivate,
+                                   mBackingStore,
+                                   promise,
+                                   aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<WorkerDataStoreCursor>
+WorkerDataStore::Sync(JSContext* aCx,
+                      const nsAString& aRevisionId,
+                      ErrorResult& aRv)
+{
+  // Create a WorkerDataStoreCursor on the worker. DataStoreSyncStoreRunnable
+  // will point that to the DataStoreCursor created on the main thread.
+  nsRefPtr<WorkerDataStoreCursor> workerCursor = new WorkerDataStoreCursor();
+
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreSyncStoreRunnable> runnable =
+    new DataStoreSyncStoreRunnable(workerPrivate,
+                                   mBackingStore,
+                                   workerCursor,
+                                   aRevisionId,
+                                   aRv);
+  runnable->Dispatch(aCx);
+
+  return workerCursor.forget();
+}
+
+void
+WorkerDataStore::SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv)
+{
+  NS_NOTREACHED("We don't use this for the WorkerDataStore!");
+}
+
+void
+WorkerDataStore::SetBackingDataStore(
+  const nsMainThreadPtrHandle<DataStore>& aBackingStore)
+{
+  mBackingStore = aBackingStore;
+}
+
+// TODO How to handle the event? Will fix this in my later patch.
+
+END_WORKERS_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStore.h
@@ -0,0 +1,102 @@
+/* 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_workers_DataStore_h
+#define mozilla_dom_workers_DataStore_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class Promise;
+class DataStore;
+class DataStoreImpl;
+class StringOrUnsignedLong;
+class OwningStringOrUnsignedLong;
+
+namespace workers {
+
+class WorkerDataStoreCursor;
+class WorkerGlobalScope;
+
+class WorkerDataStore MOZ_FINAL : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  WorkerDataStore(WorkerGlobalScope* aScope);
+
+  // WebIDL (internal functions)
+
+  static already_AddRefed<WorkerDataStore> Constructor(GlobalObject& aGlobal,
+                                                       ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
+
+  // WebIDL (public APIs)
+
+  void GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv);
+
+  void GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv);
+
+  bool GetReadOnly(JSContext* aCx, ErrorResult& aRv);
+
+  already_AddRefed<Promise> Get(JSContext* aCx,
+                                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(JSContext* aCx,
+                                   const StringOrUnsignedLong& aId,
+                                   const nsAString& aRevisionId,
+                                   ErrorResult& aRv);
+
+  already_AddRefed<Promise> Clear(JSContext* aCx,
+                                  const nsAString& aRevisionId,
+                                  ErrorResult& aRv);
+
+  void GetRevisionId(JSContext* aCx, nsAString& aRevisionId, ErrorResult& aRv);
+
+  already_AddRefed<Promise> GetLength(JSContext* aCx, ErrorResult& aRv);
+
+  already_AddRefed<WorkerDataStoreCursor> Sync(JSContext* aCx,
+                                               const nsAString& aRevisionId,
+                                               ErrorResult& aRv);
+
+  IMPL_EVENT_HANDLER(change)
+
+  // We don't use this for the WorkerDataStore.
+  void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv);
+
+  void SetBackingDataStore(
+    const nsMainThreadPtrHandle<DataStore>& aBackingStore);
+
+protected:
+  virtual ~WorkerDataStore() {}
+
+private:
+  nsMainThreadPtrHandle<DataStore> mBackingStore;
+};
+
+} //namespace workers
+} //namespace dom
+} //namespace mozilla
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStoreCursor.cpp
@@ -0,0 +1,218 @@
+/* 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 "DataStore.h"
+#include "DataStoreCursor.h"
+
+#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/dom/PromiseWorkerProxy.h"
+#include "mozilla/ErrorResult.h"
+
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+#include "WorkerScope.h"
+
+BEGIN_WORKERS_NAMESPACE
+
+already_AddRefed<WorkerDataStoreCursor>
+WorkerDataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  nsRefPtr<WorkerDataStoreCursor> workerCursor = new WorkerDataStoreCursor();
+  return workerCursor.forget();
+}
+
+JSObject*
+WorkerDataStoreCursor::WrapObject(JSContext* aCx)
+{
+  return DataStoreCursorBinding_workers::Wrap(aCx, this);
+}
+
+// A WorkerMainThreadRunnable which holds a reference to DataStoreCursor.
+class DataStoreCursorRunnable : public WorkerMainThreadRunnable
+{
+protected:
+  nsMainThreadPtrHandle<DataStoreCursor> mBackingCursor;
+
+public:
+  DataStoreCursorRunnable(WorkerPrivate* aWorkerPrivate,
+                          const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mBackingCursor(aBackingCursor)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+};
+
+// A DataStoreCursorRunnable to run DataStoreCursor::GetStore(...) on the main
+// thread.
+class DataStoreCursorGetStoreRunnable MOZ_FINAL : public DataStoreCursorRunnable
+{
+  WorkerDataStore* mWorkerStore;
+  ErrorResult& mRv;
+
+public:
+  DataStoreCursorGetStoreRunnable(WorkerPrivate* aWorkerPrivate,
+                                  const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor,
+                                  WorkerDataStore* aWorkerStore,
+                                  ErrorResult& aRv)
+    : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor)
+    , mWorkerStore(aWorkerStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Point WorkerDataStore to DataStore.
+    nsRefPtr<DataStore> store = mBackingCursor->GetStore(mRv);
+    nsMainThreadPtrHandle<DataStore> backingStore =
+      new nsMainThreadPtrHolder<DataStore>(store);
+    mWorkerStore->SetBackingDataStore(backingStore);
+
+    return true;
+  }
+};
+
+// A DataStoreCursorRunnable to run DataStoreCursor::Next(...) on the main
+// thread.
+class DataStoreCursorNextRunnable MOZ_FINAL : public DataStoreCursorRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  ErrorResult& mRv;
+
+public:
+  DataStoreCursorNextRunnable(WorkerPrivate* aWorkerPrivate,
+                              const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor,
+                              Promise* aWorkerPromise,
+                              ErrorResult& aRv)
+    : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingCursor->Next(mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreCursorRunnable to run DataStoreCursor::Close(...) on the main
+// thread.
+class DataStoreCursorCloseRunnable MOZ_FINAL : public DataStoreCursorRunnable
+{
+  ErrorResult& mRv;
+
+public:
+  DataStoreCursorCloseRunnable(WorkerPrivate* aWorkerPrivate,
+                               const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor,
+                               ErrorResult& aRv)
+    : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    mBackingCursor->Close(mRv);
+    return true;
+  }
+};
+
+already_AddRefed<WorkerDataStore>
+WorkerDataStoreCursor::GetStore(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  // Create a WorkerDataStore on the worker. DataStoreCursorGetStoreRunnable
+  // will point that to the DataStore created on the main thread.
+  nsRefPtr<WorkerDataStore> workerStore =
+    new WorkerDataStore(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreCursorGetStoreRunnable> runnable =
+    new DataStoreCursorGetStoreRunnable(workerPrivate,
+                                        mBackingCursor,
+                                        workerStore,
+                                        aRv);
+  runnable->Dispatch(aCx);
+
+  return workerStore.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStoreCursor::Next(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreCursorNextRunnable> runnable =
+    new DataStoreCursorNextRunnable(workerPrivate,
+                                    mBackingCursor,
+                                    promise,
+                                    aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+void
+WorkerDataStoreCursor::Close(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreCursorCloseRunnable> runnable =
+    new DataStoreCursorCloseRunnable(workerPrivate, mBackingCursor, aRv);
+  runnable->Dispatch(aCx);
+}
+
+void
+WorkerDataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor)
+{
+  NS_NOTREACHED("We don't use this for the WorkerDataStoreCursor!");
+}
+
+void
+WorkerDataStoreCursor::SetBackingDataStoreCursor(
+  const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor)
+{
+  mBackingCursor = aBackingCursor;
+}
+
+END_WORKERS_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStoreCursor.h
@@ -0,0 +1,62 @@
+/* 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_workers_DataStoreCursor_h
+#define mozilla_dom_workers_DataStoreCursor_h
+
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class Promise;
+class GlobalObject;
+class DataStoreCursor;
+class DataStoreCursorImpl;
+
+namespace workers {
+
+class WorkerDataStore;
+
+class WorkerDataStoreCursor MOZ_FINAL
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(WorkerDataStoreCursor)
+
+  // WebIDL (internal functions)
+
+  static already_AddRefed<WorkerDataStoreCursor> Constructor(GlobalObject& aGlobal,
+                                                             ErrorResult& aRv);
+
+  JSObject* WrapObject(JSContext *aCx);
+
+  // WebIDL (public APIs)
+
+  already_AddRefed<WorkerDataStore> GetStore(JSContext *aCx, ErrorResult& aRv);
+
+  already_AddRefed<Promise> Next(JSContext *aCx, ErrorResult& aRv);
+
+  void Close(JSContext *aCx, ErrorResult& aRv);
+
+  // We don't use this for the WorkerDataStore.
+  void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor);
+
+  void SetBackingDataStoreCursor(
+    const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor);
+
+protected:
+  virtual ~WorkerDataStoreCursor() {}
+
+private:
+  nsMainThreadPtrHandle<DataStoreCursor> mBackingCursor;
+};
+
+} //namespace workers
+} //namespace dom
+} //namespace mozilla
+
+#endif
\ No newline at end of file
--- a/dom/workers/Navigator.cpp
+++ b/dom/workers/Navigator.cpp
@@ -1,19 +1,29 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "Navigator.h"
+#include "DataStore.h"
 
+#include "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 
+#include "Navigator.h"
+#include "nsProxyRelease.h"
 #include "RuntimeService.h"
 
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+#include "WorkerScope.h"
+
 BEGIN_WORKERS_NAMESPACE
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
 
 /* static */ already_AddRefed<WorkerNavigator>
@@ -34,9 +44,174 @@ WorkerNavigator::Create(bool aOnLine)
 }
 
 JSObject*
 WorkerNavigator::WrapObject(JSContext* aCx)
 {
   return WorkerNavigatorBinding_workers::Wrap(aCx, this);
 }
 
+#define WORKER_DATA_STORES_TAG JS_SCTAG_USER_MIN
+
+static JSObject*
+GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx,
+                                          JSStructuredCloneReader* aReader,
+                                          uint32_t aTag,
+                                          uint32_t aData,
+                                          void* aClosure)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  if (aTag != WORKER_DATA_STORES_TAG) {
+    MOZ_ASSERT(false, "aTag must be WORKER_DATA_STORES_TAG!");
+    return nullptr;
+  }
+
+  NS_ASSERTION(!aData, "aData should be empty");
+
+  // Read the holder from the buffer, which points to the data store.
+  nsMainThreadPtrHolder<DataStore>* dataStoreholder;
+  if (!JS_ReadBytes(aReader, &dataStoreholder, sizeof(dataStoreholder))) {
+    MOZ_ASSERT(false, "cannot read bytes for dataStoreholder!");
+    return nullptr;
+  }
+
+  // Point WorkerDataStore to DataStore.
+  nsRefPtr<WorkerDataStore> workerStore =
+    new WorkerDataStore(workerPrivate->GlobalScope());
+  nsMainThreadPtrHandle<DataStore> backingStore = dataStoreholder;
+  workerStore->SetBackingDataStore(backingStore);
+
+  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+  if (!global) {
+    MOZ_ASSERT(false, "cannot get global!");
+    return nullptr;
+  }
+
+  JS::Rooted<JSObject*> workerStoreObj(aCx, workerStore->WrapObject(aCx));
+  if (!JS_WrapObject(aCx, &workerStoreObj)) {
+    MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!");
+    return nullptr;
+  }
+
+  return workerStoreObj;
+}
+
+static bool
+GetDataStoresStructuredCloneCallbacksWrite(JSContext* aCx,
+                                           JSStructuredCloneWriter* aWriter,
+                                           JS::Handle<JSObject*> aObj,
+                                           void* aClosure)
+{
+  AssertIsOnMainThread();
+
+  PromiseWorkerProxy* proxy = static_cast<PromiseWorkerProxy*>(aClosure);
+  NS_ASSERTION(proxy, "must have proxy!");
+
+  if (!JS_WriteUint32Pair(aWriter, WORKER_DATA_STORES_TAG, 0)) {
+    MOZ_ASSERT(false, "cannot write pair for WORKER_DATA_STORES_TAG!");
+    return false;
+  }
+
+  JS::Rooted<JSObject*> storeObj(aCx, aObj);
+
+  DataStore* store = nullptr;
+  nsresult rv = UNWRAP_OBJECT(DataStore, storeObj, store);
+  if (NS_FAILED(rv)) {
+    MOZ_ASSERT(false, "cannot unwrap the DataStore object!");
+    return false;
+  }
+
+  // We keep the data store alive here.
+  proxy->StoreISupports(store);
+
+  // Construct the nsMainThreadPtrHolder pointing to the data store.
+  nsMainThreadPtrHolder<DataStore>* dataStoreholder =
+    new nsMainThreadPtrHolder<DataStore>(store);
+
+  // And write the dataStoreholder into the buffer.
+  if (!JS_WriteBytes(aWriter, &dataStoreholder, sizeof(dataStoreholder))) {
+    MOZ_ASSERT(false, "cannot write bytes for dataStoreholder!");
+    return false;
+  }
+
+  return true;
+}
+
+static JSStructuredCloneCallbacks kGetDataStoresStructuredCloneCallbacks = {
+  GetDataStoresStructuredCloneCallbacksRead,
+  GetDataStoresStructuredCloneCallbacksWrite,
+  nullptr
+};
+
+// A WorkerMainThreadRunnable to run WorkerNavigator::GetDataStores(...) on the
+// main thread.
+class NavigatorGetDataStoresRunnable MOZ_FINAL : public WorkerMainThreadRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  const nsString mName;
+  ErrorResult& mRv;
+
+public:
+  NavigatorGetDataStoresRunnable(WorkerPrivate* aWorkerPrivate,
+                                 Promise* aWorkerPromise,
+                                 const nsAString& aName,
+                                 ErrorResult& aRv)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mName(aName)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate,
+                             aWorkerPromise,
+                             &kGetDataStoresStructuredCloneCallbacks);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Walk up to the containing window.
+    WorkerPrivate* wp = mWorkerPrivate;
+    while (wp->GetParent()) {
+      wp = wp->GetParent();
+    }
+    nsPIDOMWindow* window = wp->GetWindow();
+
+    // TODO SharedWorker has null window. Don't need to worry about at this
+    // point, though.
+    if (!window) {
+      mRv.Throw(NS_ERROR_FAILURE);
+      return false;
+    }
+
+    nsRefPtr<Promise> promise = Navigator::GetDataStores(window, mName, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+already_AddRefed<Promise>
+WorkerNavigator::GetDataStores(JSContext* aCx,
+                               const nsAString& aName,
+                               ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<NavigatorGetDataStoresRunnable> runnable =
+    new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/Navigator.h
+++ b/dom/workers/Navigator.h
@@ -5,16 +5,26 @@
 
 #ifndef mozilla_dom_workers_navigator_h__
 #define mozilla_dom_workers_navigator_h__
 
 #include "Workers.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 
+// Need this to use Navigator::HasDataStoreSupport() in
+// WorkerNavigatorBinding.cpp
+#include "mozilla/dom/Navigator.h"
+
+namespace mozilla {
+namespace dom {
+class Promise;
+}
+}
+
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerNavigator MOZ_FINAL : public nsWrapperCache
 {
   nsString mAppName;
   nsString mAppVersion;
   nsString mPlatform;
   nsString mUserAgent;
@@ -92,13 +102,17 @@ public:
     return mOnline;
   }
 
   // Worker thread only!
   void SetOnLine(bool aOnline)
   {
     mOnline = aOnline;
   }
+
+  already_AddRefed<Promise> GetDataStores(JSContext* aCx,
+                                          const nsAString& aName,
+                                          ErrorResult& aRv);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_navigator_h__
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -14,29 +14,33 @@ EXPORTS.mozilla.dom += [
 ]
 
 EXPORTS.mozilla.dom.workers += [
     'Workers.h',
 ]
 
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
+    'DataStore.h',
+    'DataStoreCursor.h',
     'FileReaderSync.h',
     'Location.h',
     'MessagePort.h',
     'Navigator.h',
     'SharedWorker.h',
     'URL.h',
     'WorkerFeature.h',
     'XMLHttpRequest.h',
     'XMLHttpRequestUpload.h',
 ]
 
 SOURCES += [
     'ChromeWorkerScope.cpp',
+    'DataStore.cpp',
+    'DataStoreCursor.cpp',
     'File.cpp',
     'FileReaderSync.cpp',
     'Location.cpp',
     'MessagePort.cpp',
     'Navigator.cpp',
     'Principal.cpp',
     'RegisterBindings.cpp',
     'RuntimeService.cpp',