LCOV - code coverage report
Current view: directory - js/src - jsweakmap.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 187 127 67.9 %
Date: 2012-06-02 Functions: 17 14 82.4 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Mozilla Foundation
      22                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *   Andreas Gal <gal@mozilla.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include <string.h>
      43                 : #include "jsapi.h"
      44                 : #include "jscntxt.h"
      45                 : #include "jsfriendapi.h"
      46                 : #include "jsgc.h"
      47                 : #include "jsobj.h"
      48                 : #include "jsgcmark.h"
      49                 : #include "jsweakmap.h"
      50                 : 
      51                 : #include "vm/GlobalObject.h"
      52                 : 
      53                 : #include "jsgcinlines.h"
      54                 : #include "jsobjinlines.h"
      55                 : 
      56                 : #include "vm/MethodGuard-inl.h"
      57                 : 
      58                 : using namespace js;
      59                 : 
      60                 : namespace js {
      61                 : 
      62                 : bool
      63          102504 : WeakMapBase::markAllIteratively(JSTracer *tracer)
      64                 : {
      65          102504 :     bool markedAny = false;
      66          102504 :     JSRuntime *rt = tracer->runtime;
      67          122276 :     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next) {
      68           19772 :         if (m->markIteratively(tracer))
      69             610 :             markedAny = true;
      70                 :     }
      71          102504 :     return markedAny;
      72                 : }
      73                 : 
      74                 : void
      75           51092 : WeakMapBase::sweepAll(JSTracer *tracer)
      76                 : {
      77           51092 :     JSRuntime *rt = tracer->runtime;
      78           59820 :     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
      79            8728 :         m->sweep(tracer);
      80           51092 : }
      81                 : 
      82                 : void
      83            1910 : WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
      84                 : {
      85            1910 :     JSRuntime *rt = tracer->runtime;
      86            1911 :     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
      87               1 :         m->traceMappings(tracer);
      88            1910 : }
      89                 : 
      90                 : void
      91           51092 : WeakMapBase::resetWeakMapList(JSRuntime *rt)
      92                 : {
      93                 :     JS_ASSERT(WeakMapNotInList != NULL);
      94                 : 
      95           51092 :     WeakMapBase *m = rt->gcWeakMapList;
      96           51092 :     rt->gcWeakMapList = NULL;
      97          110912 :     while (m) {
      98            8728 :         WeakMapBase *n = m->next;
      99            8728 :         m->next = WeakMapNotInList;
     100            8728 :         m = n;
     101                 :     }
     102           51092 : }
     103                 : 
     104                 : bool
     105               0 : WeakMapBase::saveWeakMapList(JSRuntime *rt, WeakMapVector &vector)
     106                 : {
     107               0 :     WeakMapBase *m = rt->gcWeakMapList;
     108               0 :     while (m) {
     109               0 :         if (!vector.append(m))
     110               0 :             return false;
     111               0 :         m = m->next;
     112                 :     }
     113               0 :     return true;
     114                 : }
     115                 : 
     116                 : void
     117               0 : WeakMapBase::restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector)
     118                 : {
     119               0 :     JS_ASSERT(!rt->gcWeakMapList);
     120               0 :     for (WeakMapBase **p = vector.begin(); p != vector.end(); p++) {
     121               0 :         WeakMapBase *m = *p;
     122               0 :         JS_ASSERT(m->next == WeakMapNotInList);
     123               0 :         m->next = rt->gcWeakMapList;
     124               0 :         rt->gcWeakMapList = m;
     125                 :     }
     126               0 : }
     127                 : 
     128                 : } /* namespace js */
     129                 : 
     130                 : typedef WeakMap<HeapPtr<JSObject>, HeapValue> ObjectValueMap;
     131                 : 
     132                 : static ObjectValueMap *
     133            5705 : GetObjectMap(JSObject *obj)
     134                 : {
     135            5705 :     JS_ASSERT(obj->isWeakMap());
     136            5705 :     return (ObjectValueMap *)obj->getPrivate();
     137                 : }
     138                 : 
     139                 : static JSObject *
     140            1160 : GetKeyArg(JSContext *cx, CallArgs &args) 
     141                 : {
     142            1160 :     Value *vp = &args[0];
     143            1160 :     if (vp->isPrimitive()) {
     144               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
     145               0 :         return NULL;
     146                 :     }
     147            1160 :     JSObject &key = vp->toObject();
     148                 : 
     149                 :     // If the key is from another compartment, and we store the wrapper as the key
     150                 :     // the wrapper might be GC-ed since it is not strong referenced (Bug 673468).
     151                 :     // To avoid this we always use the unwrapped object as the key instead of its
     152                 :     // security wrapper. This also means that if the keys are ever exposed they must
     153                 :     // be re-wrapped (see: JS_NondeterministicGetWeakMapKeys).
     154            1160 :     return JS_UnwrapObject(&key);
     155                 : }
     156                 : 
     157                 : static JSBool
     158             509 : WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
     159                 : {
     160             509 :     CallArgs args = CallArgsFromVp(argc, vp);
     161                 : 
     162                 :     bool ok;
     163             509 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &ok);
     164             509 :     if (!obj)
     165              63 :         return ok;
     166                 : 
     167             446 :     if (args.length() < 1) {
     168                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
     169               0 :                              "WeakMap.has", "0", "s");
     170               0 :         return false;
     171                 :     }
     172             446 :     JSObject *key = GetKeyArg(cx, args);
     173             446 :     if (!key)
     174               0 :         return false;
     175                 : 
     176             446 :     ObjectValueMap *map = GetObjectMap(obj);
     177             446 :     if (map) {
     178             334 :         ObjectValueMap::Ptr ptr = map->lookup(key);
     179             334 :         if (ptr) {
     180              70 :             args.rval() = BooleanValue(true);
     181              70 :             return true;
     182                 :         }
     183                 :     }
     184                 : 
     185             376 :     args.rval() = BooleanValue(false);
     186             376 :     return true;
     187                 : }
     188                 : 
     189                 : static JSBool
     190             269 : WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
     191                 : {
     192             269 :     CallArgs args = CallArgsFromVp(argc, vp);
     193                 : 
     194                 :     bool ok;
     195             269 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &ok);
     196             269 :     if (!obj)
     197              63 :         return ok;
     198                 : 
     199             206 :     if (args.length() < 1) {
     200                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
     201               0 :                              "WeakMap.get", "0", "s");
     202               0 :         return false;
     203                 :     }
     204             206 :     JSObject *key = GetKeyArg(cx, args);
     205             206 :     if (!key)
     206               0 :         return false;
     207                 : 
     208             206 :     ObjectValueMap *map = GetObjectMap(obj);
     209             206 :     if (map) {
     210             178 :         ObjectValueMap::Ptr ptr = map->lookup(key);
     211             178 :         if (ptr) {
     212             175 :             args.rval() = ptr->value;
     213             175 :             return true;
     214                 :         }
     215                 :     }
     216                 : 
     217              31 :     args.rval() = (args.length() > 1) ? args[1] : UndefinedValue();
     218              31 :     return true;
     219                 : }
     220                 : 
     221                 : static JSBool
     222              96 : WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
     223                 : {
     224              96 :     CallArgs args = CallArgsFromVp(argc, vp);
     225                 : 
     226                 :     bool ok;
     227              96 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &ok);
     228              96 :     if (!obj)
     229              63 :         return ok;
     230                 : 
     231              33 :     if (args.length() < 1) {
     232                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
     233               0 :                              "WeakMap.delete", "0", "s");
     234               0 :         return false;
     235                 :     }
     236              33 :     JSObject *key = GetKeyArg(cx, args);
     237              33 :     if (!key)
     238               0 :         return false;
     239                 :     
     240              33 :     ObjectValueMap *map = GetObjectMap(obj);
     241              33 :     if (map) {
     242               6 :         ObjectValueMap::Ptr ptr = map->lookup(key);
     243               6 :         if (ptr) {
     244               6 :             map->remove(ptr);
     245               6 :             args.rval() = BooleanValue(true);
     246               6 :             return true;
     247                 :         }
     248                 :     }
     249                 : 
     250              27 :     args.rval() = BooleanValue(false);
     251              27 :     return true;
     252                 : }
     253                 : 
     254                 : static JSBool
     255             538 : WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
     256                 : {
     257             538 :     CallArgs args = CallArgsFromVp(argc, vp);
     258                 : 
     259                 :     bool ok;
     260             538 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &ok);
     261             538 :     if (!obj)
     262              63 :         return ok;
     263                 : 
     264             475 :     if (args.length() < 1) {
     265                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
     266               0 :                              "WeakMap.set", "0", "s");
     267               0 :         return false;
     268                 :     }
     269             475 :     JSObject *key = GetKeyArg(cx, args);
     270             475 :     if (!key)
     271               0 :         return false;
     272                 :     
     273             475 :     Value value = (args.length() > 1) ? args[1] : UndefinedValue();
     274                 : 
     275             475 :     ObjectValueMap *map = GetObjectMap(obj);
     276             475 :     if (!map) {
     277             122 :         map = cx->new_<ObjectValueMap>(cx, obj);
     278             122 :         if (!map->init()) {
     279               0 :             cx->delete_(map);
     280               0 :             goto out_of_memory;
     281                 :         }
     282             122 :         obj->setPrivate(map);
     283                 :     }
     284                 : 
     285             475 :     if (!map->put(key, value))
     286               0 :         goto out_of_memory;
     287                 : 
     288                 :     // Preserve wrapped native keys to prevent wrapper optimization.
     289             475 :     if (key->getClass()->ext.isWrappedNative) {
     290               0 :         if (!cx->runtime->preserveWrapperCallback ||
     291               0 :             !cx->runtime->preserveWrapperCallback(cx, key)) {
     292               0 :             JS_ReportWarning(cx, "Failed to preserve wrapper of wrapped native weak map key.");
     293                 :         }
     294                 :     }
     295                 : 
     296             475 :     args.rval().setUndefined();
     297             475 :     return true;
     298                 : 
     299                 :   out_of_memory:
     300               0 :     JS_ReportOutOfMemory(cx);
     301               0 :     return false;
     302                 : }
     303                 : 
     304                 : JS_FRIEND_API(JSBool)
     305               0 : JS_NondeterministicGetWeakMapKeys(JSContext *cx, JSObject *obj, JSObject **ret)
     306                 : {
     307               0 :     if (!obj || !obj->isWeakMap()) {
     308               0 :         *ret = NULL;
     309               0 :         return true;
     310                 :     }
     311               0 :     JSObject *arr = NewDenseEmptyArray(cx);
     312               0 :     if (!arr)
     313               0 :         return false;
     314               0 :     ObjectValueMap *map = GetObjectMap(obj);
     315               0 :     if (map) {
     316               0 :         for (ObjectValueMap::Range r = map->nondeterministicAll(); !r.empty(); r.popFront()) {
     317               0 :             JSObject *key = r.front().key;
     318                 :             // Re-wrapping the key (see comment of GetKeyArg)
     319               0 :             if (!JS_WrapObject(cx, &key))
     320               0 :                 return false;
     321                 : 
     322               0 :             if (!js_NewbornArrayPush(cx, arr, ObjectValue(*key)))
     323               0 :                 return false;
     324                 :         }
     325                 :     }
     326               0 :     *ret = arr;
     327               0 :     return true;
     328                 : }
     329                 : 
     330                 : static void
     331            3387 : WeakMap_mark(JSTracer *trc, JSObject *obj)
     332                 : {
     333            3387 :     if (ObjectValueMap *map = GetObjectMap(obj))
     334              22 :         map->trace(trc);
     335            3387 : }
     336                 : 
     337                 : static void
     338            1158 : WeakMap_finalize(JSContext *cx, JSObject *obj)
     339                 : {
     340            1158 :     if (ObjectValueMap *map = GetObjectMap(obj)) {
     341             122 :         map->check();
     342                 : #ifdef DEBUG
     343             122 :         map->~ObjectValueMap();
     344             122 :         memset(static_cast<void *>(map), 0xdc, sizeof(*map));
     345             122 :         cx->free_(map);
     346                 : #else
     347                 :         cx->delete_(map);
     348                 : #endif
     349                 :     }
     350            1158 : }
     351                 : 
     352                 : static JSBool
     353             309 : WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
     354                 : {
     355             309 :     JSObject *obj = NewBuiltinClassInstance(cx, &WeakMapClass);
     356             309 :     if (!obj)
     357               0 :         return false;
     358                 : 
     359             309 :     vp->setObject(*obj);
     360             309 :     return true;
     361                 : }
     362                 : 
     363                 : Class js::WeakMapClass = {
     364                 :     "WeakMap",
     365                 :     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     366                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap),
     367                 :     JS_PropertyStub,         /* addProperty */
     368                 :     JS_PropertyStub,         /* delProperty */
     369                 :     JS_PropertyStub,         /* getProperty */
     370                 :     JS_StrictPropertyStub,   /* setProperty */
     371                 :     JS_EnumerateStub,
     372                 :     JS_ResolveStub,
     373                 :     JS_ConvertStub,
     374                 :     WeakMap_finalize,
     375                 :     NULL,                    /* checkAccess */
     376                 :     NULL,                    /* call        */
     377                 :     NULL,                    /* construct   */
     378                 :     NULL,                    /* xdrObject   */
     379                 :     WeakMap_mark
     380                 : };
     381                 : 
     382                 : static JSFunctionSpec weak_map_methods[] = {
     383                 :     JS_FN("has",    WeakMap_has, 1, 0),
     384                 :     JS_FN("get",    WeakMap_get, 2, 0),
     385                 :     JS_FN("delete", WeakMap_delete, 1, 0),
     386                 :     JS_FN("set",    WeakMap_set, 2, 0),
     387                 :     JS_FS_END
     388                 : };
     389                 : 
     390                 : JSObject *
     391             850 : js_InitWeakMapClass(JSContext *cx, JSObject *obj)
     392                 : {
     393             850 :     JS_ASSERT(obj->isNative());
     394                 : 
     395             850 :     GlobalObject *global = &obj->asGlobal();
     396                 : 
     397             850 :     JSObject *weakMapProto = global->createBlankPrototype(cx, &WeakMapClass);
     398             850 :     if (!weakMapProto)
     399               0 :         return NULL;
     400                 : 
     401                 :     JSFunction *ctor = global->createConstructor(cx, WeakMap_construct, &WeakMapClass,
     402             850 :                                                  CLASS_ATOM(cx, WeakMap), 0);
     403             850 :     if (!ctor)
     404               0 :         return NULL;
     405                 : 
     406             850 :     if (!LinkConstructorAndPrototype(cx, ctor, weakMapProto))
     407               0 :         return NULL;
     408                 : 
     409             850 :     if (!DefinePropertiesAndBrand(cx, weakMapProto, NULL, weak_map_methods))
     410               0 :         return NULL;
     411                 : 
     412             850 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_WeakMap, ctor, weakMapProto))
     413               0 :         return NULL;
     414             850 :     return weakMapProto;
     415                 : }

Generated by: LCOV version 1.7