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 : #ifndef jit_TypePolicy_h
8 : #define jit_TypePolicy_h
9 :
10 : #include "jit/IonTypes.h"
11 : #include "jit/JitAllocPolicy.h"
12 :
13 : namespace js {
14 : namespace jit {
15 :
16 : class MInstruction;
17 : class MDefinition;
18 :
19 : extern MDefinition*
20 : AlwaysBoxAt(TempAllocator& alloc, MInstruction* at, MDefinition* operand);
21 :
22 : // A type policy directs the type analysis phases, which insert conversion,
23 : // boxing, unboxing, and type changes as necessary.
24 : class TypePolicy
25 : {
26 : public:
27 : // Analyze the inputs of the instruction and perform one of the following
28 : // actions for each input:
29 : // * Nothing; the input already type-checks.
30 : // * If untyped, optionally ask the input to try and specialize its value.
31 : // * Replace the operand with a conversion instruction.
32 : // * Insert an unconditional deoptimization (no conversion possible).
33 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) = 0;
34 : };
35 :
36 2503 : struct TypeSpecializationData
37 : {
38 : protected:
39 : // Specifies three levels of specialization:
40 : // - < Value. This input is expected and required.
41 : // - == None. This op should not be specialized.
42 : MIRType specialization_;
43 :
44 18 : MIRType thisTypeSpecialization() {
45 18 : return specialization_;
46 : }
47 :
48 : public:
49 29 : MIRType specialization() const {
50 29 : return specialization_;
51 : }
52 : };
53 :
54 : #define EMPTY_DATA_ \
55 : struct Data \
56 : { \
57 : static TypePolicy* thisTypePolicy(); \
58 : }
59 :
60 : #define INHERIT_DATA_(DATA_TYPE) \
61 : struct Data : public DATA_TYPE \
62 : { \
63 : static TypePolicy* thisTypePolicy(); \
64 : }
65 :
66 : #define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
67 :
68 : class NoTypePolicy
69 : {
70 : public:
71 13739 : struct Data
72 : {
73 1505 : static TypePolicy* thisTypePolicy() {
74 1505 : return nullptr;
75 : }
76 : };
77 : };
78 :
79 : class BoxInputsPolicy final : public TypePolicy
80 : {
81 : public:
82 2276 : SPECIALIZATION_DATA_;
83 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
84 155 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
85 155 : return staticAdjustInputs(alloc, def);
86 : }
87 : };
88 :
89 : class ArithPolicy final : public TypePolicy
90 : {
91 : public:
92 219 : SPECIALIZATION_DATA_;
93 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
94 : };
95 :
96 : class AllDoublePolicy final : public TypePolicy
97 : {
98 : public:
99 0 : EMPTY_DATA_;
100 : MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def);
101 : };
102 :
103 : class BitwisePolicy final : public TypePolicy
104 : {
105 : public:
106 8 : SPECIALIZATION_DATA_;
107 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
108 : };
109 :
110 : class ComparePolicy final : public TypePolicy
111 : {
112 : public:
113 269 : EMPTY_DATA_;
114 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
115 : };
116 :
117 : // Policy for MTest instructions.
118 : class TestPolicy final : public TypePolicy
119 : {
120 : public:
121 1060 : EMPTY_DATA_;
122 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
123 : };
124 :
125 : class TypeBarrierPolicy final : public TypePolicy
126 : {
127 : public:
128 3494 : EMPTY_DATA_;
129 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
130 : };
131 :
132 : class CallPolicy final : public TypePolicy
133 : {
134 : public:
135 1145 : EMPTY_DATA_;
136 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
137 : };
138 :
139 : // Policy for MPow. First operand Double; second Double or Int32.
140 : class PowPolicy final : public TypePolicy
141 : {
142 : public:
143 0 : SPECIALIZATION_DATA_;
144 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
145 : };
146 :
147 : // Expect a string for operand Op. If the input is a Value, it is unboxed.
148 : template <unsigned Op>
149 : class StringPolicy final : public TypePolicy
150 : {
151 : public:
152 15 : EMPTY_DATA_;
153 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
154 6 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
155 6 : return staticAdjustInputs(alloc, def);
156 : }
157 : };
158 :
159 : // Expect a string for operand Op. Else a ToString instruction is inserted.
160 : template <unsigned Op>
161 : class ConvertToStringPolicy final : public TypePolicy
162 : {
163 : public:
164 0 : EMPTY_DATA_;
165 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
166 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
167 0 : return staticAdjustInputs(alloc, def);
168 : }
169 : };
170 :
171 : // Expect an Boolean for operand Op. If the input is a Value, it is unboxed.
172 : template <unsigned Op>
173 : class BooleanPolicy final : private TypePolicy
174 : {
175 : public:
176 : EMPTY_DATA_;
177 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
178 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
179 : return staticAdjustInputs(alloc, def);
180 : }
181 : };
182 :
183 : // Expect an Int for operand Op. If the input is a Value, it is unboxed.
184 : template <unsigned Op>
185 : class IntPolicy final : private TypePolicy
186 : {
187 : public:
188 8 : EMPTY_DATA_;
189 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
190 4 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
191 4 : return staticAdjustInputs(alloc, def);
192 : }
193 : };
194 :
195 : // Expect an Int for operand Op. Else a ToInt32 instruction is inserted.
196 : template <unsigned Op>
197 : class ConvertToInt32Policy final : public TypePolicy
198 : {
199 : public:
200 8 : EMPTY_DATA_;
201 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
202 5 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
203 5 : return staticAdjustInputs(alloc, def);
204 : }
205 : };
206 :
207 : // Expect an Int for operand Op. Else a TruncateToInt32 instruction is inserted.
208 : template <unsigned Op>
209 : class TruncateToInt32Policy final : public TypePolicy
210 : {
211 : public:
212 : EMPTY_DATA_;
213 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
214 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
215 : return staticAdjustInputs(alloc, def);
216 : }
217 : };
218 :
219 : // Expect a double for operand Op. If the input is a Value, it is unboxed.
220 : template <unsigned Op>
221 : class DoublePolicy final : public TypePolicy
222 : {
223 : public:
224 0 : EMPTY_DATA_;
225 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
226 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
227 0 : return staticAdjustInputs(alloc, def);
228 : }
229 : };
230 :
231 : // Expect a float32 for operand Op. If the input is a Value, it is unboxed.
232 : template <unsigned Op>
233 : class Float32Policy final : public TypePolicy
234 : {
235 : public:
236 : EMPTY_DATA_;
237 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
238 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
239 : return staticAdjustInputs(alloc, def);
240 : }
241 : };
242 :
243 : // Expect a float32 OR a double for operand Op, but will prioritize Float32
244 : // if the result type is set as such. If the input is a Value, it is unboxed.
245 : template <unsigned Op>
246 : class FloatingPointPolicy final : public TypePolicy
247 : {
248 : public:
249 0 : SPECIALIZATION_DATA_;
250 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
251 : };
252 :
253 : template <unsigned Op>
254 : class NoFloatPolicy final : public TypePolicy
255 : {
256 : public:
257 44 : EMPTY_DATA_;
258 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
259 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
260 0 : return staticAdjustInputs(alloc, def);
261 : }
262 : };
263 :
264 : // Policy for guarding variadic instructions such as object / array state
265 : // instructions.
266 : template <unsigned FirstOp>
267 : class NoFloatPolicyAfter final : public TypePolicy
268 : {
269 : public:
270 69 : EMPTY_DATA_;
271 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
272 : };
273 :
274 : // Box objects or strings as an input to a ToDouble instruction.
275 : class ToDoublePolicy final : public TypePolicy
276 : {
277 : public:
278 0 : EMPTY_DATA_;
279 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
280 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
281 0 : return staticAdjustInputs(alloc, def);
282 : }
283 : };
284 :
285 : // Box objects, strings and undefined as input to a ToInt32 instruction.
286 : class ToInt32Policy final : public TypePolicy
287 : {
288 : public:
289 22 : EMPTY_DATA_;
290 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
291 15 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
292 15 : return staticAdjustInputs(alloc, def);
293 : }
294 : };
295 :
296 : // Box objects as input to a ToString instruction.
297 : class ToStringPolicy final : public TypePolicy
298 : {
299 : public:
300 4 : EMPTY_DATA_;
301 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
302 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
303 0 : return staticAdjustInputs(alloc, def);
304 : }
305 : };
306 :
307 : template <unsigned Op>
308 : class ObjectPolicy final : public TypePolicy
309 : {
310 : public:
311 1120 : EMPTY_DATA_;
312 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
313 109 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
314 109 : return staticAdjustInputs(alloc, ins);
315 : }
316 : };
317 :
318 : // Single-object input. If the input is a Value, it is unboxed. If it is
319 : // a primitive, we use ValueToNonNullObject.
320 : typedef ObjectPolicy<0> SingleObjectPolicy;
321 :
322 : // Convert an operand to have a type identical to the scalar type of the
323 : // returned type of the instruction.
324 : template <unsigned Op>
325 : class SimdScalarPolicy final : public TypePolicy
326 : {
327 : public:
328 0 : EMPTY_DATA_;
329 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
330 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override {
331 0 : return staticAdjustInputs(alloc, def);
332 : }
333 : };
334 :
335 : class SimdAllPolicy final : public TypePolicy
336 : {
337 : public:
338 0 : SPECIALIZATION_DATA_;
339 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
340 : };
341 :
342 : template <unsigned Op>
343 : class SimdPolicy final : public TypePolicy
344 : {
345 : public:
346 0 : SPECIALIZATION_DATA_;
347 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
348 : };
349 :
350 : class SimdSelectPolicy final : public TypePolicy
351 : {
352 : public:
353 0 : SPECIALIZATION_DATA_;
354 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
355 : };
356 :
357 : class SimdShufflePolicy final : public TypePolicy
358 : {
359 : public:
360 0 : SPECIALIZATION_DATA_;
361 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
362 : };
363 :
364 : // SIMD value-type policy, use the returned type of the instruction to determine
365 : // how to unbox its operand.
366 : template <unsigned Op>
367 : class SimdSameAsReturnedTypePolicy final : public TypePolicy
368 : {
369 : public:
370 0 : EMPTY_DATA_;
371 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
372 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
373 0 : return staticAdjustInputs(alloc, ins);
374 : }
375 : };
376 :
377 : template <unsigned Op>
378 : class BoxPolicy final : public TypePolicy
379 : {
380 : public:
381 2 : EMPTY_DATA_;
382 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
383 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
384 0 : return staticAdjustInputs(alloc, ins);
385 : }
386 : };
387 :
388 : // Boxes everything except inputs of type Type.
389 : template <unsigned Op, MIRType Type>
390 : class BoxExceptPolicy final : public TypePolicy
391 : {
392 : public:
393 0 : EMPTY_DATA_;
394 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
395 0 : MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) {
396 0 : return staticAdjustInputs(alloc, ins);
397 : }
398 : };
399 :
400 : // Box if not a typical property id (string, symbol, int32).
401 : template <unsigned Op>
402 : class CacheIdPolicy final : public TypePolicy
403 : {
404 : public:
405 : EMPTY_DATA_;
406 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
407 : MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) {
408 : return staticAdjustInputs(alloc, ins);
409 : }
410 : };
411 :
412 : // Combine multiple policies.
413 : template <class Lhs, class Rhs>
414 : class MixPolicy final : public TypePolicy
415 : {
416 : public:
417 706 : EMPTY_DATA_;
418 102 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
419 102 : return Lhs::staticAdjustInputs(alloc, ins) && Rhs::staticAdjustInputs(alloc, ins);
420 : }
421 102 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
422 102 : return staticAdjustInputs(alloc, ins);
423 : }
424 : };
425 :
426 : // Combine three policies.
427 : template <class Policy1, class Policy2, class Policy3>
428 : class Mix3Policy final : public TypePolicy
429 : {
430 : public:
431 62 : EMPTY_DATA_;
432 6 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
433 12 : return Policy1::staticAdjustInputs(alloc, ins) &&
434 12 : Policy2::staticAdjustInputs(alloc, ins) &&
435 12 : Policy3::staticAdjustInputs(alloc, ins);
436 : }
437 6 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
438 6 : return staticAdjustInputs(alloc, ins);
439 : }
440 : };
441 :
442 : // Combine four policies. (Missing variadic templates yet?)
443 : template <class Policy1, class Policy2, class Policy3, class Policy4>
444 : class Mix4Policy : public TypePolicy
445 : {
446 : public:
447 0 : EMPTY_DATA_;
448 0 : static MOZ_MUST_USE bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins) {
449 0 : return Policy1::staticAdjustInputs(alloc, ins) &&
450 0 : Policy2::staticAdjustInputs(alloc, ins) &&
451 0 : Policy3::staticAdjustInputs(alloc, ins) &&
452 0 : Policy4::staticAdjustInputs(alloc, ins);
453 : }
454 0 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override {
455 0 : return staticAdjustInputs(alloc, ins);
456 : }
457 : };
458 :
459 : class CallSetElementPolicy final : public TypePolicy
460 : {
461 : public:
462 23 : EMPTY_DATA_;
463 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
464 : };
465 :
466 : // First operand will be boxed to a Value (except for an object)
467 : // Second operand (if specified) will forcefully be unboxed to an object
468 : class InstanceOfPolicy final : public TypePolicy
469 : {
470 : public:
471 0 : EMPTY_DATA_;
472 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
473 : };
474 :
475 : class StoreTypedArrayHolePolicy;
476 : class StoreTypedArrayElementStaticPolicy;
477 :
478 : class StoreUnboxedScalarPolicy : public TypePolicy
479 : {
480 : private:
481 : static MOZ_MUST_USE bool adjustValueInput(TempAllocator& alloc, MInstruction* ins,
482 : Scalar::Type arrayType, MDefinition* value,
483 : int valueOperand);
484 :
485 : friend class StoreTypedArrayHolePolicy;
486 : friend class StoreTypedArrayElementStaticPolicy;
487 :
488 : public:
489 0 : EMPTY_DATA_;
490 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
491 : };
492 :
493 : class StoreTypedArrayHolePolicy final : public StoreUnboxedScalarPolicy
494 : {
495 : public:
496 0 : EMPTY_DATA_;
497 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
498 : };
499 :
500 : class StoreTypedArrayElementStaticPolicy final : public StoreUnboxedScalarPolicy
501 : {
502 : public:
503 0 : EMPTY_DATA_;
504 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
505 : };
506 :
507 : class StoreUnboxedObjectOrNullPolicy final : public TypePolicy
508 : {
509 : public:
510 0 : EMPTY_DATA_;
511 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* def) override;
512 : };
513 :
514 : // Accepts integers and doubles. Everything else is boxed.
515 : class ClampPolicy final : public TypePolicy
516 : {
517 : public:
518 0 : EMPTY_DATA_;
519 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
520 : };
521 :
522 : class FilterTypeSetPolicy final : public TypePolicy
523 : {
524 : public:
525 47 : EMPTY_DATA_;
526 : virtual MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) override;
527 : };
528 :
529 : #undef SPECIALIZATION_DATA_
530 : #undef INHERIT_DATA_
531 : #undef EMPTY_DATA_
532 :
533 : } // namespace jit
534 : } // namespace js
535 :
536 : #endif /* jit_TypePolicy_h */
|