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 } |
| 43 return bitset; |
| 44 } else { |
| 45 Map* map = |
| 46 this->is_class() ? *this->as_class() : this->as_constant()->map(); |
| 47 switch (map->instance_type()) { |
| 48 case STRING_TYPE: |
| 49 case ASCII_STRING_TYPE: |
| 50 case CONS_STRING_TYPE: |
| 51 case CONS_ASCII_STRING_TYPE: |
| 52 case SLICED_STRING_TYPE: |
| 53 case EXTERNAL_STRING_TYPE: |
| 54 case EXTERNAL_ASCII_STRING_TYPE: |
| 55 case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: |
| 56 case SHORT_EXTERNAL_STRING_TYPE: |
| 57 case SHORT_EXTERNAL_ASCII_STRING_TYPE: |
| 58 case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: |
| 59 case INTERNALIZED_STRING_TYPE: |
| 60 case ASCII_INTERNALIZED_STRING_TYPE: |
| 61 case CONS_INTERNALIZED_STRING_TYPE: |
| 62 case CONS_ASCII_INTERNALIZED_STRING_TYPE: |
| 63 case EXTERNAL_INTERNALIZED_STRING_TYPE: |
| 64 case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE: |
| 65 case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: |
| 66 case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE: |
| 67 case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE: |
| 68 case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: |
| 69 return kString; |
| 70 case SYMBOL_TYPE: |
| 71 return kSymbol; |
| 72 case ODDBALL_TYPE: |
| 73 return kOddball; |
| 74 case HEAP_NUMBER_TYPE: |
| 75 return kDouble; |
| 76 case JS_VALUE_TYPE: |
| 77 case JS_DATE_TYPE: |
| 78 case JS_OBJECT_TYPE: |
| 79 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
| 80 case JS_GENERATOR_OBJECT_TYPE: |
| 81 case JS_MODULE_TYPE: |
| 82 case JS_GLOBAL_OBJECT_TYPE: |
| 83 case JS_BUILTINS_OBJECT_TYPE: |
| 84 case JS_GLOBAL_PROXY_TYPE: |
| 85 case JS_ARRAY_BUFFER_TYPE: |
| 86 case JS_TYPED_ARRAY_TYPE: |
| 87 case JS_WEAK_MAP_TYPE: |
| 88 case JS_REGEXP_TYPE: |
| 89 return kOtherObject; |
| 90 case JS_ARRAY_TYPE: |
| 91 return kArray; |
| 92 case JS_FUNCTION_TYPE: |
| 93 return kFunction; |
| 94 case JS_PROXY_TYPE: |
| 95 case JS_FUNCTION_PROXY_TYPE: |
| 96 return kProxy; |
| 97 default: |
| 98 UNREACHABLE(); |
| 99 return kNone; |
| 100 } |
| 101 } |
| 102 } |
| 103 |
| 104 |
| 105 // Get the largest bitset subsumed by this type. |
| 106 int Type::GlbBitset() { |
| 107 if (this->is_bitset()) { |
| 108 return this->as_bitset(); |
| 109 } else if (this->is_union()) { |
| 110 // All but the first are non-bitsets and thus would yield kNone anyway. |
| 111 return union_get(this->as_union(), 0)->GlbBitset(); |
| 112 } else { |
| 113 return kNone; |
| 114 } |
| 115 } |
| 116 |
| 117 |
| 118 // Check this <= that. |
| 119 bool Type::Is(Handle<Type> that) { |
| 120 // Fast path for bitsets. |
| 121 if (that->is_bitset()) { |
| 122 return (this->LubBitset() | that->as_bitset()) == that->as_bitset(); |
| 123 } |
| 124 |
| 125 if (that->is_class()) { |
| 126 return this->is_class() && *this->as_class() == *that->as_class(); |
| 127 } |
| 128 if (that->is_constant()) { |
| 129 return this->is_constant() && *this->as_constant() == *that->as_constant(); |
| 130 } |
| 131 |
| 132 // (T1 \/ ... \/ Tn) <= T <=> (T1 <= T) /\ ... /\ (Tn <= T) |
| 133 if (this->is_union()) { |
| 134 Handle<Unioned> unioned = this->as_union(); |
| 135 for (int i = 0; i < unioned->length(); ++i) { |
| 136 Handle<Type> this_i = union_get(unioned, i); |
| 137 if (!this_i->Is(that)) return false; |
| 138 } |
| 139 return true; |
| 140 } |
| 141 |
| 142 // T <= (T1 \/ ... \/ Tn) <=> (T <= T1) \/ ... \/ (T <= Tn) |
| 143 // (iff T is not a union) |
| 144 if (that->is_union()) { |
| 145 Handle<Unioned> unioned = that->as_union(); |
| 146 for (int i = 0; i < unioned->length(); ++i) { |
| 147 Handle<Type> that_i = union_get(unioned, i); |
| 148 if (this->Is(that_i)) return true; |
| 149 if (this->is_bitset()) break; // Fast fail, no other field is a bitset. |
| 150 } |
| 151 return false; |
| 152 } |
| 153 |
| 154 return false; |
| 155 } |
| 156 |
| 157 |
| 158 // Check this overlaps that. |
| 159 bool Type::Maybe(Handle<Type> that) { |
| 160 // Fast path for bitsets. |
| 161 if (this->is_bitset()) { |
| 162 return (this->as_bitset() & that->LubBitset()) != 0; |
| 163 } |
| 164 if (that->is_bitset()) { |
| 165 return (this->LubBitset() & that->as_bitset()) != 0; |
| 166 } |
| 167 |
| 168 if (this->is_class()) { |
| 169 return that->is_class() && *this->as_class() == *that->as_class(); |
| 170 } |
| 171 if (this->is_constant()) { |
| 172 return that->is_constant() && *this->as_constant() == *that->as_constant(); |
| 173 } |
| 174 |
| 175 // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T) |
| 176 if (this->is_union()) { |
| 177 Handle<Unioned> unioned = this->as_union(); |
| 178 for (int i = 0; i < unioned->length(); ++i) { |
| 179 Handle<Type> this_i = union_get(unioned, i); |
| 180 if (this_i->Maybe(that)) return true; |
| 181 } |
| 182 return false; |
| 183 } |
| 184 |
| 185 // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn) |
| 186 if (that->is_union()) { |
| 187 Handle<Unioned> unioned = that->as_union(); |
| 188 for (int i = 0; i < unioned->length(); ++i) { |
| 189 Handle<Type> that_i = union_get(unioned, i); |
| 190 if (this->Maybe(that_i)) return true; |
| 191 } |
| 192 return false; |
| 193 } |
| 194 |
| 195 return false; |
| 196 } |
| 197 |
| 198 |
| 199 bool Type::InUnion(Handle<Unioned> unioned, int current_size) { |
| 200 ASSERT(!this->is_union()); |
| 201 for (int i = 0; i < current_size; ++i) { |
| 202 Handle<Type> type = union_get(unioned, i); |
| 203 if (type->is_bitset() ? this->Is(type) : this == *type) return true; |
| 204 } |
| 205 return false; |
| 206 } |
| 207 |
| 208 // Get non-bitsets from this which are not subsumed by that, store at unioned, |
| 209 // starting at index. Returns updated index. |
| 210 int Type::ExtendUnion(Handle<Unioned> result, int current_size) { |
| 211 int old_size = current_size; |
| 212 if (this->is_class() || this->is_constant()) { |
| 213 if (!this->InUnion(result, old_size)) result->set(current_size++, this); |
| 214 } else if (this->is_union()) { |
| 215 Handle<Unioned> unioned = this->as_union(); |
| 216 for (int i = 0; i < unioned->length(); ++i) { |
| 217 Handle<Type> type = union_get(unioned, i); |
| 218 ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0)))); |
| 219 if (type->is_bitset()) continue; |
| 220 if (!type->InUnion(result, old_size)) result->set(current_size++, *type); |
| 221 } |
| 222 } |
| 223 return current_size; |
| 224 } |
| 225 |
| 226 |
| 227 // Union is O(1) on simple bit unions, but O(n*m) on structured unions. |
| 228 // TODO(rossberg): Should we use object sets somehow? Is it worth it? |
| 229 Type* Type::Union(Handle<Type> type1, Handle<Type> type2) { |
| 230 // Fast case: bit sets. |
| 231 if (type1->is_bitset() && type2->is_bitset()) { |
| 232 return from_bitset(type1->as_bitset() | type2->as_bitset()); |
| 233 } |
| 234 |
| 235 // Semi-fast case: Unioned objects are neither involved nor produced. |
| 236 if (!(type1->is_union() || type2->is_union())) { |
| 237 if (type1->Is(type2)) return *type2; |
| 238 if (type2->Is(type1)) return *type1; |
| 239 } |
| 240 |
| 241 // Slow case: may need to produce a Unioned object. |
| 242 Isolate* isolate = NULL; |
| 243 int size = type1->is_bitset() || type2->is_bitset() ? 1 : 0; |
| 244 if (!type1->is_bitset()) { |
| 245 isolate = HeapObject::cast(*type1)->GetIsolate(); |
| 246 size += (type1->is_union() ? type1->as_union()->length() : 1); |
| 247 } |
| 248 if (!type2->is_bitset()) { |
| 249 isolate = HeapObject::cast(*type2)->GetIsolate(); |
| 250 size += (type2->is_union() ? type2->as_union()->length() : 1); |
| 251 } |
| 252 ASSERT(isolate != NULL); |
| 253 ASSERT(size >= 2); |
| 254 Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size); |
| 255 size = 0; |
| 256 |
| 257 int bitset = type1->GlbBitset() | type2->GlbBitset(); |
| 258 if (bitset != kNone) unioned->set(size++, from_bitset(bitset)); |
| 259 size = type1->ExtendUnion(unioned, size); |
| 260 size = type2->ExtendUnion(unioned, size); |
| 261 |
| 262 if (size == 1) { |
| 263 return *union_get(unioned, 0); |
| 264 } else if (size == unioned->length()) { |
| 265 return from_handle(unioned); |
| 266 } |
| 267 |
| 268 // There was an overlap. Copy to smaller union. |
| 269 Handle<Unioned> result = isolate->factory()->NewFixedArray(size); |
| 270 for (int i = 0; i < size; ++i) result->set(i, unioned->get(i)); |
| 271 return from_handle(result); |
| 272 } |
| 273 |
| 274 |
| 275 Type* Type::Optional(Handle<Type> type) { |
| 276 return type->is_bitset() |
| 277 ? from_bitset(type->as_bitset() | kUndefined) |
| 278 : Union(type, Undefined()->handle_via_isolate_of(*type)); |
| 279 } |
| 280 |
| 281 } } // namespace v8::internal |
OLD | NEW |