Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/workers/Worker.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "Worker.h"
8
9
#include "MessageEventRunnable.h"
10
#include "mozilla/dom/WorkerBinding.h"
11
#include "mozilla/TimelineConsumers.h"
12
#include "mozilla/WorkerTimelineMarker.h"
13
#include "nsContentUtils.h"
14
#include "WorkerPrivate.h"
15
16
namespace mozilla {
17
namespace dom {
18
19
/* static */ already_AddRefed<Worker>
20
Worker::Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
21
                    const WorkerOptions& aOptions, ErrorResult& aRv)
22
0
{
23
0
  JSContext* cx = aGlobal.Context();
24
0
25
0
  RefPtr<WorkerPrivate> workerPrivate =
26
0
    WorkerPrivate::Constructor(cx, aScriptURL, false /* aIsChromeWorker */,
27
0
                               WorkerTypeDedicated, aOptions.mName,
28
0
                               VoidCString(), nullptr /*aLoadInfo */, aRv);
29
0
  if (NS_WARN_IF(aRv.Failed())) {
30
0
    return nullptr;
31
0
  }
32
0
33
0
  nsCOMPtr<nsIGlobalObject> globalObject =
34
0
    do_QueryInterface(aGlobal.GetAsSupports());
35
0
36
0
  RefPtr<Worker> worker = new Worker(globalObject, workerPrivate.forget());
37
0
  return worker.forget();
38
0
}
39
40
Worker::Worker(nsIGlobalObject* aGlobalObject,
41
               already_AddRefed<WorkerPrivate> aWorkerPrivate)
42
  : DOMEventTargetHelper(aGlobalObject)
43
  , mWorkerPrivate(std::move(aWorkerPrivate))
44
0
{
45
0
  MOZ_ASSERT(mWorkerPrivate);
46
0
  mWorkerPrivate->SetParentEventTargetRef(this);
47
0
}
48
49
Worker::~Worker()
50
0
{
51
0
  Terminate();
52
0
}
53
54
JSObject*
55
Worker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
56
0
{
57
0
  JS::Rooted<JSObject*> wrapper(aCx,
58
0
    Worker_Binding::Wrap(aCx, this, aGivenProto));
59
0
  if (wrapper) {
60
0
    // Most DOM objects don't assume they have a reflector. If they don't have
61
0
    // one and need one, they create it. But in workers code, we assume that the
62
0
    // reflector is always present.  In order to guarantee that it's always
63
0
    // present, we have to preserve it. Otherwise the GC will happily collect it
64
0
    // as needed.
65
0
    MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
66
0
  }
67
0
68
0
  return wrapper;
69
0
}
70
71
void
72
Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
73
                    const Sequence<JSObject*>& aTransferable,
74
                    ErrorResult& aRv)
75
0
{
76
0
  NS_ASSERT_OWNINGTHREAD(Worker);
77
0
78
0
  if (!mWorkerPrivate ||
79
0
      mWorkerPrivate->ParentStatusProtected() > Running) {
80
0
    return;
81
0
  }
82
0
83
0
  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
84
0
85
0
  aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
86
0
                                                          &transferable);
87
0
  if (NS_WARN_IF(aRv.Failed())) {
88
0
    return;
89
0
  }
90
0
91
0
  RefPtr<MessageEventRunnable> runnable =
92
0
    new MessageEventRunnable(mWorkerPrivate,
93
0
                             WorkerRunnable::WorkerThreadModifyBusyCount);
94
0
95
0
  UniquePtr<AbstractTimelineMarker> start;
96
0
  UniquePtr<AbstractTimelineMarker> end;
97
0
  RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
98
0
  bool isTimelineRecording = timelines && !timelines->IsEmpty();
99
0
100
0
  if (isTimelineRecording) {
101
0
    start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
102
0
      ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
103
0
      : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
104
0
      MarkerTracingType::START);
105
0
  }
106
0
107
0
  runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv);
108
0
109
0
  if (isTimelineRecording) {
110
0
    end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
111
0
      ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
112
0
      : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
113
0
      MarkerTracingType::END);
114
0
    timelines->AddMarkerForAllObservedDocShells(start);
115
0
    timelines->AddMarkerForAllObservedDocShells(end);
116
0
  }
117
0
118
0
  if (NS_WARN_IF(aRv.Failed())) {
119
0
    return;
120
0
  }
121
0
122
0
  if (!runnable->Dispatch()) {
123
0
    aRv.Throw(NS_ERROR_FAILURE);
124
0
  }
125
0
}
126
127
void
128
Worker::Terminate()
129
0
{
130
0
  NS_ASSERT_OWNINGTHREAD(Worker);
131
0
132
0
  if (mWorkerPrivate) {
133
0
    mWorkerPrivate->Cancel();
134
0
    mWorkerPrivate = nullptr;
135
0
  }
136
0
}
137
138
NS_IMPL_CYCLE_COLLECTION_CLASS(Worker)
139
140
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
141
0
  if (tmp->mWorkerPrivate) {
142
0
    tmp->mWorkerPrivate->Traverse(cb);
143
0
  }
144
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
145
146
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
147
0
  tmp->Terminate();
148
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
149
150
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
151
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
152
153
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker)
154
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
155
156
NS_IMPL_ADDREF_INHERITED(Worker, DOMEventTargetHelper)
157
NS_IMPL_RELEASE_INHERITED(Worker, DOMEventTargetHelper)
158
159
} // dom namespace
160
} // mozilla namespace