The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / types.cc @ f230a1cf

History | View | Annotate | Download (17.5 KB)

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
#include "string-stream.h"
30

    
31
namespace v8 {
32
namespace internal {
33

    
34
int Type::NumClasses() {
35
  if (is_class()) {
36
    return 1;
37
  } else if (is_union()) {
38
    Handle<Unioned> unioned = as_union();
39
    int result = 0;
40
    for (int i = 0; i < unioned->length(); ++i) {
41
      if (union_get(unioned, i)->is_class()) ++result;
42
    }
43
    return result;
44
  } else {
45
    return 0;
46
  }
47
}
48

    
49

    
50
int Type::NumConstants() {
51
  if (is_constant()) {
52
    return 1;
53
  } else if (is_union()) {
54
    Handle<Unioned> unioned = as_union();
55
    int result = 0;
56
    for (int i = 0; i < unioned->length(); ++i) {
57
      if (union_get(unioned, i)->is_constant()) ++result;
58
    }
59
    return result;
60
  } else {
61
    return 0;
62
  }
63
}
64

    
65

    
66
template<class T>
67
Handle<Type> Type::Iterator<T>::get_type() {
68
  ASSERT(!Done());
69
  return type_->is_union() ? union_get(type_->as_union(), index_) : type_;
70
}
71

    
72
template<>
73
Handle<Map> Type::Iterator<Map>::Current() {
74
  return get_type()->as_class();
75
}
76

    
77
template<>
78
Handle<v8::internal::Object> Type::Iterator<v8::internal::Object>::Current() {
79
  return get_type()->as_constant();
80
}
81

    
82

    
83
template<>
84
bool Type::Iterator<Map>::matches(Handle<Type> type) {
85
  return type->is_class();
86
}
87

    
88
template<>
89
bool Type::Iterator<v8::internal::Object>::matches(Handle<Type> type) {
90
  return type->is_constant();
91
}
92

    
93

    
94
template<class T>
95
void Type::Iterator<T>::Advance() {
96
  ++index_;
97
  if (type_->is_union()) {
98
    Handle<Unioned> unioned = type_->as_union();
99
    for (; index_ < unioned->length(); ++index_) {
100
      if (matches(union_get(unioned, index_))) return;
101
    }
102
  } else if (index_ == 0 && matches(type_)) {
103
    return;
104
  }
105
  index_ = -1;
106
}
107

    
108
template class Type::Iterator<Map>;
109
template class Type::Iterator<v8::internal::Object>;
110

    
111

    
112
// Get the smallest bitset subsuming this type.
113
int Type::LubBitset() {
114
  if (this->is_bitset()) {
115
    return this->as_bitset();
116
  } else if (this->is_union()) {
117
    Handle<Unioned> unioned = this->as_union();
118
    int bitset = kNone;
119
    for (int i = 0; i < unioned->length(); ++i) {
120
      bitset |= union_get(unioned, i)->LubBitset();
121
    }
122
    return bitset;
123
  } else {
124
    Map* map = NULL;
125
    if (this->is_class()) {
126
      map = *this->as_class();
127
    } else {
128
      Handle<v8::internal::Object> value = this->as_constant();
129
      if (value->IsSmi()) return kSmi;
130
      map = HeapObject::cast(*value)->map();
131
      if (map->instance_type() == HEAP_NUMBER_TYPE) {
132
        int32_t i;
133
        uint32_t u;
134
        if (value->ToInt32(&i)) return Smi::IsValid(i) ? kSmi : kOtherSigned32;
135
        if (value->ToUint32(&u)) return kUnsigned32;
136
        return kDouble;
137
      }
138
      if (map->instance_type() == ODDBALL_TYPE) {
139
        if (value->IsUndefined()) return kUndefined;
140
        if (value->IsNull()) return kNull;
141
        if (value->IsTrue() || value->IsFalse()) return kBoolean;
142
        if (value->IsTheHole()) return kAny;  // TODO(rossberg): kNone?
143
        UNREACHABLE();
144
      }
145
    }
146
    switch (map->instance_type()) {
147
      case STRING_TYPE:
148
      case ASCII_STRING_TYPE:
149
      case CONS_STRING_TYPE:
150
      case CONS_ASCII_STRING_TYPE:
151
      case SLICED_STRING_TYPE:
152
      case SLICED_ASCII_STRING_TYPE:
153
      case EXTERNAL_STRING_TYPE:
154
      case EXTERNAL_ASCII_STRING_TYPE:
155
      case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
156
      case SHORT_EXTERNAL_STRING_TYPE:
157
      case SHORT_EXTERNAL_ASCII_STRING_TYPE:
158
      case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
159
      case INTERNALIZED_STRING_TYPE:
160
      case ASCII_INTERNALIZED_STRING_TYPE:
161
      case CONS_INTERNALIZED_STRING_TYPE:
162
      case CONS_ASCII_INTERNALIZED_STRING_TYPE:
163
      case EXTERNAL_INTERNALIZED_STRING_TYPE:
164
      case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
165
      case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
166
      case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
167
      case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
168
      case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
169
        return kString;
170
      case SYMBOL_TYPE:
171
        return kSymbol;
172
      case ODDBALL_TYPE:
173
        return kOddball;
174
      case HEAP_NUMBER_TYPE:
175
        return kDouble;
176
      case JS_VALUE_TYPE:
177
      case JS_DATE_TYPE:
178
      case JS_OBJECT_TYPE:
179
      case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
180
      case JS_GENERATOR_OBJECT_TYPE:
181
      case JS_MODULE_TYPE:
182
      case JS_GLOBAL_OBJECT_TYPE:
183
      case JS_BUILTINS_OBJECT_TYPE:
184
      case JS_GLOBAL_PROXY_TYPE:
185
      case JS_ARRAY_BUFFER_TYPE:
186
      case JS_TYPED_ARRAY_TYPE:
187
      case JS_DATA_VIEW_TYPE:
188
      case JS_SET_TYPE:
189
      case JS_MAP_TYPE:
190
      case JS_WEAK_MAP_TYPE:
191
      case JS_WEAK_SET_TYPE:
192
        if (map->is_undetectable()) return kUndetectable;
193
        return kOtherObject;
194
      case JS_ARRAY_TYPE:
195
        return kArray;
196
      case JS_FUNCTION_TYPE:
197
        return kFunction;
198
      case JS_REGEXP_TYPE:
199
        return kRegExp;
200
      case JS_PROXY_TYPE:
201
      case JS_FUNCTION_PROXY_TYPE:
202
        return kProxy;
203
      case MAP_TYPE:
204
        // When compiling stub templates, the meta map is used as a place holder
205
        // for the actual map with which the template is later instantiated.
206
        // We treat it as a kind of type variable whose upper bound is Any.
207
        // TODO(rossberg): for caching of CompareNilIC stubs to work correctly,
208
        // we must exclude Undetectable here. This makes no sense, really,
209
        // because it means that the template isn't actually parametric.
210
        // Also, it doesn't apply elsewhere. 8-(
211
        // We ought to find a cleaner solution for compiling stubs parameterised
212
        // over type or class variables, esp ones with bounds...
213
        return kDetectable;
214
      case DECLARED_ACCESSOR_INFO_TYPE:
215
      case EXECUTABLE_ACCESSOR_INFO_TYPE:
216
      case ACCESSOR_PAIR_TYPE:
217
      case FIXED_ARRAY_TYPE:
218
        return kInternal;
219
      default:
220
        UNREACHABLE();
221
        return kNone;
222
    }
223
  }
224
}
225

    
226

    
227
// Get the largest bitset subsumed by this type.
228
int Type::GlbBitset() {
229
  if (this->is_bitset()) {
230
    return this->as_bitset();
231
  } else if (this->is_union()) {
232
    // All but the first are non-bitsets and thus would yield kNone anyway.
233
    return union_get(this->as_union(), 0)->GlbBitset();
234
  } else {
235
    return kNone;
236
  }
237
}
238

    
239

    
240
// Check this <= that.
241
bool Type::SlowIs(Type* that) {
242
  // Fast path for bitsets.
243
  if (this->is_none()) return true;
244
  if (that->is_bitset()) {
245
    return (this->LubBitset() | that->as_bitset()) == that->as_bitset();
246
  }
247

    
248
  if (that->is_class()) {
249
    return this->is_class() && *this->as_class() == *that->as_class();
250
  }
251
  if (that->is_constant()) {
252
    return this->is_constant() && *this->as_constant() == *that->as_constant();
253
  }
254

    
255
  // (T1 \/ ... \/ Tn) <= T  <=>  (T1 <= T) /\ ... /\ (Tn <= T)
256
  if (this->is_union()) {
257
    Handle<Unioned> unioned = this->as_union();
258
    for (int i = 0; i < unioned->length(); ++i) {
259
      Handle<Type> this_i = union_get(unioned, i);
260
      if (!this_i->Is(that)) return false;
261
    }
262
    return true;
263
  }
264

    
265
  // T <= (T1 \/ ... \/ Tn)  <=>  (T <= T1) \/ ... \/ (T <= Tn)
266
  // (iff T is not a union)
267
  ASSERT(!this->is_union());
268
  if (that->is_union()) {
269
    Handle<Unioned> unioned = that->as_union();
270
    for (int i = 0; i < unioned->length(); ++i) {
271
      Handle<Type> that_i = union_get(unioned, i);
272
      if (this->Is(that_i)) return true;
273
      if (this->is_bitset()) break;  // Fast fail, no other field is a bitset.
274
    }
275
    return false;
276
  }
277

    
278
  return false;
279
}
280

    
281

    
282
// Check this overlaps that.
283
bool Type::Maybe(Type* that) {
284
  // Fast path for bitsets.
285
  if (this->is_bitset()) {
286
    return (this->as_bitset() & that->LubBitset()) != 0;
287
  }
288
  if (that->is_bitset()) {
289
    return (this->LubBitset() & that->as_bitset()) != 0;
290
  }
291

    
292
  // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T)
293
  if (this->is_union()) {
294
    Handle<Unioned> unioned = this->as_union();
295
    for (int i = 0; i < unioned->length(); ++i) {
296
      Handle<Type> this_i = union_get(unioned, i);
297
      if (this_i->Maybe(that)) return true;
298
    }
299
    return false;
300
  }
301

    
302
  // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn)
303
  if (that->is_union()) {
304
    Handle<Unioned> unioned = that->as_union();
305
    for (int i = 0; i < unioned->length(); ++i) {
306
      Handle<Type> that_i = union_get(unioned, i);
307
      if (this->Maybe(that_i)) return true;
308
    }
309
    return false;
310
  }
311

    
312
  ASSERT(!that->is_union());
313
  if (this->is_class()) {
314
    return that->is_class() && *this->as_class() == *that->as_class();
315
  }
316
  if (this->is_constant()) {
317
    return that->is_constant() && *this->as_constant() == *that->as_constant();
318
  }
319

    
320
  return false;
321
}
322

    
323

    
324
bool Type::InUnion(Handle<Unioned> unioned, int current_size) {
325
  ASSERT(!this->is_union());
326
  for (int i = 0; i < current_size; ++i) {
327
    Handle<Type> type = union_get(unioned, i);
328
    if (this->Is(type)) return true;
329
  }
330
  return false;
331
}
332

    
333

    
334
// Get non-bitsets from this which are not subsumed by union, store at unioned,
335
// starting at index. Returns updated index.
336
int Type::ExtendUnion(Handle<Unioned> result, int current_size) {
337
  int old_size = current_size;
338
  if (this->is_class() || this->is_constant()) {
339
    if (!this->InUnion(result, old_size)) result->set(current_size++, this);
340
  } else if (this->is_union()) {
341
    Handle<Unioned> unioned = this->as_union();
342
    for (int i = 0; i < unioned->length(); ++i) {
343
      Handle<Type> type = union_get(unioned, i);
344
      ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0))));
345
      if (type->is_bitset()) continue;
346
      if (!type->InUnion(result, old_size)) result->set(current_size++, *type);
347
    }
