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