Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 : #include "jit/TypedObjectPrediction.h"
8 :
9 : using namespace js;
10 : using namespace jit;
11 :
12 : static const size_t ALL_FIELDS = SIZE_MAX;
13 :
14 : // Sets the prediction to be the common prefix of descrA and descrB,
15 : // considering at most the first max fields.
16 : //
17 : // In the case where the current prediction is a specific struct,
18 : // and we are now seeing a second struct, then descrA and descrB will be
19 : // the current and new struct and max will be ALL_FIELDS.
20 : //
21 : // In the case where the current prediction is already a prefix, and
22 : // we are now seeing an additional struct, then descrA will be the
23 : // current struct and max will be the current prefix length, and
24 : // descrB will be the new struct.
25 : //
26 : // (Note that in general it is not important which struct is passed as
27 : // descrA and which struct is passed as descrB, as the operation is
28 : // symmetric.)
29 : void
30 0 : TypedObjectPrediction::markAsCommonPrefix(const StructTypeDescr& descrA,
31 : const StructTypeDescr& descrB,
32 : size_t max)
33 : {
34 : // count is the number of fields in common. It begins as the min
35 : // of the number of fields from descrA, descrB, and max, and then
36 : // is decremented as we find uncommon fields.
37 0 : if (max > descrA.fieldCount())
38 0 : max = descrA.fieldCount();
39 0 : if (max > descrB.fieldCount())
40 0 : max = descrB.fieldCount();
41 :
42 0 : size_t i = 0;
43 0 : for (; i < max; i++) {
44 0 : if (&descrA.fieldName(i) != &descrB.fieldName(i))
45 0 : break;
46 0 : if (&descrA.fieldDescr(i) != &descrB.fieldDescr(i))
47 0 : break;
48 0 : MOZ_ASSERT(descrA.fieldOffset(i) == descrB.fieldOffset(i));
49 : }
50 :
51 0 : if (i == 0) {
52 : // empty prefix is not particularly useful.
53 0 : markInconsistent();
54 : } else {
55 0 : setPrefix(descrA, i);
56 : }
57 0 : }
58 :
59 : void
60 0 : TypedObjectPrediction::addDescr(const TypeDescr& descr)
61 : {
62 0 : switch (predictionKind()) {
63 : case Empty:
64 0 : return setDescr(descr);
65 :
66 : case Inconsistent:
67 0 : return; // keep same state
68 :
69 : case Descr: {
70 0 : if (&descr == data_.descr)
71 0 : return; // keep same state
72 :
73 0 : if (descr.kind() != data_.descr->kind())
74 0 : return markInconsistent();
75 :
76 0 : if (descr.kind() != type::Struct)
77 0 : return markInconsistent();
78 :
79 0 : const StructTypeDescr& structDescr = descr.as<StructTypeDescr>();
80 0 : const StructTypeDescr& currentDescr = data_.descr->as<StructTypeDescr>();
81 0 : markAsCommonPrefix(structDescr, currentDescr, ALL_FIELDS);
82 0 : return;
83 : }
84 :
85 : case Prefix:
86 0 : if (descr.kind() != type::Struct)
87 0 : return markInconsistent();
88 :
89 0 : markAsCommonPrefix(*data_.prefix.descr,
90 : descr.as<StructTypeDescr>(),
91 0 : data_.prefix.fields);
92 0 : return;
93 : }
94 :
95 0 : MOZ_CRASH("Bad predictionKind");
96 : }
97 :
98 : type::Kind
99 0 : TypedObjectPrediction::kind() const
100 : {
101 0 : switch (predictionKind()) {
102 : case TypedObjectPrediction::Empty:
103 : case TypedObjectPrediction::Inconsistent:
104 0 : break;
105 :
106 : case TypedObjectPrediction::Descr:
107 0 : return descr().kind();
108 :
109 : case TypedObjectPrediction::Prefix:
110 0 : return prefix().descr->kind();
111 : }
112 :
113 0 : MOZ_CRASH("Bad prediction kind");
114 : }
115 :
116 : bool
117 0 : TypedObjectPrediction::ofArrayKind() const
118 : {
119 0 : switch (kind()) {
120 : case type::Scalar:
121 : case type::Reference:
122 : case type::Simd:
123 : case type::Struct:
124 0 : return false;
125 :
126 : case type::Array:
127 0 : return true;
128 : }
129 :
130 0 : MOZ_CRASH("Bad kind");
131 : }
132 :
133 : bool
134 0 : TypedObjectPrediction::hasKnownSize(uint32_t* out) const
135 : {
136 0 : switch (predictionKind()) {
137 : case TypedObjectPrediction::Empty:
138 : case TypedObjectPrediction::Inconsistent:
139 0 : return false;
140 :
141 : case TypedObjectPrediction::Descr:
142 0 : *out = descr().size();
143 0 : return true;
144 :
145 : case TypedObjectPrediction::Prefix:
146 : // We only know a prefix of the struct fields, hence we do not
147 : // know its complete size.
148 0 : return false;
149 :
150 : default:
151 0 : MOZ_CRASH("Bad prediction kind");
152 : }
153 : }
154 :
155 : const TypedProto*
156 0 : TypedObjectPrediction::getKnownPrototype() const
157 : {
158 0 : switch (predictionKind()) {
159 : case TypedObjectPrediction::Empty:
160 : case TypedObjectPrediction::Inconsistent:
161 0 : return nullptr;
162 :
163 : case TypedObjectPrediction::Descr:
164 0 : if (descr().is<ComplexTypeDescr>())
165 0 : return &descr().as<ComplexTypeDescr>().instancePrototype();
166 0 : return nullptr;
167 :
168 : case TypedObjectPrediction::Prefix:
169 : // We only know a prefix of the struct fields, hence we cannot
170 : // say for certain what its prototype will be.
171 0 : return nullptr;
172 :
173 : default:
174 0 : MOZ_CRASH("Bad prediction kind");
175 : }
176 : }
177 :
178 : template<typename T>
179 : typename T::Type
180 0 : TypedObjectPrediction::extractType() const
181 : {
182 0 : MOZ_ASSERT(kind() == T::Kind);
183 0 : switch (predictionKind()) {
184 : case TypedObjectPrediction::Empty:
185 : case TypedObjectPrediction::Inconsistent:
186 0 : break;
187 :
188 : case TypedObjectPrediction::Descr:
189 0 : return descr().as<T>().type();
190 :
191 : case TypedObjectPrediction::Prefix:
192 0 : break; // Prefixes are always structs, never scalars etc
193 : }
194 :
195 0 : MOZ_CRASH("Bad prediction kind");
196 : }
197 :
198 : ScalarTypeDescr::Type
199 0 : TypedObjectPrediction::scalarType() const
200 : {
201 0 : return extractType<ScalarTypeDescr>();
202 : }
203 :
204 : ReferenceTypeDescr::Type
205 0 : TypedObjectPrediction::referenceType() const
206 : {
207 0 : return extractType<ReferenceTypeDescr>();
208 : }
209 :
210 : SimdType
211 0 : TypedObjectPrediction::simdType() const
212 : {
213 0 : return descr().as<SimdTypeDescr>().type();
214 : }
215 :
216 : bool
217 0 : TypedObjectPrediction::hasKnownArrayLength(int32_t* length) const
218 : {
219 0 : switch (predictionKind()) {
220 : case TypedObjectPrediction::Empty:
221 : case TypedObjectPrediction::Inconsistent:
222 0 : return false;
223 :
224 : case TypedObjectPrediction::Descr:
225 : // In later patches, this condition will always be true
226 : // so long as this represents an array
227 0 : if (descr().is<ArrayTypeDescr>()) {
228 0 : *length = descr().as<ArrayTypeDescr>().length();
229 0 : return true;
230 : }
231 0 : return false;
232 :
233 : case TypedObjectPrediction::Prefix:
234 : // Prefixes are always structs, never arrays
235 0 : return false;
236 :
237 : default:
238 0 : MOZ_CRASH("Bad prediction kind");
239 : }
240 : }
241 :
242 : TypedObjectPrediction
243 0 : TypedObjectPrediction::arrayElementType() const
244 : {
245 0 : MOZ_ASSERT(ofArrayKind());
246 0 : switch (predictionKind()) {
247 : case TypedObjectPrediction::Empty:
248 : case TypedObjectPrediction::Inconsistent:
249 0 : break;
250 :
251 : case TypedObjectPrediction::Descr:
252 0 : return TypedObjectPrediction(descr().as<ArrayTypeDescr>().elementType());
253 :
254 : case TypedObjectPrediction::Prefix:
255 0 : break; // Prefixes are always structs, never arrays
256 : }
257 0 : MOZ_CRASH("Bad prediction kind");
258 : }
259 :
260 : bool
261 0 : TypedObjectPrediction::hasFieldNamedPrefix(const StructTypeDescr& descr,
262 : size_t fieldCount,
263 : jsid id,
264 : size_t* fieldOffset,
265 : TypedObjectPrediction* out,
266 : size_t* index) const
267 : {
268 : // Find the index of the field |id| if any.
269 0 : if (!descr.fieldIndex(id, index))
270 0 : return false;
271 :
272 : // Check whether the index falls within our known safe prefix.
273 0 : if (*index >= fieldCount)
274 0 : return false;
275 :
276 : // Load the offset and type.
277 0 : *fieldOffset = descr.fieldOffset(*index);
278 0 : *out = TypedObjectPrediction(descr.fieldDescr(*index));
279 0 : return true;
280 : }
281 :
282 : bool
283 0 : TypedObjectPrediction::hasFieldNamed(jsid id,
284 : size_t* fieldOffset,
285 : TypedObjectPrediction* fieldType,
286 : size_t* fieldIndex) const
287 : {
288 0 : MOZ_ASSERT(kind() == type::Struct);
289 :
290 0 : switch (predictionKind()) {
291 : case TypedObjectPrediction::Empty:
292 : case TypedObjectPrediction::Inconsistent:
293 0 : return false;
294 :
295 : case TypedObjectPrediction::Descr:
296 0 : return hasFieldNamedPrefix(
297 0 : descr().as<StructTypeDescr>(), ALL_FIELDS,
298 0 : id, fieldOffset, fieldType, fieldIndex);
299 :
300 : case TypedObjectPrediction::Prefix:
301 : return hasFieldNamedPrefix(
302 0 : *prefix().descr, prefix().fields,
303 0 : id, fieldOffset, fieldType, fieldIndex);
304 :
305 : default:
306 0 : MOZ_CRASH("Bad prediction kind");
307 : }
308 : }
|