]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSValue.cpp
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / runtime / JSValue.cpp
1 /*
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.
5 *
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.
10 *
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.
15 *
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.
20 *
21 */
22
23 #include "config.h"
24 #include "JSValue.h"
25
26 #include "BooleanConstructor.h"
27 #include "BooleanPrototype.h"
28 #include "Error.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>
37
38 namespace JSC {
39
40 static const double D32 = 4294967296.0;
41
42 // ECMA 9.4
43 double JSValue::toInteger(ExecState* exec) const
44 {
45 if (isInt32())
46 return asInt32();
47 double d = toNumber(exec);
48 return isnan(d) ? 0.0 : trunc(d);
49 }
50
51 double JSValue::toIntegerPreserveNaN(ExecState* exec) const
52 {
53 if (isInt32())
54 return asInt32();
55 return trunc(toNumber(exec));
56 }
57
58 double JSValue::toNumberSlowCase(ExecState* exec) const
59 {
60 ASSERT(!isInt32() && !isDouble());
61 if (isCell())
62 return asCell()->toNumber(exec);
63 if (isTrue())
64 return 1.0;
65 return isUndefined() ? std::numeric_limits<double>::quiet_NaN() : 0; // null and false both convert to 0.
66 }
67
68 JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
69 {
70 ASSERT(!isCell());
71
72 if (isInt32() || isDouble())
73 return constructNumber(exec, globalObject, asValue());
74 if (isTrue() || isFalse())
75 return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
76
77 ASSERT(isUndefinedOrNull());
78 throwError(exec, createNotAnObjectError(exec, *this));
79 return JSNotAnObject::create(exec);
80 }
81
82 JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
83 {
84 ASSERT(!isCell());
85
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();
92 }
93
94 JSObject* JSValue::synthesizePrototype(ExecState* exec) const
95 {
96 if (isCell()) {
97 ASSERT(isString());
98 return exec->lexicalGlobalObject()->stringPrototype();
99 }
100
101 if (isNumber())
102 return exec->lexicalGlobalObject()->numberPrototype();
103 if (isBoolean())
104 return exec->lexicalGlobalObject()->booleanPrototype();
105
106 ASSERT(isUndefinedOrNull());
107 throwError(exec, createNotAnObjectError(exec, *this));
108 return JSNotAnObject::create(exec);
109 }
110
111 // ECMA 8.7.2
112 void JSValue::putToPrimitive(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
113 {
114 JSGlobalData& globalData = exec->globalData();
115
116 // Check if there are any setters or getters in the prototype chain
117 JSObject* obj = synthesizePrototype(exec);
118 JSValue prototype;
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);
125 return;
126 }
127 }
128 }
129
130 for (; ; obj = asObject(prototype)) {
131 unsigned attributes;
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));
138 return;
139 }
140
141 JSValue gs = obj->getDirectOffset(offset);
142 if (gs.isGetterSetter()) {
143 JSObject* setterFunc = asGetterSetter(gs)->setter();
144 if (!setterFunc) {
145 if (slot.isStrictMode())
146 throwError(exec, createTypeError(exec, "setting a property that has only a getter"));
147 return;
148 }
149
150 CallData callData;
151 CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
152 MarkedArgumentBuffer args;
153 args.append(value);
154
155 // If this is WebCore's global object then we need to substitute the shell.
156 call(exec, setterFunc, callType, callData, *this, args);
157 return;
158 }
159
160 // If there's an existing property on the object or one of its
161 // prototypes it should be replaced, so break here.
162 break;
163 }
164
165 prototype = obj->prototype();
166 if (prototype.isNull())
167 break;
168 }
169
170 if (slot.isStrictMode())
171 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
172 return;
173 }
174
175 char* JSValue::description()
176 {
177 static const size_t size = 128;
178 static char description[size];
179
180 if (!*this)
181 snprintf(description, size, "<JSValue()>");
182 else if (isInt32())
183 snprintf(description, size, "Int32: %d", asInt32());
184 else if (isDouble()) {
185 #if USE(JSVALUE64)
186 snprintf(description, size, "Double: %lx, %lf", reinterpretDoubleToIntptr(asDouble()), asDouble());
187 #else
188 union {
189 double asDouble;
190 uint32_t asTwoInt32s[2];
191 } u;
192 u.asDouble = asDouble();
193 snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
194 #endif
195 } else if (isCell())
196 snprintf(description, size, "Cell: %p", asCell());
197 else if (isTrue())
198 snprintf(description, size, "True");
199 else if (isFalse())
200 snprintf(description, size, "False");
201 else if (isNull())
202 snprintf(description, size, "Null");
203 else if (isUndefined())
204 snprintf(description, size, "Undefined");
205 else
206 snprintf(description, size, "INVALID");
207
208 return description;
209 }
210
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
214 // ToUInt32).
215 //
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)
219 {
220 int64_t bits = WTF::bitwise_cast<int64_t>(number);
221 int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
222
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)
229 return 0;
230
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
236 // accordingly.
237 int32_t result = (exp > 52)
238 ? static_cast<int32_t>(bits << (exp - 52))
239 : static_cast<int32_t>(bits >> (52 - exp));
240
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.
245 if (exp < 32) {
246 int32_t missingOne = 1 << exp;
247 result &= missingOne - 1;
248 result += missingOne;
249 }
250
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;
254 }
255
256 bool JSValue::isValidCallee()
257 {
258 return asObject(asCell())->globalObject();
259 }
260
261 JSString* JSValue::toStringSlowCase(ExecState* exec) const
262 {
263 JSGlobalData& globalData = exec->globalData();
264 ASSERT(!isString());
265 if (isInt32())
266 return jsString(&globalData, globalData.numericStrings.add(asInt32()));
267 if (isDouble())
268 return jsString(&globalData, globalData.numericStrings.add(asDouble()));
269 if (isTrue())
270 return globalData.smallStrings.trueString(&globalData);
271 if (isFalse())
272 return globalData.smallStrings.falseString(&globalData);
273 if (isNull())
274 return globalData.smallStrings.nullString(&globalData);
275 if (isUndefined())
276 return globalData.smallStrings.undefinedString(&globalData);
277
278 ASSERT(isCell());
279 JSValue value = asCell()->toPrimitive(exec, PreferString);
280 if (exec->hadException())
281 return jsEmptyString(exec);
282 ASSERT(!value.isObject());
283 return value.toString(exec);
284 }
285
286 UString JSValue::toUStringSlowCase(ExecState* exec) const
287 {
288 return inlineJSValueNotStringtoUString(*this, exec);
289 }
290
291 } // namespace JSC