summaryrefslogtreecommitdiffstats
path: root/js/src/jsarray.h
blob: d0084731f9db121708db548faf09988738e72f71 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* JS Array interface. */

#ifndef jsarray_h
#define jsarray_h

#include "jsobj.h"
#include "jspubtd.h"

#include "vm/ArrayObject.h"

namespace js {
/* 2^32-2, inclusive */
const uint32_t MAX_ARRAY_INDEX = 4294967294u;

inline bool
IdIsIndex(jsid id, uint32_t* indexp)
{
    if (JSID_IS_INT(id)) {
        int32_t i = JSID_TO_INT(id);
        MOZ_ASSERT(i >= 0);
        *indexp = (uint32_t)i;
        return true;
    }

    if (MOZ_UNLIKELY(!JSID_IS_STRING(id)))
        return false;

    return js::StringIsArrayIndex(JSID_TO_ATOM(id), indexp);
}

// The methods below only create dense boxed arrays.

/* Create a dense array with no capacity allocated, length set to 0. */
extern ArrayObject * JS_FASTCALL
NewDenseEmptyArray(JSContext* cx, HandleObject proto = nullptr,
                   NewObjectKind newKind = GenericObject);

/*
 * Create a dense array with a set length, but without allocating space for the
 * contents. This is useful, e.g., when accepting length from the user.
 */
extern ArrayObject * JS_FASTCALL
NewDenseUnallocatedArray(ExclusiveContext* cx, uint32_t length, HandleObject proto = nullptr,
                         NewObjectKind newKind = GenericObject);

/*
 * Create a dense array with length and capacity == |length|, initialized length set to 0,
 * but with only |EagerAllocationMaxLength| elements allocated.
 */
extern ArrayObject * JS_FASTCALL
NewDensePartlyAllocatedArray(ExclusiveContext* cx, uint32_t length, HandleObject proto = nullptr,
                             NewObjectKind newKind = GenericObject);

/* Create a dense array with length and capacity == 'length', initialized length set to 0. */
extern ArrayObject * JS_FASTCALL
NewDenseFullyAllocatedArray(ExclusiveContext* cx, uint32_t length, HandleObject proto = nullptr,
                            NewObjectKind newKind = GenericObject);

/* Create a dense array from the given array values, which must be rooted */
extern ArrayObject*
NewDenseCopiedArray(ExclusiveContext* cx, uint32_t length, const Value* values,
                    HandleObject proto = nullptr, NewObjectKind newKind = GenericObject);

/* Create a dense array based on templateObject with the given length. */
extern ArrayObject*
NewDenseFullyAllocatedArrayWithTemplate(JSContext* cx, uint32_t length, JSObject* templateObject);

/* Create a dense array with the same copy-on-write elements as another object. */
extern ArrayObject*
NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc::InitialHeap heap);

extern ArrayObject*
NewFullyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
                                  NewObjectKind newKind = GenericObject);

extern ArrayObject*
NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length);

extern ArrayObject*
NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length,
                                    NewObjectKind newKind = GenericObject);

extern ArrayObject*
NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length);

extern ArrayObject*
NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length,
                                               NewObjectKind newKind = GenericObject);

extern ArrayObject*
NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto);

extern ArrayObject*
NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
                          const Value* vp, size_t length,
                          NewObjectKind newKind = GenericObject,
                          ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);

extern ArrayObject*
NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
                                       HandleObject proto = nullptr);

extern bool
NewValuePair(JSContext* cx, const Value& val1, const Value& val2, MutableHandleValue rval);

/*
 * Determines whether a write to the given element on |obj| should fail because
 * |obj| is an Array with a non-writable length, and writing that element would
 * increase the length of the array.
 */
extern bool
WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index);

extern bool
GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp);

extern bool
SetLengthProperty(JSContext* cx, HandleObject obj, double length);

extern bool
ObjectMayHaveExtraIndexedProperties(JSObject* obj);

/*
 * Copy 'length' elements from aobj to vp.
 *
 * This function assumes 'length' is effectively the result of calling
 * GetLengthProperty on aobj. vp must point to rooted memory.
 */
extern bool
GetElements(JSContext* cx, HandleObject aobj, uint32_t length, js::Value* vp);

/* Natives exposed for optimization by the interpreter and JITs. */

extern bool
array_sort(JSContext* cx, unsigned argc, js::Value* vp);

extern bool
array_push(JSContext* cx, unsigned argc, js::Value* vp);

extern bool
array_pop(JSContext* cx, unsigned argc, js::Value* vp);

extern bool
array_join(JSContext* cx, unsigned argc, js::Value* vp);

extern void
ArrayShiftMoveElements(NativeObject* obj);

extern bool
array_shift(JSContext* cx, unsigned argc, js::Value* vp);

extern bool
array_unshift(JSContext* cx, unsigned argc, js::Value* vp);

extern bool
array_slice(JSContext* cx, unsigned argc, js::Value* vp);

extern JSObject*
array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t end, HandleObject result);

extern bool
array_reverse(JSContext* cx, unsigned argc, js::Value* vp);

extern bool
array_splice(JSContext* cx, unsigned argc, js::Value* vp);

extern const JSJitInfo array_splice_info;

/*
 * Append the given (non-hole) value to the end of an array.  The array must be
 * a newborn array -- that is, one which has not been exposed to script for
 * arbitrary manipulation.  (This method optimizes on the assumption that
 * extending the array to accommodate the element will never make the array
 * sparse, which requires that the array be completely filled.)
 */
extern bool
NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v);

extern ArrayObject*
ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt);

#ifdef DEBUG
extern bool
ArrayInfo(JSContext* cx, unsigned argc, Value* vp);
#endif

/* Array constructor native. Exposed only so the JIT can know its address. */
extern bool
ArrayConstructor(JSContext* cx, unsigned argc, Value* vp);

// Like Array constructor, but doesn't perform GetPrototypeFromConstructor.
extern bool
array_construct(JSContext* cx, unsigned argc, Value* vp);

extern bool
IsWrappedArrayConstructor(JSContext* cx, const Value& v, bool* result);

} /* namespace js */

#endif /* jsarray_h */