1/*
2 * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "SpeculatedType.h"
29#include <wtf/LockAlgorithm.h>
30#include <wtf/StdLibExtras.h>
31
32namespace JSC {
33
34/*
35 Structure of the IndexingType
36 =============================
37 Conceptually, the IndexingTypeAndMisc looks like this:
38
39 struct IndexingTypeAndMisc {
40 struct IndexingModeIncludingHistory {
41 struct IndexingMode {
42 struct IndexingType {
43 uint8_t isArray:1; // bit 0
44 uint8_t shape:3; // bit 1 - 3
45 };
46 uint8_t copyOnWrite:1; // bit 4
47 };
48 uint8_t mayHaveIndexedAccessors:1; // bit 5
49 };
50 uint8_t cellLockBits:2; // bit 6 - 7
51 };
52
53 The shape values (e.g. Int32Shape, ContiguousShape, etc) are an enumeration of
54 various shapes (though not necessarily sequential in terms of their values).
55 Hence, shape values are not bitwise exclusive with respect to each other.
56
57 It's also common to refer to shape + copyOnWrite as IndexingShapeWithWritability.
58*/
59
60typedef uint8_t IndexingType;
61
62// Flags for testing the presence of capabilities.
63static const IndexingType IsArray = 0x01;
64
65// The shape of the indexed property storage.
66static const IndexingType NoIndexingShape = 0x00;
67static const IndexingType UndecidedShape = 0x02; // Only useful for arrays.
68static const IndexingType Int32Shape = 0x04;
69static const IndexingType DoubleShape = 0x06;
70static const IndexingType ContiguousShape = 0x08;
71static const IndexingType ArrayStorageShape = 0x0A;
72static const IndexingType SlowPutArrayStorageShape = 0x0C;
73
74static const IndexingType IndexingShapeMask = 0x0E;
75static const IndexingType IndexingShapeShift = 1;
76static const IndexingType NumberOfIndexingShapes = 7;
77static const IndexingType IndexingTypeMask = IndexingShapeMask | IsArray;
78
79// Whether or not the butterfly is copy on write. If it is copy on write then the butterfly is actually a JSImmutableButterfly. This should only ever be set if there are no named properties.
80static const IndexingType CopyOnWrite = 0x10;
81static const IndexingType IndexingShapeAndWritabilityMask = CopyOnWrite | IndexingShapeMask;
82static const IndexingType IndexingModeMask = CopyOnWrite | IndexingTypeMask;
83static const IndexingType NumberOfCopyOnWriteIndexingModes = 3; // We only have copy on write for int32, double, and contiguous shapes.
84static const IndexingType NumberOfArrayIndexingModes = NumberOfIndexingShapes + NumberOfCopyOnWriteIndexingModes;
85
86// Additional flags for tracking the history of the type. These are usually
87// masked off unless you ask for them directly.
88static const IndexingType MayHaveIndexedAccessors = 0x20;
89
90// The IndexingType field of JSCells is stolen for locks and remembering if the object has been a
91// prototype.
92static const IndexingType IndexingTypeLockIsHeld = 0x40;
93static const IndexingType IndexingTypeLockHasParked = 0x80;
94
95// List of acceptable array types.
96static const IndexingType NonArray = 0x0;
97static const IndexingType NonArrayWithInt32 = Int32Shape;
98static const IndexingType NonArrayWithDouble = DoubleShape;
99static const IndexingType NonArrayWithContiguous = ContiguousShape;
100static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape;
101static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape;
102static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
103static const IndexingType ArrayWithUndecided = IsArray | UndecidedShape;
104static const IndexingType ArrayWithInt32 = IsArray | Int32Shape;
105static const IndexingType ArrayWithDouble = IsArray | DoubleShape;
106static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape;
107static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape;
108static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape;
109static const IndexingType CopyOnWriteArrayWithInt32 = IsArray | Int32Shape | CopyOnWrite;
110static const IndexingType CopyOnWriteArrayWithDouble = IsArray | DoubleShape | CopyOnWrite;
111static const IndexingType CopyOnWriteArrayWithContiguous = IsArray | ContiguousShape | CopyOnWrite;
112
113#define ALL_BLANK_INDEXING_TYPES \
114 NonArray: \
115 case ArrayClass
116
117#define ALL_UNDECIDED_INDEXING_TYPES \
118 ArrayWithUndecided
119
120#define ALL_WRITABLE_INT32_INDEXING_TYPES \
121 NonArrayWithInt32: \
122 case ArrayWithInt32
123
124#define ALL_INT32_INDEXING_TYPES \
125 ALL_WRITABLE_INT32_INDEXING_TYPES: \
126 case CopyOnWriteArrayWithInt32
127
128#define ALL_WRITABLE_DOUBLE_INDEXING_TYPES \
129 NonArrayWithDouble: \
130 case ArrayWithDouble \
131
132#define ALL_DOUBLE_INDEXING_TYPES \
133 ALL_WRITABLE_DOUBLE_INDEXING_TYPES: \
134 case CopyOnWriteArrayWithDouble
135
136#define ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES \
137 NonArrayWithContiguous: \
138 case ArrayWithContiguous \
139
140#define ALL_CONTIGUOUS_INDEXING_TYPES \
141 ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES: \
142 case CopyOnWriteArrayWithContiguous
143
144#define ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES \
145 ArrayWithArrayStorage: \
146 case ArrayWithSlowPutArrayStorage
147
148#define ALL_ARRAY_STORAGE_INDEXING_TYPES \
149 NonArrayWithArrayStorage: \
150 case NonArrayWithSlowPutArrayStorage: \
151 case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES
152
153inline bool hasIndexedProperties(IndexingType indexingType)
154{
155 return (indexingType & IndexingShapeMask) != NoIndexingShape;
156}
157
158inline bool hasUndecided(IndexingType indexingType)
159{
160 return (indexingType & IndexingShapeMask) == UndecidedShape;
161}
162
163inline bool hasInt32(IndexingType indexingType)
164{
165 return (indexingType & IndexingShapeMask) == Int32Shape;
166}
167
168inline bool hasDouble(IndexingType indexingType)
169{
170 return (indexingType & IndexingShapeMask) == DoubleShape;
171}
172
173inline bool hasContiguous(IndexingType indexingType)
174{
175 return (indexingType & IndexingShapeMask) == ContiguousShape;
176}
177
178inline bool hasArrayStorage(IndexingType indexingType)
179{
180 return (indexingType & IndexingShapeMask) == ArrayStorageShape;
181}
182
183inline bool hasAnyArrayStorage(IndexingType indexingType)
184{
185 return static_cast<uint8_t>(indexingType & IndexingShapeMask) >= ArrayStorageShape;
186}
187
188inline bool hasSlowPutArrayStorage(IndexingType indexingType)
189{
190 return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape;
191}
192
193inline bool shouldUseSlowPut(IndexingType indexingType)
194{
195 return hasSlowPutArrayStorage(indexingType);
196}
197
198constexpr bool isCopyOnWrite(IndexingType indexingMode)
199{
200 return indexingMode & CopyOnWrite;
201}
202
203inline unsigned arrayIndexFromIndexingType(IndexingType indexingType)
204{
205 if (isCopyOnWrite(indexingType))
206 return ((indexingType & IndexingShapeMask) - UndecidedShape + SlowPutArrayStorageShape) >> IndexingShapeShift;
207 return (indexingType & IndexingShapeMask) >> IndexingShapeShift;
208}
209
210inline IndexingType indexingTypeForValue(JSValue value)
211{
212 if (value.isInt32())
213 return Int32Shape;
214
215 if (value.isNumber() && value.asNumber() == value.asNumber())
216 return DoubleShape;
217
218 return ContiguousShape;
219}
220
221// Return an indexing type that can handle all of the elements of both indexing types.
222IndexingType leastUpperBoundOfIndexingTypes(IndexingType, IndexingType);
223
224IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType, SpeculatedType);
225IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue);
226
227void dumpIndexingType(PrintStream&, IndexingType);
228MAKE_PRINT_ADAPTOR(IndexingTypeDump, IndexingType, dumpIndexingType);
229
230static const IndexingType AllWritableArrayTypes = IndexingShapeMask | IsArray;
231static const IndexingType AllArrayTypes = AllWritableArrayTypes | CopyOnWrite;
232static const IndexingType AllWritableArrayTypesAndHistory = AllWritableArrayTypes | MayHaveIndexedAccessors;
233static const IndexingType AllArrayTypesAndHistory = AllArrayTypes | MayHaveIndexedAccessors;
234
235typedef LockAlgorithm<IndexingType, IndexingTypeLockIsHeld, IndexingTypeLockHasParked> IndexingTypeLockAlgorithm;
236
237} // namespace JSC
238