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
/* JS Array interface. */
8
9
#ifndef builtin_Array_h
10
#define builtin_Array_h
11
12
#include "mozilla/Attributes.h"
13
#include "mozilla/TextUtils.h"
14
15
#include "jspubtd.h"
16
17
#include "vm/ArrayObject.h"
18
#include "vm/JSObject.h"
19
20
namespace js {
21
/* 2^32-2, inclusive */
22
const uint32_t MAX_ARRAY_INDEX = 4294967294u;
23
24
MOZ_ALWAYS_INLINE bool IdIsIndex(jsid id, uint32_t* indexp) {
25
if (JSID_IS_INT(id)) {
26
int32_t i = JSID_TO_INT(id);
27
MOZ_ASSERT(i >= 0);
28
*indexp = (uint32_t)i;
29
return true;
30
}
31
32
if (MOZ_UNLIKELY(!JSID_IS_STRING(id))) {
33
return false;
34
}
35
36
JSAtom* atom = JSID_TO_ATOM(id);
37
if (atom->length() == 0 ||
38
!mozilla::IsAsciiDigit(atom->latin1OrTwoByteChar(0))) {
39
return false;
40
}
41
42
return js::StringIsArrayIndex(atom, indexp);
43
}
44
45
// The methods below only create dense boxed arrays.
46
47
// Create a dense array with no capacity allocated, length set to 0.
48
extern ArrayObject* JS_FASTCALL
49
NewDenseEmptyArray(JSContext* cx, HandleObject proto = nullptr,
50
NewObjectKind newKind = GenericObject);
51
52
// Create a dense array with a set length, but without allocating space for the
53
// contents. This is useful, e.g., when accepting length from the user.
54
extern ArrayObject* JS_FASTCALL NewDenseUnallocatedArray(
55
JSContext* cx, uint32_t length, HandleObject proto = nullptr,
56
NewObjectKind newKind = GenericObject);
57
58
// Create a dense array with length and capacity == |length|, initialized length
59
// set to 0, but with only |EagerAllocationMaxLength| elements allocated.
60
extern ArrayObject* JS_FASTCALL NewDensePartlyAllocatedArray(
61
JSContext* cx, uint32_t length, HandleObject proto = nullptr,
62
NewObjectKind newKind = GenericObject);
63
64
// Create a dense array with length and capacity == 'length', initialized length
65
// set to 0.
66
extern ArrayObject* JS_FASTCALL NewDenseFullyAllocatedArray(
67
JSContext* cx, uint32_t length, HandleObject proto = nullptr,
68
NewObjectKind newKind = GenericObject);
69
70
// Create a dense array from the given array values, which must be rooted.
71
extern ArrayObject* NewDenseCopiedArray(JSContext* cx, uint32_t length,
72
const Value* values,
73
HandleObject proto = nullptr,
74
NewObjectKind newKind = GenericObject);
75
76
// Create a dense array based on templateObject with the given length.
77
extern ArrayObject* NewDenseFullyAllocatedArrayWithTemplate(
78
JSContext* cx, uint32_t length, JSObject* templateObject);
79
80
// Create a dense array with the same copy-on-write elements as another object.
81
extern ArrayObject* NewDenseCopyOnWriteArray(JSContext* cx,
82
HandleArrayObject templateObject);
83
84
extern ArrayObject* NewFullyAllocatedArrayTryUseGroup(
85
JSContext* cx, HandleObjectGroup group, size_t length,
86
NewObjectKind newKind = GenericObject);
87
88
extern ArrayObject* NewPartlyAllocatedArrayTryUseGroup(JSContext* cx,
89
HandleObjectGroup group,
90
size_t length);
91
92
extern ArrayObject* NewFullyAllocatedArrayTryReuseGroup(
93
JSContext* cx, HandleObject obj, size_t length,
94
NewObjectKind newKind = GenericObject);
95
96
extern ArrayObject* NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx,
97
HandleObject obj,
98
size_t length);
99
100
extern ArrayObject* NewFullyAllocatedArrayForCallingAllocationSite(
101
JSContext* cx, size_t length, NewObjectKind newKind = GenericObject);
102
103
extern ArrayObject* NewPartlyAllocatedArrayForCallingAllocationSite(
104
JSContext* cx, size_t length, HandleObject proto);
105
106
extern ArrayObject* NewCopiedArrayTryUseGroup(
107
JSContext* cx, HandleObjectGroup group, const Value* vp, size_t length,
108
NewObjectKind newKind = GenericObject,
109
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
110
111
extern ArrayObject* NewCopiedArrayForCallingAllocationSite(
112
JSContext* cx, const Value* vp, size_t length,
113
HandleObject proto = nullptr);
114
115
extern ArrayObject* NewArrayWithGroup(JSContext* cx, uint32_t length,
116
HandleObjectGroup group,
117
bool convertDoubleElements);
118
119
extern bool GetLengthProperty(JSContext* cx, HandleObject obj,
120
uint32_t* lengthp);
121
122
extern bool SetLengthProperty(JSContext* cx, HandleObject obj, uint32_t length);
123
124
/*
125
* Copy 'length' elements from aobj to vp.
126
*
127
* This function assumes 'length' is effectively the result of calling
128
* GetLengthProperty on aobj. vp must point to rooted memory.
129
*/
130
extern bool GetElements(JSContext* cx, HandleObject aobj, uint32_t length,
131
js::Value* vp);
132
133
/* Natives exposed for optimization by the interpreter and JITs. */
134
135
extern bool intrinsic_ArrayNativeSort(JSContext* cx, unsigned argc,
136
js::Value* vp);
137
138
extern bool array_push(JSContext* cx, unsigned argc, js::Value* vp);
139
140
extern bool array_pop(JSContext* cx, unsigned argc, js::Value* vp);
141
142
extern bool array_join(JSContext* cx, unsigned argc, js::Value* vp);
143
144
extern void ArrayShiftMoveElements(NativeObject* obj);
145
146
extern bool array_shift(JSContext* cx, unsigned argc, js::Value* vp);
147
148
extern bool array_unshift(JSContext* cx, unsigned argc, js::Value* vp);
149
150
extern bool array_slice(JSContext* cx, unsigned argc, js::Value* vp);
151
152
extern JSObject* ArraySliceDense(JSContext* cx, HandleObject obj, int32_t begin,
153
int32_t end, HandleObject result);
154
155
extern bool array_reverse(JSContext* cx, unsigned argc, js::Value* vp);
156
157
extern bool array_splice(JSContext* cx, unsigned argc, js::Value* vp);
158
159
extern const JSJitInfo array_splice_info;
160
161
/*
162
* Append the given (non-hole) value to the end of an array. The array must be
163
* a newborn array -- that is, one which has not been exposed to script for
164
* arbitrary manipulation. (This method optimizes on the assumption that
165
* extending the array to accommodate the element will never make the array
166
* sparse, which requires that the array be completely filled.)
167
*/
168
extern bool NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v);
169
170
extern ArrayObject* ArrayConstructorOneArg(JSContext* cx,
171
HandleObjectGroup group,
172
int32_t lengthInt);
173
174
#ifdef DEBUG
175
extern bool ArrayInfo(JSContext* cx, unsigned argc, Value* vp);
176
#endif
177
178
/* Array constructor native. Exposed only so the JIT can know its address. */
179
extern bool ArrayConstructor(JSContext* cx, unsigned argc, Value* vp);
180
181
// Like Array constructor, but doesn't perform GetPrototypeFromConstructor.
182
extern bool array_construct(JSContext* cx, unsigned argc, Value* vp);
183
184
extern bool IsCrossRealmArrayConstructor(JSContext* cx, const Value& v,
185
bool* result);
186
187
extern bool ObjectMayHaveExtraIndexedProperties(JSObject* obj);
188
189
// JS::IsArray has multiple overloads, use js::IsArrayFromJit to disambiguate.
190
extern bool IsArrayFromJit(JSContext* cx, HandleObject obj, bool* isArray);
191
192
class MOZ_NON_TEMPORARY_CLASS ArraySpeciesLookup final {
193
/*
194
* An ArraySpeciesLookup holds the following:
195
*
196
* Array.prototype (arrayProto_)
197
* To ensure that the incoming array has the standard proto.
198
*
199
* Array.prototype's shape (arrayProtoShape_)
200
* To ensure that Array.prototype has not been modified.
201
*
202
* Array (arrayConstructor_)
203
* Array's shape (arrayConstructorShape_)
204
* To ensure that Array has not been modified.
205
*
206
* Array.prototype's slot number for constructor (arrayProtoConstructorSlot_)
207
* To quickly retrieve and ensure that the Array constructor
208
* stored in the slot has not changed.
209
*
210
* Array's shape for the @@species getter. (arraySpeciesShape_)
211
* Array's canonical value for @@species (canonicalSpeciesFunc_)
212
* To quickly retrieve and ensure that the @@species getter for Array
213
* has not changed.
214
*
215
* MOZ_INIT_OUTSIDE_CTOR fields below are set in |initialize()|. The
216
* constructor only initializes a |state_| field, that defines whether the
217
* other fields are accessible.
218
*/
219
220
// Pointer to canonical Array.prototype and Array.
221
MOZ_INIT_OUTSIDE_CTOR NativeObject* arrayProto_;
222
MOZ_INIT_OUTSIDE_CTOR NativeObject* arrayConstructor_;
223
224
// Shape of matching Array, and slot containing the @@species
225
// property, and the canonical value.
226
MOZ_INIT_OUTSIDE_CTOR Shape* arrayConstructorShape_;
227
#ifdef DEBUG
228
MOZ_INIT_OUTSIDE_CTOR Shape* arraySpeciesShape_;
229
MOZ_INIT_OUTSIDE_CTOR JSFunction* canonicalSpeciesFunc_;
230
#endif
231
232
// Shape of matching Array.prototype object, and slot containing the
233
// constructor for it.
234
MOZ_INIT_OUTSIDE_CTOR Shape* arrayProtoShape_;
235
MOZ_INIT_OUTSIDE_CTOR uint32_t arrayProtoConstructorSlot_;
236
237
enum class State : uint8_t {
238
// Flags marking the lazy initialization of the above fields.
239
Uninitialized,
240
Initialized,
241
242
// The disabled flag is set when we don't want to try optimizing
243
// anymore because core objects were changed.
244
Disabled
245
};
246
247
State state_ = State::Uninitialized;
248
249
// Initialize the internal fields.
250
void initialize(JSContext* cx);
251
252
// Reset the cache.
253
void reset();
254
255
// Check if the global array-related objects have not been messed with
256
// in a way that would disable this cache.
257
bool isArrayStateStillSane();
258
259
public:
260
/** Construct an |ArraySpeciesLookup| in the uninitialized state. */
261
ArraySpeciesLookup() { reset(); }
262
263
// Try to optimize the @@species lookup for an array.
264
bool tryOptimizeArray(JSContext* cx, ArrayObject* array);
265
266
// Purge the cache and all info associated with it.
267
void purge() {
268
if (state_ == State::Initialized) {
269
reset();
270
}
271
}
272
};
273
274
} /* namespace js */
275
276
#endif /* builtin_Array_h */