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(); | |
Jakob Kummerow
2013/06/05 14:53:24
nit: {}
rossberg
2013/06/05 15:37:02
Done.
| |
42 return bitset; | |
43 } else { | |
44 Map* map = this->is_class()? *this->as_class() : this->as_constant()->map(); | |
Jakob Kummerow
2013/06/05 14:53:24
nit: space before '?'. If that causes a line break
rossberg
2013/06/05 15:37:02
Done.
| |
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: | |
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(); | |
Jakob Kummerow
2013/06/05 14:53:24
I think it would be cleaner to use Handle::is_iden
rossberg
2013/06/05 15:37:02
Added a comment to types.h. Left comparisons as is
| |
125 } | |
126 if (that->is_constant()) { | |
127 return this->is_constant() && *this->as_constant() == *that->as_constant(); | |
128 } | |
129 | |
130 // (T1 \/ ... \/ Tn) <= T <=> (T1 <= T) /\ ... /\ (Tn <= T) | |
131 if (this->is_union()) { | |
132 Handle<Unioned> unioned = this->as_union(); | |
133 for (int i = 0; i < unioned->length(); ++i) { | |
134 Handle<Type> this_i = union_get(unioned, i); | |
135 if (!this_i->Is(that)) return false; | |
136 } | |
137 return true; | |
138 } | |
139 | |
140 // T <= (T1 \/ ... \/ Tn) <=> (T <= T1) \/ ... \/ (T <= Tn) | |
141 // (iff T is not a union) | |
142 if (that->is_union()) { | |
143 Handle<Unioned> unioned = that->as_union(); | |
144 for (int i = 0; i < unioned->length(); ++i) { | |
145 Handle<Type> that_i = union_get(unioned, i); | |
146 if (this->Is(that_i)) return true; | |
147 if (this->is_bitset()) break; // Fast fail, no other field is a bitset. | |
148 } | |
149 return false; | |
150 } | |
151 | |
152 return false; | |
153 } | |
154 | |
155 | |
156 // Check this overlaps that. | |
157 bool Type::Maybe(Handle<Type> that) { | |
158 // Fast path for bitsets. | |
159 if (this->is_bitset()) { | |
160 return (this->as_bitset() & that->LubBitset()) != 0; | |
161 } | |
162 if (that->is_bitset()) { | |
163 return (this->LubBitset() & that->as_bitset()) != 0; | |
164 } | |
165 | |
166 if (this->is_class()) { | |
167 return that->is_class() && *this->as_class() == *that->as_class(); | |
168 } | |
169 if (this->is_constant()) { | |
170 return that->is_constant() && *this->as_constant() == *that->as_constant(); | |
171 } | |
172 | |
173 // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T) | |
174 if (this->is_union()) { | |
175 Handle<Unioned> unioned = this->as_union(); | |
176 for (int i = 0; i < unioned->length(); ++i) { | |
177 Handle<Type> this_i = union_get(unioned, i); | |
178 if (this_i->Maybe(that)) return true; | |
179 } | |
180 return false; | |
181 } | |
182 | |
183 // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn) | |
184 if (that->is_union()) { | |
185 Handle<Unioned> unioned = that->as_union(); | |
186 for (int i = 0; i < unioned->length(); ++i) { | |
187 Handle<Type> that_i = union_get(unioned, i); | |
188 if (this->Maybe(that_i)) return true; | |
189 } | |
190 return false; | |
191 } | |
192 | |
193 return false; | |
194 } | |
195 | |
196 | |
197 bool Type::InUnion(Handle<Unioned> unioned, int current_size) { | |
198 ASSERT(!this->is_union()); | |
199 for (int i = 0; i < current_size; ++i) { | |
200 Handle<Type> type = union_get(unioned, i); | |
201 if (type->is_bitset() ? this->Is(type) : this == *type) return true; | |
202 } | |
203 return false; | |
204 } | |
205 | |
206 // Get non-bitsets from this which are not subsumed by that, store at unioned, | |
207 // starting at index. Returns updated index. | |
208 int Type::ExtendUnion(Handle<Unioned> result, int current_size) { | |
209 int old_size = current_size; | |
210 if (this->is_class() || this->is_constant()) { | |
211 if (!this->InUnion(result, old_size)) result->set(current_size++, this); | |
212 } else if (this->is_union()) { | |
213 Handle<Unioned> unioned = this->as_union(); | |
214 for (int i = 0; i < unioned->length(); ++i) { | |
215 Handle<Type> type = union_get(unioned, i); | |
216 ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0)))); | |
217 if (type->is_bitset()) continue; | |
218 if (!type->InUnion(result, old_size)) result->set(current_size++, *type); | |
219 } | |
220 } | |
221 return current_size; | |
222 } | |
223 | |
224 | |
225 // Union is O(1) on simple bit unions, but O(n*m) on structured unions. | |
226 // TODO(rossberg): Should we use object sets somehow? Is it worth it? | |
227 Type* Type::Union(Handle<Type> type1, Handle<Type> type2) { | |
228 // Fast case: bit sets. | |
229 if (type1->is_bitset() && type2->is_bitset()) { | |
230 return from_bitset(type1->as_bitset() | type2->as_bitset()); | |
231 } | |
232 | |
233 // Semi-fast case: Unioned objects are neither involved nor produced. | |
234 if (!(type1->is_union() || type2->is_union())) { | |
235 if (type1->Is(type2)) return *type2; | |
236 if (type2->Is(type1)) return *type1; | |
237 } | |
238 | |
239 // Slow case: may need to produce a Unioned object. | |
240 Isolate* isolate = NULL; | |
241 int size = type1->is_bitset() || type2->is_bitset() ? 1 : 0; | |
242 if (!type1->is_bitset()) { | |
243 isolate = HeapObject::cast(*type1)->GetIsolate(); | |
244 size += (type1->is_union() ? type1->as_union()->length() : 1); | |
245 } | |
246 if (!type2->is_bitset()) { | |
247 isolate = HeapObject::cast(*type2)->GetIsolate(); | |
248 size += (type2->is_union() ? type2->as_union()->length() : 1); | |
249 } | |
250 ASSERT(isolate != NULL); | |
251 ASSERT(size >= 2); | |
252 Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size); | |
253 size = 0; | |
254 | |
255 int bitset = type1->GlbBitset() | type2->GlbBitset(); | |
256 if (bitset != kNone) unioned->set(size++, from_bitset(bitset)); | |
257 size = type1->ExtendUnion(unioned, size); | |
258 size = type2->ExtendUnion(unioned, size); | |
259 | |
260 if (size == 1) | |
261 return *union_get(unioned, 0); | |
Jakob Kummerow
2013/06/05 14:53:24
nit: {}
rossberg
2013/06/05 15:37:02
Done.
| |
262 else if (size == unioned->length()) | |
263 return from_handle(unioned); | |
264 | |
265 // There was an overlap. Copy to smaller union. | |
266 Handle<Unioned> result = isolate->factory()->NewFixedArray(size); | |
267 for (int i = 0; i < size; ++i) result->set(i, unioned->get(i)); | |
268 return from_handle(result); | |
269 } | |
270 | |
271 | |
272 Type* Type::Optional(Handle<Type> type) { | |
273 return type->is_bitset() | |
274 ? from_bitset(type->as_bitset() | kUndefined) | |
275 : Union(type, Undefined()->handle_via(*type)); | |
276 } | |
277 | |
278 } } // namespace v8::internal | |
OLD | NEW |