~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/jsweakmap.cpp

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * This Source Code Form is subject to the terms of the Mozilla Public
 
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
7
 
 
8
#include <string.h>
 
9
#include "jsapi.h"
 
10
#include "jscntxt.h"
 
11
#include "jsfriendapi.h"
 
12
#include "jsgc.h"
 
13
#include "jsobj.h"
 
14
#include "jsweakmap.h"
 
15
 
 
16
#include "gc/Marking.h"
 
17
#include "vm/GlobalObject.h"
 
18
 
 
19
#include "jsgcinlines.h"
 
20
#include "jsobjinlines.h"
 
21
 
 
22
using namespace js;
 
23
 
 
24
namespace js {
 
25
 
 
26
bool
 
27
WeakMapBase::markAllIteratively(JSTracer *tracer)
 
28
{
 
29
    bool markedAny = false;
 
30
    JSRuntime *rt = tracer->runtime;
 
31
    for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next) {
 
32
        if (m->markIteratively(tracer))
 
33
            markedAny = true;
 
34
    }
 
35
    return markedAny;
 
36
}
 
37
 
 
38
void
 
39
WeakMapBase::sweepAll(JSTracer *tracer)
 
40
{
 
41
    JSRuntime *rt = tracer->runtime;
 
42
    for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
 
43
        m->sweep(tracer);
 
44
}
 
45
 
 
46
void
 
47
WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
 
48
{
 
49
    JSRuntime *rt = tracer->runtime;
 
50
    for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
 
51
        m->traceMappings(tracer);
 
52
}
 
53
 
 
54
void
 
55
WeakMapBase::resetWeakMapList(JSRuntime *rt)
 
56
{
 
57
    JS_ASSERT(WeakMapNotInList != NULL);
 
58
 
 
59
    WeakMapBase *m = rt->gcWeakMapList;
 
60
    rt->gcWeakMapList = NULL;
 
61
    while (m) {
 
62
        WeakMapBase *n = m->next;
 
63
        m->next = WeakMapNotInList;
 
64
        m = n;
 
65
    }
 
66
}
 
67
 
 
68
bool
 
69
WeakMapBase::saveWeakMapList(JSRuntime *rt, WeakMapVector &vector)
 
70
{
 
71
    WeakMapBase *m = rt->gcWeakMapList;
 
72
    while (m) {
 
73
        if (!vector.append(m))
 
74
            return false;
 
75
        m = m->next;
 
76
    }
 
77
    return true;
 
78
}
 
79
 
 
80
void
 
81
WeakMapBase::restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector)
 
82
{
 
83
    JS_ASSERT(!rt->gcWeakMapList);
 
84
    for (WeakMapBase **p = vector.begin(); p != vector.end(); p++) {
 
85
        WeakMapBase *m = *p;
 
86
        JS_ASSERT(m->next == WeakMapNotInList);
 
87
        m->next = rt->gcWeakMapList;
 
88
        rt->gcWeakMapList = m;
 
89
    }
 
90
}
 
91
 
 
92
} /* namespace js */
 
93
 
 
94
typedef WeakMap<EncapsulatedPtrObject, RelocatableValue> ObjectValueMap;
 
95
 
 
96
static ObjectValueMap *
 
97
GetObjectMap(JSObject *obj)
 
98
{
 
99
    JS_ASSERT(obj->isWeakMap());
 
100
    return (ObjectValueMap *)obj->getPrivate();
 
101
}
 
102
 
 
103
static JSObject *
 
104
GetKeyArg(JSContext *cx, CallArgs &args)
 
105
{
 
106
    Value *vp = &args[0];
 
107
    if (vp->isPrimitive()) {
 
108
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
 
109
        return NULL;
 
110
    }
 
111
    return &vp->toObject();
 
112
}
 
113
 
 
114
JS_ALWAYS_INLINE bool
 
115
IsWeakMap(const Value &v)
 
116
{
 
117
    return v.isObject() && v.toObject().hasClass(&WeakMapClass);
 
118
}
 
119
 
 
120
JS_ALWAYS_INLINE bool
 
121
WeakMap_has_impl(JSContext *cx, CallArgs args)
 
122
{
 
123
    JS_ASSERT(IsWeakMap(args.thisv()));
 
124
 
 
125
    if (args.length() < 1) {
 
126
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
 
127
                             "WeakMap.has", "0", "s");
 
128
        return false;
 
129
    }
 
130
    JSObject *key = GetKeyArg(cx, args);
 
131
    if (!key)
 
132
        return false;
 
133
 
 
134
    if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) {
 
135
        if (map->has(key)) {
 
136
            args.rval().setBoolean(true);
 
137
            return true;
 
138
        }
 
139
    }
 
