1 // Copyright 2018 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_OBJECTS_SMI_H_ 6 #define V8_OBJECTS_SMI_H_ 7 8 #include "src/common/globals.h" 9 #include "src/objects/heap-object.h" 10 11 // Has to be the last include (doesn't have include guards): 12 #include "src/objects/object-macros.h" 13 14 namespace v8 { 15 namespace internal { 16 17 // Smi represents integer Numbers that can be stored in 31 bits. 18 // Smis are immediate which means they are NOT allocated in the heap. 19 // The ptr_ value has the following format: [31 bit signed int] 0 20 // For long smis it has the following format: 21 // [32 bit signed int] [31 bits zero padding] 0 22 // Smi stands for small integer. 23 class Smi : public Object { 24 public: 25 // This replaces the OBJECT_CONSTRUCTORS macro, because Smis are special 26 // in that we want them to be constexprs. Smi()27 constexpr Smi() : Object() {} Smi(Address ptr)28 explicit constexpr Smi(Address ptr) : Object(ptr) { 29 DCHECK(HAS_SMI_TAG(ptr)); 30 } 31 32 // Returns the integer value. value()33 inline int value() const { return Internals::SmiValue(ptr()); } ToUint32Smi()34 inline Smi ToUint32Smi() { 35 if (value() <= 0) return Smi::FromInt(0); 36 return Smi::FromInt(static_cast<uint32_t>(value())); 37 } 38 39 // Convert a Smi object to an int. ToInt(const Object object)40 static inline int ToInt(const Object object) { 41 return Smi::cast(object).value(); 42 } 43 44 // Convert a value to a Smi object. FromInt(int value)45 static inline constexpr Smi FromInt(int value) { 46 DCHECK(Smi::IsValid(value)); 47 return Smi(Internals::IntToSmi(value)); 48 } 49 FromIntptr(intptr_t value)50 static inline Smi FromIntptr(intptr_t value) { 51 DCHECK(Smi::IsValid(value)); 52 int smi_shift_bits = kSmiTagSize + kSmiShiftSize; 53 return Smi((static_cast<Address>(value) << smi_shift_bits) | kSmiTag); 54 } 55 56 // Given {value} in [0, 2^31-1], force it into Smi range by changing at most 57 // the MSB (leaving the lower 31 bit unchanged). From31BitPattern(int value)58 static inline Smi From31BitPattern(int value) { 59 return Smi::FromInt((value << (32 - kSmiValueSize)) >> 60 (32 - kSmiValueSize)); 61 } 62 63 template <typename E, 64 typename = typename std::enable_if<std::is_enum<E>::value>::type> FromEnum(E value)65 static inline Smi FromEnum(E value) { 66 STATIC_ASSERT(sizeof(E) <= sizeof(int)); 67 return FromInt(static_cast<int>(value)); 68 } 69 70 // Returns whether value can be represented in a Smi. IsValid(intptr_t value)71 static inline bool constexpr IsValid(intptr_t value) { 72 DCHECK_EQ(Internals::IsValidSmi(value), 73 value >= kMinValue && value <= kMaxValue); 74 return Internals::IsValidSmi(value); 75 } 76 77 // Compare two Smis x, y as if they were converted to strings and then 78 // compared lexicographically. Returns: 79 // -1 if x < y. 80 // 0 if x == y. 81 // 1 if x > y. 82 // Returns the result (a tagged Smi) as a raw Address for ExternalReference 83 // usage. 84 V8_EXPORT_PRIVATE static Address LexicographicCompare(Isolate* isolate, Smi x, 85 Smi y); 86 87 DECL_CAST(Smi) 88 89 // Dispatched behavior. 90 V8_EXPORT_PRIVATE void SmiPrint(std::ostream& os) const; DECL_VERIFIER(Smi)91 DECL_VERIFIER(Smi) 92 93 // Since this is a constexpr, "calling" it is just as efficient 94 // as reading a constant. 95 static inline constexpr Smi zero() { return Smi::FromInt(0); } 96 static constexpr int kMinValue = kSmiMinValue; 97 static constexpr int kMaxValue = kSmiMaxValue; 98 99 // Smi value for filling in not-yet initialized tagged field values with a 100 // valid tagged pointer. A field value equal to this doesn't necessarily 101 // indicate that a field is uninitialized, but an uninitialized field should 102 // definitely equal this value. 103 // 104 // This _has_ to be kNullAddress, so that an uninitialized field value read as 105 // an embedded pointer field is interpreted as nullptr. This is so that 106 // uninitialised embedded pointers are not forwarded to the embedder as part 107 // of embedder tracing (and similar mechanisms), as nullptrs are skipped for 108 // those cases and otherwise the embedder would try to dereference the 109 // uninitialized pointer value. uninitialized_deserialization_value()110 static constexpr Smi uninitialized_deserialization_value() { 111 return Smi(kNullAddress); 112 } 113 }; 114 115 CAST_ACCESSOR(Smi) 116 117 } // namespace internal 118 } // namespace v8 119 120 #include "src/objects/object-macros-undef.h" 121 122 #endif // V8_OBJECTS_SMI_H_ 123