OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include "types.h" | |
29 | |
30 namespace v8 { | |
31 namespace internal { | |
32 | |
33 // Get the smallest bitset subsuming this type. | |
34 int Type::LubBitset() { | |
35 if (this->is_bitset()) { | |
36 return this->as_bitset(); | |
37 } else if (this->is_union()) { | |
38 Handle<Unioned> unioned = this->as_union(); | |
39 int bitset = kNone; | |
40 for (int i = 0; i < unioned->length(); ++i) | |
41 bitset |= union_get(unioned, i)->LubBitset(); | |
42 return bitset; | |
43 } else { | |
44 Map* map = this->is_class()? *this->as_class() : this->as_constant()->map(); | |
45 switch (map->instance_type()) { | |
46 case STRING_TYPE: | |
47 case ASCII_STRING_TYPE: | |
48 case CONS_STRING_TYPE: | |
49 case CONS_ASCII_STRING_TYPE: | |
50 case SLICED_STRING_TYPE: | |
51 case EXTERNAL_STRING_TYPE: | |
52 case EXTERNAL_ASCII_STRING_TYPE: | |
53 case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: | |
54 case SHORT_EXTERNAL_STRING_TYPE: | |
55 case SHORT_EXTERNAL_ASCII_STRING_TYPE: | |
56 case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: | |
57 case INTERNALIZED_STRING_TYPE: | |
58 case ASCII_INTERNALIZED_STRING_TYPE: | |
59 case CONS_INTERNALIZED_STRING_TYPE: | |
60 case CONS_ASCII_INTERNALIZED_STRING_TYPE: | |
61 case EXTERNAL_INTERNALIZED_STRING_TYPE: | |
62 case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE: | |
63 case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: | |
64 case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE: | |
65 case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE: | |
66 case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: | |
67 return kString; | |
68 case SYMBOL_TYPE: | |
69 return kSymbol; | |
70 case ODDBALL_TYPE: | |
71 return kOddball; | |
72 case HEAP_NUMBER_TYPE: | |
73 return kDouble; | |
74 case JS_VALUE_TYPE: | |
75 case JS_DATE_TYPE: | |
76 case JS_OBJECT_TYPE: | |
77 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: | |
78 case JS_GENERATOR_OBJECT_TYPE: | |
79 case JS_MODULE_TYPE: | |
80 case JS_GLOBAL_OBJECT_TYPE: | |
81 case JS_BUILTINS_OBJECT_TYPE: | |
82 case JS_GLOBAL_PROXY_TYPE: | |
83 case JS_ARRAY_BUFFER_TYPE: | |
84 case JS_TYPED_ARRAY_TYPE: | |
85 case JS_WEAK_MAP_TYPE: | |
86 case JS_REGEXP_TYPE: | |
87 return kOtherObject; | |
88 case JS_ARRAY_TYPE: | |
89 return kArray; | |
90 case JS_FUNCTION_TYPE: | |
91 return kFunction; | |
92 case JS_PROXY_TYPE: | |
93 case JS_FUNCTION_PROXY_TYPE: | |
94 return kProxy; | |
95 default: | |
Sven Panne
2013/06/05 08:02:41
Are there really unhandled cases? If yes, how many
rossberg
2013/06/05 09:44:24
I know, unfortunately, there are several dozens of
| |
96 UNREACHABLE(); | |
97 return kNone; | |
98 } | |
99 } | |
100 } | |
101 | |
102 | |
103 // Get the largest bitset subsumed by this type. | |
104 int Type::GlbBitset() { | |
105 if (this->is_bitset()) { | |
106 return this->as_bitset(); | |
107 } else if (this->is_union()) { | |
108 // All but the first are non-bitsets and thus would yield kNone anyway. | |
109 return union_get(this->as_union(), 0)->GlbBitset(); | |
110 } else { | |
111 return kNone; | |
112 } | |
113 } | |
114 | |
115 | |
116 // Check this <= that. | |
117 bool Type::Is(Handle<Type> that) { | |
118 // Fast path for bitsets. | |
119 if (that->is_bitset()) { | |
120 return (this->LubBitset() | that->as_bitset()) == that->as_bitset(); | |
121 } | |
122 | |
123 if (that->is_class()) { | |
124 return this->is_class() && *this->as_class() == *that->as_class(); | |
125 } | |
126 if (that->is_constant()) { | |
127 return this->is_constant() && *this->as_constant() == *that->as_constant(); | |
128 } | |
129 | |
130 // T <= (T1 \/ ... \/ Tn) <=> (T <= T1) \/ ... \/ (T <= Tn) | |
131 if (that->is_union()) { | |
132 Handle<Unioned> unioned = that->as_union(); | |
133 for (int i = 0; i < unioned->length(); ++i) { | |
134 Handle<Type> that_i = union_get(unioned, i); | |
135 if (this->Is(that_i)) return true; | |
136 if (this->is_bitset()) break; // Fast fail, no other field is a bitset. | |
137 } | |
138 return false; | |
139 } | |
140 | |
141 // (T1 \/ ... \/ Tn) <= T <=> (T1 <= T) /\ ... /\ (Tn <= T) | |
142 if (this->is_union()) { | |
143 Handle<Unioned> unioned = this->as_union(); | |
144 for (int i = 0; i < unioned->length(); ++i) { | |
145 Handle<Type> this_i = union_get(unioned, i); | |
146 if (!this_i->Is(that)) return false; | |
147 } | |
148 return true; | |
149 } | |
150 | |
151 return false; | |
152 } | |
153 | |
154 | |
155 // Check this overlaps that. | |
156 bool Type::Maybe(Handle<Type> that) { | |
157 // Fast path for bitsets. | |
158 if (this->is_bitset()) { | |
159 return (this->as_bitset() & that->LubBitset()) != 0; | |
160 } | |
161 if (that->is_bitset()) { | |
162 return (this->LubBitset() & that->as_bitset()) != 0; | |
163 } | |
164 | |
165 if (this->is_class()) { | |
166 return that->is_class() && *this->as_class() == *that->as_class(); | |
167 } | |
168 if (this->is_constant()) { | |
169 return that->is_constant() && *this->as_constant() == *that->as_constant(); | |
170 } | |
171 | |
172 // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T) | |
173 if (this->is_union()) { | |
174 Handle<Unioned> unioned = this->as_union(); | |
175 for (int i = 0; i < unioned->length(); ++i) { | |
176 Handle<Type> this_i = union_get(unioned, i); | |
177 if (this_i->Maybe(that)) return true; | |
178 } | |
179 return false; | |
180 } | |
181 | |
182 // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn) | |
183 if (that->is_union()) { | |
184 Handle<Unioned> unioned = that->as_union(); | |
185 for (int i = 0; i < unioned->length(); ++i) { | |
186 Handle<Type> that_i = union_get(unioned, i); | |
187 if (this->Maybe(that_i)) return true; | |
188 } | |
189 return false; | |
190 } | |
191 | |
192 return false; | |
193 } | |
194 | |
195 | |
196 bool Type::InUnion(Handle<Unioned> unioned, int current_size) { | |
197 ASSERT(!this->is_union()); | |
198 for (int i = 0; i < current_size; ++i) { | |
199 Handle<Type> type = union_get(unioned, i); | |
200 if (type->is_bitset() ? this->Is(type) : this == *type) return true; | |
201 } | |
202 return false; | |
203 } | |
204 | |
205 // Get non-bitsets from this which are not subsumed by that, store at unioned, | |
206 // starting at index. Returns updated index. | |
207 int Type::ExtendUnion(Handle<Unioned> result, int current_size) { | |
208 int old_size = current_size; | |
209 if (this->is_class() || this->is_constant()) { | |
210 if (!this->InUnion(result, old_size)) result->set(current_size++, this); | |
211 } else if (this->is_union()) { | |
212 Handle<Unioned> unioned = this->as_union(); | |
213 for (int i = 0; i < unioned->length(); ++i) { | |
214 Handle<Type> type = union_get(unioned, i); | |
215 ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0)))); | |
216 if (type->is_bitset()) continue; | |
217 if (!type->InUnion(result, old_size)) result->set(current_size++, *type); | |
218 } | |
219 } | |
220 return current_size; | |
221 } | |
222 | |
223 | |
224 // Union is O(1) on simple bit unions, but O(n*m) on structured unions. | |
225 // TODO(rossberg): Should we use object sets somehow? Is it worth it? | |
226 Type* Type::Union(Handle<Type> type1, Handle<Type> type2) { | |
227 // Fast case: bit sets. | |
228 if (type1->is_bitset() && type2->is_bitset()) { | |
229 return from_bitset(type1->as_bitset() | type2->as_bitset()); | |
230 } | |
231 | |
232 // Semi-fast case: Unioned objects are neither involved nor produced. | |
233 if (!(type1->is_union() || type2->is_union())) { | |
234 if (type1->Is(type2)) return *type2; | |
235 if (type2->Is(type1)) return *type1; | |
236 } | |
237 | |
238 // Slow case: may need to produce a Unioned object. | |
239 Isolate* isolate = NULL; | |
240 int size = type1->is_bitset() || type2->is_bitset() ? 1 : 0; | |
241 if (!type1->is_bitset()) { | |
242 isolate = HeapObject::cast(*type1)->GetIsolate(); | |
243 size += (type1->is_union() ? type1->as_union()->length() : 1); | |
244 } | |
245 if (!type2->is_bitset()) { | |
246 if (isolate == NULL) isolate = HeapObject::cast(*type2)->GetIsolate(); | |
Sven Panne
2013/06/05 08:02:41
The test is a nano-optimization, leaving it out ma
rossberg
2013/06/05 09:44:24
Done.
| |
247 size += (type2->is_union() ? type2->as_union()->length() : 1); | |
248 } | |
249 ASSERT(isolate != NULL); | |
250 ASSERT(size >= 2); | |
251 Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size); | |
252 size = 0; | |
253 | |
254 int bitset = type1->GlbBitset() | type2->GlbBitset(); | |
255 if (bitset != kNone) unioned->set(size++, from_bitset(bitset)); | |
256 size = type1->ExtendUnion(unioned, size); | |
257 size = type2->ExtendUnion(unioned, size); | |
258 | |
259 if (size == 1) | |
260 return *union_get(unioned, 0); | |
261 else if (size == unioned->length()) | |
262 return from_handle(unioned); | |
263 | |
264 // There was an overlap. Copy to smaller union. | |
265 Handle<Unioned> result = isolate->factory()->NewFixedArray(size); | |
266 for (int i = 0; i < size; ++i) result->set(i, unioned->get(i)); | |
267 return from_handle(result); | |
268 } | |
269 | |
270 | |
271 Type* Type::Optional(Handle<Type> type) { | |
272 if (type->is_bitset()) | |
Sven Panne
2013/06/05 08:02:41
I would have expected a ternary ?: from you... ;-)
rossberg
2013/06/05 09:44:24
Right you are! :)
| |
273 return from_bitset(type->as_bitset() | kUndefined); | |
274 else | |
275 return Union(type, Undefined()->handle_via(*type)); | |
276 } | |
277 | |
278 } } // namespace v8::internal | |
OLD | NEW |