140
 
 
141
    args.rval().setBoolean(false);
 
142
    return true;
 
143
}
 
144
 
 
145
JSBool
 
146
WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
 
147
{
 
148
    CallArgs args = CallArgsFromVp(argc, vp);
 
149
    return CallNonGenericMethod<IsWeakMap, WeakMap_has_impl>(cx, args);
 
150
}
 
151
 
 
152
JS_ALWAYS_INLINE bool
 
153
WeakMap_get_impl(JSContext *cx, CallArgs args)
 
154
{
 
155
    JS_ASSERT(IsWeakMap(args.thisv()));
 
156
 
 
157
    if (args.length() < 1) {
 
158
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
 
159
                             "WeakMap.get", "0", "s");
 
160
        return false;
 
161
    }
 
162
    JSObject *key = GetKeyArg(cx, args);
 
163
    if (!key)
 
164
        return false;
 
165
 
 
166
    if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) {
 
167
        if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
 
168
            // Read barrier to prevent an incorrectly gray value from escaping the
 
169
            // weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp
 
170
            ExposeValueToActiveJS(ptr->value.get());
 
171
 
 
172
            args.rval().set(ptr->value);
 
173
            return true;
 
174
        }
 
175
    }
 
176
 
 
177
    args.rval().set((args.length() > 1) ? args[1] : UndefinedValue());
 
178
    return true;
 
179
}
 
180
 
 
181
JSBool
 
182
WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
 
183
{
 
184
    CallArgs args = CallArgsFromVp(argc, vp);
 
185
    return CallNonGenericMethod<IsWeakMap, WeakMap_get_impl>(cx, args);
 
186
}
 
187
 
 
188
JS_ALWAYS_INLINE bool
 
189
WeakMap_delete_impl(JSContext *cx, CallArgs args)
 
190
{
 
191
    JS_ASSERT(IsWeakMap(args.thisv()));
 
192
 
 
193
    if (args.length() < 1) {
 
194
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
 
195
                             "WeakMap.delete", "0", "s");
 
196
        return false;
 
197
    }
 
198
    JSObject *key = GetKeyArg(cx, args);
 
199
    if (!key)
 
200
        return false;
 
201
 
 
202
    if (ObjectValueMap *map = GetObjectMap(&args.thisv().toObject())) {
 
203
        if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
 
204
            map->remove(ptr);
 
205
            args.rval().setBoolean(true);
 
206
            return true;
 
207
        }
 
208
    }
 
209
 
 
210
    args.rval().setBoolean(false);
 
211
    return true;
 
212
}
 
213
 
 
214
JSBool
 
215
WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
 
216
{
 
217
    CallArgs args = CallArgsFromVp(argc, vp);
 
218
    return CallNonGenericMethod<IsWeakMap, WeakMap_delete_impl>(cx, args);
 
219
}
 
220
 
 
221
JS_ALWAYS_INLINE bool
 
222
WeakMap_set_impl(JSContext *cx, CallArgs args)
 
223
{
 
224
    JS_ASSERT(IsWeakMap(args.thisv()));
 
225
 
 
226
    if (args.length() < 1) {
 
227
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
 
228
                             "WeakMap.set", "0", "s");
 
229
        return false;
 
230
    }
 
231
    RootedObject key(cx, GetKeyArg(cx, args));
 
232
    if (!key)
 
233
        return false;
 
234
 
 
235
    Value value = (args.length() > 1) ? args[1] : UndefinedValue();
 
236
 
 
237
    Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
 
238
    ObjectValueMap *map = GetObjectMap(thisObj);
 
239
    if (!map) {
 
240
        map = cx->new_<ObjectValueMap>(cx, thisObj.get());
 
241
        if (!map->init()) {
 
242
            cx->delete_(map);
 
243
            JS_ReportOutOfMemory(cx);
 
244
            return false;
 
245
        }
 
246
        thisObj->setPrivate(map);
 
247
    }
 
248
 
 
249
    // Preserve wrapped native keys to prevent wrapper optimization.
 
250
    if (key->getClass()->ext.isWrappedNative) {
 
251
        JS_ASSERT(cx->runtime->preserveWrapperCallback);
 
252
        if (!cx->runtime->preserveWrapperCallback(cx, key)) {
 
253
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_WEAKMAP_KEY);
 
254
            return false;
 
255
        }
 
256
    }
 
257
 
 
258
    if (!map->put(key, value)) {
 
259
        JS_ReportOutOfMemory(cx);
 
260
        return false;
 
261
    }
 
262
    HashTableWriteBarrierPost(cx->compartment, map, key);
 
