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