OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of ssa; | |
6 | |
7 /** | |
8 * [InvokeDynamicSpecializer] and its subclasses are helpers to | |
9 * optimize intercepted dynamic calls. It knows what input types | |
10 * would be beneficial for performance, and how to change a invoke | |
11 * dynamic to a builtin instruction (e.g. HIndex, HBitNot). | |
12 */ | |
13 class InvokeDynamicSpecializer { | |
14 const InvokeDynamicSpecializer(); | |
15 | |
16 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
17 Compiler compiler) { | |
18 Selector selector = instruction.selector; | |
19 return TypeMaskFactory.inferredTypeForSelector(selector, compiler); | |
20 } | |
21 | |
22 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
23 Compiler compiler) { | |
24 return null; | |
25 } | |
26 | |
27 Operation operation(ConstantSystem constantSystem) => null; | |
28 | |
29 static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { | |
30 if (selector.kind == SelectorKind.INDEX) { | |
31 return selector.name == '[]' | |
32 ? const IndexSpecializer() | |
33 : const IndexAssignSpecializer(); | |
34 } else if (selector.kind == SelectorKind.OPERATOR) { | |
35 if (selector.name == 'unary-') { | |
36 return const UnaryNegateSpecializer(); | |
37 } else if (selector.name == '~') { | |
38 return const BitNotSpecializer(); | |
39 } else if (selector.name == '+') { | |
40 return const AddSpecializer(); | |
41 } else if (selector.name == '-') { | |
42 return const SubtractSpecializer(); | |
43 } else if (selector.name == '*') { | |
44 return const MultiplySpecializer(); | |
45 } else if (selector.name == '/') { | |
46 return const DivideSpecializer(); | |
47 } else if (selector.name == '~/') { | |
48 return const TruncatingDivideSpecializer(); | |
49 } else if (selector.name == '%') { | |
50 return const ModuloSpecializer(); | |
51 } else if (selector.name == '>>') { | |
52 return const ShiftRightSpecializer(); | |
53 } else if (selector.name == '<<') { | |
54 return const ShiftLeftSpecializer(); | |
55 } else if (selector.name == '&') { | |
56 return const BitAndSpecializer(); | |
57 } else if (selector.name == '|') { | |
58 return const BitOrSpecializer(); | |
59 } else if (selector.name == '^') { | |
60 return const BitXorSpecializer(); | |
61 } else if (selector.name == '==') { | |
62 return const EqualsSpecializer(); | |
63 } else if (selector.name == '<') { | |
64 return const LessSpecializer(); | |
65 } else if (selector.name == '<=') { | |
66 return const LessEqualSpecializer(); | |
67 } else if (selector.name == '>') { | |
68 return const GreaterSpecializer(); | |
69 } else if (selector.name == '>=') { | |
70 return const GreaterEqualSpecializer(); | |
71 } | |
72 } | |
73 return const InvokeDynamicSpecializer(); | |
74 } | |
75 } | |
76 | |
77 class IndexAssignSpecializer extends InvokeDynamicSpecializer { | |
78 const IndexAssignSpecializer(); | |
79 | |
80 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
81 Compiler compiler) { | |
82 if (instruction.inputs[1].isMutableIndexable(compiler)) { | |
83 if (!instruction.inputs[2].isInteger(compiler) | |
84 && compiler.enableTypeAssertions) { | |
85 // We want the right checked mode error. | |
86 return null; | |
87 } | |
88 return new HIndexAssign(instruction.inputs[1], | |
89 instruction.inputs[2], | |
90 instruction.inputs[3], | |
91 instruction.selector); | |
92 } | |
93 return null; | |
94 } | |
95 } | |
96 | |
97 class IndexSpecializer extends InvokeDynamicSpecializer { | |
98 const IndexSpecializer(); | |
99 | |
100 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
101 Compiler compiler) { | |
102 if (!instruction.inputs[1].isIndexablePrimitive(compiler)) return null; | |
103 if (!instruction.inputs[2].isInteger(compiler) | |
104 && compiler.enableTypeAssertions) { | |
105 // We want the right checked mode error. | |
106 return null; | |
107 } | |
108 TypeMask receiverType = | |
109 instruction.getDartReceiver(compiler).instructionType; | |
110 Selector refined = new TypedSelector(receiverType, instruction.selector, | |
111 compiler.world); | |
112 TypeMask type = TypeMaskFactory.inferredTypeForSelector(refined, compiler); | |
113 return new HIndex( | |
114 instruction.inputs[1], instruction.inputs[2], | |
115 instruction.selector, type); | |
116 } | |
117 } | |
118 | |
119 class BitNotSpecializer extends InvokeDynamicSpecializer { | |
120 const BitNotSpecializer(); | |
121 | |
122 UnaryOperation operation(ConstantSystem constantSystem) { | |
123 return constantSystem.bitNot; | |
124 } | |
125 | |
126 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
127 Compiler compiler) { | |
128 // All bitwise operations on primitive types either produce an | |
129 // integer or throw an error. | |
130 JavaScriptBackend backend = compiler.backend; | |
131 if (instruction.inputs[1].isPrimitiveOrNull(compiler)) { | |
132 return backend.uint32Type; | |
133 } | |
134 return super.computeTypeFromInputTypes(instruction, compiler); | |
135 } | |
136 | |
137 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
138 Compiler compiler) { | |
139 JavaScriptBackend backend = compiler.backend; | |
140 HInstruction input = instruction.inputs[1]; | |
141 if (input.isNumber(compiler)) { | |
142 return new HBitNot(input, instruction.selector, | |
143 computeTypeFromInputTypes(instruction, compiler)); | |
144 } | |
145 return null; | |
146 } | |
147 } | |
148 | |
149 class UnaryNegateSpecializer extends InvokeDynamicSpecializer { | |
150 const UnaryNegateSpecializer(); | |
151 | |
152 UnaryOperation operation(ConstantSystem constantSystem) { | |
153 return constantSystem.negate; | |
154 } | |
155 | |
156 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
157 Compiler compiler) { | |
158 TypeMask operandType = instruction.inputs[1].instructionType; | |
159 if (instruction.inputs[1].isNumberOrNull(compiler)) return operandType; | |
160 return super.computeTypeFromInputTypes(instruction, compiler); | |
161 } | |
162 | |
163 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
164 Compiler compiler) { | |
165 HInstruction input = instruction.inputs[1]; | |
166 if (input.isNumber(compiler)) { | |
167 return new HNegate(input, instruction.selector, input.instructionType); | |
168 } | |
169 return null; | |
170 } | |
171 } | |
172 | |
173 abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer { | |
174 const BinaryArithmeticSpecializer(); | |
175 | |
176 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
177 Compiler compiler) { | |
178 HInstruction left = instruction.inputs[1]; | |
179 HInstruction right = instruction.inputs[2]; | |
180 JavaScriptBackend backend = compiler.backend; | |
181 if (left.isIntegerOrNull(compiler) && right.isIntegerOrNull(compiler)) { | |
182 return backend.intType; | |
183 } | |
184 if (left.isNumberOrNull(compiler)) { | |
185 if (left.isDoubleOrNull(compiler) || right.isDoubleOrNull(compiler)) { | |
186 return backend.doubleType; | |
187 } | |
188 return backend.numType; | |
189 } | |
190 return super.computeTypeFromInputTypes(instruction, compiler); | |
191 } | |
192 | |
193 bool isBuiltin(HInvokeDynamic instruction, Compiler compiler) { | |
194 return instruction.inputs[1].isNumber(compiler) | |
195 && instruction.inputs[2].isNumber(compiler); | |
196 } | |
197 | |
198 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
199 Compiler compiler) { | |
200 if (isBuiltin(instruction, compiler)) { | |
201 HInstruction builtin = newBuiltinVariant(instruction, compiler); | |
202 if (builtin != null) return builtin; | |
203 // Even if there is no builtin equivalent instruction, we know | |
204 // the instruction does not have any side effect, and that it | |
205 // can be GVN'ed. | |
206 clearAllSideEffects(instruction); | |
207 } | |
208 return null; | |
209 } | |
210 | |
211 void clearAllSideEffects(HInstruction instruction) { | |
212 instruction.sideEffects.clearAllSideEffects(); | |
213 instruction.sideEffects.clearAllDependencies(); | |
214 instruction.setUseGvn(); | |
215 } | |
216 | |
217 bool inputsArePositiveIntegers(HInstruction instruction, Compiler compiler) { | |
218 HInstruction left = instruction.inputs[1]; | |
219 HInstruction right = instruction.inputs[2]; | |
220 JavaScriptBackend backend = compiler.backend; | |
221 return left.isPositiveIntegerOrNull(compiler) | |
222 && right.isPositiveIntegerOrNull(compiler); | |
223 } | |
224 | |
225 HInstruction newBuiltinVariant(HInvokeDynamic instruction, Compiler compiler); | |
226 | |
227 Selector renameToOptimizedSelector(String name, | |
228 Selector selector, | |
229 Compiler compiler) { | |
230 if (selector.name == name) return selector; | |
231 JavaScriptBackend backend = compiler.backend; | |
232 Selector newSelector = new Selector( | |
233 SelectorKind.CALL, name, backend.interceptorsLibrary, | |
234 selector.argumentCount); | |
235 return selector.mask == null | |
236 ? newSelector | |
237 : new TypedSelector(selector.mask, newSelector, compiler.world); | |
238 } | |
239 } | |
240 | |
241 class AddSpecializer extends BinaryArithmeticSpecializer { | |
242 const AddSpecializer(); | |
243 | |
244 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
245 Compiler compiler) { | |
246 if (inputsArePositiveIntegers(instruction, compiler)) { | |
247 JavaScriptBackend backend = compiler.backend; | |
248 return backend.positiveIntType; | |
249 } | |
250 return super.computeTypeFromInputTypes(instruction, compiler); | |
251 } | |
252 | |
253 BinaryOperation operation(ConstantSystem constantSystem) { | |
254 return constantSystem.add; | |
255 } | |
256 | |
257 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
258 Compiler compiler) { | |
259 return new HAdd( | |
260 instruction.inputs[1], instruction.inputs[2], | |
261 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
262 } | |
263 } | |
264 | |
265 class DivideSpecializer extends BinaryArithmeticSpecializer { | |
266 const DivideSpecializer(); | |
267 | |
268 BinaryOperation operation(ConstantSystem constantSystem) { | |
269 return constantSystem.divide; | |
270 } | |
271 | |
272 TypeMask computeTypeFromInputTypes(HInstruction instruction, | |
273 Compiler compiler) { | |
274 HInstruction left = instruction.inputs[1]; | |
275 JavaScriptBackend backend = compiler.backend; | |
276 if (left.isNumberOrNull(compiler)) { | |
277 return backend.doubleType; | |
278 } | |
279 return super.computeTypeFromInputTypes(instruction, compiler); | |
280 } | |
281 | |
282 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
283 Compiler compiler) { | |
284 JavaScriptBackend backend = compiler.backend; | |
285 return new HDivide( | |
286 instruction.inputs[1], instruction.inputs[2], | |
287 instruction.selector, backend.doubleType); | |
288 } | |
289 } | |
290 | |
291 class ModuloSpecializer extends BinaryArithmeticSpecializer { | |
292 const ModuloSpecializer(); | |
293 | |
294 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
295 Compiler compiler) { | |
296 if (inputsArePositiveIntegers(instruction, compiler)) { | |
297 JavaScriptBackend backend = compiler.backend; | |
298 return backend.positiveIntType; | |
299 } | |
300 return super.computeTypeFromInputTypes(instruction, compiler); | |
301 } | |
302 | |
303 BinaryOperation operation(ConstantSystem constantSystem) { | |
304 return constantSystem.modulo; | |
305 } | |
306 | |
307 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
308 Compiler compiler) { | |
309 // Modulo cannot be mapped to the native operator (different semantics). | |
310 return null; | |
311 } | |
312 } | |
313 | |
314 class MultiplySpecializer extends BinaryArithmeticSpecializer { | |
315 const MultiplySpecializer(); | |
316 | |
317 BinaryOperation operation(ConstantSystem constantSystem) { | |
318 return constantSystem.multiply; | |
319 } | |
320 | |
321 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
322 Compiler compiler) { | |
323 if (inputsArePositiveIntegers(instruction, compiler)) { | |
324 JavaScriptBackend backend = compiler.backend; | |
325 return backend.positiveIntType; | |
326 } | |
327 return super.computeTypeFromInputTypes(instruction, compiler); | |
328 } | |
329 | |
330 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
331 Compiler compiler) { | |
332 return new HMultiply( | |
333 instruction.inputs[1], instruction.inputs[2], | |
334 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
335 } | |
336 } | |
337 | |
338 class SubtractSpecializer extends BinaryArithmeticSpecializer { | |
339 const SubtractSpecializer(); | |
340 | |
341 BinaryOperation operation(ConstantSystem constantSystem) { | |
342 return constantSystem.subtract; | |
343 } | |
344 | |
345 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
346 Compiler compiler) { | |
347 return new HSubtract( | |
348 instruction.inputs[1], instruction.inputs[2], | |
349 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
350 } | |
351 } | |
352 | |
353 class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer { | |
354 const TruncatingDivideSpecializer(); | |
355 | |
356 BinaryOperation operation(ConstantSystem constantSystem) { | |
357 return constantSystem.truncatingDivide; | |
358 } | |
359 | |
360 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
361 Compiler compiler) { | |
362 if (inputsArePositiveIntegers(instruction, compiler)) { | |
363 JavaScriptBackend backend = compiler.backend; | |
364 return backend.positiveIntType; | |
365 } | |
366 return super.computeTypeFromInputTypes(instruction, compiler); | |
367 } | |
368 | |
369 bool isNotZero(HInstruction instruction, Compiler compiler) { | |
370 if (!instruction.isConstantInteger()) return false; | |
371 HConstant rightConstant = instruction; | |
372 IntConstantValue intConstant = rightConstant.constant; | |
373 int count = intConstant.primitiveValue; | |
374 return count != 0; | |
375 } | |
376 | |
377 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
378 Compiler compiler) { | |
379 HInstruction left = instruction.inputs[1]; | |
380 HInstruction right = instruction.inputs[2]; | |
381 if (isBuiltin(instruction, compiler)) { | |
382 if (right.isPositiveInteger(compiler) && isNotZero(right, compiler)) { | |
383 if (left.isUInt31(compiler)) { | |
384 return newBuiltinVariant(instruction, compiler); | |
385 } | |
386 // We can call _tdivFast because the rhs is a 32bit integer | |
387 // and not 0, nor -1. | |
388 instruction.selector = renameToOptimizedSelector( | |
389 '_tdivFast', instruction.selector, compiler); | |
390 } | |
391 clearAllSideEffects(instruction); | |
392 } | |
393 return null; | |
394 } | |
395 | |
396 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
397 Compiler compiler) { | |
398 return new HTruncatingDivide( | |
399 instruction.inputs[1], instruction.inputs[2], | |
400 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
401 } | |
402 } | |
403 | |
404 abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer { | |
405 const BinaryBitOpSpecializer(); | |
406 | |
407 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
408 Compiler compiler) { | |
409 // All bitwise operations on primitive types either produce an | |
410 // integer or throw an error. | |
411 HInstruction left = instruction.inputs[1]; | |
412 JavaScriptBackend backend = compiler.backend; | |
413 if (left.isPrimitiveOrNull(compiler)) { | |
414 return backend.uint32Type; | |
415 } | |
416 return super.computeTypeFromInputTypes(instruction, compiler); | |
417 } | |
418 | |
419 bool argumentLessThan32(HInstruction instruction) { | |
420 if (!instruction.isConstantInteger()) return false; | |
421 HConstant rightConstant = instruction; | |
422 IntConstantValue intConstant = rightConstant.constant; | |
423 int count = intConstant.primitiveValue; | |
424 return count >= 0 && count <= 31; | |
425 } | |
426 | |
427 bool isPositive(HInstruction instruction, Compiler compiler) { | |
428 // TODO: We should use the value range analysis. Currently, ranges | |
429 // are discarded just after the analysis. | |
430 return instruction.isPositiveInteger(compiler); | |
431 } | |
432 } | |
433 | |
434 class ShiftLeftSpecializer extends BinaryBitOpSpecializer { | |
435 const ShiftLeftSpecializer(); | |
436 | |
437 BinaryOperation operation(ConstantSystem constantSystem) { | |
438 return constantSystem.shiftLeft; | |
439 } | |
440 | |
441 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
442 Compiler compiler) { | |
443 HInstruction left = instruction.inputs[1]; | |
444 HInstruction right = instruction.inputs[2]; | |
445 if (left.isNumber(compiler)) { | |
446 if (argumentLessThan32(right)) { | |
447 return newBuiltinVariant(instruction, compiler); | |
448 } | |
449 // Even if there is no builtin equivalent instruction, we know | |
450 // the instruction does not have any side effect, and that it | |
451 // can be GVN'ed. | |
452 clearAllSideEffects(instruction); | |
453 Selector selector = instruction.selector; | |
454 if (isPositive(right, compiler)) { | |
455 instruction.selector = renameToOptimizedSelector( | |
456 '_shlPositive', instruction.selector, compiler); | |
457 } | |
458 } | |
459 return null; | |
460 } | |
461 | |
462 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
463 Compiler compiler) { | |
464 JavaScriptBackend backend = compiler.backend; | |
465 return new HShiftLeft( | |
466 instruction.inputs[1], instruction.inputs[2], | |
467 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
468 } | |
469 } | |
470 | |
471 class ShiftRightSpecializer extends BinaryBitOpSpecializer { | |
472 const ShiftRightSpecializer(); | |
473 | |
474 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
475 Compiler compiler) { | |
476 HInstruction left = instruction.inputs[1]; | |
477 HInstruction right = instruction.inputs[2]; | |
478 JavaScriptBackend backend = compiler.backend; | |
479 if (left.isUInt32(compiler)) return left.instructionType; | |
480 return super.computeTypeFromInputTypes(instruction, compiler); | |
481 } | |
482 | |
483 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
484 Compiler compiler) { | |
485 HInstruction left = instruction.inputs[1]; | |
486 HInstruction right = instruction.inputs[2]; | |
487 if (left.isNumber(compiler)) { | |
488 if (argumentLessThan32(right) && isPositive(left, compiler)) { | |
489 return newBuiltinVariant(instruction, compiler); | |
490 } | |
491 // Even if there is no builtin equivalent instruction, we know | |
492 // the instruction does not have any side effect, and that it | |
493 // can be GVN'ed. | |
494 clearAllSideEffects(instruction); | |
495 if (isPositive(right, compiler) && isPositive(left, compiler)) { | |
496 instruction.selector = renameToOptimizedSelector( | |
497 '_shrBothPositive', instruction.selector, compiler); | |
498 } else if (isPositive(left, compiler) && right.isNumber(compiler)) { | |
499 instruction.selector = renameToOptimizedSelector( | |
500 '_shrReceiverPositive', instruction.selector, compiler); | |
501 } else if (isPositive(right, compiler)) { | |
502 instruction.selector = renameToOptimizedSelector( | |
503 '_shrOtherPositive', instruction.selector, compiler); | |
504 } | |
505 } | |
506 return null; | |
507 } | |
508 | |
509 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
510 Compiler compiler) { | |
511 JavaScriptBackend backend = compiler.backend; | |
512 return new HShiftRight( | |
513 instruction.inputs[1], instruction.inputs[2], | |
514 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
515 } | |
516 | |
517 BinaryOperation operation(ConstantSystem constantSystem) { | |
518 return constantSystem.shiftRight; | |
519 } | |
520 } | |
521 | |
522 class BitOrSpecializer extends BinaryBitOpSpecializer { | |
523 const BitOrSpecializer(); | |
524 | |
525 BinaryOperation operation(ConstantSystem constantSystem) { | |
526 return constantSystem.bitOr; | |
527 } | |
528 | |
529 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
530 Compiler compiler) { | |
531 HInstruction left = instruction.inputs[1]; | |
532 HInstruction right = instruction.inputs[2]; | |
533 JavaScriptBackend backend = compiler.backend; | |
534 if (left.isUInt31(compiler) && right.isUInt31(compiler)) { | |
535 return backend.uint31Type; | |
536 } | |
537 return super.computeTypeFromInputTypes(instruction, compiler); | |
538 } | |
539 | |
540 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
541 Compiler compiler) { | |
542 JavaScriptBackend backend = compiler.backend; | |
543 return new HBitOr( | |
544 instruction.inputs[1], instruction.inputs[2], | |
545 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
546 } | |
547 } | |
548 | |
549 class BitAndSpecializer extends BinaryBitOpSpecializer { | |
550 const BitAndSpecializer(); | |
551 | |
552 BinaryOperation operation(ConstantSystem constantSystem) { | |
553 return constantSystem.bitAnd; | |
554 } | |
555 | |
556 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
557 Compiler compiler) { | |
558 HInstruction left = instruction.inputs[1]; | |
559 HInstruction right = instruction.inputs[2]; | |
560 JavaScriptBackend backend = compiler.backend; | |
561 if (left.isUInt31(compiler) || right.isUInt31(compiler)) { | |
562 return backend.uint31Type; | |
563 } | |
564 return super.computeTypeFromInputTypes(instruction, compiler); | |
565 } | |
566 | |
567 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
568 Compiler compiler) { | |
569 JavaScriptBackend backend = compiler.backend; | |
570 return new HBitAnd( | |
571 instruction.inputs[1], instruction.inputs[2], | |
572 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
573 } | |
574 } | |
575 | |
576 class BitXorSpecializer extends BinaryBitOpSpecializer { | |
577 const BitXorSpecializer(); | |
578 | |
579 BinaryOperation operation(ConstantSystem constantSystem) { | |
580 return constantSystem.bitXor; | |
581 } | |
582 | |
583 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
584 Compiler compiler) { | |
585 HInstruction left = instruction.inputs[1]; | |
586 HInstruction right = instruction.inputs[2]; | |
587 JavaScriptBackend backend = compiler.backend; | |
588 if (left.isUInt31(compiler) && right.isUInt31(compiler)) { | |
589 return backend.uint31Type; | |
590 } | |
591 return super.computeTypeFromInputTypes(instruction, compiler); | |
592 } | |
593 | |
594 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
595 Compiler compiler) { | |
596 JavaScriptBackend backend = compiler.backend; | |
597 return new HBitXor( | |
598 instruction.inputs[1], instruction.inputs[2], | |
599 instruction.selector, computeTypeFromInputTypes(instruction, compiler)); | |
600 } | |
601 } | |
602 | |
603 abstract class RelationalSpecializer extends InvokeDynamicSpecializer { | |
604 const RelationalSpecializer(); | |
605 | |
606 TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, | |
607 Compiler compiler) { | |
608 JavaScriptBackend backend = compiler.backend; | |
609 if (instruction.inputs[1].isPrimitiveOrNull(compiler)) { | |
610 return backend.boolType; | |
611 } | |
612 return super.computeTypeFromInputTypes(instruction, compiler); | |
613 } | |
614 | |
615 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
616 Compiler compiler) { | |
617 HInstruction left = instruction.inputs[1]; | |
618 HInstruction right = instruction.inputs[2]; | |
619 if (left.isNumber(compiler) && right.isNumber(compiler)) { | |
620 return newBuiltinVariant(instruction, compiler); | |
621 } | |
622 return null; | |
623 } | |
624 | |
625 HInstruction newBuiltinVariant(HInvokeDynamic instruction, Compiler compiler); | |
626 } | |
627 | |
628 class EqualsSpecializer extends RelationalSpecializer { | |
629 const EqualsSpecializer(); | |
630 | |
631 HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, | |
632 Compiler compiler) { | |
633 HInstruction left = instruction.inputs[1]; | |
634 HInstruction right = instruction.inputs[2]; | |
635 TypeMask instructionType = left.instructionType; | |
636 if (right.isConstantNull() || left.isPrimitiveOrNull(compiler)) { | |
637 return newBuiltinVariant(instruction, compiler); | |
638 } | |
639 World world = compiler.world; | |
640 Selector selector = | |
641 new TypedSelector(instructionType, instruction.selector, world); | |
642 JavaScriptBackend backend = compiler.backend; | |
643 Iterable<Element> matches = world.allFunctions.filter(selector); | |
644 // This test relies the on `Object.==` and `Interceptor.==` always being | |
645 // implemented because if the selector matches by subtype, it still will be | |
646 // a regular object or an interceptor. | |
647 if (matches.every(backend.isDefaultEqualityImplementation)) { | |
648 return newBuiltinVariant(instruction, compiler); | |
649 } | |
650 return null; | |
651 } | |
652 | |
653 BinaryOperation operation(ConstantSystem constantSystem) { | |
654 return constantSystem.equal; | |
655 } | |
656 | |
657 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
658 Compiler compiler) { | |
659 JavaScriptBackend backend = compiler.backend; | |
660 return new HIdentity( | |
661 instruction.inputs[1], instruction.inputs[2], | |
662 instruction.selector, backend.boolType); | |
663 } | |
664 } | |
665 | |
666 class LessSpecializer extends RelationalSpecializer { | |
667 const LessSpecializer(); | |
668 | |
669 BinaryOperation operation(ConstantSystem constantSystem) { | |
670 return constantSystem.less; | |
671 } | |
672 | |
673 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
674 Compiler compiler) { | |
675 JavaScriptBackend backend = compiler.backend; | |
676 return new HLess( | |
677 instruction.inputs[1], instruction.inputs[2], | |
678 instruction.selector, backend.boolType); | |
679 } | |
680 } | |
681 | |
682 class GreaterSpecializer extends RelationalSpecializer { | |
683 const GreaterSpecializer(); | |
684 | |
685 BinaryOperation operation(ConstantSystem constantSystem) { | |
686 return constantSystem.greater; | |
687 } | |
688 | |
689 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
690 Compiler compiler) { | |
691 JavaScriptBackend backend = compiler.backend; | |
692 return new HGreater( | |
693 instruction.inputs[1], instruction.inputs[2], | |
694 instruction.selector, backend.boolType); | |
695 } | |
696 } | |
697 | |
698 class GreaterEqualSpecializer extends RelationalSpecializer { | |
699 const GreaterEqualSpecializer(); | |
700 | |
701 BinaryOperation operation(ConstantSystem constantSystem) { | |
702 return constantSystem.greaterEqual; | |
703 } | |
704 | |
705 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
706 Compiler compiler) { | |
707 JavaScriptBackend backend = compiler.backend; | |
708 return new HGreaterEqual( | |
709 instruction.inputs[1], instruction.inputs[2], | |
710 instruction.selector, backend.boolType); | |
711 } | |
712 } | |
713 | |
714 class LessEqualSpecializer extends RelationalSpecializer { | |
715 const LessEqualSpecializer(); | |
716 | |
717 BinaryOperation operation(ConstantSystem constantSystem) { | |
718 return constantSystem.lessEqual; | |
719 } | |
720 | |
721 HInstruction newBuiltinVariant(HInvokeDynamic instruction, | |
722 Compiler compiler) { | |
723 JavaScriptBackend backend = compiler.backend; | |
724 return new HLessEqual( | |
725 instruction.inputs[1], instruction.inputs[2], | |
726 instruction.selector, backend.boolType); | |
727 } | |
728 } | |
OLD | NEW |