263
 
 
264
    args.rval().setUndefined();
 
265
    return true;
 
266
}
 
267
 
 
268
JSBool
 
269
WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
 
270
{
 
271
    CallArgs args = CallArgsFromVp(argc, vp);
 
272
    return CallNonGenericMethod<IsWeakMap, WeakMap_set_impl>(cx, args);
 
273
}
 
274
 
 
275
JS_FRIEND_API(JSBool)
 
276
JS_NondeterministicGetWeakMapKeys(JSContext *cx, JSObject *obj, JSObject **ret)
 
277
{
 
278
    if (!obj || !obj->isWeakMap()) {
 
279
        *ret = NULL;
 
280
        return true;
 
281
    }
 
282
    RootedObject arr(cx, NewDenseEmptyArray(cx));
 
283
    if (!arr)
 
284
        return false;
 
285
    ObjectValueMap *map = GetObjectMap(obj);
 
286
    if (map) {
 
287
        for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
 
288
            if (!js_NewbornArrayPush(cx, arr, ObjectValue(*r.front().key)))
 
289
                return false;
 
290
        }
 
291
    }
 
292
    *ret = arr;
 
293
    return true;
 
294
}
 
295
 
 
296
static void
 
297
WeakMap_mark(JSTracer *trc, JSObject *obj)
 
298
{
 
299
    if (ObjectValueMap *map = GetObjectMap(obj))
 
300
        map->trace(trc);
 
301
}
 
302
 
 
303
static void
 
304
WeakMap_finalize(FreeOp *fop, JSObject *obj)
 
305
{
 
306
    if (ObjectValueMap *map = GetObjectMap(obj)) {
 
307
        map->check();
 
308
#ifdef DEBUG
 
309
        map->~ObjectValueMap();
 
310
        memset(static_cast<void *>(map), 0xdc, sizeof(*map));
 
311
        fop->free_(map);
 
312
#else
 
313
        fop->delete_(map);
 
314
#endif
 
315
    }
 
316
}
 
317
 
 
318
static JSBool
 
319
WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
 
320
{
 
321
    JSObject *obj = NewBuiltinClassInstance(cx, &WeakMapClass);
 
322
    if (!obj)
 
323
        return false;
 
324
 
 
325
    vp->setObject(*obj);
 
326
    return true;
 
327
}
 
328
 
 
329
Class js::WeakMapClass = {
 
330
    "WeakMap",
 
331
    JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
 
332
    JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap),
 
333
    JS_PropertyStub,         /* addProperty */
 
334
    JS_PropertyStub,         /* delProperty */
 
335
    JS_PropertyStub,         /* getProperty */
 
336
    JS_StrictPropertyStub,   /* setProperty */
 
337
    JS_EnumerateStub,
 
338
    JS_ResolveStub,
 
339
    JS_ConvertStub,
 
340
    WeakMap_finalize,
 
341
    NULL,                    /* checkAccess */
 
342
    NULL,                    /* call        */
 
343
    NULL,                    /* construct   */
 
344
    NULL,                    /* xdrObject   */
 
345
    WeakMap_mark
 
346
};
 
347
 
 
348
static JSFunctionSpec weak_map_methods[] = {
 
349
    JS_FN("has",    WeakMap_has, 1, 0),
 
350
    JS_FN("get",    WeakMap_get, 2, 0),
 
351
    JS_FN("delete", WeakMap_delete, 1, 0),
 
352
    JS_FN("set",    WeakMap_set, 2, 0),
 
353
    JS_FS_END
 
354
};
 
355
 
 
356
JSObject *
 
357
js_InitWeakMapClass(JSContext *cx, JSObject *obj)
 
358
{
 
359
    JS_ASSERT(obj->isNative());
 
360
 
 
361
    Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
362
 
 
363
    RootedObject weakMapProto(cx, global->createBlankPrototype(cx, &WeakMapClass));
 
364
    if (!weakMapProto)
 
365
        return NULL;
 
366
 
 
367
    RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct,
 
368
                                                      CLASS_NAME(cx, WeakMap), 0));
 
369
    if (!ctor)
 
370
        return NULL;
 
371
 
 
372
    if (!LinkConstructorAndPrototype(cx, ctor, weakMapProto))
 
373
        return NULL;
 
374
 
 
375
    if (!DefinePropertiesAndBrand(cx, weakMapProto, NULL, weak_map_methods))
 
376
        return NULL;
 
377
 
 
378
    if (!DefineConstructorAndPrototype(cx, global, JSProto_WeakMap, ctor, weakMapProto))
 
379
        return NULL;
 
380
    return weakMapProto;
 
381
}