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/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
14namespace v8 {
15namespace 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.
23class 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.
27 constexpr Smi() : Object() {}
28 explicit constexpr Smi(Address ptr) : Object(ptr) {
29#if V8_CAN_HAVE_DCHECK_IN_CONSTEXPR
30 DCHECK(HAS_SMI_TAG(ptr));
31#endif
32 }
33 Smi* operator->() { return this; }
34 const Smi* operator->() const { return this; }
35
36 // Returns the integer value.
37 inline int value() const { return Internals::SmiValue(ptr()); }
38 inline Smi ToUint32Smi() {
39 if (value() <= 0) return Smi::FromInt(0);
40 return Smi::FromInt(static_cast<uint32_t>(value()));
41 }
42
43 // Convert a Smi object to an int.
44 static inline int ToInt(const Object object);
45
46 // Convert a value to a Smi object.
47 static inline constexpr Smi FromInt(int value) {
48#if V8_CAN_HAVE_DCHECK_IN_CONSTEXPR
49 DCHECK(Smi::IsValid(value));
50#endif
51 return Smi(Internals::IntToSmi(value));
52 }
53
54 static inline Smi FromIntptr(intptr_t value) {
55 DCHECK(Smi::IsValid(value));
56 int smi_shift_bits = kSmiTagSize + kSmiShiftSize;
57 return Smi((static_cast<Address>(value) << smi_shift_bits) | kSmiTag);
58 }
59
60 // Given {value} in [0, 2^31-1], force it into Smi range by changing at most
61 // the MSB (leaving the lower 31 bit unchanged).
62 static inline Smi From31BitPattern(int value) {
63 return Smi::FromInt((value << (32 - kSmiValueSize)) >>
64 (32 - kSmiValueSize));
65 }
66
67 template <typename E,
68 typename = typename std::enable_if<std::is_enum<E>::value>::type>
69 static inline Smi FromEnum(E value) {
70 STATIC_ASSERT(sizeof(E) <= sizeof(int));
71 return FromInt(static_cast<int>(value));
72 }
73
74 // Returns whether value can be represented in a Smi.
75 static inline bool constexpr IsValid(intptr_t value) {
76#if V8_CAN_HAVE_DCHECK_IN_CONSTEXPR
77 DCHECK(Internals::IsValidSmi(value) ==
78 (value >= kMinValue && value <= kMaxValue));
79#endif
80 return Internals::IsValidSmi(value);
81 }
82
83 // Compare two Smis x, y as if they were converted to strings and then
84 // compared lexicographically. Returns:
85 // -1 if x < y.
86 // 0 if x == y.
87 // 1 if x > y.
88 // Returns the result (a tagged Smi) as a raw Address for ExternalReference
89 // usage.
90 V8_EXPORT_PRIVATE static Address LexicographicCompare(Isolate* isolate, Smi x,
91 Smi y);
92
93 DECL_CAST(Smi)
94
95 // Dispatched behavior.
96 V8_EXPORT_PRIVATE void SmiPrint(std::ostream& os) const; // NOLINT
97 DECL_VERIFIER(Smi)
98
99 // C++ does not allow us to have an object of type Smi within class Smi,
100 // so the kZero value has type Object. Consider it deprecated; new code
101 // should use zero() instead.
102 V8_EXPORT_PRIVATE static constexpr Object kZero = Object(0);
103 // If you need something with type Smi, call zero() instead. Since it is
104 // a constexpr, "calling" it is just as efficient as reading kZero.
105 static inline constexpr Smi zero() { return Smi::FromInt(0); }
106 static constexpr int kMinValue = kSmiMinValue;
107 static constexpr int kMaxValue = kSmiMaxValue;
108};
109
110} // namespace internal
111} // namespace v8
112
113#include "src/objects/object-macros-undef.h"
114
115#endif // V8_OBJECTS_SMI_H_
116