348
  }
349
  return current_size;
350
}
351

    
352

    
353
// Union is O(1) on simple bit unions, but O(n*m) on structured unions.
354
// TODO(rossberg): Should we use object sets somehow? Is it worth it?
355
Type* Type::Union(Handle<Type> type1, Handle<Type> type2) {
356
  // Fast case: bit sets.
357
  if (type1->is_bitset() && type2->is_bitset()) {
358
    return from_bitset(type1->as_bitset() | type2->as_bitset());
359
  }
360

    
361
  // Fast case: top or bottom types.
362
  if (type1->SameValue(Type::Any())) return *type1;
363
  if (type2->SameValue(Type::Any())) return *type2;
364
  if (type1->SameValue(Type::None())) return *type2;
365
  if (type2->SameValue(Type::None())) return *type1;
366

    
367
  // Semi-fast case: Unioned objects are neither involved nor produced.
368
  if (!(type1->is_union() || type2->is_union())) {
369
    if (type1->Is(type2)) return *type2;
370
    if (type2->Is(type1)) return *type1;
371
  }
372

    
373
  // Slow case: may need to produce a Unioned object.
374
  Isolate* isolate = NULL;
375
  int size = type1->is_bitset() || type2->is_bitset() ? 1 : 0;
376
  if (!type1->is_bitset()) {
377
    isolate = HeapObject::cast(*type1)->GetIsolate();
378
    size += (type1->is_union() ? type1->as_union()->length() : 1);
379
  }
380
  if (!type2->is_bitset()) {
381
    isolate = HeapObject::cast(*type2)->GetIsolate();
382
    size += (type2->is_union() ? type2->as_union()->length() : 1);
383
  }
384
  ASSERT(isolate != NULL);
385
  ASSERT(size >= 2);
386
  Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size);
