| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_TYPES_H_ | 5 #ifndef V8_TYPES_H_ |
| 6 #define V8_TYPES_H_ | 6 #define V8_TYPES_H_ |
| 7 | 7 |
| 8 #include "src/conversions.h" | 8 #include "src/conversions.h" |
| 9 #include "src/handles.h" | 9 #include "src/handles.h" |
| 10 #include "src/objects.h" | 10 #include "src/objects.h" |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 #define PROPER_BITSET_TYPE_LIST(V) \ | 252 #define PROPER_BITSET_TYPE_LIST(V) \ |
| 253 REPRESENTATION_BITSET_TYPE_LIST(V) \ | 253 REPRESENTATION_BITSET_TYPE_LIST(V) \ |
| 254 SEMANTIC_BITSET_TYPE_LIST(V) | 254 SEMANTIC_BITSET_TYPE_LIST(V) |
| 255 | 255 |
| 256 #define BITSET_TYPE_LIST(V) \ | 256 #define BITSET_TYPE_LIST(V) \ |
| 257 MASK_BITSET_TYPE_LIST(V) \ | 257 MASK_BITSET_TYPE_LIST(V) \ |
| 258 REPRESENTATION_BITSET_TYPE_LIST(V) \ | 258 REPRESENTATION_BITSET_TYPE_LIST(V) \ |
| 259 INTERNAL_BITSET_TYPE_LIST(V) \ | 259 INTERNAL_BITSET_TYPE_LIST(V) \ |
| 260 SEMANTIC_BITSET_TYPE_LIST(V) | 260 SEMANTIC_BITSET_TYPE_LIST(V) |
| 261 | 261 |
| 262 class Type; |
| 262 | 263 |
| 263 // ----------------------------------------------------------------------------- | 264 // ----------------------------------------------------------------------------- |
| 264 // The abstract Type class, parameterized over the low-level representation. | 265 // Bitset types (internal). |
| 265 | 266 |
| 266 // struct Config { | 267 class BitsetType { |
| 267 // typedef TypeImpl<Config> Type; | |
| 268 // typedef Base; | |
| 269 // typedef Struct; | |
| 270 // typedef Range; | |
| 271 // typedef Region; | |
| 272 // template<class> struct Handle { typedef type; } // No template typedefs... | |
| 273 // | |
| 274 // template<class T> static Handle<T>::type null_handle(); | |
| 275 // template<class T> static Handle<T>::type handle(T* t); // !is_bitset(t) | |
| 276 // template<class T> static Handle<T>::type cast(Handle<Type>::type); | |
| 277 // | |
| 278 // static bool is_bitset(Type*); | |
| 279 // static bool is_class(Type*); | |
| 280 // static bool is_struct(Type*, int tag); | |
| 281 // static bool is_range(Type*); | |
| 282 // | |
| 283 // static bitset as_bitset(Type*); | |
| 284 // static i::Handle<i::Map> as_class(Type*); | |
| 285 // static Handle<Struct>::type as_struct(Type*); | |
| 286 // static Handle<Range>::type as_range(Type*); | |
| 287 // | |
| 288 // static Type* from_bitset(bitset); | |
| 289 // static Handle<Type>::type from_bitset(bitset, Region*); | |
| 290 // static Handle<Type>::type from_class(i::Handle<Map>, Region*); | |
| 291 // static Handle<Type>::type from_struct(Handle<Struct>::type, int tag); | |
| 292 // static Handle<Type>::type from_range(Handle<Range>::type); | |
| 293 // | |
| 294 // static Handle<Struct>::type struct_create(int tag, int length, Region*); | |
| 295 // static void struct_shrink(Handle<Struct>::type, int length); | |
| 296 // static int struct_tag(Handle<Struct>::type); | |
| 297 // static int struct_length(Handle<Struct>::type); | |
| 298 // static Handle<Type>::type struct_get(Handle<Struct>::type, int); | |
| 299 // static void struct_set(Handle<Struct>::type, int, Handle<Type>::type); | |
| 300 // template<class V> | |
| 301 // static i::Handle<V> struct_get_value(Handle<Struct>::type, int); | |
| 302 // template<class V> | |
| 303 // static void struct_set_value(Handle<Struct>::type, int, i::Handle<V>); | |
| 304 // | |
| 305 // static Handle<Range>::type range_create(Region*); | |
| 306 // static int range_get_bitset(Handle<Range>::type); | |
| 307 // static void range_set_bitset(Handle<Range>::type, int); | |
| 308 // static double range_get_double(Handle<Range>::type, int); | |
| 309 // static void range_set_double(Handle<Range>::type, int, double, Region*); | |
| 310 // } | |
| 311 template<class Config> | |
| 312 class TypeImpl : public Config::Base { | |
| 313 public: | 268 public: |
| 314 // Auxiliary types. | 269 typedef uint32_t bitset; // Internal |
| 315 | 270 |
| 316 typedef uint32_t bitset; // Internal | 271 enum : uint32_t { |
| 317 class BitsetType; // Internal | 272 #define DECLARE_TYPE(type, value) k##type = (value), |
| 318 class StructuralType; // Internal | 273 BITSET_TYPE_LIST(DECLARE_TYPE) |
| 319 class UnionType; // Internal | 274 #undef DECLARE_TYPE |
| 275 kUnusedEOL = 0 |
| 276 }; |
| 320 | 277 |
| 321 class ClassType; | 278 static bitset SignedSmall(); |
| 322 class ConstantType; | 279 static bitset UnsignedSmall(); |
| 323 class RangeType; | |
| 324 class ContextType; | |
| 325 class ArrayType; | |
| 326 class FunctionType; | |
| 327 class TupleType; | |
| 328 | 280 |
| 329 typedef typename Config::template Handle<TypeImpl>::type TypeHandle; | 281 bitset Bitset() { |
| 330 typedef typename Config::template Handle<ClassType>::type ClassHandle; | 282 return static_cast<bitset>(reinterpret_cast<uintptr_t>(this) ^ 1u); |
| 331 typedef typename Config::template Handle<ConstantType>::type ConstantHandle; | |
| 332 typedef typename Config::template Handle<RangeType>::type RangeHandle; | |
| 333 typedef typename Config::template Handle<ContextType>::type ContextHandle; | |
| 334 typedef typename Config::template Handle<ArrayType>::type ArrayHandle; | |
| 335 typedef typename Config::template Handle<FunctionType>::type FunctionHandle; | |
| 336 typedef typename Config::template Handle<UnionType>::type UnionHandle; | |
| 337 typedef typename Config::template Handle<TupleType>::type TupleHandle; | |
| 338 typedef typename Config::Region Region; | |
| 339 | |
| 340 // Constructors. | |
| 341 | |
| 342 #define DEFINE_TYPE_CONSTRUCTOR(type, value) \ | |
| 343 static TypeImpl* type() { \ | |
| 344 return BitsetType::New(BitsetType::k##type); \ | |
| 345 } \ | |
| 346 static TypeHandle type(Region* region) { \ | |
| 347 return BitsetType::New(BitsetType::k##type, region); \ | |
| 348 } | |
| 349 PROPER_BITSET_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) | |
| 350 #undef DEFINE_TYPE_CONSTRUCTOR | |
| 351 | |
| 352 static TypeImpl* SignedSmall() { | |
| 353 return BitsetType::New(BitsetType::SignedSmall()); | |
| 354 } | |
| 355 static TypeHandle SignedSmall(Region* region) { | |
| 356 return BitsetType::New(BitsetType::SignedSmall(), region); | |
| 357 } | |
| 358 static TypeImpl* UnsignedSmall() { | |
| 359 return BitsetType::New(BitsetType::UnsignedSmall()); | |
| 360 } | |
| 361 static TypeHandle UnsignedSmall(Region* region) { | |
| 362 return BitsetType::New(BitsetType::UnsignedSmall(), region); | |
| 363 } | 283 } |
| 364 | 284 |
| 365 static TypeHandle Class(i::Handle<i::Map> map, Region* region) { | 285 static bool IsInhabited(bitset bits) { |
| 366 return ClassType::New(map, region); | 286 return SEMANTIC(bits) != kNone && REPRESENTATION(bits) != kNone; |
| 367 } | |
| 368 static TypeHandle Constant(i::Handle<i::Object> value, Region* region) { | |
| 369 return ConstantType::New(value, region); | |
| 370 } | |
| 371 static TypeHandle Range(double min, double max, Region* region) { | |
| 372 return RangeType::New( | |
| 373 min, max, BitsetType::New(REPRESENTATION(BitsetType::kTagged | | |
| 374 BitsetType::kUntaggedNumber), | |
| 375 region), | |
| 376 region); | |
| 377 } | |
| 378 static TypeHandle Context(TypeHandle outer, Region* region) { | |
| 379 return ContextType::New(outer, region); | |
| 380 } | |
| 381 static TypeHandle Array(TypeHandle element, Region* region) { | |
| 382 return ArrayType::New(element, region); | |
| 383 } | |
| 384 static FunctionHandle Function( | |
| 385 TypeHandle result, TypeHandle receiver, int arity, Region* region) { | |
| 386 return FunctionType::New(result, receiver, arity, region); | |
| 387 } | |
| 388 static TypeHandle Function(TypeHandle result, Region* region) { | |
| 389 return Function(result, Any(region), 0, region); | |
| 390 } | |
| 391 static TypeHandle Function( | |
| 392 TypeHandle result, TypeHandle param0, Region* region) { | |
| 393 FunctionHandle function = Function(result, Any(region), 1, region); | |
| 394 function->InitParameter(0, param0); | |
| 395 return function; | |
| 396 } | |
| 397 static TypeHandle Function( | |
| 398 TypeHandle result, TypeHandle param0, TypeHandle param1, Region* region) { | |
| 399 FunctionHandle function = Function(result, Any(region), 2, region); | |
| 400 function->InitParameter(0, param0); | |
| 401 function->InitParameter(1, param1); | |
| 402 return function; | |
| 403 } | |
| 404 static TypeHandle Function( | |
| 405 TypeHandle result, TypeHandle param0, TypeHandle param1, | |
| 406 TypeHandle param2, Region* region) { | |
| 407 FunctionHandle function = Function(result, Any(region), 3, region); | |
| 408 function->InitParameter(0, param0); | |
| 409 function->InitParameter(1, param1); | |
| 410 function->InitParameter(2, param2); | |
| 411 return function; | |
| 412 } | |
| 413 static TypeHandle Function(TypeHandle result, int arity, TypeHandle* params, | |
| 414 Region* region) { | |
| 415 FunctionHandle function = Function(result, Any(region), arity, region); | |
| 416 for (int i = 0; i < arity; ++i) { | |
| 417 function->InitParameter(i, params[i]); | |
| 418 } | |
| 419 return function; | |
| 420 } | |
| 421 static TypeHandle Tuple(TypeHandle first, TypeHandle second, TypeHandle third, | |
| 422 Region* region) { | |
| 423 TupleHandle tuple = TupleType::New(3, region); | |
| 424 tuple->InitElement(0, first); | |
| 425 tuple->InitElement(1, second); | |
| 426 tuple->InitElement(2, third); | |
| 427 return tuple; | |
| 428 } | 287 } |
| 429 | 288 |
| 430 #define CONSTRUCT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \ | 289 static bool SemanticIsInhabited(bitset bits) { |
| 431 static TypeHandle Name(Isolate* isolate, Region* region); | 290 return SEMANTIC(bits) != kNone; |
| 432 SIMD128_TYPES(CONSTRUCT_SIMD_TYPE) | |
| 433 #undef CONSTRUCT_SIMD_TYPE | |
| 434 | |
| 435 static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region* reg); | |
| 436 static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg); | |
| 437 | |
| 438 static TypeHandle Of(double value, Region* region) { | |
| 439 return Config::from_bitset(BitsetType::ExpandInternals( | |
| 440 BitsetType::Lub(value)), region); | |
| 441 } | |
| 442 static TypeHandle Of(i::Object* value, Region* region) { | |
| 443 return Config::from_bitset(BitsetType::ExpandInternals( | |
| 444 BitsetType::Lub(value)), region); | |
| 445 } | |
| 446 static TypeHandle Of(i::Handle<i::Object> value, Region* region) { | |
| 447 return Of(*value, region); | |
| 448 } | 291 } |
| 449 | 292 |
| 450 // Extraction of components. | 293 static bool Is(bitset bits1, bitset bits2) { |
| 451 static TypeHandle Representation(TypeHandle t, Region* region); | 294 return (bits1 | bits2) == bits2; |
| 452 static TypeHandle Semantic(TypeHandle t, Region* region); | |
| 453 | |
| 454 // Predicates. | |
| 455 bool IsInhabited() { return BitsetType::IsInhabited(this->BitsetLub()); } | |
| 456 | |
| 457 bool Is(TypeImpl* that) { return this == that || this->SlowIs(that); } | |
| 458 template<class TypeHandle> | |
| 459 bool Is(TypeHandle that) { return this->Is(*that); } | |
| 460 | |
| 461 bool Maybe(TypeImpl* that); | |
| 462 template<class TypeHandle> | |
| 463 bool Maybe(TypeHandle that) { return this->Maybe(*that); } | |
| 464 | |
| 465 bool Equals(TypeImpl* that) { return this->Is(that) && that->Is(this); } | |
| 466 template<class TypeHandle> | |
| 467 bool Equals(TypeHandle that) { return this->Equals(*that); } | |
| 468 | |
| 469 // Equivalent to Constant(val)->Is(this), but avoiding allocation. | |
| 470 bool Contains(i::Object* val); | |
| 471 bool Contains(i::Handle<i::Object> val) { return this->Contains(*val); } | |
| 472 | |
| 473 // State-dependent versions of the above that consider subtyping between | |
| 474 // a constant and its map class. | |
| 475 inline static TypeHandle NowOf(i::Object* value, Region* region); | |
| 476 static TypeHandle NowOf(i::Handle<i::Object> value, Region* region) { | |
| 477 return NowOf(*value, region); | |
| 478 } | |
| 479 bool NowIs(TypeImpl* that); | |
| 480 template<class TypeHandle> | |
| 481 bool NowIs(TypeHandle that) { return this->NowIs(*that); } | |
| 482 inline bool NowContains(i::Object* val); | |
| 483 bool NowContains(i::Handle<i::Object> val) { return this->NowContains(*val); } | |
| 484 | |
| 485 bool NowStable(); | |
| 486 | |
| 487 // Inspection. | |
| 488 | |
| 489 bool IsRange() { return Config::is_range(this); } | |
| 490 bool IsClass() { | |
| 491 return Config::is_class(this) | |
| 492 || Config::is_struct(this, StructuralType::kClassTag); | |
| 493 } | |
| 494 bool IsConstant() { | |
| 495 return Config::is_struct(this, StructuralType::kConstantTag); | |
| 496 } | |
| 497 bool IsContext() { | |
| 498 return Config::is_struct(this, StructuralType::kContextTag); | |
| 499 } | |
| 500 bool IsArray() { | |
| 501 return Config::is_struct(this, StructuralType::kArrayTag); | |
| 502 } | |
| 503 bool IsFunction() { | |
| 504 return Config::is_struct(this, StructuralType::kFunctionTag); | |
| 505 } | |
| 506 bool IsTuple() { return Config::is_struct(this, StructuralType::kTupleTag); } | |
| 507 | |
| 508 ClassType* AsClass() { return ClassType::cast(this); } | |
| 509 ConstantType* AsConstant() { return ConstantType::cast(this); } | |
| 510 RangeType* AsRange() { return RangeType::cast(this); } | |
| 511 ContextType* AsContext() { return ContextType::cast(this); } | |
| 512 ArrayType* AsArray() { return ArrayType::cast(this); } | |
| 513 FunctionType* AsFunction() { return FunctionType::cast(this); } | |
| 514 TupleType* AsTuple() { return TupleType::cast(this); } | |
| 515 | |
| 516 // Minimum and maximum of a numeric type. | |
| 517 // These functions do not distinguish between -0 and +0. If the type equals | |
| 518 // kNaN, they return NaN; otherwise kNaN is ignored. Only call these | |
| 519 // functions on subtypes of Number. | |
| 520 double Min(); | |
| 521 double Max(); | |
| 522 | |
| 523 // Extracts a range from the type: if the type is a range or a union | |
| 524 // containing a range, that range is returned; otherwise, NULL is returned. | |
| 525 RangeType* GetRange(); | |
| 526 | |
| 527 static bool IsInteger(double x) { | |
| 528 return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities. | |
| 529 } | |
| 530 static bool IsInteger(i::Object* x) { | |
| 531 return x->IsNumber() && IsInteger(x->Number()); | |
| 532 } | 295 } |
| 533 | 296 |
| 534 int NumClasses(); | 297 static double Min(bitset); |
| 535 int NumConstants(); | 298 static double Max(bitset); |
| 536 | 299 |
| 537 template<class T> class Iterator; | 300 static bitset Glb(Type* type); // greatest lower bound that's a bitset |
| 538 Iterator<i::Map> Classes() { | 301 static bitset Glb(double min, double max); |
| 539 if (this->IsBitset()) return Iterator<i::Map>(); | 302 static bitset Lub(Type* type); // least upper bound that's a bitset |
| 540 return Iterator<i::Map>(Config::handle(this)); | 303 static bitset Lub(i::Map* map); |
| 541 } | 304 static bitset Lub(i::Object* value); |
| 542 Iterator<i::Object> Constants() { | 305 static bitset Lub(double value); |
| 543 if (this->IsBitset()) return Iterator<i::Object>(); | 306 static bitset Lub(double min, double max); |
| 544 return Iterator<i::Object>(Config::handle(this)); | 307 static bitset ExpandInternals(bitset bits); |
| 308 |
| 309 static const char* Name(bitset); |
| 310 static void Print(std::ostream& os, bitset); // NOLINT |
| 311 #ifdef DEBUG |
| 312 static void Print(bitset); |
| 313 #endif |
| 314 |
| 315 static bitset NumberBits(bitset bits); |
| 316 |
| 317 static bool IsBitset(Type* type) { |
| 318 return reinterpret_cast<uintptr_t>(type) & 1; |
| 545 } | 319 } |
| 546 | 320 |
| 547 // Casting and conversion. | 321 static Type* NewForTesting(bitset bits) { return New(bits); } |
| 548 | 322 |
| 549 static inline TypeImpl* cast(typename Config::Base* object); | 323 private: |
| 324 friend class Type; |
| 550 | 325 |
| 551 // Printing. | 326 static Type* New(bitset bits) { |
| 327 return reinterpret_cast<Type*>(static_cast<uintptr_t>(bits | 1u)); |
| 328 } |
| 552 | 329 |
| 553 enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM }; | 330 struct Boundary { |
| 331 bitset internal; |
| 332 bitset external; |
| 333 double min; |
| 334 }; |
| 335 static const Boundary BoundariesArray[]; |
| 336 static inline const Boundary* Boundaries(); |
| 337 static inline size_t BoundariesSize(); |
| 338 }; |
| 554 | 339 |
| 555 void PrintTo(std::ostream& os, PrintDimension dim = BOTH_DIMS); // NOLINT | 340 // ----------------------------------------------------------------------------- |
| 341 // Superclass for non-bitset types (internal). |
| 342 class TypeBase { |
| 343 protected: |
| 344 friend class Type; |
| 556 | 345 |
| 557 #ifdef DEBUG | 346 enum Kind { |
| 558 void Print(); | 347 kClass, |
| 559 #endif | 348 kConstant, |
| 349 kContext, |
| 350 kArray, |
| 351 kFunction, |
| 352 kTuple, |
| 353 kUnion, |
| 354 kRange |
| 355 }; |
| 560 | 356 |
| 561 bool IsUnionForTesting() { return IsUnion(); } | 357 Kind kind() const { return kind_; } |
| 358 explicit TypeBase(Kind kind) : kind_(kind) {} |
| 562 | 359 |
| 563 protected: | 360 static bool IsKind(Type* type, Kind kind) { |
| 564 // Friends. | 361 if (BitsetType::IsBitset(type)) return false; |
| 362 TypeBase* base = reinterpret_cast<TypeBase*>(type); |
| 363 return base->kind() == kind; |
| 364 } |
| 565 | 365 |
| 566 template<class> friend class Iterator; | 366 // The hacky conversion to/from Type*. |
| 567 template<class> friend class TypeImpl; | 367 static Type* AsType(TypeBase* type) { return reinterpret_cast<Type*>(type); } |
| 368 static TypeBase* FromType(Type* type) { |
| 369 return reinterpret_cast<TypeBase*>(type); |
| 370 } |
| 568 | 371 |
| 569 // Handle conversion. | 372 private: |
| 373 Kind kind_; |
| 374 }; |
| 570 | 375 |
| 571 template<class T> | 376 // ----------------------------------------------------------------------------- |
| 572 static typename Config::template Handle<T>::type handle(T* type) { | 377 // Class types. |
| 573 return Config::handle(type); | 378 |
| 379 class ClassType : public TypeBase { |
| 380 public: |
| 381 i::Handle<i::Map> Map() { return map_; } |
| 382 |
| 383 private: |
| 384 friend class Type; |
| 385 friend class BitsetType; |
| 386 |
| 387 static Type* New(i::Handle<i::Map> map, Zone* zone) { |
| 388 return AsType(new (zone->New(sizeof(ClassType))) |
| 389 ClassType(BitsetType::Lub(*map), map)); |
| 574 } | 390 } |
| 575 TypeImpl* unhandle() { return this; } | |
| 576 | 391 |
| 577 // Internal inspection. | 392 static ClassType* cast(Type* type) { |
| 393 DCHECK(IsKind(type, kClass)); |
| 394 return static_cast<ClassType*>(FromType(type)); |
| 395 } |
| 578 | 396 |
| 579 bool IsNone() { return this == None(); } | 397 ClassType(BitsetType::bitset bitset, i::Handle<i::Map> map) |
| 580 bool IsAny() { return this == Any(); } | 398 : TypeBase(kClass), bitset_(bitset), map_(map) {} |
| 581 bool IsBitset() { return Config::is_bitset(this); } | |
| 582 bool IsUnion() { return Config::is_struct(this, StructuralType::kUnionTag); } | |
| 583 | 399 |
| 584 bitset AsBitset() { | 400 BitsetType::bitset Lub() { return bitset_; } |
| 585 DCHECK(this->IsBitset()); | 401 |
| 586 return static_cast<BitsetType*>(this)->Bitset(); | 402 BitsetType::bitset bitset_; |
| 403 Handle<i::Map> map_; |
| 404 }; |
| 405 |
| 406 // ----------------------------------------------------------------------------- |
| 407 // Constant types. |
| 408 |
| 409 class ConstantType : public TypeBase { |
| 410 public: |
| 411 i::Handle<i::Object> Value() { return object_; } |
| 412 |
| 413 private: |
| 414 friend class Type; |
| 415 friend class BitsetType; |
| 416 |
| 417 static Type* New(i::Handle<i::Object> value, Zone* zone) { |
| 418 BitsetType::bitset bitset = BitsetType::Lub(*value); |
| 419 return AsType(new (zone->New(sizeof(ConstantType))) |
| 420 ConstantType(bitset, value)); |
| 587 } | 421 } |
| 588 UnionType* AsUnion() { return UnionType::cast(this); } | |
| 589 | 422 |
| 590 bitset Representation(); | 423 static ConstantType* cast(Type* type) { |
| 424 DCHECK(IsKind(type, kConstant)); |
| 425 return static_cast<ConstantType*>(FromType(type)); |
| 426 } |
| 591 | 427 |
| 592 // Auxiliary functions. | 428 ConstantType(BitsetType::bitset bitset, i::Handle<i::Object> object) |
| 593 bool SemanticMaybe(TypeImpl* that); | 429 : TypeBase(kConstant), bitset_(bitset), object_(object) {} |
| 594 | 430 |
| 595 bitset BitsetGlb() { return BitsetType::Glb(this); } | 431 BitsetType::bitset Lub() { return bitset_; } |
| 596 bitset BitsetLub() { return BitsetType::Lub(this); } | |
| 597 | 432 |
| 598 bool SlowIs(TypeImpl* that); | 433 BitsetType::bitset bitset_; |
| 599 bool SemanticIs(TypeImpl* that); | 434 Handle<i::Object> object_; |
| 435 }; |
| 436 // TODO(neis): Also cache value if numerical. |
| 437 // TODO(neis): Allow restricting the representation. |
| 600 | 438 |
| 439 // ----------------------------------------------------------------------------- |
| 440 // Range types. |
| 441 |
| 442 class RangeType : public TypeBase { |
| 443 public: |
| 601 struct Limits { | 444 struct Limits { |
| 602 double min; | 445 double min; |
| 603 double max; | 446 double max; |
| 604 Limits(double min, double max) : min(min), max(max) {} | 447 Limits(double min, double max) : min(min), max(max) {} |
| 605 explicit Limits(RangeType* range) : min(range->Min()), max(range->Max()) {} | 448 explicit Limits(RangeType* range) : min(range->Min()), max(range->Max()) {} |
| 606 bool IsEmpty(); | 449 bool IsEmpty(); |
| 607 static Limits Empty() { return Limits(1, 0); } | 450 static Limits Empty() { return Limits(1, 0); } |
| 608 static Limits Intersect(Limits lhs, Limits rhs); | 451 static Limits Intersect(Limits lhs, Limits rhs); |
| 609 static Limits Union(Limits lhs, Limits rhs); | 452 static Limits Union(Limits lhs, Limits rhs); |
| 610 }; | 453 }; |
| 611 | 454 |
| 612 static bool Overlap(RangeType* lhs, RangeType* rhs); | 455 double Min() { return limits_.min; } |
| 613 static bool Contains(RangeType* lhs, RangeType* rhs); | 456 double Max() { return limits_.max; } |
| 614 static bool Contains(RangeType* range, ConstantType* constant); | |
| 615 static bool Contains(RangeType* range, i::Object* val); | |
| 616 | 457 |
| 617 static int UpdateRange( | 458 private: |
| 618 RangeHandle type, UnionHandle result, int size, Region* region); | 459 friend class Type; |
| 460 friend class BitsetType; |
| 461 friend class UnionType; |
| 619 | 462 |
| 620 static Limits IntersectRangeAndBitset(TypeHandle range, TypeHandle bits, | 463 static Type* New(double min, double max, BitsetType::bitset representation, |
| 621 Region* region); | 464 Zone* zone) { |
| 622 static Limits ToLimits(bitset bits, Region* region); | 465 return New(Limits(min, max), representation, zone); |
| 466 } |
| 623 | 467 |
| 624 bool SimplyEquals(TypeImpl* that); | 468 static bool IsInteger(double x) { |
| 625 template<class TypeHandle> | 469 return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities. |
| 626 bool SimplyEquals(TypeHandle that) { return this->SimplyEquals(*that); } | 470 } |
| 627 | 471 |
| 628 static int AddToUnion( | 472 static Type* New(Limits lim, BitsetType::bitset representation, Zone* zone) { |
| 629 TypeHandle type, UnionHandle result, int size, Region* region); | 473 DCHECK(IsInteger(lim.min) && IsInteger(lim.max)); |
| 630 static int IntersectAux(TypeHandle type, TypeHandle other, UnionHandle result, | 474 DCHECK(lim.min <= lim.max); |
| 631 int size, Limits* limits, Region* region); | 475 DCHECK(REPRESENTATION(representation) == representation); |
| 632 static TypeHandle NormalizeUnion(UnionHandle unioned, int size, | 476 BitsetType::bitset bits = |
| 633 Region* region); | 477 SEMANTIC(BitsetType::Lub(lim.min, lim.max)) | representation; |
| 634 static TypeHandle NormalizeRangeAndBitset(RangeHandle range, bitset* bits, | 478 |
| 635 Region* region); | 479 return AsType(new (zone->New(sizeof(RangeType))) RangeType(bits, lim)); |
| 480 } |
| 481 |
| 482 static RangeType* cast(Type* type) { |
| 483 DCHECK(IsKind(type, kRange)); |
| 484 return static_cast<RangeType*>(FromType(type)); |
| 485 } |
| 486 |
| 487 RangeType(BitsetType::bitset bitset, Limits limits) |
| 488 : TypeBase(kRange), bitset_(bitset), limits_(limits) {} |
| 489 |
| 490 BitsetType::bitset Lub() { return bitset_; } |
| 491 |
| 492 BitsetType::bitset bitset_; |
| 493 Limits limits_; |
| 636 }; | 494 }; |
| 637 | 495 |
| 496 // ----------------------------------------------------------------------------- |
| 497 // Context types. |
| 498 |
| 499 class ContextType : public TypeBase { |
| 500 public: |
| 501 Type* Outer() { return outer_; } |
| 502 |
| 503 private: |
| 504 friend class Type; |
| 505 |
| 506 static Type* New(Type* outer, Zone* zone) { |
| 507 return AsType(new (zone->New(sizeof(ContextType))) ContextType(outer)); |
| 508 } |
| 509 |
| 510 static ContextType* cast(Type* type) { |
| 511 DCHECK(IsKind(type, kContext)); |
| 512 return static_cast<ContextType*>(FromType(type)); |
| 513 } |
| 514 |
| 515 explicit ContextType(Type* outer) : TypeBase(kContext), outer_(outer) {} |
| 516 |
| 517 Type* outer_; |
| 518 }; |
| 638 | 519 |
| 639 // ----------------------------------------------------------------------------- | 520 // ----------------------------------------------------------------------------- |
| 640 // Bitset types (internal). | 521 // Array types. |
| 641 | 522 |
| 642 template<class Config> | 523 class ArrayType : public TypeBase { |
| 643 class TypeImpl<Config>::BitsetType : public TypeImpl<Config> { | 524 public: |
| 644 protected: | 525 Type* Element() { return element_; } |
| 645 friend class TypeImpl<Config>; | |
| 646 | 526 |
| 647 enum : uint32_t { | 527 private: |
| 648 #define DECLARE_TYPE(type, value) k##type = (value), | 528 friend class Type; |
| 649 BITSET_TYPE_LIST(DECLARE_TYPE) | |
| 650 #undef DECLARE_TYPE | |
| 651 kUnusedEOL = 0 | |
| 652 }; | |
| 653 | 529 |
| 654 static bitset SignedSmall(); | 530 explicit ArrayType(Type* element) : TypeBase(kArray), element_(element) {} |
| 655 static bitset UnsignedSmall(); | |
| 656 | 531 |
| 657 bitset Bitset() { return Config::as_bitset(this); } | 532 static Type* New(Type* element, Zone* zone) { |
| 658 | 533 return AsType(new (zone->New(sizeof(ArrayType))) ArrayType(element)); |
| 659 static TypeImpl* New(bitset bits) { | |
| 660 return Config::from_bitset(bits); | |
| 661 } | |
| 662 static TypeHandle New(bitset bits, Region* region) { | |
| 663 return Config::from_bitset(bits, region); | |
| 664 } | 534 } |
| 665 | 535 |
| 666 static bool IsInhabited(bitset bits) { | 536 static ArrayType* cast(Type* type) { |
| 667 return SEMANTIC(bits) != kNone && REPRESENTATION(bits) != kNone; | 537 DCHECK(IsKind(type, kArray)); |
| 538 return static_cast<ArrayType*>(FromType(type)); |
| 668 } | 539 } |
| 669 | 540 |
| 670 static bool SemanticIsInhabited(bitset bits) { | 541 Type* element_; |
| 671 return SEMANTIC(bits) != kNone; | 542 }; |
| 543 |
| 544 // ----------------------------------------------------------------------------- |
| 545 // Superclass for types with variable number of type fields. |
| 546 class StructuralType : public TypeBase { |
| 547 public: |
| 548 int LengthForTesting() { return Length(); } |
| 549 |
| 550 protected: |
| 551 friend class Type; |
| 552 |
| 553 int Length() { return length_; } |
| 554 |
| 555 Type* Get(int i) { |
| 556 DCHECK(0 <= i && i < this->Length()); |
| 557 return elements_[i]; |
| 672 } | 558 } |
| 673 | 559 |
| 674 static bool Is(bitset bits1, bitset bits2) { | 560 void Set(int i, Type* type) { |
| 675 return (bits1 | bits2) == bits2; | 561 DCHECK(0 <= i && i < this->Length()); |
| 562 elements_[i] = type; |
| 676 } | 563 } |
| 677 | 564 |
| 678 static double Min(bitset); | 565 void Shrink(int length) { |
| 679 static double Max(bitset); | 566 DCHECK(2 <= length && length <= this->Length()); |
| 567 length_ = length; |
| 568 } |
| 680 | 569 |
| 681 static bitset Glb(TypeImpl* type); // greatest lower bound that's a bitset | 570 StructuralType(Kind kind, int length, i::Zone* zone) |
| 682 static bitset Glb(double min, double max); | 571 : TypeBase(kind), length_(length) { |
| 683 static bitset Lub(TypeImpl* type); // least upper bound that's a bitset | 572 elements_ = reinterpret_cast<Type**>(zone->New(sizeof(Type*) * length)); |
| 684 static bitset Lub(i::Map* map); | 573 } |
| 685 static bitset Lub(i::Object* value); | |
| 686 static bitset Lub(double value); | |
| 687 static bitset Lub(double min, double max); | |
| 688 static bitset ExpandInternals(bitset bits); | |
| 689 | |
| 690 static const char* Name(bitset); | |
| 691 static void Print(std::ostream& os, bitset); // NOLINT | |
| 692 #ifdef DEBUG | |
| 693 static void Print(bitset); | |
| 694 #endif | |
| 695 | |
| 696 static bitset NumberBits(bitset bits); | |
| 697 | 574 |
| 698 private: | 575 private: |
| 699 struct Boundary { | 576 int length_; |
| 700 bitset internal; | 577 Type** elements_; |
| 701 bitset external; | |
| 702 double min; | |
| 703 }; | |
| 704 static const Boundary BoundariesArray[]; | |
| 705 static inline const Boundary* Boundaries(); | |
| 706 static inline size_t BoundariesSize(); | |
| 707 }; | 578 }; |
| 708 | 579 |
| 580 // ----------------------------------------------------------------------------- |
| 581 // Function types. |
| 709 | 582 |
| 710 // ----------------------------------------------------------------------------- | 583 class FunctionType : public StructuralType { |
| 711 // Superclass for non-bitset types (internal). | 584 public: |
| 712 // Contains a tag and a variable number of type or value fields. | 585 int Arity() { return this->Length() - 2; } |
| 586 Type* Result() { return this->Get(0); } |
| 587 Type* Receiver() { return this->Get(1); } |
| 588 Type* Parameter(int i) { return this->Get(2 + i); } |
| 713 | 589 |
| 714 template<class Config> | 590 void InitParameter(int i, Type* type) { this->Set(2 + i, type); } |
| 715 class TypeImpl<Config>::StructuralType : public TypeImpl<Config> { | |
| 716 protected: | |
| 717 template<class> friend class TypeImpl; | |
| 718 friend struct ZoneTypeConfig; // For tags. | |
| 719 friend struct HeapTypeConfig; | |
| 720 | 591 |
| 721 enum Tag { | 592 private: |
| 722 kClassTag, | 593 friend class Type; |
| 723 kConstantTag, | |
| 724 kContextTag, | |
| 725 kArrayTag, | |
| 726 kFunctionTag, | |
| 727 kTupleTag, | |
| 728 kUnionTag | |
| 729 }; | |
| 730 | 594 |
| 731 int Length() { | 595 FunctionType(Type* result, Type* receiver, int arity, Zone* zone) |
| 732 return Config::struct_length(Config::as_struct(this)); | 596 : StructuralType(kFunction, 2 + arity, zone) { |
| 733 } | 597 Set(0, result); |
| 734 TypeHandle Get(int i) { | 598 Set(1, receiver); |
| 735 DCHECK(0 <= i && i < this->Length()); | |
| 736 return Config::struct_get(Config::as_struct(this), i); | |
| 737 } | |
| 738 void Set(int i, TypeHandle type) { | |
| 739 DCHECK(0 <= i && i < this->Length()); | |
| 740 Config::struct_set(Config::as_struct(this), i, type); | |
| 741 } | |
| 742 void Shrink(int length) { | |
| 743 DCHECK(2 <= length && length <= this->Length()); | |
| 744 Config::struct_shrink(Config::as_struct(this), length); | |
| 745 } | |
| 746 template<class V> i::Handle<V> GetValue(int i) { | |
| 747 DCHECK(0 <= i && i < this->Length()); | |
| 748 return Config::template struct_get_value<V>(Config::as_struct(this), i); | |
| 749 } | |
| 750 template<class V> void SetValue(int i, i::Handle<V> x) { | |
| 751 DCHECK(0 <= i && i < this->Length()); | |
| 752 Config::struct_set_value(Config::as_struct(this), i, x); | |
| 753 } | 599 } |
| 754 | 600 |
| 755 static TypeHandle New(Tag tag, int length, Region* region) { | 601 static Type* New(Type* result, Type* receiver, int arity, Zone* zone) { |
| 756 DCHECK(1 <= length); | 602 return AsType(new (zone->New(sizeof(FunctionType))) |
| 757 return Config::from_struct(Config::struct_create(tag, length, region)); | 603 FunctionType(result, receiver, arity, zone)); |
| 604 } |
| 605 |
| 606 static FunctionType* cast(Type* type) { |
| 607 DCHECK(IsKind(type, kFunction)); |
| 608 return static_cast<FunctionType*>(FromType(type)); |
| 758 } | 609 } |
| 759 }; | 610 }; |
| 760 | 611 |
| 612 // ----------------------------------------------------------------------------- |
| 613 // Tuple types. |
| 614 |
| 615 class TupleType : public StructuralType { |
| 616 public: |
| 617 int Arity() { return this->Length(); } |
| 618 Type* Element(int i) { return this->Get(i); } |
| 619 |
| 620 void InitElement(int i, Type* type) { this->Set(i, type); } |
| 621 |
| 622 private: |
| 623 friend class Type; |
| 624 |
| 625 TupleType(int length, Zone* zone) : StructuralType(kTuple, length, zone) {} |
| 626 |
| 627 static Type* New(int length, Zone* zone) { |
| 628 return AsType(new (zone->New(sizeof(TupleType))) TupleType(length, zone)); |
| 629 } |
| 630 |
| 631 static TupleType* cast(Type* type) { |
| 632 DCHECK(IsKind(type, kTuple)); |
| 633 return static_cast<TupleType*>(FromType(type)); |
| 634 } |
| 635 }; |
| 761 | 636 |
| 762 // ----------------------------------------------------------------------------- | 637 // ----------------------------------------------------------------------------- |
| 763 // Union types (internal). | 638 // Union types (internal). |
| 764 // A union is a structured type with the following invariants: | 639 // A union is a structured type with the following invariants: |
| 765 // - its length is at least 2 | 640 // - its length is at least 2 |
| 766 // - at most one field is a bitset, and it must go into index 0 | 641 // - at most one field is a bitset, and it must go into index 0 |
| 767 // - no field is a union | 642 // - no field is a union |
| 768 // - no field is a subtype of any other field | 643 // - no field is a subtype of any other field |
| 769 template<class Config> | 644 class UnionType : public StructuralType { |
| 770 class TypeImpl<Config>::UnionType : public StructuralType { | 645 private: |
| 771 public: | 646 friend Type; |
| 772 static UnionHandle New(int length, Region* region) { | 647 friend BitsetType; |
| 773 return Config::template cast<UnionType>( | 648 |
| 774 StructuralType::New(StructuralType::kUnionTag, length, region)); | 649 UnionType(int length, Zone* zone) : StructuralType(kUnion, length, zone) {} |
| 775 } | 650 |
| 776 | 651 static Type* New(int length, Zone* zone) { |
| 777 static UnionType* cast(TypeImpl* type) { | 652 return AsType(new (zone->New(sizeof(UnionType))) UnionType(length, zone)); |
| 778 DCHECK(type->IsUnion()); | 653 } |
| 779 return static_cast<UnionType*>(type); | 654 |
| 655 static UnionType* cast(Type* type) { |
| 656 DCHECK(IsKind(type, kUnion)); |
| 657 return static_cast<UnionType*>(FromType(type)); |
| 780 } | 658 } |
| 781 | 659 |
| 782 bool Wellformed(); | 660 bool Wellformed(); |
| 783 }; | 661 }; |
| 784 | 662 |
| 785 | 663 class Type { |
| 786 // ----------------------------------------------------------------------------- | |
| 787 // Class types. | |
| 788 | |
| 789 template<class Config> | |
| 790 class TypeImpl<Config>::ClassType : public StructuralType { | |
| 791 public: | 664 public: |
| 792 i::Handle<i::Map> Map() { | 665 typedef BitsetType::bitset bitset; // Internal |
| 793 return Config::is_class(this) ? Config::as_class(this) : | 666 |
| 794 this->template GetValue<i::Map>(1); | 667 // Constructors. |
| 795 } | 668 #define DEFINE_TYPE_CONSTRUCTOR(type, value) \ |
| 796 | 669 static Type* type() { return BitsetType::New(BitsetType::k##type); } |
| 797 static ClassHandle New(i::Handle<i::Map> map, Region* region) { | 670 PROPER_BITSET_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) |
| 798 ClassHandle type = | 671 #undef DEFINE_TYPE_CONSTRUCTOR |
| 799 Config::template cast<ClassType>(Config::from_class(map, region)); | 672 |
| 800 if (!type->IsClass()) { | 673 static Type* SignedSmall() { |
| 801 type = Config::template cast<ClassType>( | 674 return BitsetType::New(BitsetType::SignedSmall()); |
| 802 StructuralType::New(StructuralType::kClassTag, 2, region)); | 675 } |
| 803 type->Set(0, BitsetType::New(BitsetType::Lub(*map), region)); | 676 static Type* UnsignedSmall() { |
| 804 type->SetValue(1, map); | 677 return BitsetType::New(BitsetType::UnsignedSmall()); |
| 678 } |
| 679 |
| 680 static Type* Class(i::Handle<i::Map> map, Zone* zone) { |
| 681 return ClassType::New(map, zone); |
| 682 } |
| 683 static Type* Constant(i::Handle<i::Object> value, Zone* zone) { |
| 684 return ConstantType::New(value, zone); |
| 685 } |
| 686 static Type* Range(double min, double max, Zone* zone) { |
| 687 return RangeType::New(min, max, REPRESENTATION(BitsetType::kTagged | |
| 688 BitsetType::kUntaggedNumber), |
| 689 zone); |
| 690 } |
| 691 static Type* Context(Type* outer, Zone* zone) { |
| 692 return ContextType::New(outer, zone); |
| 693 } |
| 694 static Type* Array(Type* element, Zone* zone) { |
| 695 return ArrayType::New(element, zone); |
| 696 } |
| 697 static Type* Function(Type* result, Type* receiver, int arity, Zone* zone) { |
| 698 return FunctionType::New(result, receiver, arity, zone); |
| 699 } |
| 700 static Type* Function(Type* result, Zone* zone) { |
| 701 return Function(result, Any(), 0, zone); |
| 702 } |
| 703 static Type* Function(Type* result, Type* param0, Zone* zone) { |
| 704 Type* function = Function(result, Any(), 1, zone); |
| 705 function->AsFunction()->InitParameter(0, param0); |
| 706 return function; |
| 707 } |
| 708 static Type* Function(Type* result, Type* param0, Type* param1, Zone* zone) { |
| 709 Type* function = Function(result, Any(), 2, zone); |
| 710 function->AsFunction()->InitParameter(0, param0); |
| 711 function->AsFunction()->InitParameter(1, param1); |
| 712 return function; |
| 713 } |
| 714 static Type* Function(Type* result, Type* param0, Type* param1, Type* param2, |
| 715 Zone* zone) { |
| 716 Type* function = Function(result, Any(), 3, zone); |
| 717 function->AsFunction()->InitParameter(0, param0); |
| 718 function->AsFunction()->InitParameter(1, param1); |
| 719 function->AsFunction()->InitParameter(2, param2); |
| 720 return function; |
| 721 } |
| 722 static Type* Function(Type* result, int arity, Type** params, Zone* zone) { |
| 723 Type* function = Function(result, Any(), arity, zone); |
| 724 for (int i = 0; i < arity; ++i) { |
| 725 function->AsFunction()->InitParameter(i, params[i]); |
| 805 } | 726 } |
| 806 return type; | 727 return function; |
| 807 } | 728 } |
| 808 | 729 static Type* Tuple(Type* first, Type* second, Type* third, Zone* zone) { |
| 809 static ClassType* cast(TypeImpl* type) { | 730 Type* tuple = TupleType::New(3, zone); |
| 810 DCHECK(type->IsClass()); | 731 tuple->AsTuple()->InitElement(0, first); |
| 811 return static_cast<ClassType*>(type); | 732 tuple->AsTuple()->InitElement(1, second); |
| 812 } | 733 tuple->AsTuple()->InitElement(2, third); |
| 734 return tuple; |
| 735 } |
| 736 |
| 737 #define CONSTRUCT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \ |
| 738 static Type* Name(Isolate* isolate, Zone* zone); |
| 739 SIMD128_TYPES(CONSTRUCT_SIMD_TYPE) |
| 740 #undef CONSTRUCT_SIMD_TYPE |
| 741 |
| 742 static Type* Union(Type* type1, Type* type2, Zone* reg); |
| 743 static Type* Intersect(Type* type1, Type* type2, Zone* reg); |
| 744 |
| 745 static Type* Of(double value, Zone* zone) { |
| 746 return BitsetType::New(BitsetType::ExpandInternals(BitsetType::Lub(value))); |
| 747 } |
| 748 static Type* Of(i::Object* value, Zone* zone) { |
| 749 return BitsetType::New(BitsetType::ExpandInternals(BitsetType::Lub(value))); |
| 750 } |
| 751 static Type* Of(i::Handle<i::Object> value, Zone* zone) { |
| 752 return Of(*value, zone); |
| 753 } |
| 754 |
| 755 // Extraction of components. |
| 756 static Type* Representation(Type* t, Zone* zone); |
| 757 static Type* Semantic(Type* t, Zone* zone); |
| 758 |
| 759 // Predicates. |
| 760 bool IsInhabited() { return BitsetType::IsInhabited(this->BitsetLub()); } |
| 761 |
| 762 bool Is(Type* that) { return this == that || this->SlowIs(that); } |
| 763 bool Maybe(Type* that); |
| 764 bool Equals(Type* that) { return this->Is(that) && that->Is(this); } |
| 765 |
| 766 // Equivalent to Constant(val)->Is(this), but avoiding allocation. |
| 767 bool Contains(i::Object* val); |
| 768 bool Contains(i::Handle<i::Object> val) { return this->Contains(*val); } |
| 769 |
| 770 // State-dependent versions of the above that consider subtyping between |
| 771 // a constant and its map class. |
| 772 static Type* NowOf(i::Object* value, Zone* zone); |
| 773 static Type* NowOf(i::Handle<i::Object> value, Zone* zone) { |
| 774 return NowOf(*value, zone); |
| 775 } |
| 776 bool NowIs(Type* that); |
| 777 bool NowContains(i::Object* val); |
| 778 bool NowContains(i::Handle<i::Object> val) { return this->NowContains(*val); } |
| 779 |
| 780 bool NowStable(); |
| 781 |
| 782 // Inspection. |
| 783 bool IsRange() { return IsKind(TypeBase::kRange); } |
| 784 bool IsClass() { return IsKind(TypeBase::kClass); } |
| 785 bool IsConstant() { return IsKind(TypeBase::kConstant); } |
| 786 bool IsContext() { return IsKind(TypeBase::kContext); } |
| 787 bool IsArray() { return IsKind(TypeBase::kArray); } |
| 788 bool IsFunction() { return IsKind(TypeBase::kFunction); } |
| 789 bool IsTuple() { return IsKind(TypeBase::kTuple); } |
| 790 |
| 791 ClassType* AsClass() { return ClassType::cast(this); } |
| 792 ConstantType* AsConstant() { return ConstantType::cast(this); } |
| 793 RangeType* AsRange() { return RangeType::cast(this); } |
| 794 ContextType* AsContext() { return ContextType::cast(this); } |
| 795 ArrayType* AsArray() { return ArrayType::cast(this); } |
| 796 FunctionType* AsFunction() { return FunctionType::cast(this); } |
| 797 TupleType* AsTuple() { return TupleType::cast(this); } |
| 798 |
| 799 // Minimum and maximum of a numeric type. |
| 800 // These functions do not distinguish between -0 and +0. If the type equals |
| 801 // kNaN, they return NaN; otherwise kNaN is ignored. Only call these |
| 802 // functions on subtypes of Number. |
| 803 double Min(); |
| 804 double Max(); |
| 805 |
| 806 // Extracts a range from the type: if the type is a range or a union |
| 807 // containing a range, that range is returned; otherwise, NULL is returned. |
| 808 Type* GetRange(); |
| 809 |
| 810 static bool IsInteger(i::Object* x); |
| 811 static bool IsInteger(double x) { |
| 812 return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities. |
| 813 } |
| 814 |
| 815 int NumClasses(); |
| 816 int NumConstants(); |
| 817 |
| 818 template <class T> |
| 819 class Iterator { |
| 820 public: |
| 821 bool Done() const { return index_ < 0; } |
| 822 i::Handle<T> Current(); |
| 823 void Advance(); |
| 824 |
| 825 private: |
| 826 friend class Type; |
| 827 |
| 828 Iterator() : index_(-1) {} |
| 829 explicit Iterator(Type* type) : type_(type), index_(-1) { Advance(); } |
| 830 |
| 831 inline bool matches(Type* type); |
| 832 inline Type* get_type(); |
| 833 |
| 834 Type* type_; |
| 835 int index_; |
| 836 }; |
| 837 |
| 838 Iterator<i::Map> Classes() { |
| 839 if (this->IsBitset()) return Iterator<i::Map>(); |
| 840 return Iterator<i::Map>(this); |
| 841 } |
| 842 Iterator<i::Object> Constants() { |
| 843 if (this->IsBitset()) return Iterator<i::Object>(); |
| 844 return Iterator<i::Object>(this); |
| 845 } |
| 846 |
| 847 // Printing. |
| 848 |
| 849 enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM }; |
| 850 |
| 851 void PrintTo(std::ostream& os, PrintDimension dim = BOTH_DIMS); // NOLINT |
| 852 |
| 853 #ifdef DEBUG |
| 854 void Print(); |
| 855 #endif |
| 856 |
| 857 // Helpers for testing. |
| 858 bool IsBitsetForTesting() { return IsBitset(); } |
| 859 bool IsUnionForTesting() { return IsUnion(); } |
| 860 bitset AsBitsetForTesting() { return AsBitset(); } |
| 861 UnionType* AsUnionForTesting() { return AsUnion(); } |
| 813 | 862 |
| 814 private: | 863 private: |
| 815 template<class> friend class TypeImpl; | 864 // Friends. |
| 816 bitset Lub() { | 865 template <class> |
| 817 return Config::is_class(this) ? | 866 friend class Iterator; |
| 818 BitsetType::Lub(*Config::as_class(this)) : | 867 friend BitsetType; |
| 819 this->Get(0)->AsBitset(); | 868 friend UnionType; |
| 820 } | 869 |
| 870 // Internal inspection. |
| 871 bool IsKind(TypeBase::Kind kind) { return TypeBase::IsKind(this, kind); } |
| 872 |
| 873 bool IsNone() { return this == None(); } |
| 874 bool IsAny() { return this == Any(); } |
| 875 bool IsBitset() { return BitsetType::IsBitset(this); } |
| 876 bool IsUnion() { return IsKind(TypeBase::kUnion); } |
| 877 |
| 878 bitset AsBitset() { |
| 879 DCHECK(this->IsBitset()); |
| 880 return reinterpret_cast<BitsetType*>(this)->Bitset(); |
| 881 } |
| 882 UnionType* AsUnion() { return UnionType::cast(this); } |
| 883 |
| 884 bitset Representation(); |
| 885 |
| 886 // Auxiliary functions. |
| 887 bool SemanticMaybe(Type* that); |
| 888 |
| 889 bitset BitsetGlb() { return BitsetType::Glb(this); } |
| 890 bitset BitsetLub() { return BitsetType::Lub(this); } |
| 891 |
| 892 bool SlowIs(Type* that); |
| 893 bool SemanticIs(Type* that); |
| 894 |
| 895 static bool Overlap(RangeType* lhs, RangeType* rhs); |
| 896 static bool Contains(RangeType* lhs, RangeType* rhs); |
| 897 static bool Contains(RangeType* range, ConstantType* constant); |
| 898 static bool Contains(RangeType* range, i::Object* val); |
| 899 |
| 900 static int UpdateRange(Type* type, UnionType* result, int size, Zone* zone); |
| 901 |
| 902 static RangeType::Limits IntersectRangeAndBitset(Type* range, Type* bits, |
| 903 Zone* zone); |
| 904 static RangeType::Limits ToLimits(bitset bits, Zone* zone); |
| 905 |
| 906 bool SimplyEquals(Type* that); |
| 907 |
| 908 static int AddToUnion(Type* type, UnionType* result, int size, Zone* zone); |
| 909 static int IntersectAux(Type* type, Type* other, UnionType* result, int size, |
| 910 RangeType::Limits* limits, Zone* zone); |
| 911 static Type* NormalizeUnion(Type* unioned, int size, Zone* zone); |
| 912 static Type* NormalizeRangeAndBitset(Type* range, bitset* bits, Zone* zone); |
| 821 }; | 913 }; |
| 822 | 914 |
| 823 | |
| 824 // ----------------------------------------------------------------------------- | |
| 825 // Constant types. | |
| 826 | |
| 827 template<class Config> | |
| 828 class TypeImpl<Config>::ConstantType : public StructuralType { | |
| 829 public: | |
| 830 i::Handle<i::Object> Value() { return this->template GetValue<i::Object>(1); } | |
| 831 | |
| 832 static ConstantHandle New(i::Handle<i::Object> value, Region* region) { | |
| 833 ConstantHandle type = Config::template cast<ConstantType>( | |
| 834 StructuralType::New(StructuralType::kConstantTag, 2, region)); | |
| 835 type->Set(0, BitsetType::New(BitsetType::Lub(*value), region)); | |
| 836 type->SetValue(1, value); | |
| 837 return type; | |
| 838 } | |
| 839 | |
| 840 static ConstantType* cast(TypeImpl* type) { | |
| 841 DCHECK(type->IsConstant()); | |
| 842 return static_cast<ConstantType*>(type); | |
| 843 } | |
| 844 | |
| 845 private: | |
| 846 template<class> friend class TypeImpl; | |
| 847 bitset Lub() { return this->Get(0)->AsBitset(); } | |
| 848 }; | |
| 849 // TODO(neis): Also cache value if numerical. | |
| 850 // TODO(neis): Allow restricting the representation. | |
| 851 | |
| 852 | |
| 853 // ----------------------------------------------------------------------------- | |
| 854 // Range types. | |
| 855 | |
| 856 template <class Config> | |
| 857 class TypeImpl<Config>::RangeType : public TypeImpl<Config> { | |
| 858 public: | |
| 859 double Min() { return Config::range_get_double(Config::as_range(this), 0); } | |
| 860 double Max() { return Config::range_get_double(Config::as_range(this), 1); } | |
| 861 | |
| 862 static RangeHandle New(double min, double max, TypeHandle representation, | |
| 863 Region* region) { | |
| 864 DCHECK(IsInteger(min) && IsInteger(max)); | |
| 865 DCHECK(min <= max); | |
| 866 bitset representation_bits = representation->AsBitset(); | |
| 867 DCHECK(REPRESENTATION(representation_bits) == representation_bits); | |
| 868 | |
| 869 typename Config::template Handle<typename Config::Range>::type range = | |
| 870 Config::range_create(region); | |
| 871 | |
| 872 bitset bits = SEMANTIC(BitsetType::Lub(min, max)) | representation_bits; | |
| 873 Config::range_set_bitset(range, bits); | |
| 874 Config::range_set_double(range, 0, min, region); | |
| 875 Config::range_set_double(range, 1, max, region); | |
| 876 return Config::template cast<RangeType>(Config::from_range(range)); | |
| 877 } | |
| 878 | |
| 879 static RangeHandle New(Limits lim, bitset representation, Region* region) { | |
| 880 return New(lim.min, lim.max, BitsetType::New(representation, region), | |
| 881 region); | |
| 882 } | |
| 883 | |
| 884 static RangeType* cast(TypeImpl* type) { | |
| 885 DCHECK(type->IsRange()); | |
| 886 return static_cast<RangeType*>(type); | |
| 887 } | |
| 888 | |
| 889 private: | |
| 890 template<class> friend class TypeImpl; | |
| 891 bitset Lub() { | |
| 892 return Config::range_get_bitset(Config::as_range(this)); | |
| 893 } | |
| 894 }; | |
| 895 | |
| 896 | |
| 897 // ----------------------------------------------------------------------------- | |
| 898 // Context types. | |
| 899 | |
| 900 template<class Config> | |
| 901 class TypeImpl<Config>::ContextType : public StructuralType { | |
| 902 public: | |
| 903 TypeHandle Outer() { return this->Get(0); } | |
| 904 | |
| 905 static ContextHandle New(TypeHandle outer, Region* region) { | |
| 906 ContextHandle type = Config::template cast<ContextType>( | |
| 907 StructuralType::New(StructuralType::kContextTag, 1, region)); | |
| 908 type->Set(0, outer); | |
| 909 return type; | |
| 910 } | |
| 911 | |
| 912 static ContextType* cast(TypeImpl* type) { | |
| 913 DCHECK(type->IsContext()); | |
| 914 return static_cast<ContextType*>(type); | |
| 915 } | |
| 916 }; | |
| 917 | |
| 918 | |
| 919 // ----------------------------------------------------------------------------- | |
| 920 // Array types. | |
| 921 | |
| 922 template<class Config> | |
| 923 class TypeImpl<Config>::ArrayType : public StructuralType { | |
| 924 public: | |
| 925 TypeHandle Element() { return this->Get(0); } | |
| 926 | |
| 927 static ArrayHandle New(TypeHandle element, Region* region) { | |
| 928 ArrayHandle type = Config::template cast<ArrayType>( | |
| 929 StructuralType::New(StructuralType::kArrayTag, 1, region)); | |
| 930 type->Set(0, element); | |
| 931 return type; | |
| 932 } | |
| 933 | |
| 934 static ArrayType* cast(TypeImpl* type) { | |
| 935 DCHECK(type->IsArray()); | |
| 936 return static_cast<ArrayType*>(type); | |
| 937 } | |
| 938 }; | |
| 939 | |
| 940 | |
| 941 // ----------------------------------------------------------------------------- | |
| 942 // Function types. | |
| 943 | |
| 944 template<class Config> | |
| 945 class TypeImpl<Config>::FunctionType : public StructuralType { | |
| 946 public: | |
| 947 int Arity() { return this->Length() - 2; } | |
| 948 TypeHandle Result() { return this->Get(0); } | |
| 949 TypeHandle Receiver() { return this->Get(1); } | |
| 950 TypeHandle Parameter(int i) { return this->Get(2 + i); } | |
| 951 | |
| 952 void InitParameter(int i, TypeHandle type) { this->Set(2 + i, type); } | |
| 953 | |
| 954 static FunctionHandle New( | |
| 955 TypeHandle result, TypeHandle receiver, int arity, Region* region) { | |
| 956 FunctionHandle type = Config::template cast<FunctionType>( | |
| 957 StructuralType::New(StructuralType::kFunctionTag, 2 + arity, region)); | |
| 958 type->Set(0, result); | |
| 959 type->Set(1, receiver); | |
| 960 return type; | |
| 961 } | |
| 962 | |
| 963 static FunctionType* cast(TypeImpl* type) { | |
| 964 DCHECK(type->IsFunction()); | |
| 965 return static_cast<FunctionType*>(type); | |
| 966 } | |
| 967 }; | |
| 968 | |
| 969 | |
| 970 // ----------------------------------------------------------------------------- | |
| 971 // Tuple types. | |
| 972 | |
| 973 template <class Config> | |
| 974 class TypeImpl<Config>::TupleType : public StructuralType { | |
| 975 public: | |
| 976 int Arity() { return this->Length(); } | |
| 977 TypeHandle Element(int i) { return this->Get(i); } | |
| 978 | |
| 979 void InitElement(int i, TypeHandle type) { this->Set(i, type); } | |
| 980 | |
| 981 static TupleHandle New(int length, Region* region) { | |
| 982 TupleHandle type = Config::template cast<TupleType>( | |
| 983 StructuralType::New(StructuralType::kTupleTag, length, region)); | |
| 984 return type; | |
| 985 } | |
| 986 | |
| 987 static TupleType* cast(TypeImpl* type) { | |
| 988 DCHECK(type->IsTuple()); | |
| 989 return static_cast<TupleType*>(type); | |
| 990 } | |
| 991 }; | |
| 992 | |
| 993 | |
| 994 // ----------------------------------------------------------------------------- | |
| 995 // Type iterators. | |
| 996 | |
| 997 template<class Config> template<class T> | |
| 998 class TypeImpl<Config>::Iterator { | |
| 999 public: | |
| 1000 bool Done() const { return index_ < 0; } | |
| 1001 i::Handle<T> Current(); | |
| 1002 void Advance(); | |
| 1003 | |
| 1004 private: | |
| 1005 template<class> friend class TypeImpl; | |
| 1006 | |
| 1007 Iterator() : index_(-1) {} | |
| 1008 explicit Iterator(TypeHandle type) : type_(type), index_(-1) { | |
| 1009 Advance(); | |
| 1010 } | |
| 1011 | |
| 1012 inline bool matches(TypeHandle type); | |
| 1013 inline TypeHandle get_type(); | |
| 1014 | |
| 1015 TypeHandle type_; | |
| 1016 int index_; | |
| 1017 }; | |
| 1018 | |
| 1019 | |
| 1020 // ----------------------------------------------------------------------------- | |
| 1021 // Zone-allocated types; they are either (odd) integers to represent bitsets, or | |
| 1022 // (even) pointers to structures for everything else. | |
| 1023 | |
| 1024 struct ZoneTypeConfig { | |
| 1025 typedef TypeImpl<ZoneTypeConfig> Type; | |
| 1026 class Base {}; | |
| 1027 typedef void* Struct; | |
| 1028 // Hack: the Struct and Range types can be aliased in memory, the first | |
| 1029 // pointer word of each both must be the tag (kRangeStructTag for Range, | |
| 1030 // anything else for Struct) so that we can differentiate them. | |
| 1031 struct Range { | |
| 1032 void* tag; | |
| 1033 int bitset; | |
| 1034 double limits[2]; | |
| 1035 }; | |
| 1036 typedef i::Zone Region; | |
| 1037 template<class T> struct Handle { typedef T* type; }; | |
| 1038 | |
| 1039 static const int kRangeStructTag = 0x1000; | |
| 1040 | |
| 1041 template<class T> static inline T* null_handle() { return nullptr; } | |
| 1042 template<class T> static inline T* handle(T* type); | |
| 1043 template<class T> static inline T* cast(Type* type); | |
| 1044 | |
| 1045 static inline bool is_bitset(Type* type); | |
| 1046 static inline bool is_class(Type* type); | |
| 1047 static inline bool is_struct(Type* type, int tag); | |
| 1048 static inline bool is_range(Type* type); | |
| 1049 | |
| 1050 static inline Type::bitset as_bitset(Type* type); | |
| 1051 static inline i::Handle<i::Map> as_class(Type* type); | |
| 1052 static inline Struct* as_struct(Type* type); | |
| 1053 static inline Range* as_range(Type* type); | |
| 1054 | |
| 1055 static inline Type* from_bitset(Type::bitset); | |
| 1056 static inline Type* from_bitset(Type::bitset, Zone* zone); | |
| 1057 static inline Type* from_class(i::Handle<i::Map> map, Zone* zone); | |
| 1058 static inline Type* from_struct(Struct* structured); | |
| 1059 static inline Type* from_range(Range* range); | |
| 1060 | |
| 1061 static inline Struct* struct_create(int tag, int length, Zone* zone); | |
| 1062 static inline void struct_shrink(Struct* structure, int length); | |
| 1063 static inline int struct_tag(Struct* structure); | |
| 1064 static inline int struct_length(Struct* structure); | |
| 1065 static inline Type* struct_get(Struct* structure, int i); | |
| 1066 static inline void struct_set(Struct* structure, int i, Type* type); | |
| 1067 template<class V> | |
| 1068 static inline i::Handle<V> struct_get_value(Struct* structure, int i); | |
| 1069 template<class V> static inline void struct_set_value( | |
| 1070 Struct* structure, int i, i::Handle<V> x); | |
| 1071 | |
| 1072 static inline Range* range_create(Zone* zone); | |
| 1073 static inline int range_get_bitset(Range* range); | |
| 1074 static inline void range_set_bitset(Range* range, int); | |
| 1075 static inline double range_get_double(Range*, int index); | |
| 1076 static inline void range_set_double(Range*, int index, double value, Zone*); | |
| 1077 }; | |
| 1078 | |
| 1079 typedef TypeImpl<ZoneTypeConfig> Type; | |
| 1080 | |
| 1081 // ----------------------------------------------------------------------------- | 915 // ----------------------------------------------------------------------------- |
| 1082 // Type bounds. A simple struct to represent a pair of lower/upper types. | 916 // Type bounds. A simple struct to represent a pair of lower/upper types. |
| 1083 | 917 |
| 1084 template<class Config> | 918 struct Bounds { |
| 1085 struct BoundsImpl { | 919 Type* lower; |
| 1086 typedef TypeImpl<Config> Type; | 920 Type* upper; |
| 1087 typedef typename Type::TypeHandle TypeHandle; | 921 |
| 1088 typedef typename Type::Region Region; | 922 Bounds() |
| 1089 | 923 : // Make sure accessing uninitialized bounds crashes big-time. |
| 1090 TypeHandle lower; | 924 lower(nullptr), |
| 1091 TypeHandle upper; | 925 upper(nullptr) {} |
| 1092 | 926 explicit Bounds(Type* t) : lower(t), upper(t) {} |
| 1093 BoundsImpl() : // Make sure accessing uninitialized bounds crashes big-time. | 927 Bounds(Type* l, Type* u) : lower(l), upper(u) { DCHECK(lower->Is(upper)); } |
| 1094 lower(Config::template null_handle<Type>()), | |
| 1095 upper(Config::template null_handle<Type>()) {} | |
| 1096 explicit BoundsImpl(TypeHandle t) : lower(t), upper(t) {} | |
| 1097 BoundsImpl(TypeHandle l, TypeHandle u) : lower(l), upper(u) { | |
| 1098 DCHECK(lower->Is(upper)); | |
| 1099 } | |
| 1100 | 928 |
| 1101 // Unrestricted bounds. | 929 // Unrestricted bounds. |
| 1102 static BoundsImpl Unbounded() { | 930 static Bounds Unbounded() { return Bounds(Type::None(), Type::Any()); } |
| 1103 return BoundsImpl(Type::None(), Type::Any()); | |
| 1104 } | |
| 1105 | 931 |
| 1106 // Meet: both b1 and b2 are known to hold. | 932 // Meet: both b1 and b2 are known to hold. |
| 1107 static BoundsImpl Both(BoundsImpl b1, BoundsImpl b2, Region* region) { | 933 static Bounds Both(Bounds b1, Bounds b2, Zone* zone) { |
| 1108 TypeHandle lower = Type::Union(b1.lower, b2.lower, region); | 934 Type* lower = Type::Union(b1.lower, b2.lower, zone); |
| 1109 TypeHandle upper = Type::Intersect(b1.upper, b2.upper, region); | 935 Type* upper = Type::Intersect(b1.upper, b2.upper, zone); |
| 1110 // Lower bounds are considered approximate, correct as necessary. | 936 // Lower bounds are considered approximate, correct as necessary. |
| 1111 if (!lower->Is(upper)) lower = upper; | 937 if (!lower->Is(upper)) lower = upper; |
| 1112 return BoundsImpl(lower, upper); | 938 return Bounds(lower, upper); |
| 1113 } | 939 } |
| 1114 | 940 |
| 1115 // Join: either b1 or b2 is known to hold. | 941 // Join: either b1 or b2 is known to hold. |
| 1116 static BoundsImpl Either(BoundsImpl b1, BoundsImpl b2, Region* region) { | 942 static Bounds Either(Bounds b1, Bounds b2, Zone* zone) { |
| 1117 TypeHandle lower = Type::Intersect(b1.lower, b2.lower, region); | 943 Type* lower = Type::Intersect(b1.lower, b2.lower, zone); |
| 1118 TypeHandle upper = Type::Union(b1.upper, b2.upper, region); | 944 Type* upper = Type::Union(b1.upper, b2.upper, zone); |
| 1119 return BoundsImpl(lower, upper); | 945 return Bounds(lower, upper); |
| 1120 } | 946 } |
| 1121 | 947 |
| 1122 static BoundsImpl NarrowLower(BoundsImpl b, TypeHandle t, Region* region) { | 948 static Bounds NarrowLower(Bounds b, Type* t, Zone* zone) { |
| 1123 TypeHandle lower = Type::Union(b.lower, t, region); | 949 Type* lower = Type::Union(b.lower, t, zone); |
| 1124 // Lower bounds are considered approximate, correct as necessary. | 950 // Lower bounds are considered approximate, correct as necessary. |
| 1125 if (!lower->Is(b.upper)) lower = b.upper; | 951 if (!lower->Is(b.upper)) lower = b.upper; |
| 1126 return BoundsImpl(lower, b.upper); | 952 return Bounds(lower, b.upper); |
| 1127 } | 953 } |
| 1128 static BoundsImpl NarrowUpper(BoundsImpl b, TypeHandle t, Region* region) { | 954 static Bounds NarrowUpper(Bounds b, Type* t, Zone* zone) { |
| 1129 TypeHandle lower = b.lower; | 955 Type* lower = b.lower; |
| 1130 TypeHandle upper = Type::Intersect(b.upper, t, region); | 956 Type* upper = Type::Intersect(b.upper, t, zone); |
| 1131 // Lower bounds are considered approximate, correct as necessary. | 957 // Lower bounds are considered approximate, correct as necessary. |
| 1132 if (!lower->Is(upper)) lower = upper; | 958 if (!lower->Is(upper)) lower = upper; |
| 1133 return BoundsImpl(lower, upper); | 959 return Bounds(lower, upper); |
| 1134 } | 960 } |
| 1135 | 961 |
| 1136 bool Narrows(BoundsImpl that) { | 962 bool Narrows(Bounds that) { |
| 1137 return that.lower->Is(this->lower) && this->upper->Is(that.upper); | 963 return that.lower->Is(this->lower) && this->upper->Is(that.upper); |
| 1138 } | 964 } |
| 1139 }; | 965 }; |
| 1140 | 966 |
| 1141 typedef BoundsImpl<ZoneTypeConfig> Bounds; | |
| 1142 | |
| 1143 class FieldType : public Object { | 967 class FieldType : public Object { |
| 1144 public: | 968 public: |
| 1145 static FieldType* None(); | 969 static FieldType* None(); |
| 1146 static FieldType* Any(); | 970 static FieldType* Any(); |
| 1147 static Handle<FieldType> None(Isolate* isolate); | 971 static Handle<FieldType> None(Isolate* isolate); |
| 1148 static Handle<FieldType> Any(Isolate* isolate); | 972 static Handle<FieldType> Any(Isolate* isolate); |
| 1149 static FieldType* Class(i::Map* map); | 973 static FieldType* Class(i::Map* map); |
| 1150 static Handle<FieldType> Class(i::Handle<i::Map> map, Isolate* isolate); | 974 static Handle<FieldType> Class(i::Handle<i::Map> map, Isolate* isolate); |
| 1151 static FieldType* cast(Object* object); | 975 static FieldType* cast(Object* object); |
| 1152 | 976 |
| 1153 bool NowContains(Object* value); | 977 bool NowContains(Object* value); |
| 1154 bool NowContains(Handle<Object> value); | 978 bool NowContains(Handle<Object> value); |
| 1155 bool IsClass(); | 979 bool IsClass(); |
| 1156 Handle<i::Map> AsClass(); | 980 Handle<i::Map> AsClass(); |
| 1157 bool IsNone() { return this == None(); } | 981 bool IsNone() { return this == None(); } |
| 1158 bool IsAny() { return this == Any(); } | 982 bool IsAny() { return this == Any(); } |
| 1159 bool NowStable(); | 983 bool NowStable(); |
| 1160 bool NowIs(FieldType* other); | 984 bool NowIs(FieldType* other); |
| 1161 bool NowIs(Handle<FieldType> other); | 985 bool NowIs(Handle<FieldType> other); |
| 1162 Type* Convert(Zone* zone); | 986 Type* Convert(Zone* zone); |
| 1163 | 987 |
| 1164 void PrintTo(std::ostream& os); | 988 void PrintTo(std::ostream& os); |
| 1165 }; | 989 }; |
| 1166 | 990 |
| 1167 } // namespace internal | 991 } // namespace internal |
| 1168 } // namespace v8 | 992 } // namespace v8 |
| 1169 | 993 |
| 1170 #endif // V8_TYPES_H_ | 994 #endif // V8_TYPES_H_ |
| OLD | NEW |