]>
git.saurik.com Git - apple/javascriptcore.git/blob - kjs/JSImmediate.h
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 #ifndef KJS_JS_IMMEDIATE_H
23 #define KJS_JS_IMMEDIATE_H
26 #include <wtf/Assertions.h>
27 #include <wtf/AlwaysInline.h>
28 #include <wtf/MathExtras.h>
42 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
43 * signed int masquerading as a pointer). The low two bits in a JSValue* are available
44 * for type tagging because allocator alignment guarantees they will be 00 in cell pointers.
46 * For example, on a 32 bit system:
48 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
49 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
51 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
52 * [ high 30 bits: signed int ] [ low 2 bits -- type tag ]
54 * The bit "payload" (the high 30 bits) is a 30 bit signed int for immediate numbers, a flag to distinguish true/false
57 * Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits
58 * available for type tagging, we tag the null immediate with UndefinedType, and JSImmediate::type() has
64 static ALWAYS_INLINE
bool isImmediate(const JSValue
* v
)
66 return getTag(v
) != 0;
69 static ALWAYS_INLINE
bool isNumber(const JSValue
* v
)
71 return (getTag(v
) == NumberType
);
74 static ALWAYS_INLINE
bool isBoolean(const JSValue
* v
)
76 return (getTag(v
) == BooleanType
);
79 // Since we have room for only 3 unique tags, null and undefined have to share.
80 static ALWAYS_INLINE
bool isUndefinedOrNull(const JSValue
* v
)
82 return (getTag(v
) == UndefinedType
);
85 static JSValue
* from(char);
86 static JSValue
* from(signed char);
87 static JSValue
* from(unsigned char);
88 static JSValue
* from(short);
89 static JSValue
* from(unsigned short);
90 static JSValue
* from(int);
91 static JSValue
* from(unsigned);
92 static JSValue
* from(long);
93 static JSValue
* from(unsigned long);
94 static JSValue
* from(long long);
95 static JSValue
* from(unsigned long long);
96 static JSValue
* from(double);
98 static ALWAYS_INLINE
bool areBothImmediateNumbers(const JSValue
* v1
, const JSValue
* v2
)
100 return (reinterpret_cast<uintptr_t>(v1
) & reinterpret_cast<uintptr_t>(v2
) & TagMask
) == NumberType
;
103 static ALWAYS_INLINE JSValue
* andImmediateNumbers(const JSValue
* v1
, const JSValue
* v2
)
105 ASSERT(areBothImmediateNumbers(v1
, v2
));
106 return reinterpret_cast<JSValue
*>(reinterpret_cast<uintptr_t>(v1
) & reinterpret_cast<uintptr_t>(v2
));
109 static double toDouble(const JSValue
*);
110 static bool toBoolean(const JSValue
*);
111 static JSObject
* toObject(const JSValue
*, ExecState
*);
112 static UString
toString(const JSValue
*);
113 static JSType
type(const JSValue
*);
115 static bool getUInt32(const JSValue
*, uint32_t&);
116 static bool getTruncatedInt32(const JSValue
*, int32_t&);
117 static bool getTruncatedUInt32(const JSValue
*, uint32_t&);
119 static int32_t getTruncatedInt32(const JSValue
*);
121 static JSValue
* trueImmediate();
122 static JSValue
* falseImmediate();
123 static JSValue
* undefinedImmediate();
124 static JSValue
* nullImmediate();
127 static const uintptr_t TagMask
= 3; // type tags are 2 bits long
129 // Immediate values are restricted to a 30 bit signed value.
130 static const int minImmediateInt
= -(1 << 29);
131 static const int maxImmediateInt
= (1 << 29) - 1;
132 static const unsigned maxImmediateUInt
= maxImmediateInt
;
134 static ALWAYS_INLINE JSValue
* tag(uintptr_t bits
, uintptr_t tag
)
136 return reinterpret_cast<JSValue
*>(bits
| tag
);
139 static ALWAYS_INLINE
uintptr_t unTag(const JSValue
* v
)
141 return reinterpret_cast<uintptr_t>(v
) & ~TagMask
;
144 static ALWAYS_INLINE
uintptr_t getTag(const JSValue
* v
)
146 return reinterpret_cast<uintptr_t>(v
) & TagMask
;
150 ALWAYS_INLINE JSValue
* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType
); }
151 ALWAYS_INLINE JSValue
* JSImmediate::falseImmediate() { return tag(0, BooleanType
); }
152 ALWAYS_INLINE JSValue
* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType
); }
153 ALWAYS_INLINE JSValue
* JSImmediate::nullImmediate() { return tag(0, UndefinedType
); }
155 ALWAYS_INLINE
bool JSImmediate::toBoolean(const JSValue
* v
)
157 ASSERT(isImmediate(v
));
158 uintptr_t bits
= unTag(v
);
159 return (bits
!= 0) & (JSImmediate::getTag(v
) != UndefinedType
);
162 ALWAYS_INLINE JSValue
* JSImmediate::from(char i
)
164 return tag(i
<< 2, NumberType
);
167 ALWAYS_INLINE JSValue
* JSImmediate::from(signed char i
)
169 return tag(i
<< 2, NumberType
);
172 ALWAYS_INLINE JSValue
* JSImmediate::from(unsigned char i
)
174 return tag(i
<< 2, NumberType
);
177 ALWAYS_INLINE JSValue
* JSImmediate::from(short i
)
179 return tag(i
<< 2, NumberType
);
182 ALWAYS_INLINE JSValue
* JSImmediate::from(unsigned short i
)
184 return tag(i
<< 2, NumberType
);
187 ALWAYS_INLINE JSValue
* JSImmediate::from(int i
)
189 if ((i
< minImmediateInt
) | (i
> maxImmediateInt
))
191 return tag(i
<< 2, NumberType
);
194 ALWAYS_INLINE JSValue
* JSImmediate::from(unsigned i
)
196 if (i
> maxImmediateUInt
)
198 return tag(i
<< 2, NumberType
);
201 ALWAYS_INLINE JSValue
* JSImmediate::from(long i
)
203 if ((i
< minImmediateInt
) | (i
> maxImmediateInt
))
205 return tag(i
<< 2, NumberType
);
208 ALWAYS_INLINE JSValue
* JSImmediate::from(unsigned long i
)
210 if (i
> maxImmediateUInt
)
212 return tag(i
<< 2, NumberType
);
215 ALWAYS_INLINE JSValue
* JSImmediate::from(long long i
)
217 if ((i
< minImmediateInt
) | (i
> maxImmediateInt
))
219 return tag(static_cast<uintptr_t>(i
) << 2, NumberType
);
222 ALWAYS_INLINE JSValue
* JSImmediate::from(unsigned long long i
)
224 if (i
> maxImmediateUInt
)
226 return tag(static_cast<uintptr_t>(i
) << 2, NumberType
);
229 ALWAYS_INLINE JSValue
* JSImmediate::from(double d
)
231 const int intVal
= static_cast<int>(d
);
233 if ((intVal
< minImmediateInt
) | (intVal
> maxImmediateInt
))
236 // Check for data loss from conversion to int.
237 if ((intVal
!= d
) || (!intVal
&& signbit(d
)))
240 return tag(intVal
<< 2, NumberType
);
243 ALWAYS_INLINE
int32_t JSImmediate::getTruncatedInt32(const JSValue
* v
)
246 return static_cast<int32_t>(unTag(v
)) >> 2;
249 ALWAYS_INLINE
double JSImmediate::toDouble(const JSValue
* v
)
251 ASSERT(isImmediate(v
));
252 const int32_t i
= static_cast<int32_t>(unTag(v
)) >> 2;
253 if (JSImmediate::getTag(v
) == UndefinedType
&& i
)
254 return std::numeric_limits
<double>::quiet_NaN();
258 ALWAYS_INLINE
bool JSImmediate::getUInt32(const JSValue
* v
, uint32_t& i
)
260 const int32_t si
= static_cast<int32_t>(unTag(v
)) >> 2;
262 return isNumber(v
) & (si
>= 0);
265 ALWAYS_INLINE
bool JSImmediate::getTruncatedInt32(const JSValue
* v
, int32_t& i
)
267 i
= static_cast<int32_t>(unTag(v
)) >> 2;
271 ALWAYS_INLINE
bool JSImmediate::getTruncatedUInt32(const JSValue
* v
, uint32_t& i
)
273 return getUInt32(v
, i
);