387
  size = 0;
388

    
389
  int bitset = type1->GlbBitset() | type2->GlbBitset();
390
  if (bitset != kNone) unioned->set(size++, from_bitset(bitset));
391
  size = type1->ExtendUnion(unioned, size);
392
  size = type2->ExtendUnion(unioned, size);
393

    
394
  if (size == 1) {
395
    return *union_get(unioned, 0);
396
  } else if (size == unioned->length()) {
397
    return from_handle(unioned);
398
  }
399

    
400
  // There was an overlap. Copy to smaller union.
401
  Handle<Unioned> result = isolate->factory()->NewFixedArray(size);
402
  for (int i = 0; i < size; ++i) result->set(i, unioned->get(i));
403
  return from_handle(result);
404
}
405

    
406

    
407
// Get non-bitsets from this which are also in that, store at unioned,
408
// starting at index. Returns updated index.
409
int Type::ExtendIntersection(
410
    Handle<Unioned> result, Handle<Type> that, int current_size) {
411
  int old_size = current_size;
412
  if (this->is_class() || this->is_constant()) {
413
    if (this->Is(that) && !this->InUnion(result, old_size))
414
      result->set(current_size++, this);
415
  } else if (this->is_union()) {
416
    Handle<Unioned> unioned = this->as_union();
417
    for (int i = 0; i < unioned->length(); ++i) {
418
      Handle<Type> type = union_get(unioned, i);
419
      ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0))));
