source: webkit/trunk/JavaScriptCore/kjs/JSImmediate.h@ 37240

Last change on this file since 37240 was 36802, checked in by [email protected], 17 years ago

JavaScriptCore:

2008-09-23 Maciej Stachowiak <[email protected]>

Reviewed by Darin.


~2% speedup on EarleyBoyer

The idea here is to record in the StructureID whether the class
needs a special hasInstance or if it can use the normal logic from
JSObject.


Based on this I inlined the real work directly into
cti_op_instanceof and put the fastest checks up front and the
error handling at the end (so it should be fairly straightforward
to split off the beginning to be inlined if desired).

I only did this for CTI, not the bytecode interpreter.


  • API/JSCallbackObject.h: (JSC::JSCallbackObject::createStructureID):
  • ChangeLog:
  • VM/Machine.cpp: (JSC::Machine::cti_op_instanceof):
  • kjs/JSImmediate.h: (JSC::JSImmediate::isAnyImmediate):
  • kjs/TypeInfo.h: (JSC::TypeInfo::overridesHasInstance): (JSC::TypeInfo::flags):

WebCore:

2008-09-23 Maciej Stachowiak <[email protected]>

Reviewed by Darin.

~2% speedup on EarleyBoyer

(WebCore updates.)


  • bindings/js/JSQuarantinedObjectWrapper.h: (WebCore::JSQuarantinedObjectWrapper::createStructureID):
  • Property svn:eol-style set to native
