LCOV - app.info - js/src/jsweakmap.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jsweakmap.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 187 | 123 | 65.8 %
| Date: | 2012-04-07 | Functions: | 17 | 15 | 88.2 %

           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           77192 : WeakMapBase::markAllIteratively(JSTracer *tracer)
          64                 : {
          65           77192 :     bool markedAny = false;
          66           77192 :     JSRuntime *rt = tracer->runtime;
          67           96974 :     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next) {
          68           19782 :         if (m->markIteratively(tracer))
          69             603 :             markedAny = true;
          70                 :     }
          71           77192 :     return markedAny;
          72                 : }
          73                 :
          74                 : void
          75           38427 : WeakMapBase::sweepAll(JSTracer *tracer)
          76                 : {
          77           38427 :     JSRuntime *rt = tracer->runtime;
          78           47157 :     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
          79            8730 :         m->sweep(tracer);
          80           38427 : }
          81                 :
          82                 : void
          83               0 : WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
          84                 : {
          85               0 :     JSRuntime *rt = tracer->runtime;
          86               0 :     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
          87               0 :         m->traceMappings(tracer);
          88               0 : }
          89                 :
          90                 : void
          91           38472 : WeakMapBase::resetWeakMapList(JSRuntime *rt)
          92                 : {
          93                 :     JS_ASSERT(WeakMapNotInList != NULL);
          94                 :
          95           38472 :     WeakMapBase *m = rt->gcWeakMapList;
          96           38472 :     rt->gcWeakMapList = NULL;
          97           85674 :     while (m) {
          98            8730 :         WeakMapBase *n = m->next;
          99            8730 :         m->next = WeakMapNotInList;
         100            8730 :         m = n;
         101                 :     }
         102           38472 : }
         103                 :
         104                 : bool
         105               9 : WeakMapBase::saveWeakMapList(JSRuntime *rt, WeakMapVector &vector)
         106                 : {
         107               9 :     WeakMapBase *m = rt->gcWeakMapList;
         108              18 :     while (m) {
         109               0 :         if (!vector.append(m))
         110               0 :             return false;
         111               0 :         m = m->next;
         112                 :     }
         113               9 :     return true;
         114                 : }
         115                 :
         116                 : void
         117               9 : WeakMapBase::restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector)
         118                 : {
         119               9 :     JS_ASSERT(!rt->gcWeakMapList);
         120               9 :     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               9 : }
         127                 :
         128                 : } /* namespace js */
         129                 :
         130                 : typedef WeakMap<HeapPtrObject, HeapValue> ObjectValueMap;
         131                 :
         132                 : static ObjectValueMap *
         133            1463 : GetObjectMap(JSObject *obj)
         134                 : {
         135            1463 :     JS_ASSERT(obj->isWeakMap());
         136            1463 :     return (ObjectValueMap *)obj->getPrivate();
         137                 : }
         138                 :
         139                 : static JSObject *
         140             666 : GetKeyArg(JSContext *cx, CallArgs &args)
         141                 : {
         142             666 :     Value *vp = &args[0];
         143             666 :     if (vp->isPrimitive()) {
         144               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
         145               0 :         return NULL;
         146                 :     }
         147             666 :     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             666 :     return JS_UnwrapObject(&key);
         155                 : }
         156                 :
         157                 : static JSBool
         158             279 : WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
         159                 : {
         160             279 :     CallArgs args = CallArgsFromVp(argc, vp);
         161                 :
         162                 :     bool ok;
         163             279 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &ok);
         164             279 :     if (!obj)
         165              63 :         return ok;
         166                 :
         167             216 :     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             216 :     JSObject *key = GetKeyArg(cx, args);
         173             216 :     if (!key)
         174               0 :         return false;
         175                 :
         176             216 :     ObjectValueMap *map = GetObjectMap(obj);
         177             216 :     if (map) {
         178             171 :         ObjectValueMap::Ptr ptr = map->lookup(key);
         179             171 :         if (ptr) {
         180               0 :             args.rval() = BooleanValue(true);
         181               0 :             return true;
         182                 :         }
         183                 :     }
         184                 :
         185             216 :     args.rval() = BooleanValue(false);
         186             216 :     return true;
         187                 : }
         188                 :
         189                 : static JSBool
         190             180 : WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
         191                 : {
         192             180 :     CallArgs args = CallArgsFromVp(argc, vp);
         193                 :
         194                 :     bool ok;
         195             180 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &ok);
         196             180 :     if (!obj)
         197              63 :         return ok;
         198                 :
         199             117 :     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             117 :     JSObject *key = GetKeyArg(cx, args);
         205             117 :     if (!key)
         206               0 :         return false;
         207                 :
         208             117 :     ObjectValueMap *map = GetObjectMap(obj);
         209             117 :     if (map) {
         210              90 :         ObjectValueMap::Ptr ptr = map->lookup(key);
         211              90 :         if (ptr) {
         212              90 :             args.rval() = ptr->value;
         213              90 :             return true;
         214                 :         }
         215                 :     }
         216                 :
         217              27 :     args.rval() = (args.length() > 1) ? args[1] : UndefinedValue();
         218              27 :     return true;
         219                 : }
         220                 :
         221                 : static JSBool
         222              90 : WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
         223                 : {
         224              90 :     CallArgs args = CallArgsFromVp(argc, vp);
         225                 :
         226                 :     bool ok;
         227              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &ok);
         228              90 :     if (!obj)
         229              63 :         return ok;
         230                 :
         231              27 :     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              27 :     JSObject *key = GetKeyArg(cx, args);
         237              27 :     if (!key)
         238               0 :         return false;
         239                 :
         240              27 :     ObjectValueMap *map = GetObjectMap(obj);
         241              27 :     if (map) {
         242               0 :         ObjectValueMap::Ptr ptr = map->lookup(key);
         243               0 :         if (ptr) {
         244               0 :             map->remove(ptr);
         245               0 :             args.rval() = BooleanValue(true);
         246               0 :             return true;
         247                 :         }
         248                 :     }
         249                 :
         250              27 :     args.rval() = BooleanValue(false);
         251              27 :     return true;
         252                 : }
         253                 :
         254                 : static JSBool
         255             369 : WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
         256                 : {
         257             369 :     CallArgs args = CallArgsFromVp(argc, vp);
         258                 :
         259                 :     bool ok;
         260             369 :     JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &ok);
         261             369 :     if (!obj)
         262              63 :         return ok;
         263                 :
         264             306 :     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             306 :     JSObject *key = GetKeyArg(cx, args);
         270             306 :     if (!key)
         271               0 :         return false;
         272                 :
         273             306 :     Value value = (args.length() > 1) ? args[1] : UndefinedValue();
         274                 :
         275             306 :     ObjectValueMap *map = GetObjectMap(obj);
         276             306 :     if (!map) {
         277              54 :         map = cx->new_<ObjectValueMap>(cx, obj);
         278              54 :         if (!map->init()) {
         279               0 :             cx->delete_(map);
         280               0 :             goto out_of_memory;
         281                 :         }
         282              54 :         obj->setPrivate(map);
         283                 :     }
         284                 :
         285             306 :     if (!map->put(key, value))
         286               0 :         goto out_of_memory;
         287                 :
         288                 :     // Preserve wrapped native keys to prevent wrapper optimization.
         289             306 :     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             306 :     args.rval().setUndefined();
         297             306 :     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             128 : WeakMap_mark(JSTracer *trc, JSObject *obj)
         332                 : {
         333             128 :     if (ObjectValueMap *map = GetObjectMap(obj))
         334              18 :         map->trace(trc);
         335             128 : }
         336                 :
         337                 : static void
         338             669 : WeakMap_finalize(FreeOp *fop, JSObject *obj)
         339                 : {
         340             669 :     if (ObjectValueMap *map = GetObjectMap(obj)) {
         341              54 :         map->check();
         342                 : #ifdef DEBUG
         343              54 :         map->~ObjectValueMap();
         344              54 :         memset(static_cast<void *>(map), 0xdc, sizeof(*map));
         345              54 :         fop->free_(map);
         346                 : #else
         347                 :         fop->delete_(map);
         348                 : #endif
         349                 :     }
         350             669 : }
         351                 :
         352                 : static JSBool
         353             135 : WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
         354                 : {
         355             135 :     JSObject *obj = NewBuiltinClassInstance(cx, &WeakMapClass);
         356             135 :     if (!obj)
         357               0 :         return false;
         358                 :
         359             135 :     vp->setObject(*obj);
         360             135 :     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             534 : js_InitWeakMapClass(JSContext *cx, JSObject *obj)
         392                 : {
         393             534 :     JS_ASSERT(obj->isNative());
         394                 :
         395             534 :     GlobalObject *global = &obj->asGlobal();
         396                 :
         397             534 :     JSObject *weakMapProto = global->createBlankPrototype(cx, &WeakMapClass);
         398             534 :     if (!weakMapProto)
         399               0 :         return NULL;
         400                 :
         401                 :     JSFunction *ctor = global->createConstructor(cx, WeakMap_construct,
         402             534 :                                                  CLASS_ATOM(cx, WeakMap), 0);
         403             534 :     if (!ctor)
         404               0 :         return NULL;
         405                 :
         406             534 :     if (!LinkConstructorAndPrototype(cx, ctor, weakMapProto))
         407               0 :         return NULL;
         408                 :
         409             534 :     if (!DefinePropertiesAndBrand(cx, weakMapProto, NULL, weak_map_methods))
         410               0 :         return NULL;
         411                 :
         412             534 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_WeakMap, ctor, weakMapProto))
         413               0 :         return NULL;
         414             534 :     return weakMapProto;
         415                 : }

Generated by: LCOV version 1.7