2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
26 #include "BooleanConstructor.h"
27 #include "BooleanPrototype.h"
29 #include "ExceptionHelpers.h"
30 #include "GetterSetter.h"
31 #include "JSGlobalObject.h"
32 #include "JSFunction.h"
33 #include "JSNotAnObject.h"
34 #include "NumberObject.h"
35 #include <wtf/MathExtras.h>
36 #include <wtf/StringExtras.h>
40 static const double D32
= 4294967296.0;
43 double JSValue::toInteger(ExecState
* exec
) const
47 double d
= toNumber(exec
);
48 return isnan(d
) ? 0.0 : trunc(d
);
51 double JSValue::toIntegerPreserveNaN(ExecState
* exec
) const
55 return trunc(toNumber(exec
));
58 double JSValue::toNumberSlowCase(ExecState
* exec
) const
60 ASSERT(!isInt32() && !isDouble());
62 return asCell()->toNumber(exec
);
65 return isUndefined() ? std::numeric_limits
<double>::quiet_NaN() : 0; // null and false both convert to 0.
68 JSObject
* JSValue::toObjectSlowCase(ExecState
* exec
, JSGlobalObject
* globalObject
) const
72 if (isInt32() || isDouble())
73 return constructNumber(exec
, globalObject
, asValue());
74 if (isTrue() || isFalse())
75 return constructBooleanFromImmediateBoolean(exec
, globalObject
, asValue());
77 ASSERT(isUndefinedOrNull());
78 throwError(exec
, createNotAnObjectError(exec
, *this));
79 return JSNotAnObject::create(exec
);
82 JSObject
* JSValue::toThisObjectSlowCase(ExecState
* exec
) const
86 if (isInt32() || isDouble())
87 return constructNumber(exec
, exec
->lexicalGlobalObject(), asValue());
88 if (isTrue() || isFalse())
89 return constructBooleanFromImmediateBoolean(exec
, exec
->lexicalGlobalObject(), asValue());
90 ASSERT(isUndefinedOrNull());
91 return exec
->globalThisValue();
94 JSObject
* JSValue::synthesizePrototype(ExecState
* exec
) const
98 return exec
->lexicalGlobalObject()->stringPrototype();
102 return exec
->lexicalGlobalObject()->numberPrototype();
104 return exec
->lexicalGlobalObject()->booleanPrototype();
106 ASSERT(isUndefinedOrNull());
107 throwError(exec
, createNotAnObjectError(exec
, *this));
108 return JSNotAnObject::create(exec
);
112 void JSValue::putToPrimitive(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
114 JSGlobalData
& globalData
= exec
->globalData();
116 // Check if there are any setters or getters in the prototype chain
117 JSObject
* obj
= synthesizePrototype(exec
);
119 if (propertyName
!= exec
->propertyNames().underscoreProto
) {
120 for (; !obj
->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj
= asObject(prototype
)) {
121 prototype
= obj
->prototype();
122 if (prototype
.isNull()) {
123 if (slot
.isStrictMode())
124 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
130 for (; ; obj
= asObject(prototype
)) {
132 JSCell
* specificValue
;
133 size_t offset
= obj
->structure()->get(globalData
, propertyName
, attributes
, specificValue
);
134 if (offset
!= WTF::notFound
) {
135 if (attributes
& ReadOnly
) {
136 if (slot
.isStrictMode())
137 throwError(exec
, createTypeError(exec
, StrictModeReadonlyPropertyWriteError
));
141 JSValue gs
= obj
->getDirectOffset(offset
);
142 if (gs
.isGetterSetter()) {
143 JSObject
* setterFunc
= asGetterSetter(gs
)->setter();
145 if (slot
.isStrictMode())
146 throwError(exec
, createTypeError(exec
, "setting a property that has only a getter"));
151 CallType callType
= setterFunc
->methodTable()->getCallData(setterFunc
, callData
);
152 MarkedArgumentBuffer args
;
155 // If this is WebCore's global object then we need to substitute the shell.
156 call(exec
, setterFunc
, callType
, callData
, *this, args
);
160 // If there's an existing property on the object or one of its
161 // prototypes it should be replaced, so break here.
165 prototype
= obj
->prototype();
166 if (prototype
.isNull())
170 if (slot
.isStrictMode())
171 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
175 char* JSValue::description()
177 static const size_t size
= 128;
178 static char description
[size
];
181 snprintf(description
, size
, "<JSValue()>");
183 snprintf(description
, size
, "Int32: %d", asInt32());
184 else if (isDouble()) {
186 snprintf(description
, size
, "Double: %lx, %lf", reinterpretDoubleToIntptr(asDouble()), asDouble());
190 uint32_t asTwoInt32s
[2];
192 u
.asDouble
= asDouble();
193 snprintf(description
, size
, "Double: %08x:%08x, %lf", u
.asTwoInt32s
[1], u
.asTwoInt32s
[0], asDouble());
196 snprintf(description
, size
, "Cell: %p", asCell());
198 snprintf(description
, size
, "True");
200 snprintf(description
, size
, "False");
202 snprintf(description
, size
, "Null");
203 else if (isUndefined())
204 snprintf(description
, size
, "Undefined");
206 snprintf(description
, size
, "INVALID");
211 // This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
212 // Note that this operation is identical to ToUInt32 other than to interpretation
213 // of the resulting bit-pattern (as such this metod is also called to implement
216 // The operation can be descibed as round towards zero, then select the 32 least
217 // bits of the resulting value in 2s-complement representation.
218 int32_t toInt32(double number
)
220 int64_t bits
= WTF::bitwise_cast
<int64_t>(number
);
221 int32_t exp
= (static_cast<int32_t>(bits
>> 52) & 0x7ff) - 0x3ff;
223 // If exponent < 0 there will be no bits to the left of the decimal point
224 // after rounding; if the exponent is > 83 then no bits of precision can be
225 // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
226 // of fractional precision).
227 // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
228 if (exp
< 0 || exp
> 83)
231 // Select the appropriate 32-bits from the floating point mantissa. If the
232 // exponent is 52 then the bits we need to select are already aligned to the
233 // lowest bits of the 64-bit integer representation of tghe number, no need
234 // to shift. If the exponent is greater than 52 we need to shift the value
235 // left by (exp - 52), if the value is less than 52 we need to shift right
237 int32_t result
= (exp
> 52)
238 ? static_cast<int32_t>(bits
<< (exp
- 52))
239 : static_cast<int32_t>(bits
>> (52 - exp
));
241 // IEEE-754 double precision values are stored omitting an implicit 1 before
242 // the decimal point; we need to reinsert this now. We may also the shifted
243 // invalid bits into the result that are not a part of the mantissa (the sign
244 // and exponent bits from the floatingpoint representation); mask these out.
246 int32_t missingOne
= 1 << exp
;
247 result
&= missingOne
- 1;
248 result
+= missingOne
;
251 // If the input value was negative (we could test either 'number' or 'bits',
252 // but testing 'bits' is likely faster) invert the result appropriately.
253 return bits
< 0 ? -result
: result
;
256 bool JSValue::isValidCallee()
258 return asObject(asCell())->globalObject();
261 JSString
* JSValue::toStringSlowCase(ExecState
* exec
) const
263 JSGlobalData
& globalData
= exec
->globalData();
266 return jsString(&globalData
, globalData
.numericStrings
.add(asInt32()));
268 return jsString(&globalData
, globalData
.numericStrings
.add(asDouble()));
270 return globalData
.smallStrings
.trueString(&globalData
);
272 return globalData
.smallStrings
.falseString(&globalData
);
274 return globalData
.smallStrings
.nullString(&globalData
);
276 return globalData
.smallStrings
.undefinedString(&globalData
);
279 JSValue value
= asCell()->toPrimitive(exec
, PreferString
);
280 if (exec
->hadException())
281 return jsEmptyString(exec
);
282 ASSERT(!value
.isObject());
283 return value
.toString(exec
);
286 UString
JSValue::toUStringSlowCase(ExecState
* exec
) const
288 return inlineJSValueNotStringtoUString(*this, exec
);