420
      if (type->is_bitset()) continue;
421
      if (type->Is(that) && !type->InUnion(result, old_size))
422
        result->set(current_size++, *type);
423
    }
424
  }
425
  return current_size;
426
}
427

    
428

    
429
// Intersection is O(1) on simple bit unions, but O(n*m) on structured unions.
430
// TODO(rossberg): Should we use object sets somehow? Is it worth it?
431
Type* Type::Intersect(Handle<Type> type1, Handle<Type> type2) {
432
  // Fast case: bit sets.
433
  if (type1->is_bitset() && type2->is_bitset()) {
434
    return from_bitset(type1->as_bitset() & type2->as_bitset());
435
  }
436

    
437
  // Fast case: top or bottom types.
438
  if (type1->SameValue(Type::None())) return *type1;
439
  if (type2->SameValue(Type::None())) return *type2;
440
  if (type1->SameValue(Type::Any())) return *type2;
441
  if (type2->SameValue(Type::Any())) return *type1;
442

    
443
  // Semi-fast case: Unioned objects are neither involved nor produced.
444
  if (!(type1->is_union() || type2->is_union())) {
445
    if (type1->Is(type2)) return *type1;
446
    if (type2->Is(type1)) return *type2;
447
  }
448

    
449
  // Slow case: may need to produce a Unioned object.
450
  Isolate* isolate = NULL;
451
  int size = 0;
452
  if (!type1->is_bitset()) {
453
    isolate = HeapObject::cast(*type1)->GetIsolate();
454
    size = (type1->is_union() ? type1->as_union()->length() : 2);
455
  }
456
  if (!type2->is_bitset()) {
457
    isolate = HeapObject::cast(*type2)->GetIsolate();
458
    int size2 = (type2->is_union() ? type2->as_union()->length() : 2);
459
    size = (size == 0 ? size2 : Min(size, size2));
460
  }
461
  ASSERT(isolate != NULL);
462
  ASSERT(size >= 2);
463
  Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size);
