Chromium Code Reviews| 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 |