source: webkit/trunk/JavaScriptCore/runtime/JSImmediate.h@ 38247

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

JavaScriptCore:

2008-11-05 Gavin Barraclough <[email protected]>

Reviewed by Maciej Stachowiak.

https://bugs.webkit.org/show_bug.cgi?id=22094

Fix for bug where the callee incorrectly recieves the caller's lexical
global object as this, rather than its own. Implementation closely
follows the spec, passing jsNull, checking in the callee and replacing
with the global object where necessary.

  • VM/CTI.cpp: (JSC::CTI::compileOpCall):
  • VM/Machine.cpp: (JSC::Machine::cti_op_call_NotJSFunction): (JSC::Machine::cti_op_call_eval):
  • runtime/JSCell.h: (JSC::JSValue::toThisObject):
  • runtime/JSImmediate.cpp: (JSC::JSImmediate::toThisObject):
  • runtime/JSImmediate.h:

LayoutTests:

2008-11-05 Gavin Barraclough <[email protected]>

Reviewed by Maciej Stachowiak.

Previosly the test 'cross-site-this' checked that the second level deep method called
across frames recieved the correct this pointer, when no base object is provided.


Test updated so that it check that the code in the child frame, and both the first
and second functions called in the parent frame recieve the correct this values.

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