1/*
2 * Copyright (C) 2012-2018 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#include "config.h"
27#include "ArrayProfile.h"
28
29#include "CodeBlock.h"
30#include "JSCInlines.h"
31#include <wtf/CommaPrinter.h>
32#include <wtf/StringPrintStream.h>
33
34namespace JSC {
35
36#if !ASSERT_DISABLED
37const char* const ArrayProfile::s_typeName = "ArrayProfile";
38#endif
39
40// Keep in sync with the order of TypedArrayType.
41const ArrayModes typedArrayModes[NumberOfTypedArrayTypesExcludingDataView] = {
42 Int8ArrayMode,
43 Uint8ArrayMode,
44 Uint8ClampedArrayMode,
45 Int16ArrayMode,
46 Uint16ArrayMode,
47 Int32ArrayMode,
48 Uint32ArrayMode,
49 Float32ArrayMode,
50 Float64ArrayMode,
51};
52
53void dumpArrayModes(PrintStream& out, ArrayModes arrayModes)
54{
55 if (!arrayModes) {
56 out.print("<empty>");
57 return;
58 }
59
60 if (arrayModes == ALL_ARRAY_MODES) {
61 out.print("TOP");
62 return;
63 }
64
65 CommaPrinter comma("|");
66 if (arrayModes & asArrayModesIgnoringTypedArrays(NonArray))
67 out.print(comma, "NonArray");
68 if (arrayModes & asArrayModesIgnoringTypedArrays(NonArrayWithInt32))
69 out.print(comma, "NonArrayWithInt32");
70 if (arrayModes & asArrayModesIgnoringTypedArrays(NonArrayWithDouble))
71 out.print(comma, "NonArrayWithDouble");
72 if (arrayModes & asArrayModesIgnoringTypedArrays(NonArrayWithContiguous))
73 out.print(comma, "NonArrayWithContiguous");
74 if (arrayModes & asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage))
75 out.print(comma, "NonArrayWithArrayStorage");
76 if (arrayModes & asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage))
77 out.print(comma, "NonArrayWithSlowPutArrayStorage");
78 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayClass))
79 out.print(comma, "ArrayClass");
80 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayWithUndecided))
81 out.print(comma, "ArrayWithUndecided");
82 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayWithInt32))
83 out.print(comma, "ArrayWithInt32");
84 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayWithDouble))
85 out.print(comma, "ArrayWithDouble");
86 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayWithContiguous))
87 out.print(comma, "ArrayWithContiguous");
88 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage))
89 out.print(comma, "ArrayWithArrayStorage");
90 if (arrayModes & asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage))
91 out.print(comma, "ArrayWithSlowPutArrayStorage");
92 if (arrayModes & asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithInt32))
93 out.print(comma, "CopyOnWriteArrayWithInt32");
94 if (arrayModes & asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithDouble))
95 out.print(comma, "CopyOnWriteArrayWithDouble");
96 if (arrayModes & asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithContiguous))
97 out.print(comma, "CopyOnWriteArrayWithContiguous");
98
99 if (arrayModes & Int8ArrayMode)
100 out.print(comma, "Int8ArrayMode");
101 if (arrayModes & Int16ArrayMode)
102 out.print(comma, "Int16ArrayMode");
103 if (arrayModes & Int32ArrayMode)
104 out.print(comma, "Int32ArrayMode");
105 if (arrayModes & Uint8ArrayMode)
106 out.print(comma, "Uint8ArrayMode");
107 if (arrayModes & Uint8ClampedArrayMode)
108 out.print(comma, "Uint8ClampedArrayMode");
109 if (arrayModes & Uint16ArrayMode)
110 out.print(comma, "Uint16ArrayMode");
111 if (arrayModes & Uint32ArrayMode)
112 out.print(comma, "Uint32ArrayMode");
113 if (arrayModes & Float32ArrayMode)
114 out.print(comma, "Float32ArrayMode");
115 if (arrayModes & Float64ArrayMode)
116 out.print(comma, "Float64ArrayMode");
117}
118
119void ArrayProfile::computeUpdatedPrediction(const ConcurrentJSLocker& locker, CodeBlock* codeBlock)
120{
121 if (!m_lastSeenStructureID)
122 return;
123
124 Structure* lastSeenStructure = codeBlock->heap()->structureIDTable().get(m_lastSeenStructureID);
125 computeUpdatedPrediction(locker, codeBlock, lastSeenStructure);
126 m_lastSeenStructureID = 0;
127}
128
129void ArrayProfile::computeUpdatedPrediction(const ConcurrentJSLocker&, CodeBlock* codeBlock, Structure* lastSeenStructure)
130{
131 m_observedArrayModes |= arrayModesFromStructure(lastSeenStructure);
132
133 if (!m_didPerformFirstRunPruning
134 && hasTwoOrMoreBitsSet(m_observedArrayModes)) {
135 m_observedArrayModes = arrayModesFromStructure(lastSeenStructure);
136 m_didPerformFirstRunPruning = true;
137 }
138
139 m_mayInterceptIndexedAccesses |=
140 lastSeenStructure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
141 JSGlobalObject* globalObject = codeBlock->globalObject();
142 if (!globalObject->isOriginalArrayStructure(lastSeenStructure)
143 && !globalObject->isOriginalTypedArrayStructure(lastSeenStructure))
144 m_usesOriginalArrayStructures = false;
145}
146
147void ArrayProfile::observeIndexedRead(VM& vm, JSCell* cell, unsigned index)
148{
149 m_lastSeenStructureID = cell->structureID();
150
151 if (JSObject* object = jsDynamicCast<JSObject*>(vm, cell)) {
152 if (hasAnyArrayStorage(object->indexingType()) && index >= object->getVectorLength())
153 setOutOfBounds();
154 else if (index >= object->getArrayLength())
155 setOutOfBounds();
156 }
157
158 if (JSString* string = jsDynamicCast<JSString*>(vm, cell)) {
159 if (index >= string->length())
160 setOutOfBounds();
161 }
162}
163
164CString ArrayProfile::briefDescription(const ConcurrentJSLocker& locker, CodeBlock* codeBlock)
165{
166 computeUpdatedPrediction(locker, codeBlock);
167 return briefDescriptionWithoutUpdating(locker);
168}
169
170CString ArrayProfile::briefDescriptionWithoutUpdating(const ConcurrentJSLocker&)
171{
172 StringPrintStream out;
173 CommaPrinter comma;
174
175 if (m_observedArrayModes)
176 out.print(comma, ArrayModesDump(m_observedArrayModes));
177 if (m_mayStoreToHole)
178 out.print(comma, "Hole");
179 if (m_outOfBounds)
180 out.print(comma, "OutOfBounds");
181 if (m_mayInterceptIndexedAccesses)
182 out.print(comma, "Intercept");
183 if (m_usesOriginalArrayStructures)
184 out.print(comma, "Original");
185
186 return out.toCString();
187}
188
189} // namespace JSC
190
191