464
  size = 0;
465

    
466
  int bitset = type1->GlbBitset() & type2->GlbBitset();
467
  if (bitset != kNone) unioned->set(size++, from_bitset(bitset));
468
  size = type1->ExtendIntersection(unioned, type2, size);
469
  size = type2->ExtendIntersection(unioned, type1, size);
470

    
471
  if (size == 0) {
472
    return None();
473
  } else if (size == 1) {
474
    return *union_get(unioned, 0);
475
  } else if (size == unioned->length()) {
476
    return from_handle(unioned);
477
  }
478

    
479
  // There were dropped cases. Copy to smaller union.
480
  Handle<Unioned> result = isolate->factory()->NewFixedArray(size);
481
  for (int i = 0; i < size; ++i) result->set(i, unioned->get(i));
482
  return from_handle(result);
483
}
484

    
485

    
486
Type* Type::Optional(Handle<Type> type) {
487
  return type->is_bitset()
488
      ? from_bitset(type->as_bitset() | kUndefined)
489
      : Union(type, Undefined()->handle_via_isolate_of(*type));
490
}
491

    
492

    
493
Representation Representation::FromType(Handle<Type> type) {
494
  if (type->Is(Type::None())) return Representation::None();
495
  if (type->Is(Type::Smi())) return Representation::Smi();
496
  if (type->Is(Type::Signed32())) return Representation::Integer32();
497
  if (type->Is(Type::Number())) return Representation::Double();
498
  return Representation::Tagged();
499
}
500

    
501

    
502
#ifdef OBJECT_PRINT
503
void Type::TypePrint() {
504
  TypePrint(stdout);
505
  PrintF(stdout, "\n");
506
  Flush(stdout);
507
}
508

    
509

    
510
void Type::TypePrint(FILE* out) {
511
  if (is_bitset()) {
512
    int val = as_bitset();
513
    const char* composed_name = GetComposedName(val);
514
    if (composed_name != NULL) {
515
      PrintF(out, "%s", composed_name);
516
      return;
517
    }
518
    bool first_entry = true;
519
    PrintF(out, "{");
520
    for (unsigned i = 0; i < sizeof(val)*8; ++i) {
521
      int mask = (1 << i);
522
      if ((val & mask) != 0) {
523
        if (!first_entry) PrintF(out, ",");
524
        first_entry = false;
525
        PrintF(out, "%s", GetPrimitiveName(mask));
526
      }
527
    }
528
    PrintF(out, "}");
529
  } else if (is_constant()) {
530
    PrintF(out, "Constant(%p : ", static_cast<void*>(*as_constant()));
531
    from_bitset(LubBitset())->TypePrint(out);
532
    PrintF(")");
533
  } else if (is_class()) {
534
    PrintF(out, "Class(%p < ", static_cast<void*>(*as_class()));
535
    from_bitset(LubBitset())->TypePrint(out);
536
    PrintF(")");
537
  } else if (is_union()) {
538
    PrintF(out, "{");
539
    Handle<Unioned> unioned = as_union();
540
    for (int i = 0; i < unioned->length(); ++i) {
541
      Handle<Type> type_i = union_get(unioned, i);
542
      if (i > 0) PrintF(out, ",");
543
      type_i->TypePrint(out);
544
    }
545
    PrintF(out, "}");
546
  }
547
}
548
#endif
549

    
550

    
551
} }  // namespace v8::internal