LCOV - app.info - dom/workers/Worker.cpp

LCOV - code coverage report
| Current view: | directory - dom/workers - Worker.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 165 | 38 | 23.0 %
| Date: | 2012-07-07 | Functions: | 26 | 10 | 38.5 %

           1                 : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is Web Workers.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  *   The Mozilla Foundation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2011
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include "Worker.h"
          40                 :
          41                 : #include "jsapi.h"
          42                 : #include "jsfriendapi.h"
          43                 :
          44                 : #include "EventTarget.h"
          45                 : #include "RuntimeService.h"
          46                 : #include "WorkerPrivate.h"
          47                 :
          48                 : #include "WorkerInlines.h"
          49                 :
          50                 : #define PROPERTY_FLAGS \
          51                 :   (JSPROP_ENUMERATE | JSPROP_SHARED)
          52                 :
          53                 : #define FUNCTION_FLAGS \
          54                 :   JSPROP_ENUMERATE
          55                 :
          56                 : USING_WORKERS_NAMESPACE
          57                 :
          58                 : namespace {
          59                 :
          60                 : class Worker
          61                 : {
          62                 :   static JSClass sClass;
          63                 :   static JSPropertySpec sProperties[];
          64                 :   static JSFunctionSpec sFunctions[];
          65                 :
          66                 :   enum
          67                 :   {
          68                 :     STRING_onerror = 0,
          69                 :     STRING_onmessage,
          70                 :
          71                 :     STRING_COUNT
          72                 :   };
          73                 :
          74                 :   static const char* const sEventStrings[STRING_COUNT];
          75                 :
          76                 : protected:
          77                 :   enum {
          78                 :     // The constructor function holds a WorkerPrivate* in its first reserved
          79                 :     // slot.
          80                 :     CONSTRUCTOR_SLOT_PARENT = 0
          81                 :   };
          82                 :
          83                 : public:
          84                 :   static JSClass*
          85               0 :   Class()
          86                 :   {
          87               0 :     return &sClass;
          88                 :   }
          89                 :
          90                 :   static JSObject*
          91             147 :   InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
          92                 :             bool aMainRuntime)
          93                 :   {
          94                 :     JSObject* proto = js::InitClassWithReserved(aCx, aObj, aParentProto, &sClass, Construct,
          95             147 :                                                 0, sProperties, sFunctions, NULL, NULL);
          96             147 :     if (!proto) {
          97               0 :       return NULL;
          98                 :     }
          99                 :
         100             147 :     if (!aMainRuntime) {
         101               0 :       WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
         102               0 :       parent->AssertIsOnWorkerThread();
         103                 :
         104               0 :       JSObject* constructor = JS_GetConstructor(aCx, proto);
         105               0 :       if (!constructor)
         106               0 :         return NULL;
         107                 :       js::SetFunctionNativeReserved(constructor, CONSTRUCTOR_SLOT_PARENT,
         108               0 :                                     PRIVATE_TO_JSVAL(parent));
         109                 :     }
         110                 :
         111             147 :     return proto;
         112                 :   }
         113                 :
         114                 :   static void
         115               0 :   ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
         116                 :   {
         117               0 :     JS_ASSERT(!JS_IsExceptionPending(aCx));
         118                 :
         119               0 :     WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aObj);
         120               0 :     JS_ASSERT(worker);
         121                 :
         122               0 :     if (aSaveEventHandlers) {
         123               0 :       for (int index = 0; index < STRING_COUNT; index++) {
         124               0 :         const char* name = sEventStrings[index];
         125                 :         jsval listener;
         126               0 :         if (!worker->GetEventListenerOnEventTarget(aCx, name + 2, &listener) ||
         127                 :             !JS_DefineProperty(aCx, aObj, name, listener, NULL, NULL,
         128               0 :                                (PROPERTY_FLAGS & ~JSPROP_SHARED))) {
         129               0 :           JS_ClearPendingException(aCx);
         130                 :         }
         131                 :       }
         132                 :     }
         133                 :
         134               0 :     SetJSPrivateSafeish(aObj, NULL);
         135               0 :   }
         136                 :
         137                 :   static WorkerPrivate*
         138                 :   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName);
         139                 :
         140                 : protected:
         141                 :   static JSBool
         142               0 :   ConstructInternal(JSContext* aCx, unsigned aArgc, jsval* aVp,
         143                 :                     bool aIsChromeWorker)
         144                 :   {
         145               0 :     if (!aArgc) {
         146               0 :       JS_ReportError(aCx, "Constructor requires at least one argument!");
         147               0 :       return false;
         148                 :     }
         149                 :
         150               0 :     JSString* scriptURL = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
         151               0 :     if (!scriptURL) {
         152               0 :       return false;
         153                 :     }
         154                 :
         155                 :     jsval priv = js::GetFunctionNativeReserved(JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp)),
         156               0 :                                                CONSTRUCTOR_SLOT_PARENT);
         157                 :
         158                 :     RuntimeService* runtimeService;
         159                 :     WorkerPrivate* parent;
         160                 :
         161               0 :     if (JSVAL_IS_VOID(priv)) {
         162               0 :       runtimeService = RuntimeService::GetOrCreateService();
         163               0 :       if (!runtimeService) {
         164               0 :         JS_ReportError(aCx, "Failed to create runtime service!");
         165               0 :         return false;
         166                 :       }
         167               0 :       parent = NULL;
         168                 :     }
         169                 :     else {
         170               0 :       runtimeService = RuntimeService::GetService();
         171               0 :       parent = static_cast<WorkerPrivate*>(JSVAL_TO_PRIVATE(priv));
         172               0 :       parent->AssertIsOnWorkerThread();
         173                 :     }
         174                 :
         175               0 :     JSObject* obj = JS_NewObject(aCx, &sClass, nsnull, nsnull);
         176               0 :     if (!obj) {
         177               0 :       return false;
         178                 :     }
         179                 :
         180                 :     WorkerPrivate* worker = WorkerPrivate::Create(aCx, obj, parent, scriptURL,
         181               0 :                                                   aIsChromeWorker);
         182               0 :     if (!worker) {
         183               0 :       return false;
         184                 :     }
         185                 :
         186                 :     // Worker now owned by the JS object.
         187               0 :     SetJSPrivateSafeish(obj, worker);
         188                 :
         189               0 :     if (!runtimeService->RegisterWorker(aCx, worker)) {
         190               0 :       return false;
         191                 :     }
         192                 :
         193               0 :     JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
         194               0 :     return true;
         195                 :   }
         196                 :
         197                 : private:
         198                 :   // No instance of this class should ever be created so these are explicitly
         199                 :   // left without an implementation to prevent linking in case someone tries to
         200                 :   // make one.
         201                 :   Worker();
         202                 :   ~Worker();
         203                 :
         204                 :   static JSBool
         205               0 :   GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
         206                 :   {
         207               0 :     JS_ASSERT(JSID_IS_INT(aIdval));
         208               0 :     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
         209                 :
         210               0 :     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
         211               0 :     WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
         212               0 :     if (!worker) {
         213               0 :       return !JS_IsExceptionPending(aCx);
         214                 :     }
         215                 :
         216               0 :     return worker->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
         217                 :   }
         218                 :
         219                 :   static JSBool
         220               0 :   SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
         221                 :                    jsval* aVp)
         222                 :   {
         223               0 :     JS_ASSERT(JSID_IS_INT(aIdval));
         224               0 :     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
         225                 :
         226               0 :     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
         227               0 :     WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
         228               0 :     if (!worker) {
         229               0 :       return !JS_IsExceptionPending(aCx);
         230                 :     }
         231                 :
         232               0 :     return worker->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
         233                 :   }
         234                 :
         235                 :   static JSBool
         236               0 :   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
         237                 :   {
         238               0 :     return ConstructInternal(aCx, aArgc, aVp, false);
         239                 :   }
         240                 :
         241                 :   static void
         242             147 :   Finalize(JSContext* aCx, JSObject* aObj)
         243                 :   {
         244             147 :     JS_ASSERT(JS_GetClass(aObj) == &sClass);
         245             147 :     WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aObj);
         246             147 :     if (worker) {
         247               0 :       worker->FinalizeInstance(aCx, true);
         248                 :     }
         249             147 :   }
         250                 :
         251                 :   static void
         252              65 :   Trace(JSTracer* aTrc, JSObject* aObj)
         253                 :   {
         254              65 :     JS_ASSERT(JS_GetClass(aObj) == &sClass);
         255              65 :     WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aObj);
         256              65 :     if (worker) {
         257               0 :       worker->TraceInstance(aTrc);
         258                 :     }
         259              65 :   }
         260                 :
         261                 :   static JSBool
         262               0 :   Terminate(JSContext* aCx, unsigned aArgc, jsval* aVp)
         263                 :   {
         264               0 :     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
         265               0 :     if (!obj) {
         266               0 :       return false;
         267                 :     }
         268                 :
         269               0 :     const char*& name = sFunctions[0].name;
         270               0 :     WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
         271               0 :     if (!worker) {
         272               0 :       return !JS_IsExceptionPending(aCx);
         273                 :     }
         274                 :
         275               0 :     return worker->Terminate(aCx);
         276                 :   }
         277                 :
         278                 :   static JSBool
         279               0 :   PostMessage(JSContext* aCx, unsigned aArgc, jsval* aVp)
         280                 :   {
         281               0 :     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
         282               0 :     if (!obj) {
         283               0 :       return false;
         284                 :     }
         285                 :
         286               0 :     const char*& name = sFunctions[1].name;
         287               0 :     WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
         288               0 :     if (!worker) {
         289               0 :       return !JS_IsExceptionPending(aCx);
         290                 :     }
         291                 :
         292                 :     jsval message;
         293               0 :     if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &message)) {
         294               0 :       return false;
         295                 :     }
         296                 :
         297               0 :     return worker->PostMessage(aCx, message);
         298                 :   }
         299                 : };
         300                 :
         301                 : JSClass Worker::sClass = {
         302                 :   "Worker",
         303                 :   JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
         304                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
         305                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
         306                 :   NULL, NULL, NULL, NULL, Trace,
         307                 : };
         308                 :
         309                 : JSPropertySpec Worker::sProperties[] = {
         310            1464 :   { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
         311                 :     GetEventListener, SetEventListener },
         312            1464 :   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
         313                 :     GetEventListener, SetEventListener },
         314                 :   { 0, 0, 0, NULL, NULL }
         315            2928 : };
         316                 :
         317                 : JSFunctionSpec Worker::sFunctions[] = {
         318                 :   JS_FN("terminate", Terminate, 0, FUNCTION_FLAGS),
         319                 :   JS_FN("postMessage", PostMessage, 1, FUNCTION_FLAGS),
         320                 :   JS_FS_END
         321                 : };
         322                 :
         323                 : const char* const Worker::sEventStrings[STRING_COUNT] = {
         324                 :   "onerror",
         325                 :   "onmessage"
         326                 : };
         327                 :
         328                 : class ChromeWorker : public Worker
         329                 : {
         330                 :   static JSClass sClass;
         331                 :
         332                 : public:
         333                 :   static JSClass*
         334               0 :   Class()
         335                 :   {
         336               0 :     return &sClass;
         337                 :   }
         338                 :
         339                 :   static JSObject*
         340             147 :   InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
         341                 :             bool aMainRuntime)
         342                 :   {
         343                 :     JSObject* proto = js::InitClassWithReserved(aCx, aObj, aParentProto, &sClass, Construct,
         344             147 :                                                 0, NULL, NULL, NULL, NULL);
         345             147 :     if (!proto) {
         346               0 :       return NULL;
         347                 :     }
         348                 :
         349             147 :     if (!aMainRuntime) {
         350               0 :       WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
         351               0 :       parent->AssertIsOnWorkerThread();
         352                 :
         353               0 :       JSObject* constructor = JS_GetConstructor(aCx, proto);
         354               0 :       if (!constructor)
         355               0 :         return NULL;
         356                 :       js::SetFunctionNativeReserved(constructor, CONSTRUCTOR_SLOT_PARENT,
         357               0 :                                     PRIVATE_TO_JSVAL(parent));
         358                 :     }
         359                 :
         360             147 :     return proto;
         361                 :   }
         362                 :
         363                 :   static void
         364               0 :   ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
         365                 :   {
         366               0 :     Worker::ClearPrivateSlot(aCx, aObj, aSaveEventHandlers);
         367               0 :   }
         368                 :
         369                 : private:
         370                 :   // No instance of this class should ever be created so these are explicitly
         371                 :   // left without an implementation to prevent linking in case someone tries to
         372                 :   // make one.
         373                 :   ChromeWorker();
         374                 :   ~ChromeWorker();
         375                 :
         376                 :   static WorkerPrivate*
         377                 :   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
         378                 :   {
         379                 :     if (aObj) {
         380                 :       JSClass* classPtr = JS_GetClass(aObj);
         381                 :       if (classPtr == &sClass) {
         382                 :         return GetJSPrivateSafeish<WorkerPrivate>(aObj);
         383                 :       }
         384                 :     }
         385                 :
         386                 :     return Worker::GetInstancePrivate(aCx, aObj, aFunctionName);
         387                 :   }
         388                 :
         389                 :   static JSBool
         390               0 :   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
         391                 :   {
         392               0 :     return ConstructInternal(aCx, aArgc, aVp, true);
         393                 :   }
         394                 :
         395                 :   static void
         396             147 :   Finalize(JSContext* aCx, JSObject* aObj)
         397                 :   {
         398             147 :     JS_ASSERT(JS_GetClass(aObj) == &sClass);
         399             147 :     WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aObj);
         400             147 :     if (worker) {
         401               0 :       worker->FinalizeInstance(aCx, true);
         402                 :     }
         403             147 :   }
         404                 :
         405                 :   static void
         406              65 :   Trace(JSTracer* aTrc, JSObject* aObj)
         407                 :   {
         408              65 :     JS_ASSERT(JS_GetClass(aObj) == &sClass);
         409              65 :     WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aObj);
         410              65 :     if (worker) {
         411               0 :       worker->TraceInstance(aTrc);
         412                 :     }
         413              65 :   }
         414                 : };
         415                 :
         416                 : JSClass ChromeWorker::sClass = {
         417                 :   "ChromeWorker",
         418                 :   JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
         419                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
         420                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
         421                 :   NULL, NULL, NULL, NULL, Trace
         422                 : };
         423                 :
         424                 : WorkerPrivate*
         425               0 : Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
         426                 :                            const char* aFunctionName)
         427                 : {
         428               0 :   JSClass* classPtr = JS_GetClass(aObj);
         429               0 :   if (classPtr == &sClass || classPtr == ChromeWorker::Class()) {
         430               0 :     return GetJSPrivateSafeish<WorkerPrivate>(aObj);
         431                 :   }
         432                 :
         433                 :   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
         434               0 :                        sClass.name, aFunctionName, classPtr->name);
         435               0 :   return NULL;
         436                 : }
         437                 :
         438                 : } // anonymous namespace
         439                 :
         440                 : BEGIN_WORKERS_NAMESPACE
         441                 :
         442                 : namespace worker {
         443                 :
         444                 : JSObject*
         445             147 : InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
         446                 :           bool aMainRuntime)
         447                 : {
         448             147 :   return Worker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
         449                 : }
         450                 :
         451                 : void
         452               0 : ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
         453                 : {
         454               0 :   JSClass* clasp = JS_GetClass(aObj);
         455               0 :   JS_ASSERT(clasp == Worker::Class() || clasp == ChromeWorker::Class());
         456                 :
         457               0 :   if (clasp == ChromeWorker::Class()) {
         458               0 :     ChromeWorker::ClearPrivateSlot(aCx, aObj, aSaveEventHandlers);
         459                 :   }
         460                 :   else {
         461               0 :     Worker::ClearPrivateSlot(aCx, aObj, aSaveEventHandlers);
         462                 :   }
         463               0 : }
         464                 :
         465                 : } // namespace worker
         466                 :
         467                 : WorkerCrossThreadDispatcher*
         468               0 : GetWorkerCrossThreadDispatcher(JSContext* aCx, jsval aWorker)
         469                 : {
         470               0 :   if (JSVAL_IS_PRIMITIVE(aWorker)) {
         471               0 :     return NULL;
         472                 :   }
         473                 :
         474                 :   WorkerPrivate* w =
         475                 :       Worker::GetInstancePrivate(aCx, JSVAL_TO_OBJECT(aWorker),
         476               0 :                                  "GetWorkerCrossThreadDispatcher");
         477               0 :   if (!w) {
         478               0 :     return NULL;
         479                 :   }
         480               0 :   return w->GetCrossThreadDispatcher();
         481                 : }
         482                 :
         483                 :
         484                 : namespace chromeworker {
         485                 :
         486                 : bool
         487             147 : InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
         488                 :           bool aMainRuntime)
         489                 : {
         490             147 :   return !!ChromeWorker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
         491                 : }
         492                 :
         493                 : } // namespace chromeworker
         494                 :
         495                 : bool
         496               0 : ClassIsWorker(JSClass* aClass)
         497                 : {
         498               0 :   return Worker::Class() == aClass || ChromeWorker::Class() == aClass;
         499                 : }
         500                 :
         501            4392 : END_WORKERS_NAMESPACE

Generated by: LCOV version 1.7