Merge "fix: the incorrect version of tarball generated by gbs export" into tizen
[platform/upstream/js.git] / js / src / jsvalue.h
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18  * June 30, 2010
19  *
20  * The Initial Developer of the Original Code is
21  *   the Mozilla Corporation.
22  *
23  * Contributor(s):
24  *   Luke Wagner <lw@mozilla.com>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 #ifndef jsvalue_h__
41 #define jsvalue_h__
42 /*
43  * Private value interface.
44  */
45 #include "jsprvtd.h"
46 #include "jsstdint.h"
47
48 /*
49  * js::Value is a C++-ified version of jsval that provides more information and
50  * helper functions than the basic jsval interface exposed by jsapi.h. A few
51  * general notes on js::Value:
52  *
53  * - Since js::Value and jsval have the same representation, values of these
54  *   types, function pointer types differing only in these types, and structs
55  *   differing only in these types can be converted back and forth at no cost
56  *   using the Jsvalify() and Valueify(). See Jsvalify comment below.
57  *
58  * - js::Value has setX() and isX() members for X in
59  *
60  *     { Int32, Double, String, Boolean, Undefined, Null, Object, Magic }
61  *
62  *   js::Value also contains toX() for each of the non-singleton types.
63  *
64  * - Magic is a singleton type whose payload contains a JSWhyMagic "reason" for
65  *   the magic value. By providing JSWhyMagic values when creating and checking
66  *   for magic values, it is possible to assert, at runtime, that only magic
67  *   values with the expected reason flow through a particular value. For
68  *   example, if cx->exception has a magic value, the reason must be
69  *   JS_GENERATOR_CLOSING.
70  *
71  * - A key difference between jsval and js::Value is that js::Value gives null
72  *   a separate type. Thus
73  *
74  *           JSVAL_IS_OBJECT(v) === v.isObjectOrNull()
75  *       !JSVAL_IS_PRIMITIVE(v) === v.isObject()
76  *
77  *   To help prevent mistakenly boxing a nullable JSObject* as an object,
78  *   Value::setObject takes a JSObject&. (Conversely, Value::asObject returns a
79  *   JSObject&. A convenience member Value::setObjectOrNull is provided.
80  *
81  * - JSVAL_VOID is the same as the singleton value of the Undefined type.
82  *
83  * - Note that js::Value is always 64-bit. Thus, on 32-bit user code should
84  *   avoid copying jsval/js::Value as much as possible, preferring to pass by
85  *   const Value &.
86  */
87
88 /******************************************************************************/
89
90 /* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */
91
92 #include <math.h>
93 #if defined(XP_WIN) || defined(XP_OS2)
94 #include <float.h>
95 #endif
96 #ifdef SOLARIS
97 #include <ieeefp.h>
98 #endif
99
100 static inline int
101 JSDOUBLE_IS_NEGZERO(jsdouble d)
102 {
103 #ifdef WIN32
104     return (d == 0 && (_fpclass(d) & _FPCLASS_NZ));
105 #elif defined(SOLARIS)
106     return (d == 0 && copysign(1, d) < 0);
107 #else
108     return (d == 0 && signbit(d));
109 #endif
110 }
111
112 static inline bool
113 JSDOUBLE_IS_INT32(jsdouble d, int32_t* pi)
114 {
115     if (JSDOUBLE_IS_NEGZERO(d))
116         return false;
117     return d == (*pi = int32_t(d));
118 }
119
120 /******************************************************************************/
121
122 /* Additional value operations used in js::Value but not in jsapi.h. */
123
124 #if JS_BITS_PER_WORD == 32
125
126 static JS_ALWAYS_INLINE JSBool
127 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32)
128 {
129     return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
130 }
131
132 static JS_ALWAYS_INLINE JSBool
133 JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
134 {
135     return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
136 }
137
138 static JS_ALWAYS_INLINE jsval_layout
139 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
140 {
141     jsval_layout l;
142     l.s.tag = JSVAL_TAG_MAGIC;
143     l.s.payload.why = why;
144     return l;
145 }
146
147 static JS_ALWAYS_INLINE jsval_layout
148 MAGIC_TO_JSVAL_IMPL(JSObject *obj)
149 {
150     jsval_layout l;
151     l.s.tag = JSVAL_TAG_MAGIC;
152     l.s.payload.obj = obj;
153     return l;
154 }
155
156 static JS_ALWAYS_INLINE JSBool
157 JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
158 {
159     JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
160     return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
161 }
162
163 static JS_ALWAYS_INLINE jsval_layout
164 PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui)
165 {
166     jsval_layout l;
167     l.s.tag = (JSValueTag)0;
168     l.s.payload.u32 = ui;
169     JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
170     return l;
171 }
172
173 static JS_ALWAYS_INLINE uint32
174 JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
175 {
176     return l.s.payload.u32;
177 }
178
179 static JS_ALWAYS_INLINE JSValueType
180 JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
181 {
182     uint32 type = l.s.tag & 0xF;
183     JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
184     return (JSValueType)type;
185 }
186
187 static JS_ALWAYS_INLINE JSValueTag
188 JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l)
189 {
190     JSValueTag tag = l.s.tag;
191     JS_ASSERT(tag >= JSVAL_TAG_INT32);
192     return tag;
193 }
194
195 #ifdef __cplusplus
196 JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
197 JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
198 #endif
199
200 static JS_ALWAYS_INLINE jsval_layout
201 BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot)
202 {
203     jsval_layout l;
204     JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET);
205     JS_ASSERT_IF(type == JSVAL_TYPE_STRING ||
206                  type == JSVAL_TYPE_OBJECT ||
207                  type == JSVAL_TYPE_NONFUNOBJ ||
208                  type == JSVAL_TYPE_FUNOBJ,
209                  *(uint32 *)slot != 0);
210     l.s.tag = JSVAL_TYPE_TO_TAG(type & 0xF);
211     /* A 32-bit value in a 64-bit slot always occupies the low-addressed end. */
212     l.s.payload.u32 = *(uint32 *)slot;
213     return l;
214 }
215
216 static JS_ALWAYS_INLINE void
217 UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out)
218 {
219     JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l));
220     *(uint32 *)out = l.s.payload.u32;
221 }
222
223 #elif JS_BITS_PER_WORD == 64
224
225 static JS_ALWAYS_INLINE JSBool
226 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32)
227 {
228     return l.asBits == (((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32);
229 }
230
231 static JS_ALWAYS_INLINE JSBool
232 JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
233 {
234     return l.asBits == (((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
235 }
236
237 static JS_ALWAYS_INLINE jsval_layout
238 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
239 {
240     jsval_layout l;
241     l.asBits = ((uint64)(uint32)why) | JSVAL_SHIFTED_TAG_MAGIC;
242     return l;
243 }
244
245 static JS_ALWAYS_INLINE jsval_layout
246 MAGIC_TO_JSVAL_IMPL(JSObject *obj)
247 {
248     jsval_layout l;
249     l.asBits = ((uint64)obj) | JSVAL_SHIFTED_TAG_MAGIC;
250     return l;
251 }
252
253 static JS_ALWAYS_INLINE JSBool
254 JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
255 {
256     uint64 lbits = lhs.asBits, rbits = rhs.asBits;
257     return (lbits <= JSVAL_TAG_MAX_DOUBLE && rbits <= JSVAL_TAG_MAX_DOUBLE) ||
258            (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0);
259 }
260
261 static JS_ALWAYS_INLINE jsval_layout
262 PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui)
263 {
264     jsval_layout l;
265     l.asBits = (uint64)ui;
266     JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
267     return l;
268 }
269
270 static JS_ALWAYS_INLINE uint32
271 JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
272 {
273     JS_ASSERT((l.asBits >> 32) == 0);
274     return (uint32)l.asBits;
275 }
276
277 static JS_ALWAYS_INLINE JSValueType
278 JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
279 {
280    uint64 type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
281    JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
282    return (JSValueType)type;
283 }
284
285 static JS_ALWAYS_INLINE JSValueTag
286 JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l)
287 {
288     uint64 tag = l.asBits >> JSVAL_TAG_SHIFT;
289     JS_ASSERT(tag > JSVAL_TAG_MAX_DOUBLE);
290     return (JSValueTag)tag;
291 }
292
293 #ifdef __cplusplus
294 JS_STATIC_ASSERT(offsetof(jsval_layout, s.payload) == 0);
295 JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
296 JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
297 #endif
298
299 static JS_ALWAYS_INLINE jsval_layout
300 BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot)
301 {
302     /* N.B. for 32-bit payloads, the high 32 bits of the slot are trash. */
303     jsval_layout l;
304     JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET);
305     uint32 isI32 = (uint32)(type < JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET);
306     uint32 shift = isI32 * 32;
307     uint64 mask = ((uint64)-1) >> shift;
308     uint64 payload = *slot & mask;
309     JS_ASSERT_IF(type == JSVAL_TYPE_STRING ||
310                  type == JSVAL_TYPE_OBJECT ||
311                  type == JSVAL_TYPE_NONFUNOBJ ||
312                  type == JSVAL_TYPE_FUNOBJ,
313                  payload != 0);
314     l.asBits = payload | JSVAL_TYPE_TO_SHIFTED_TAG(type & 0xF);
315     return l;
316 }
317
318 static JS_ALWAYS_INLINE void
319 UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out)
320 {
321     JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l));
322     *out = (l.asBits & JSVAL_PAYLOAD_MASK);
323 }
324
325 #endif
326
327 /******************************************************************************/
328
329 namespace js {
330
331 class Value
332 {
333   public:
334     /*
335      * N.B. the default constructor leaves Value unitialized. Adding a default
336      * constructor prevents Value from being stored in a union.
337      */
338
339     /*** Mutatators ***/
340
341     JS_ALWAYS_INLINE
342     void setNull() {
343         data.asBits = JSVAL_BITS(JSVAL_NULL);
344     }
345
346     JS_ALWAYS_INLINE
347     void setUndefined() {
348         data.asBits = JSVAL_BITS(JSVAL_VOID);
349     }
350
351     JS_ALWAYS_INLINE
352     void setInt32(int32 i) {
353         data = INT32_TO_JSVAL_IMPL(i);
354     }
355
356     JS_ALWAYS_INLINE
357     int32 &getInt32Ref() {
358         JS_ASSERT(isInt32());
359         return data.s.payload.i32;
360     }
361
362     JS_ALWAYS_INLINE
363     void setDouble(double d) {
364         data = DOUBLE_TO_JSVAL_IMPL(d);
365     }
366
367     JS_ALWAYS_INLINE
368     double &getDoubleRef() {
369         JS_ASSERT(isDouble());
370         return data.asDouble;
371     }
372
373     JS_ALWAYS_INLINE
374     void setString(JSString *str) {
375         data = STRING_TO_JSVAL_IMPL(str);
376     }
377
378     JS_ALWAYS_INLINE
379     void setObject(JSObject &obj) {
380         data = OBJECT_TO_JSVAL_IMPL(&obj);
381     }
382
383     JS_ALWAYS_INLINE
384     void setBoolean(bool b) {
385         data = BOOLEAN_TO_JSVAL_IMPL(b);
386     }
387
388     JS_ALWAYS_INLINE
389     void setMagic(JSWhyMagic why) {
390         data = MAGIC_TO_JSVAL_IMPL(why);
391     }
392
393     JS_ALWAYS_INLINE
394     void setMagicWithObjectOrNullPayload(JSObject *obj) {
395         data = MAGIC_TO_JSVAL_IMPL(obj);
396     }
397
398     JS_ALWAYS_INLINE
399     JSObject *getMagicObjectOrNullPayload() const {
400         return MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(data);
401     }
402
403     JS_ALWAYS_INLINE
404     void setNumber(uint32 ui) {
405         if (ui > JSVAL_INT_MAX)
406             setDouble((double)ui);
407         else
408             setInt32((int32)ui);
409     }
410
411     JS_ALWAYS_INLINE
412     void setNumber(double d) {
413         int32_t i;
414         if (JSDOUBLE_IS_INT32(d, &i))
415             setInt32(i);
416         else
417             setDouble(d);
418     }
419
420     JS_ALWAYS_INLINE
421     void setObjectOrNull(JSObject *arg) {
422         if (arg)
423             setObject(*arg);
424         else
425             setNull();
426     }
427
428     JS_ALWAYS_INLINE
429     void setObjectOrUndefined(JSObject *arg) {
430         if (arg)
431             setObject(*arg);
432         else
433             setUndefined();
434     }
435
436     JS_ALWAYS_INLINE
437     void swap(Value &rhs) {
438         uint64 tmp = rhs.data.asBits;
439         rhs.data.asBits = data.asBits;
440         data.asBits = tmp;
441     }
442
443     /*** Value type queries ***/
444
445     JS_ALWAYS_INLINE
446     bool isUndefined() const {
447         return JSVAL_IS_UNDEFINED_IMPL(data);
448     }
449
450     JS_ALWAYS_INLINE
451     bool isNull() const {
452         return JSVAL_IS_NULL_IMPL(data);
453     }
454
455     JS_ALWAYS_INLINE
456     bool isNullOrUndefined() const {
457         return isNull() || isUndefined();
458     }
459
460     JS_ALWAYS_INLINE
461     bool isInt32() const {
462         return JSVAL_IS_INT32_IMPL(data);
463     }
464
465     JS_ALWAYS_INLINE
466     bool isInt32(int32 i32) const {
467         return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32);
468     }
469
470     JS_ALWAYS_INLINE
471     bool isDouble() const {
472         return JSVAL_IS_DOUBLE_IMPL(data);
473     }
474
475     JS_ALWAYS_INLINE
476     bool isNumber() const {
477         return JSVAL_IS_NUMBER_IMPL(data);
478     }
479
480     JS_ALWAYS_INLINE
481     bool isString() const {
482         return JSVAL_IS_STRING_IMPL(data);
483     }
484
485     JS_ALWAYS_INLINE
486     bool isObject() const {
487         return JSVAL_IS_OBJECT_IMPL(data);
488     }
489
490     JS_ALWAYS_INLINE
491     bool isPrimitive() const {
492         return JSVAL_IS_PRIMITIVE_IMPL(data);
493     }
494
495     JS_ALWAYS_INLINE
496     bool isObjectOrNull() const {
497         return JSVAL_IS_OBJECT_OR_NULL_IMPL(data);
498     }
499
500     JS_ALWAYS_INLINE
501     bool isGCThing() const {
502         return JSVAL_IS_GCTHING_IMPL(data);
503     }
504
505     JS_ALWAYS_INLINE
506     bool isBoolean() const {
507         return JSVAL_IS_BOOLEAN_IMPL(data);
508     }
509
510     JS_ALWAYS_INLINE
511     bool isTrue() const {
512         return JSVAL_IS_SPECIFIC_BOOLEAN(data, true);
513     }
514
515     JS_ALWAYS_INLINE
516     bool isFalse() const {
517         return JSVAL_IS_SPECIFIC_BOOLEAN(data, false);
518     }
519
520     JS_ALWAYS_INLINE
521     bool isMagic() const {
522         return JSVAL_IS_MAGIC_IMPL(data);
523     }
524
525     JS_ALWAYS_INLINE
526     bool isMagic(JSWhyMagic why) const {
527         JS_ASSERT_IF(isMagic(), data.s.payload.why == why);
528         return JSVAL_IS_MAGIC_IMPL(data);
529     }
530
531 #if JS_BITS_PER_WORD == 64
532     JS_ALWAYS_INLINE
533     bool hasPtrPayload() const {
534         return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET;
535     }
536 #endif
537
538     JS_ALWAYS_INLINE
539     bool isMarkable() const {
540         return JSVAL_IS_TRACEABLE_IMPL(data);
541     }
542
543     JS_ALWAYS_INLINE
544     int32 gcKind() const {
545         JS_ASSERT(isMarkable());
546         return JSVAL_TRACE_KIND_IMPL(data);
547     }
548
549 #ifdef DEBUG
550     JS_ALWAYS_INLINE
551     JSWhyMagic whyMagic() const {
552         JS_ASSERT(isMagic());
553         return data.s.payload.why;
554     }
555 #endif
556
557     /*** Comparison ***/
558
559     JS_ALWAYS_INLINE
560     bool operator==(const Value &rhs) const {
561         return data.asBits == rhs.data.asBits;
562     }
563
564     JS_ALWAYS_INLINE
565     bool operator!=(const Value &rhs) const {
566         return data.asBits != rhs.data.asBits;
567     }
568
569     /* This function used to be inlined here, but this triggered a gcc bug
570        due to SameType being used in a template method.
571        See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38850 */
572     friend bool SameType(const Value &lhs, const Value &rhs);
573
574     /*** Extract the value's typed payload ***/
575
576     JS_ALWAYS_INLINE
577     int32 toInt32() const {
578         JS_ASSERT(isInt32());
579         return JSVAL_TO_INT32_IMPL(data);
580     }
581
582     JS_ALWAYS_INLINE
583     double toDouble() const {
584         JS_ASSERT(isDouble());
585         return data.asDouble;
586     }
587
588     JS_ALWAYS_INLINE
589     double toNumber() const {
590         JS_ASSERT(isNumber());
591         return isDouble() ? toDouble() : double(toInt32());
592     }
593
594     JS_ALWAYS_INLINE
595     JSString *toString() const {
596         JS_ASSERT(isString());
597         return JSVAL_TO_STRING_IMPL(data);
598     }
599
600     JS_ALWAYS_INLINE
601     JSObject &toObject() const {
602         JS_ASSERT(isObject());
603         return *JSVAL_TO_OBJECT_IMPL(data);
604     }
605
606     JS_ALWAYS_INLINE
607     JSObject *toObjectOrNull() const {
608         JS_ASSERT(isObjectOrNull());
609         return JSVAL_TO_OBJECT_IMPL(data);
610     }
611
612     JS_ALWAYS_INLINE
613     void *toGCThing() const {
614         JS_ASSERT(isGCThing());
615         return JSVAL_TO_GCTHING_IMPL(data);
616     }
617
618     JS_ALWAYS_INLINE
619     bool toBoolean() const {
620         JS_ASSERT(isBoolean());
621         return JSVAL_TO_BOOLEAN_IMPL(data);
622     }
623
624     JS_ALWAYS_INLINE
625     uint32 payloadAsRawUint32() const {
626         JS_ASSERT(!isDouble());
627         return data.s.payload.u32;
628     }
629
630     JS_ALWAYS_INLINE
631     uint64 asRawBits() const {
632         return data.asBits;
633     }
634
635     /*
636      * In the extract/box/unbox functions below, "NonDouble" means this
637      * functions must not be called on a value that is a double. This allows
638      * these operations to be implemented more efficiently, since doubles
639      * generally already require special handling by the caller.
640      */
641     JS_ALWAYS_INLINE
642     JSValueType extractNonDoubleType() const {
643         return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
644     }
645
646     JS_ALWAYS_INLINE
647     JSValueTag extractNonDoubleTag() const {
648         return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data);
649     }
650
651     JS_ALWAYS_INLINE
652     void unboxNonDoubleTo(uint64 *out) const {
653         UNBOX_NON_DOUBLE_JSVAL(data, out);
654     }
655
656     JS_ALWAYS_INLINE
657     void boxNonDoubleFrom(JSValueType type, uint64 *out) {
658         data = BOX_NON_DOUBLE_JSVAL(type, out);
659     }
660
661     /*
662      * The trace-jit specializes JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and
663      * JSVAL_TYPE_NONFUNOBJ. Since these two operations just return the type of
664      * a value, the caller must handle JSVAL_TYPE_OBJECT separately.
665      */
666     JS_ALWAYS_INLINE
667     JSValueType extractNonDoubleObjectTraceType() const {
668         JS_ASSERT(!isObject());
669         return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
670     }
671
672     JS_ALWAYS_INLINE
673     JSValueTag extractNonDoubleObjectTraceTag() const {
674         JS_ASSERT(!isObject());
675         return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data);
676     }
677
678     /*
679      * Private API
680      *
681      * Private setters/getters allow the caller to read/write arbitrary types
682      * that fit in the 64-bit payload. It is the caller's responsibility, after
683      * storing to a value with setPrivateX to read only using getPrivateX.
684      * Privates values are given a type type which ensures they are not marked.
685      */
686
687     JS_ALWAYS_INLINE
688     void setPrivate(void *ptr) {
689         data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr);
690     }
691
692     JS_ALWAYS_INLINE
693     void *toPrivate() const {
694         JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
695         return JSVAL_TO_PRIVATE_PTR_IMPL(data);
696     }
697
698     JS_ALWAYS_INLINE
699     void setPrivateUint32(uint32 ui) {
700         data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui);
701     }
702
703     JS_ALWAYS_INLINE
704     uint32 toPrivateUint32() const {
705         JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
706         return JSVAL_TO_PRIVATE_UINT32_IMPL(data);
707     }
708
709     JS_ALWAYS_INLINE
710     uint32 &getPrivateUint32Ref() {
711         JS_ASSERT(isDouble());
712         return data.s.payload.u32;
713     }
714
715     /*
716      * An unmarked value is just a void* cast as a Value. Thus, the Value is
717      * not safe for GC and must not be marked. This API avoids raw casts
718      * and the ensuing strict-aliasing warnings.
719      */
720
721     JS_ALWAYS_INLINE
722     void setUnmarkedPtr(void *ptr) {
723         data.asPtr = ptr;
724     }
725
726     JS_ALWAYS_INLINE
727     void *toUnmarkedPtr() const {
728         return data.asPtr;
729     }
730
731     const jsuword *payloadWord() const {
732         return &data.s.payload.word;
733     }
734
735   private:
736     void staticAssertions() {
737         JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
738         JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
739         JS_STATIC_ASSERT(sizeof(JSBool) == 4);
740         JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
741         JS_STATIC_ASSERT(sizeof(jsval) == 8);
742     }
743
744     jsval_layout data;
745 } JSVAL_ALIGNMENT;
746
747 JS_ALWAYS_INLINE bool
748 SameType(const Value &lhs, const Value &rhs)
749 {
750     return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
751 }
752
753 static JS_ALWAYS_INLINE Value
754 NullValue()
755 {
756     Value v;
757     v.setNull();
758     return v;
759 }
760
761 static JS_ALWAYS_INLINE Value
762 UndefinedValue()
763 {
764     Value v;
765     v.setUndefined();
766     return v;
767 }
768
769 static JS_ALWAYS_INLINE Value
770 Int32Value(int32 i32)
771 {
772     Value v;
773     v.setInt32(i32);
774     return v;
775 }
776
777 static JS_ALWAYS_INLINE Value
778 DoubleValue(double dbl)
779 {
780     Value v;
781     v.setDouble(dbl);
782     return v;
783 }
784
785 static JS_ALWAYS_INLINE Value
786 StringValue(JSString *str)
787 {
788     Value v;
789     v.setString(str);
790     return v;
791 }
792
793 static JS_ALWAYS_INLINE Value
794 BooleanValue(bool boo)
795 {
796     Value v;
797     v.setBoolean(boo);
798     return v;
799 }
800
801 static JS_ALWAYS_INLINE Value
802 ObjectValue(JSObject &obj)
803 {
804     Value v;
805     v.setObject(obj);
806     return v;
807 }
808
809 static JS_ALWAYS_INLINE Value
810 MagicValue(JSWhyMagic why)
811 {
812     Value v;
813     v.setMagic(why);
814     return v;
815 }
816
817 static JS_ALWAYS_INLINE Value
818 NumberValue(double dbl)
819 {
820     Value v;
821     v.setNumber(dbl);
822     return v;
823 }
824
825 static JS_ALWAYS_INLINE Value
826 ObjectOrNullValue(JSObject *obj)
827 {
828     Value v;
829     v.setObjectOrNull(obj);
830     return v;
831 }
832
833 static JS_ALWAYS_INLINE Value
834 PrivateValue(void *ptr)
835 {
836     Value v;
837     v.setPrivate(ptr);
838     return v;
839 }
840
841 static JS_ALWAYS_INLINE void
842 ClearValueRange(Value *vec, uintN len, bool useHoles)
843 {
844     if (useHoles) {
845         for (uintN i = 0; i < len; i++)
846             vec[i].setMagic(JS_ARRAY_HOLE);
847     } else {
848         for (uintN i = 0; i < len; i++)
849             vec[i].setUndefined();
850     }
851 }
852
853 /******************************************************************************/
854
855 /*
856  * As asserted above, js::Value and jsval are layout equivalent. This means:
857  *  - an instance of jsval may be reinterpreted as a js::Value and vice versa;
858  *  - a pointer to a function taking jsval arguments may be reinterpreted as a
859  *    function taking the same arguments, s/jsval/js::Value/, and vice versa;
860  *  - a struct containing jsval members may be reinterpreted as a struct with
861  *    the same members, s/jsval/js::Value/, and vice versa.
862  *
863  * To prevent widespread conversion using casts, which would effectively
864  * disable the C++ typesystem in places where we want it, a set of safe
865  * conversions between known-equivalent types is provided below. Given a type
866  * JsvalT expressedin terms of jsval and an equivalent type ValueT expressed in
867  * terms of js::Value, instances may be converted back and forth using:
868  *
869  *   JsvalT *x = ...
870  *   ValueT *y = js::Valueify(x);
871  *   JsvalT *z = js::Jsvalify(y);
872  *   assert(x == z);
873  *
874  * Conversions between references is also provided for some types. If it seems
875  * like a cast is needed to convert between jsval/js::Value, consider adding a
876  * new safe overload to Jsvalify/Valueify.
877  */
878
879 static inline jsval *        Jsvalify(Value *v)        { return (jsval *)v; }
880 static inline const jsval *  Jsvalify(const Value *v)  { return (const jsval *)v; }
881 static inline jsval &        Jsvalify(Value &v)        { return (jsval &)v; }
882 static inline const jsval &  Jsvalify(const Value &v)  { return (const jsval &)v; }
883 static inline Value *        Valueify(jsval *v)        { return (Value *)v; }
884 static inline const Value *  Valueify(const jsval *v)  { return (const Value *)v; }
885 static inline Value **       Valueify(jsval **v)       { return (Value **)v; }
886 static inline Value &        Valueify(jsval &v)        { return (Value &)v; }
887 static inline const Value &  Valueify(const jsval &v)  { return (const Value &)v; }
888
889 struct Class;
890
891 typedef JSBool
892 (* Native)(JSContext *cx, uintN argc, Value *vp);
893 typedef JSBool
894 (* PropertyOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp);
895 typedef JSBool
896 (* StrictPropertyOp)(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
897 typedef JSBool
898 (* ConvertOp)(JSContext *cx, JSObject *obj, JSType type, Value *vp);
899 typedef JSBool
900 (* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
901                    Value *statep, jsid *idp);
902 typedef JSBool
903 (* HasInstanceOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
904 typedef JSBool
905 (* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
906                   Value *vp);
907 typedef JSBool
908 (* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
909 typedef JSBool
910 (* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
911                  PropertyOp getter, StrictPropertyOp setter, uintN attrs);
912 typedef JSBool
913 (* PropertyIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
914 typedef JSBool
915 (* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
916 typedef JSBool
917 (* DeleteIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
918 typedef JSBool
919 (* CallOp)(JSContext *cx, uintN argc, Value *vp);
920 typedef JSBool
921 (* LookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
922                  JSProperty **propp);
923 typedef JSBool
924 (* AttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
925 typedef JSType
926 (* TypeOfOp)(JSContext *cx, JSObject *obj);
927 typedef void
928 (* TraceOp)(JSTracer *trc, JSObject *obj);
929 typedef JSObject *
930 (* ObjectOp)(JSContext *cx, JSObject *obj);
931 typedef void
932 (* FinalizeOp)(JSContext *cx, JSObject *obj);
933
934 class AutoIdVector;
935
936 /*
937  * Prepare to make |obj| non-extensible; in particular, fully resolve its properties.
938  * On error, return false.
939  * If |obj| is now ready to become non-extensible, set |*fixed| to true and return true.
940  * If |obj| refuses to become non-extensible, set |*fixed| to false and return true; the
941  * caller will throw an appropriate error.
942  */
943 typedef JSBool
944 (* FixOp)(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props);
945
946 static inline Native             Valueify(JSNative f)           { return (Native)f; }
947 static inline JSNative           Jsvalify(Native f)             { return (JSNative)f; }
948 static inline PropertyOp         Valueify(JSPropertyOp f)       { return (PropertyOp)f; }
949 static inline JSPropertyOp       Jsvalify(PropertyOp f)         { return (JSPropertyOp)f; }
950 static inline StrictPropertyOp   Valueify(JSStrictPropertyOp f) { return (StrictPropertyOp)f; }
951 static inline JSStrictPropertyOp Jsvalify(StrictPropertyOp f)   { return (JSStrictPropertyOp)f; }
952 static inline ConvertOp          Valueify(JSConvertOp f)        { return (ConvertOp)f; }
953 static inline JSConvertOp        Jsvalify(ConvertOp f)          { return (JSConvertOp)f; }
954 static inline NewEnumerateOp     Valueify(JSNewEnumerateOp f)   { return (NewEnumerateOp)f; }
955 static inline JSNewEnumerateOp   Jsvalify(NewEnumerateOp f)     { return (JSNewEnumerateOp)f; }
956 static inline HasInstanceOp      Valueify(JSHasInstanceOp f)    { return (HasInstanceOp)f; }
957 static inline JSHasInstanceOp    Jsvalify(HasInstanceOp f)      { return (JSHasInstanceOp)f; }
958 static inline CheckAccessOp      Valueify(JSCheckAccessOp f)    { return (CheckAccessOp)f; }
959 static inline JSCheckAccessOp    Jsvalify(CheckAccessOp f)      { return (JSCheckAccessOp)f; }
960 static inline EqualityOp         Valueify(JSEqualityOp f);      /* Same type as JSHasInstanceOp */
961 static inline JSEqualityOp       Jsvalify(EqualityOp f);        /* Same type as HasInstanceOp */
962
963 static const PropertyOp       PropertyStub       = (PropertyOp)JS_PropertyStub;
964 static const StrictPropertyOp StrictPropertyStub = (StrictPropertyOp)JS_StrictPropertyStub;
965 static const JSEnumerateOp    EnumerateStub      = JS_EnumerateStub;
966 static const JSResolveOp      ResolveStub        = JS_ResolveStub;
967 static const ConvertOp        ConvertStub        = (ConvertOp)JS_ConvertStub;
968 static const JSFinalizeOp     FinalizeStub       = JS_FinalizeStub;
969
970 #define JS_CLASS_MEMBERS                                                      \
971     const char          *name;                                                \
972     uint32              flags;                                                \
973                                                                               \
974     /* Mandatory non-null function pointer members. */                        \
975     PropertyOp          addProperty;                                          \
976     PropertyOp          delProperty;                                          \
977     PropertyOp          getProperty;                                          \
978     StrictPropertyOp    setProperty;                                          \
979     JSEnumerateOp       enumerate;                                            \
980     JSResolveOp         resolve;                                              \
981     ConvertOp           convert;                                              \
982     JSFinalizeOp        finalize;                                             \
983                                                                               \
984     /* Optionally non-null members start here. */                             \
985     JSClassInternal     reserved0;                                            \
986     CheckAccessOp       checkAccess;                                          \
987     Native              call;                                                 \
988     Native              construct;                                            \
989     JSXDRObjectOp       xdrObject;                                            \
990     HasInstanceOp       hasInstance;                                          \
991     JSMarkOp            mark
992
993
994 /*
995  * The helper struct to measure the size of JS_CLASS_MEMBERS to know how much
996  * we have to padd js::Class to match the size of JSClass;
997  */
998 struct ClassSizeMeasurement {
999     JS_CLASS_MEMBERS;
1000 };
1001
1002 struct ClassExtension {
1003     EqualityOp          equality;
1004     JSObjectOp          outerObject;
1005     JSObjectOp          innerObject;
1006     JSIteratorOp        iteratorObject;
1007     void               *unused;
1008 };
1009
1010 #define JS_NULL_CLASS_EXT   {NULL,NULL,NULL,NULL,NULL}
1011
1012 struct ObjectOps {
1013     js::LookupPropOp        lookupProperty;
1014     js::DefinePropOp        defineProperty;
1015     js::PropertyIdOp        getProperty;
1016     js::StrictPropertyIdOp  setProperty;
1017     js::AttributesOp        getAttributes;
1018     js::AttributesOp        setAttributes;
1019     js::DeleteIdOp          deleteProperty;
1020     js::NewEnumerateOp      enumerate;
1021     js::TypeOfOp            typeOf;
1022     js::TraceOp             trace;
1023     js::FixOp               fix;
1024     js::ObjectOp            thisObject;
1025     js::FinalizeOp          clear;
1026 };
1027
1028 #define JS_NULL_OBJECT_OPS  {NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL}
1029
1030 struct Class {
1031     JS_CLASS_MEMBERS;
1032     ClassExtension      ext;
1033     ObjectOps           ops;
1034     uint8               pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
1035                             sizeof(ClassExtension) - sizeof(ObjectOps)];
1036
1037     /* Class is not native and its map is not a scope. */
1038     static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
1039
1040     bool isNative() const {
1041         return !(flags & NON_NATIVE);
1042     }
1043 };
1044
1045 JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
1046 JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
1047 JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
1048 JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
1049 JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
1050 JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
1051 JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate));
1052 JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve));
1053 JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert));
1054 JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize));
1055 JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0));
1056 JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess));
1057 JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call));
1058 JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct));
1059 JS_STATIC_ASSERT(offsetof(JSClass, xdrObject) == offsetof(Class, xdrObject));
1060 JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance));
1061 JS_STATIC_ASSERT(offsetof(JSClass, mark) == offsetof(Class, mark));
1062 JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
1063
1064 struct PropertyDescriptor {
1065     JSObject           *obj;
1066     uintN              attrs;
1067     PropertyOp         getter;
1068     StrictPropertyOp   setter;
1069     Value              value;
1070     uintN              shortid;
1071 };
1072 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, obj) == offsetof(PropertyDescriptor, obj));
1073 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, attrs) == offsetof(PropertyDescriptor, attrs));
1074 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, getter) == offsetof(PropertyDescriptor, getter));
1075 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, setter) == offsetof(PropertyDescriptor, setter));
1076 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, value) == offsetof(PropertyDescriptor, value));
1077 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, shortid) == offsetof(PropertyDescriptor, shortid));
1078 JS_STATIC_ASSERT(sizeof(JSPropertyDescriptor) == sizeof(PropertyDescriptor));
1079
1080 static JS_ALWAYS_INLINE JSClass *              Jsvalify(Class *c)                { return (JSClass *)c; }
1081 static JS_ALWAYS_INLINE Class *                Valueify(JSClass *c)              { return (Class *)c; }
1082 static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; }
1083 static JS_ALWAYS_INLINE PropertyDescriptor *   Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; }
1084
1085 /******************************************************************************/
1086
1087 /*
1088  * Any cast-via-function-call, inlined or not, will cause initialization to
1089  * happen at startup, rather than statically, so just cast in release builds.
1090  */
1091 #ifdef DEBUG
1092
1093 # define JS_VALUEIFY(type, v) js::Valueify(v)
1094 # define JS_JSVALIFY(type, v) js::Jsvalify(v)
1095
1096 static inline JSNative JsvalifyNative(Native n)   { return (JSNative)n; }
1097 static inline JSNative JsvalifyNative(JSNative n) { return n; }
1098 static inline Native ValueifyNative(JSNative n)   { return (Native)n; }
1099 static inline Native ValueifyNative(Native n)     { return n; }
1100
1101 # define JS_VALUEIFY_NATIVE(n) js::ValueifyNative(n)
1102 # define JS_JSVALIFY_NATIVE(n) js::JsvalifyNative(n)
1103
1104 #else
1105
1106 # define JS_VALUEIFY(type, v) ((type)(v))
1107 # define JS_JSVALIFY(type, v) ((type)(v))
1108
1109 # define JS_VALUEIFY_NATIVE(n) ((js::Native)(n))
1110 # define JS_JSVALIFY_NATIVE(n) ((JSNative)(n))
1111
1112 #endif
1113
1114 /*
1115  * JSFunctionSpec uses JSAPI jsval in function signatures whereas the engine
1116  * uses js::Value. To avoid widespread (JSNative) casting, have JS_FN perfom a
1117  * type-safe cast.
1118  */
1119 #undef JS_FN
1120 #define JS_FN(name,call,nargs,flags)                                          \
1121      {name, JS_JSVALIFY_NATIVE(call), nargs, (flags) | JSFUN_STUB_GSOPS}
1122
1123 /******************************************************************************/
1124
1125 /*
1126  * In some cases (quickstubs) we want to take a value in whatever manner is
1127  * appropriate for the architecture and normalize to a const js::Value &. On
1128  * x64, passing a js::Value may cause the to unnecessarily be passed through
1129  * memory instead of registers, so jsval, which is a builtin uint64 is used.
1130  */
1131 #if JS_BITS_PER_WORD == 32
1132 typedef const js::Value *ValueArgType;
1133
1134 static JS_ALWAYS_INLINE const js::Value &
1135 ValueArgToConstRef(const js::Value *arg)
1136 {
1137     return *arg;
1138 }
1139
1140 #elif JS_BITS_PER_WORD == 64
1141 typedef js::Value        ValueArgType;
1142
1143 static JS_ALWAYS_INLINE const Value &
1144 ValueArgToConstRef(const Value &v)
1145 {
1146     return v;
1147 }
1148 #endif
1149
1150 /******************************************************************************/
1151
1152 static JS_ALWAYS_INLINE void
1153 MakeRangeGCSafe(Value *vec, size_t len)
1154 {
1155     PodZero(vec, len);
1156 }
1157
1158 static JS_ALWAYS_INLINE void
1159 MakeRangeGCSafe(Value *beg, Value *end)
1160 {
1161     PodZero(beg, end - beg);
1162 }
1163
1164 static JS_ALWAYS_INLINE void
1165 MakeRangeGCSafe(jsid *beg, jsid *end)
1166 {
1167     for (jsid *id = beg; id != end; ++id)
1168         *id = INT_TO_JSID(0);
1169 }
1170
1171 static JS_ALWAYS_INLINE void
1172 MakeRangeGCSafe(jsid *vec, size_t len)
1173 {
1174     MakeRangeGCSafe(vec, vec + len);
1175 }
1176
1177 static JS_ALWAYS_INLINE void
1178 MakeRangeGCSafe(const Shape **beg, const Shape **end)
1179 {
1180     PodZero(beg, end - beg);
1181 }
1182
1183 static JS_ALWAYS_INLINE void
1184 MakeRangeGCSafe(const Shape **vec, size_t len)
1185 {
1186     PodZero(vec, len);
1187 }
1188
1189 static JS_ALWAYS_INLINE void
1190 SetValueRangeToUndefined(Value *beg, Value *end)
1191 {
1192     for (Value *v = beg; v != end; ++v)
1193         v->setUndefined();
1194 }
1195
1196 static JS_ALWAYS_INLINE void
1197 SetValueRangeToUndefined(Value *vec, size_t len)
1198 {
1199     SetValueRangeToUndefined(vec, vec + len);
1200 }
1201
1202 static JS_ALWAYS_INLINE void
1203 SetValueRangeToNull(Value *beg, Value *end)
1204 {
1205     for (Value *v = beg; v != end; ++v)
1206         v->setNull();
1207 }
1208
1209 static JS_ALWAYS_INLINE void
1210 SetValueRangeToNull(Value *vec, size_t len)
1211 {
1212     SetValueRangeToNull(vec, vec + len);
1213 }
1214
1215 /*
1216  * To really poison a set of values, using 'magic' or 'undefined' isn't good
1217  * enough since often these will just be ignored by buggy code (see bug 629974)
1218  * in debug builds and crash in release builds. Instead, we use a safe-for-crash
1219  * pointer.
1220  */
1221 static JS_ALWAYS_INLINE void
1222 Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
1223 {
1224 #ifdef DEBUG
1225     for (Value *v = beg; v != end; ++v)
1226         v->setObject(*reinterpret_cast<JSObject *>(0x42));
1227 #endif
1228 }
1229
1230 static JS_ALWAYS_INLINE void
1231 Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
1232 {
1233 #ifdef DEBUG
1234     Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
1235 #endif
1236 }
1237
1238 }      /* namespace js */
1239 #endif /* jsvalue_h__ */