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; | |
kasperl
2013/01/16 07:26:03
Nit: Maybe we should start using more structured n
ngeoffray
2013/01/16 09:02:54
Agree. Let's keep that in mind and do an overall r
| |
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 HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, | |
17 HInstruction input, | |
18 HTypeMap types, | |
19 Compiler compiler) { | |
20 return HType.UNKNOWN; | |
21 } | |
22 | |
23 HType computeTypeFromInputTypes(HInvokeDynamicMethod instruction, | |
24 HTypeMap types, | |
25 Compiler compiler) { | |
26 return HType.UNKNOWN; | |
27 } | |
28 | |
29 HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, | |
30 HTypeMap types) { | |
31 return null; | |
32 } | |
33 | |
34 static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { | |
35 if (selector.kind == SelectorKind.INDEX) { | |
36 return selector.name == const SourceString('[]') | |
37 ? const IndexSpecializer() | |
38 : const IndexAssignSpecializer(); | |
39 } else if (selector.kind == SelectorKind.OPERATOR) { | |
40 if (selector.name == const SourceString('unary-')) { | |
41 return const UnaryNegateSpecializer(); | |
42 } else if (selector.name == const SourceString('~')) { | |
43 return const BitNotSpecializer(); | |
44 } | |
45 } | |
46 return const InvokeDynamicSpecializer(); | |
47 } | |
48 } | |
49 | |
50 class IndexAssignSpecializer extends InvokeDynamicSpecializer { | |
51 const IndexAssignSpecializer(); | |
52 | |
53 HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, | |
54 HInstruction input, | |
55 HTypeMap types, | |
56 Compiler compiler) { | |
57 HInstruction index = instruction.inputs[2]; | |
58 if (input == instruction.inputs[1] && | |
59 (index.isTypeUnknown(types) || index.isNumber(types))) { | |
60 return HType.MUTABLE_ARRAY; | |
61 } | |
62 // The index should be an int when the receiver is a string or array. | |
63 // However it turns out that inserting an integer check in the optimized | |
64 // version is cheaper than having another bailout case. This is true, | |
65 // because the integer check will simply throw if it fails. | |
66 return HType.UNKNOWN; | |
67 } | |
68 | |
69 HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, | |
70 HTypeMap types) { | |
71 if (instruction.inputs[1].isMutableArray(types)) { | |
72 return new HIndexAssign(instruction.inputs[1], | |
73 instruction.inputs[2], | |
74 instruction.inputs[3]); | |
75 } | |
76 return null; | |
77 } | |
78 } | |
79 | |
80 class IndexSpecializer extends InvokeDynamicSpecializer { | |
81 const IndexSpecializer(); | |
82 | |
83 HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, | |
84 HInstruction input, | |
85 HTypeMap types, | |
86 Compiler compiler) { | |
87 HInstruction index = instruction.inputs[2]; | |
88 if (input == instruction.inputs[1] && | |
89 (index.isTypeUnknown(types) || index.isNumber(types))) { | |
90 return HType.INDEXABLE_PRIMITIVE; | |
91 } | |
92 // The index should be an int when the receiver is a string or array. | |
93 // However it turns out that inserting an integer check in the optimized | |
94 // version is cheaper than having another bailout case. This is true, | |
95 // because the integer check will simply throw if it fails. | |
96 return HType.UNKNOWN; | |
97 } | |
98 | |
99 HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, | |
100 HTypeMap types) { | |
101 if (instruction.inputs[1].isIndexablePrimitive(types)) { | |
102 return new HIndex(instruction.inputs[1], instruction.inputs[2]); | |
103 } | |
104 return null; | |
105 } | |
106 } | |
107 | |
108 class BitNotSpecializer extends InvokeDynamicSpecializer { | |
109 const BitNotSpecializer(); | |
110 | |
111 HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, | |
112 HInstruction input, | |
113 HTypeMap types, | |
114 Compiler compiler) { | |
115 if (input == instruction.inputs[1]) { | |
116 HType propagatedType = types[instruction]; | |
117 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | |
118 return HType.INTEGER; | |
119 } | |
120 } | |
121 return HType.UNKNOWN; | |
122 } | |
123 | |
124 HType computeTypeFromInputTypes(HInvokeDynamicMethod instruction, | |
125 HTypeMap types, | |
126 Compiler compiler) { | |
127 // All bitwise operations on primitive types either produce an | |
128 // integer or throw an error. | |
129 if (instruction.inputs[1].isPrimitive(types)) return HType.INTEGER; | |
130 return HType.UNKNOWN; | |
131 } | |
132 | |
133 HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, | |
134 HTypeMap types) { | |
135 HInstruction input = instruction.inputs[1]; | |
136 if (input.isNumber(types)) return new HBitNot(input); | |
137 return null; | |
138 } | |
139 } | |
140 | |
141 class UnaryNegateSpecializer extends InvokeDynamicSpecializer { | |
142 const UnaryNegateSpecializer(); | |
143 | |
144 HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, | |
145 HInstruction input, | |
146 HTypeMap types, | |
147 Compiler compiler) { | |
148 if (input == instruction.inputs[1]) { | |
149 HType propagatedType = types[instruction]; | |
150 // If the outgoing type should be a number (integer, double or both) we | |
151 // want the outgoing type to be the input too. | |
152 // If we don't know the outgoing type we try to make it a number. | |
153 if (propagatedType.isNumber()) return propagatedType; | |
154 if (propagatedType.isUnknown()) return HType.NUMBER; | |
155 } | |
156 return HType.UNKNOWN; | |
157 } | |
158 | |
159 HType computeTypeFromInputTypes(HInvokeDynamicMethod instruction, | |
160 HTypeMap types, | |
161 Compiler compiler) { | |
162 HType operandType = types[instruction.inputs[1]]; | |
163 if (operandType.isNumber()) return operandType; | |
164 return HType.UNKNOWN; | |
165 } | |
166 | |
167 HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, | |
168 HTypeMap types) { | |
169 HInstruction input = instruction.inputs[1]; | |
170 if (input.isNumber(types)) return new HNegate(input); | |
171 return null; | |
172 } | |
173 } | |
OLD | NEW |