File size: 17.1 KB
Line 
1/*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov ([email protected])
4 *
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.
9 *
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.
14 *
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.
19 *
20 */
21
22#ifndef KJS_JS_IMMEDIATE_H
23#define KJS_JS_IMMEDIATE_H
24
25#include <wtf/Assertions.h>
26#include <wtf/AlwaysInline.h>
27#include <wtf/MathExtras.h>
28#include <limits>
29#include <limits.h>
30#include <stdarg.h>
31#include <stdint.h>
32#include <stdlib.h>
33
34namespace JSC {
35
36 class ExecState;
37 class JSObject;
38 class JSValue;
39 class UString;
40
41 /*
42 * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
43 * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging
44 * because allocator alignment guarantees they will be 00 in cell pointers.
45 *
46 * For example, on a 32 bit system:
47 *
48 * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
49 * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
50 * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
51 * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ]
52 *
53 * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed
54 * integer, or they mark the value as being an immediate of a type other than integer, with a secondary
55 * tag used to indicate the exact type.
56 *
57 * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value.
58 * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next
59 * two bits will form an extended tag.
60 *
61 * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1
62 * [ high 30 bits of the value ] [ high bit part of value ]
63 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10
64 * [ extended 'payload' ] [ extended tag ] [ tag 'other' ]
65 *
66 * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following
67 * bit would flag the value as undefined. If neither bits are set, the value is null.
68 *
69 * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10
70 * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ]
71 *
72 * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero.
73 * For undefined or null immediates the payload is zero.
74 *
75 * Boolean: 000000000000000000000000000V 01 10
76 * [ boolean value ] [ bool ] [ tag 'other' ]
77 * Undefined: 0000000000000000000000000000 10 10
78 * [ zero ] [ undefined ] [ tag 'other' ]
79 * Null: 0000000000000000000000000000 00 10
80 * [ zero ] [ zero ] [ tag 'other' ]
81 */
82
83 class JSImmediate {
84 private:
85 friend class CTI; // Whooo!
86
87 static const uintptr_t TagMask = 0x3u; // primary tag is 2 bits long
88 static const uintptr_t TagBitTypeInteger = 0x1u; // bottom bit set indicates integer, this dominates the following bit
89 static const uintptr_t TagBitTypeOther = 0x2u; // second bit set indicates immediate other than an integer
90
91 static const uintptr_t ExtendedTagMask = 0xCu; // extended tag holds a further two bits
92 static const uintptr_t ExtendedTagBitBool = 0x4u;
93 static const uintptr_t ExtendedTagBitUndefined = 0x8u;
94
95 static const uintptr_t FullTagTypeMask = TagMask | ExtendedTagMask;
96 static const uintptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool;
97 static const uintptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined;
98 static const uintptr_t FullTagTypeNull = TagBitTypeOther;
99
100 static const uint32_t IntegerPayloadShift = 1u;
101 static const uint32_t ExtendedPayloadShift = 4u;
102
103 static const uintptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift;
104
105 public:
106 static ALWAYS_INLINE bool isImmediate(const JSValue* v)
107 {
108 return reinterpret_cast<uintptr_t>(v) & TagMask;
109 }
110
111 static ALWAYS_INLINE bool isNumber(const JSValue* v)
112 {
113 return reinterpret_cast<uintptr_t>(v) & TagBitTypeInteger;
114 }
115
116 static ALWAYS_INLINE bool isPositiveNumber(const JSValue* v)
117 {
118 // A single mask to check for the sign bit and the number tag all at once.
119 return (reinterpret_cast<uintptr_t>(v) & (0x80000000 | TagBitTypeInteger)) == TagBitTypeInteger;
120 }
121
122 static ALWAYS_INLINE bool isBoolean(const JSValue* v)
123 {
124 return (reinterpret_cast<uintptr_t>(v) & FullTagTypeMask) == FullTagTypeBool;
125 }
126
127 static ALWAYS_INLINE bool isUndefinedOrNull(const JSValue* v)
128 {
129 // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
130 return (reinterpret_cast<uintptr_t>(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull;
131 }
132
133 static bool isNegative(const JSValue* v)
134 {
135 ASSERT(isNumber(v));
136 return reinterpret_cast<uintptr_t>(v) & 0x80000000;
137 }
138
139 static JSValue* from(char);
140 static JSValue* from(signed char);
141 static JSValue* from(unsigned char);
142 static JSValue* from(short);
143 static JSValue* from(unsigned short);
144 static JSValue* from(int);
145 static JSValue* from(unsigned);
146 static JSValue* from(long);
147 static JSValue* from(unsigned long);
148 static JSValue* from(long long);
149 static JSValue* from(unsigned long long);
150 static JSValue* from(double);
151
152 static ALWAYS_INLINE bool isEitherImmediate(const JSValue* v1, const JSValue* v2)
153 {
154 return (reinterpret_cast<uintptr_t>(v1) | reinterpret_cast<uintptr_t>(v2)) & TagMask;
155 }
156
157 static ALWAYS_INLINE bool isAnyImmediate(const JSValue* v1, const JSValue* v2, JSValue* v3)
158 {
159 return (reinterpret_cast<uintptr_t>(v1) | reinterpret_cast<uintptr_t>(v2) | reinterpret_cast<uintptr_t>(v3)) & TagMask;
160 }
161
162 static ALWAYS_INLINE bool areBothImmediate(const JSValue* v1, const JSValue* v2)
163 {
164 return isImmediate(v1) & isImmediate(v2);
165 }
166
167 static ALWAYS_INLINE bool areBothImmediateNumbers(const JSValue* v1, const JSValue* v2)
168 {
169 return reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagBitTypeInteger;
170 }
171
172 static ALWAYS_INLINE JSValue* andImmediateNumbers(const JSValue* v1, const JSValue* v2)
173 {
174 ASSERT(areBothImmediateNumbers(v1, v2));
175 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2));
176 }
177
178 static ALWAYS_INLINE JSValue* xorImmediateNumbers(const JSValue* v1, const JSValue* v2)
179 {
180 ASSERT(areBothImmediateNumbers(v1, v2));
181 return reinterpret_cast<JSValue*>((reinterpret_cast<uintptr_t>(v1) ^ reinterpret_cast<uintptr_t>(v2)) | TagBitTypeInteger);
182 }
183
184 static ALWAYS_INLINE JSValue* orImmediateNumbers(const JSValue* v1, const JSValue* v2)
185 {
186 ASSERT(areBothImmediateNumbers(v1, v2));
187 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) | reinterpret_cast<uintptr_t>(v2));
188 }
189
190 static ALWAYS_INLINE JSValue* rightShiftImmediateNumbers(const JSValue* val, const JSValue* shift)
191 {
192 ASSERT(areBothImmediateNumbers(val, shift));
193 return reinterpret_cast<JSValue*>((reinterpret_cast<intptr_t>(val) >> ((reinterpret_cast<uintptr_t>(shift) >> IntegerPayloadShift) & 0x1f)) | TagBitTypeInteger);
194 }
195
196 static ALWAYS_INLINE bool canDoFastAdditiveOperations(const JSValue* v)
197 {
198 // Number is non-negative and an operation involving two of these can't overflow.
199 // Checking for allowed negative numbers takes more time than it's worth on SunSpider.
200 return (reinterpret_cast<uintptr_t>(v) & (TagBitTypeInteger + (3u << 30))) == TagBitTypeInteger;
201 }
202
203 static ALWAYS_INLINE JSValue* addImmediateNumbers(const JSValue* v1, const JSValue* v2)
204 {
205 ASSERT(canDoFastAdditiveOperations(v1));
206 ASSERT(canDoFastAdditiveOperations(v2));
207 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) + reinterpret_cast<uintptr_t>(v2) - TagBitTypeInteger);
208 }
209
210 static ALWAYS_INLINE JSValue* subImmediateNumbers(const JSValue* v1, const JSValue* v2)
211 {
212 ASSERT(canDoFastAdditiveOperations(v1));
213 ASSERT(canDoFastAdditiveOperations(v2));
214 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) - reinterpret_cast<uintptr_t>(v2) + TagBitTypeInteger);
215 }
216
217 static ALWAYS_INLINE JSValue* incImmediateNumber(const JSValue* v)
218 {
219 ASSERT(canDoFastAdditiveOperations(v));
220 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v) + (1 << IntegerPayloadShift));
221 }
222
223 static ALWAYS_INLINE JSValue* decImmediateNumber(const JSValue* v)
224 {
225 ASSERT(canDoFastAdditiveOperations(v));
226 return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v) - (1 << IntegerPayloadShift));
227 }
228
229 static double toDouble(const JSValue*);
230 static bool toBoolean(const JSValue*);
231 static JSObject* toObject(const JSValue*, ExecState*);
232 static UString toString(const JSValue*);
233
234 static bool getUInt32(const JSValue*, uint32_t&);
235 static bool getTruncatedInt32(const JSValue*, int32_t&);
236 static bool getTruncatedUInt32(const JSValue*, uint32_t&);
237
238 static int32_t getTruncatedInt32(const JSValue*);
239 static uint32_t getTruncatedUInt32(const JSValue*);
240
241 static JSValue* trueImmediate();
242 static JSValue* falseImmediate();
243 static JSValue* undefinedImmediate();
244 static JSValue* nullImmediate();
245 static JSValue* zeroImmediate();
246 static JSValue* oneImmediate();
247
248 static JSValue* impossibleValue();
249
250 static JSObject* prototype(const JSValue*, ExecState*);
251
252 private:
253 static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift;
254 static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift;
255 static const unsigned maxImmediateUInt = maxImmediateInt;
256
257 static ALWAYS_INLINE JSValue* makeInt(int32_t value)
258 {
259 return reinterpret_cast<JSValue*>((value << IntegerPayloadShift) | TagBitTypeInteger);
260 }
261
262 static ALWAYS_INLINE JSValue* makeBool(bool b)
263 {
264 return reinterpret_cast<JSValue*>((static_cast<uintptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool);
265 }
266
267 static ALWAYS_INLINE JSValue* makeUndefined()
268 {
269 return reinterpret_cast<JSValue*>(FullTagTypeUndefined);
270 }
271
272 static ALWAYS_INLINE JSValue* makeNull()
273 {
274 return reinterpret_cast<JSValue*>(FullTagTypeNull);
275 }
276
277 static ALWAYS_INLINE int32_t intValue(const JSValue* v)
278 {
279 return static_cast<int32_t>(reinterpret_cast<intptr_t>(v) >> IntegerPayloadShift);
280 }
281
282 static ALWAYS_INLINE uint32_t uintValue(const JSValue* v)
283 {
284 return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift);
285 }
286
287 static ALWAYS_INLINE bool boolValue(const JSValue* v)
288 {
289 return rawValue(v) & ExtendedPayloadBitBoolValue;
290 }
291
292 static ALWAYS_INLINE uintptr_t rawValue(const JSValue* v)
293 {
294 return reinterpret_cast<uintptr_t>(v);
295 }
296
297 static double nonInlineNaN();
298 };
299
300 ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return makeBool(true); }
301 ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return makeBool(false); }
302 ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return makeUndefined(); }
303 ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return makeNull(); }
304 ALWAYS_INLINE JSValue* JSImmediate::zeroImmediate() { return makeInt(0); }
305 ALWAYS_INLINE JSValue* JSImmediate::oneImmediate() { return makeInt(1); }
306
307 // This value is impossible because 0x4 is not a valid pointer but a tag of 0 would indicate non-immediate
308 ALWAYS_INLINE JSValue* JSImmediate::impossibleValue() { return reinterpret_cast<JSValue*>(0x4); }
309
310 ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
311 {
312 ASSERT(isImmediate(v));
313 uintptr_t bits = rawValue(v);
314 return (bits & TagBitTypeInteger)
315 ? bits != TagBitTypeInteger // !0 ints
316 : bits == (FullTagTypeBool | ExtendedPayloadBitBoolValue); // bool true
317 }
318
319 ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(const JSValue* v)
320 {
321 ASSERT(isNumber(v));
322 return intValue(v);
323 }
324
325 ALWAYS_INLINE JSValue* JSImmediate::from(char i)
326 {
327 return makeInt(i);
328 }
329
330 ALWAYS_INLINE JSValue* JSImmediate::from(signed char i)
331 {
332 return makeInt(i);
333 }
334
335 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned char i)
336 {
337 return makeInt(i);
338 }
339
340 ALWAYS_INLINE JSValue* JSImmediate::from(short i)
341 {
342 return makeInt(i);
343 }
344
345 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned short i)
346 {
347 return makeInt(i);
348 }
349
350 ALWAYS_INLINE JSValue* JSImmediate::from(int i)
351 {
352 if ((i < minImmediateInt) | (i > maxImmediateInt))
353 return 0;
354 return makeInt(i);
355 }
356
357 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned i)
358 {
359 if (i > maxImmediateUInt)
360 return 0;
361 return makeInt(i);
362 }
363
364 ALWAYS_INLINE JSValue* JSImmediate::from(long i)
365 {
366 if ((i < minImmediateInt) | (i > maxImmediateInt))
367 return 0;
368 return makeInt(i);
369 }
370
371 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long i)
372 {
373 if (i > maxImmediateUInt)
374 return 0;
375 return makeInt(i);
376 }
377
378 ALWAYS_INLINE JSValue* JSImmediate::from(long long i)
379 {
380 if ((i < minImmediateInt) | (i > maxImmediateInt))
381 return 0;
382 return makeInt(static_cast<uintptr_t>(i));
383 }
384
385 ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long long i)
386 {
387 if (i > maxImmediateUInt)
388 return 0;
389 return makeInt(static_cast<uintptr_t>(i));
390 }
391
392 ALWAYS_INLINE JSValue* JSImmediate::from(double d)
393 {
394 const int intVal = static_cast<int>(d);
395
396 if ((intVal < minImmediateInt) | (intVal > maxImmediateInt))
397 return 0;
398
399 // Check for data loss from conversion to int.
400 if (intVal != d || (!intVal && signbit(d)))
401 return 0;
402
403 return makeInt(intVal);
404 }
405
406 ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(const JSValue* v)
407 {
408 ASSERT(isNumber(v));
409 return intValue(v);
410 }
411
412 ALWAYS_INLINE double JSImmediate::toDouble(const JSValue* v)
413 {
414 ASSERT(isImmediate(v));
415 int i;
416 if (isNumber(v))
417 i = intValue(v);
418 else if (rawValue(v) == FullTagTypeUndefined)
419 return nonInlineNaN();
420 else
421 i = rawValue(v) >> ExtendedPayloadShift;
422 return i;
423 }
424
425 ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
426 {
427 i = uintValue(v);
428 return isPositiveNumber(v);
429 }
430
431 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
432 {
433 i = intValue(v);
434 return isNumber(v);
435 }
436
437 ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
438 {
439 return getUInt32(v, i);
440 }
441
442 ALWAYS_INLINE JSValue* jsUndefined()
443 {
444 return JSImmediate::undefinedImmediate();
445 }
446
447 inline JSValue* jsNull()
448 {
449 return JSImmediate::nullImmediate();
450 }
451
452 inline JSValue* jsBoolean(bool b)
453 {
454 return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
455 }
456
457} // namespace JSC
458
459#endif
Note: See TracBrowser for help on using the repository browser.