Source code

Revision control

Other Tools

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
#ifndef builtin_MapObject_h
8
#define builtin_MapObject_h
9
10
#include "builtin/SelfHostingDefines.h"
11
#include "vm/GlobalObject.h"
12
#include "vm/JSObject.h"
13
#include "vm/NativeObject.h"
14
#include "vm/PIC.h"
15
#include "vm/Runtime.h"
16
17
namespace js {
18
19
/*
20
* Comparing two ropes for equality can fail. The js::HashTable template
21
* requires infallible hash() and match() operations. Therefore we require
22
* all values to be converted to hashable form before being used as a key
23
* in a Map or Set object.
24
*
25
* All values except ropes are hashable as-is.
26
*/
27
class HashableValue {
28
// This is used for map and set keys. We use OrderedHashTableRef to update all
29
// nursery keys on minor GC, so a post barrier is not required here.
30
PreBarrieredValue value;
31
32
public:
33
struct Hasher {
34
typedef HashableValue Lookup;
35
static HashNumber hash(const Lookup& v,
36
const mozilla::HashCodeScrambler& hcs) {
37
return v.hash(hcs);
38
}
39
static bool match(const HashableValue& k, const Lookup& l) {
40
return k == l;
41
}
42
static bool isEmpty(const HashableValue& v) {
43
return v.value.isMagic(JS_HASH_KEY_EMPTY);
44
}
45
static void makeEmpty(HashableValue* vp) {
46
vp->value = MagicValue(JS_HASH_KEY_EMPTY);
47
}
48
};
49
50
HashableValue() : value(UndefinedValue()) {}
51
52
MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v);
53
HashNumber hash(const mozilla::HashCodeScrambler& hcs) const;
54
bool operator==(const HashableValue& other) const;
55
HashableValue trace(JSTracer* trc) const;
56
Value get() const { return value.get(); }
57
58
void trace(JSTracer* trc) { TraceEdge(trc, &value, "HashableValue"); }
59
};
60
61
template <typename Wrapper>
62
class WrappedPtrOperations<HashableValue, Wrapper> {
63
public:
64
Value value() const { return static_cast<const Wrapper*>(this)->get().get(); }
65
};
66
67
template <typename Wrapper>
68
class MutableWrappedPtrOperations<HashableValue, Wrapper>
69
: public WrappedPtrOperations<HashableValue, Wrapper> {
70
public:
71
MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v) {
72
return static_cast<Wrapper*>(this)->get().setValue(cx, v);
73
}
74
};
75
76
template <class Key, class Value, class OrderedHashPolicy, class AllocPolicy>
77
class OrderedHashMap;
78
79
template <class T, class OrderedHashPolicy, class AllocPolicy>
80
class OrderedHashSet;
81
82
typedef OrderedHashMap<HashableValue, HeapPtr<Value>, HashableValue::Hasher,
83
ZoneAllocPolicy>
84
ValueMap;
85
86
typedef OrderedHashSet<HashableValue, HashableValue::Hasher, ZoneAllocPolicy>
87
ValueSet;
88
89
template <typename ObjectT>
90
class OrderedHashTableRef;
91
92
struct UnbarrieredHashPolicy;
93
94
class MapObject : public NativeObject {
95
public:
96
enum IteratorKind { Keys, Values, Entries };
97
static_assert(
98
Keys == ITEM_KIND_KEY,
99
"IteratorKind Keys must match self-hosting define for item kind key.");
100
static_assert(Values == ITEM_KIND_VALUE,
101
"IteratorKind Values must match self-hosting define for item "
102
"kind value.");
103
static_assert(
104
Entries == ITEM_KIND_KEY_AND_VALUE,
105
"IteratorKind Entries must match self-hosting define for item kind "
106
"key-and-value.");
107
108
static const JSClass class_;
109
static const JSClass protoClass_;
110
111
enum { NurseryKeysSlot, HasNurseryMemorySlot, SlotCount };
112
113
static MOZ_MUST_USE bool getKeysAndValuesInterleaved(
114
HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> entries);
115
static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
116
static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
117
static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
118
119
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
120
// interfaces, etc.)
121
static uint32_t size(JSContext* cx, HandleObject obj);
122
static MOZ_MUST_USE bool get(JSContext* cx, HandleObject obj, HandleValue key,
123
MutableHandleValue rval);
124
static MOZ_MUST_USE bool has(JSContext* cx, HandleObject obj, HandleValue key,
125
bool* rval);
126
static MOZ_MUST_USE bool delete_(JSContext* cx, HandleObject obj,
127
HandleValue key, bool* rval);
128
129
// Set call for public JSAPI exposure. Does not actually return map object
130
// as stated in spec, expects caller to return a value. for instance, with
131
// webidl maplike/setlike, should return interface object.
132
static MOZ_MUST_USE bool set(JSContext* cx, HandleObject obj, HandleValue key,
133
HandleValue val);
134
static MOZ_MUST_USE bool clear(JSContext* cx, HandleObject obj);
135
static MOZ_MUST_USE bool iterator(JSContext* cx, IteratorKind kind,
136
HandleObject obj, MutableHandleValue iter);
137
138
using UnbarrieredTable =
139
OrderedHashMap<Value, Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
140
friend class OrderedHashTableRef<MapObject>;
141
142
static void sweepAfterMinorGC(JSFreeOp* fop, MapObject* mapobj);
143
144
private:
145
static const ClassSpec classSpec_;
146
static const JSClassOps classOps_;
147
148
static const JSPropertySpec properties[];
149
static const JSFunctionSpec methods[];
150
static const JSPropertySpec staticProperties[];
151
ValueMap* getData() { return static_cast<ValueMap*>(getPrivate()); }
152
static ValueMap& extract(HandleObject o);
153
static ValueMap& extract(const CallArgs& args);
154
static void trace(JSTracer* trc, JSObject* obj);
155
static void finalize(JSFreeOp* fop, JSObject* obj);
156
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
157
158
static bool is(HandleValue v);
159
static bool is(HandleObject o);
160
161
static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args,
162
IteratorKind kind);
163
164
static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
165
static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
166
static MOZ_MUST_USE bool get_impl(JSContext* cx, const CallArgs& args);
167
static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp);
168
static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
169
static MOZ_MUST_USE bool set_impl(JSContext* cx, const CallArgs& args);
170
static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp);
171
static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
172
static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
173
static MOZ_MUST_USE bool keys_impl(JSContext* cx, const CallArgs& args);
174
static MOZ_MUST_USE bool keys(JSContext* cx, unsigned argc, Value* vp);
175
static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
176
static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
177
static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
178
static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
179
static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
180
};
181
182
class MapIteratorObject : public NativeObject {
183
public:
184
static const JSClass class_;
185
186
enum { TargetSlot, RangeSlot, KindSlot, SlotCount };
187
188
static_assert(
189
TargetSlot == ITERATOR_SLOT_TARGET,
190
"TargetSlot must match self-hosting define for iterated object slot.");
191
static_assert(
192
RangeSlot == ITERATOR_SLOT_RANGE,
193
"RangeSlot must match self-hosting define for range or index slot.");
194
static_assert(KindSlot == ITERATOR_SLOT_ITEM_KIND,
195
"KindSlot must match self-hosting define for item kind slot.");
196
197
static const JSFunctionSpec methods[];
198
static MapIteratorObject* create(JSContext* cx, HandleObject mapobj,
199
ValueMap* data,
200
MapObject::IteratorKind kind);
201
static void finalize(JSFreeOp* fop, JSObject* obj);
202
static size_t objectMoved(JSObject* obj, JSObject* old);
203
204
static MOZ_MUST_USE bool next(Handle<MapIteratorObject*> mapIterator,
205
HandleArrayObject resultPairObj, JSContext* cx);
206
207
static JSObject* createResultPair(JSContext* cx);
208
209
private:
210
inline MapObject::IteratorKind kind() const;
211
};
212
213
class SetObject : public NativeObject {
214
public:
215
enum IteratorKind { Keys, Values, Entries };
216
217
static_assert(
218
Keys == ITEM_KIND_KEY,
219
"IteratorKind Keys must match self-hosting define for item kind key.");
220
static_assert(Values == ITEM_KIND_VALUE,
221
"IteratorKind Values must match self-hosting define for item "
222
"kind value.");
223
static_assert(
224
Entries == ITEM_KIND_KEY_AND_VALUE,
225
"IteratorKind Entries must match self-hosting define for item kind "
226
"key-and-value.");
227
228
static const JSClass class_;
229
static const JSClass protoClass_;
230
231
enum { NurseryKeysSlot, HasNurseryMemorySlot, SlotCount };
232
233
static MOZ_MUST_USE bool keys(JSContext* cx, HandleObject obj,
234
JS::MutableHandle<GCVector<JS::Value>> keys);
235
static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
236
static MOZ_MUST_USE bool add(JSContext* cx, HandleObject obj,
237
HandleValue key);
238
static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
239
240
// Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
241
// interfaces, etc.)
242
static SetObject* create(JSContext* cx, HandleObject proto = nullptr);
243
static uint32_t size(JSContext* cx, HandleObject obj);
244
static MOZ_MUST_USE bool has(JSContext* cx, HandleObject obj, HandleValue key,
245
bool* rval);
246
static MOZ_MUST_USE bool clear(JSContext* cx, HandleObject obj);
247
static MOZ_MUST_USE bool iterator(JSContext* cx, IteratorKind kind,
248
HandleObject obj, MutableHandleValue iter);
249
static MOZ_MUST_USE bool delete_(JSContext* cx, HandleObject obj,
250
HandleValue key, bool* rval);
251
252
using UnbarrieredTable =
253
OrderedHashSet<Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
254
friend class OrderedHashTableRef<SetObject>;
255
256
static void sweepAfterMinorGC(JSFreeOp* fop, SetObject* setobj);
257
258
private:
259
static const ClassSpec classSpec_;
260
static const JSClassOps classOps_;
261
262
static const JSPropertySpec properties[];
263
static const JSFunctionSpec methods[];
264
static const JSPropertySpec staticProperties[];
265
266
ValueSet* getData() { return static_cast<ValueSet*>(getPrivate()); }
267
static ValueSet& extract(HandleObject o);
268
static ValueSet& extract(const CallArgs& args);
269
static void trace(JSTracer* trc, JSObject* obj);
270
static void finalize(JSFreeOp* fop, JSObject* obj);
271
static bool construct(JSContext* cx, unsigned argc, Value* vp);
272
273
static bool is(HandleValue v);
274
static bool is(HandleObject o);
275
276
static bool isBuiltinAdd(HandleValue add);
277
278
static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args,
279
IteratorKind kind);
280
281
static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
282
static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
283
static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
284
static MOZ_MUST_USE bool add_impl(JSContext* cx, const CallArgs& args);
285
static MOZ_MUST_USE bool add(JSContext* cx, unsigned argc, Value* vp);
286
static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
287
static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
288
static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
289
static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
290
static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
291
static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
292
static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
293
};
294
295
class SetIteratorObject : public NativeObject {
296
public:
297
static const JSClass class_;
298
299
enum { TargetSlot, RangeSlot, KindSlot, SlotCount };
300
301
static_assert(
302
TargetSlot == ITERATOR_SLOT_TARGET,
303
"TargetSlot must match self-hosting define for iterated object slot.");
304
static_assert(
305
RangeSlot == ITERATOR_SLOT_RANGE,
306
"RangeSlot must match self-hosting define for range or index slot.");
307
static_assert(KindSlot == ITERATOR_SLOT_ITEM_KIND,
308
"KindSlot must match self-hosting define for item kind slot.");
309
310
static const JSFunctionSpec methods[];
311
static SetIteratorObject* create(JSContext* cx, HandleObject setobj,
312
ValueSet* data,
313
SetObject::IteratorKind kind);
314
static void finalize(JSFreeOp* fop, JSObject* obj);
315
static size_t objectMoved(JSObject* obj, JSObject* old);
316
317
static MOZ_MUST_USE bool next(Handle<SetIteratorObject*> setIterator,
318
HandleArrayObject resultObj, JSContext* cx);
319
320
static JSObject* createResult(JSContext* cx);
321
322
private:
323
inline SetObject::IteratorKind kind() const;
324
};
325
326
using SetInitGetPrototypeOp = NativeObject* (*)(JSContext*,
327
Handle<GlobalObject*>);
328
using SetInitIsBuiltinOp = bool (*)(HandleValue);
329
330
template <SetInitGetPrototypeOp getPrototypeOp, SetInitIsBuiltinOp isBuiltinOp>
331
static MOZ_MUST_USE bool IsOptimizableInitForSet(JSContext* cx,
332
HandleObject setObject,
333
HandleValue iterable,
334
bool* optimized) {
335
MOZ_ASSERT(!*optimized);
336
337
if (!iterable.isObject()) {
338
return true;
339
}
340
341
RootedObject array(cx, &iterable.toObject());
342
if (!IsPackedArray(array)) {
343
return true;
344
}
345
346
// Get the canonical prototype object.
347
RootedNativeObject setProto(cx, getPrototypeOp(cx, cx->global()));
348
if (!setProto) {
349
return false;
350
}
351
352
// Ensures setObject's prototype is the canonical prototype.
353
if (setObject->staticPrototype() != setProto) {
354
return true;
355
}
356
357
// Look up the 'add' value on the prototype object.
358
Shape* addShape = setProto->lookup(cx, cx->names().add);
359
if (!addShape || !addShape->isDataProperty()) {
360
return true;
361
}
362
363
// Get the referred value, ensure it holds the canonical add function.
364
RootedValue add(cx, setProto->getSlot(addShape->slot()));
365
if (!isBuiltinOp(add)) {
366
return true;
367
}
368
369
ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
370
if (!stubChain) {
371
return false;
372
}
373
374
return stubChain->tryOptimizeArray(cx, array.as<ArrayObject>(), optimized);
375
}
376
377
} /* namespace js */
378
379
#endif /* builtin_MapObject_h */