]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSCJSValue.cpp
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / runtime / JSCJSValue.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
93a37866 4 * Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All rights reserved.
9dae56ea
A
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"
93a37866 24#include "JSCJSValue.h"
9dae56ea 25
ba379fdc
A
26#include "BooleanConstructor.h"
27#include "BooleanPrototype.h"
14957cd0 28#include "Error.h"
ba379fdc 29#include "ExceptionHelpers.h"
6fe7ccc8 30#include "GetterSetter.h"
93a37866 31#include "JSCJSValueInlines.h"
9dae56ea 32#include "JSFunction.h"
93a37866 33#include "JSGlobalObject.h"
ba379fdc
A
34#include "JSNotAnObject.h"
35#include "NumberObject.h"
9dae56ea 36#include <wtf/MathExtras.h>
ba379fdc 37#include <wtf/StringExtras.h>
9dae56ea
A
38
39namespace JSC {
40
41static const double D32 = 4294967296.0;
42
43// ECMA 9.4
ba379fdc 44double JSValue::toInteger(ExecState* exec) const
9dae56ea 45{
ba379fdc
A
46 if (isInt32())
47 return asInt32();
9dae56ea 48 double d = toNumber(exec);
93a37866 49 return std::isnan(d) ? 0.0 : trunc(d);
9dae56ea
A
50}
51
ba379fdc 52double JSValue::toIntegerPreserveNaN(ExecState* exec) const
9dae56ea 53{
ba379fdc
A
54 if (isInt32())
55 return asInt32();
9dae56ea
A
56 return trunc(toNumber(exec));
57}
58
6fe7ccc8
A
59double JSValue::toNumberSlowCase(ExecState* exec) const
60{
61 ASSERT(!isInt32() && !isDouble());
62 if (isCell())
63 return asCell()->toNumber(exec);
64 if (isTrue())
65 return 1.0;
93a37866 66 return isUndefined() ? QNaN : 0; // null and false both convert to 0.
6fe7ccc8
A
67}
68
14957cd0 69JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
ba379fdc
A
70{
71 ASSERT(!isCell());
72
73 if (isInt32() || isDouble())
14957cd0 74 return constructNumber(exec, globalObject, asValue());
ba379fdc 75 if (isTrue() || isFalse())
14957cd0
A
76 return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
77
ba379fdc 78 ASSERT(isUndefinedOrNull());
14957cd0 79 throwError(exec, createNotAnObjectError(exec, *this));
6fe7ccc8 80 return JSNotAnObject::create(exec);
ba379fdc
A
81}
82
83JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
84{
85 ASSERT(!isCell());
86
87 if (isInt32() || isDouble())
14957cd0 88 return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
ba379fdc 89 if (isTrue() || isFalse())
14957cd0 90 return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
ba379fdc
A
91 ASSERT(isUndefinedOrNull());
92 return exec->globalThisValue();
93}
94
6fe7ccc8 95JSObject* JSValue::synthesizePrototype(ExecState* exec) const
ba379fdc 96{
6fe7ccc8
A
97 if (isCell()) {
98 ASSERT(isString());
99 return exec->lexicalGlobalObject()->stringPrototype();
100 }
101
ba379fdc 102 if (isNumber())
6fe7ccc8 103 return exec->lexicalGlobalObject()->numberPrototype();
ba379fdc 104 if (isBoolean())
6fe7ccc8 105 return exec->lexicalGlobalObject()->booleanPrototype();
14957cd0
A
106
107 ASSERT(isUndefinedOrNull());
108 throwError(exec, createNotAnObjectError(exec, *this));
6fe7ccc8 109 return JSNotAnObject::create(exec);
ba379fdc
A
110}
111
6fe7ccc8 112// ECMA 8.7.2
93a37866 113void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
ba379fdc 114{
93a37866
A
115 VM& vm = exec->vm();
116
117 unsigned index = propertyName.asIndex();
118 if (index != PropertyName::NotAnIndex) {
119 putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
120 return;
121 }
ba379fdc 122
6fe7ccc8
A
123 // Check if there are any setters or getters in the prototype chain
124 JSObject* obj = synthesizePrototype(exec);
125 JSValue prototype;
126 if (propertyName != exec->propertyNames().underscoreProto) {
127 for (; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
128 prototype = obj->prototype();
129 if (prototype.isNull()) {
130 if (slot.isStrictMode())
131 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
132 return;
133 }
134 }
135 }
136
137 for (; ; obj = asObject(prototype)) {
138 unsigned attributes;
139 JSCell* specificValue;
93a37866
A
140 PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
141 if (offset != invalidOffset) {
6fe7ccc8
A
142 if (attributes & ReadOnly) {
143 if (slot.isStrictMode())
144 throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
145 return;
146 }
147
93a37866 148 JSValue gs = obj->getDirect(offset);
6fe7ccc8
A
149 if (gs.isGetterSetter()) {
150 JSObject* setterFunc = asGetterSetter(gs)->setter();
151 if (!setterFunc) {
152 if (slot.isStrictMode())
93a37866 153 throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
6fe7ccc8
A
154 return;
155 }
156
157 CallData callData;
158 CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
159 MarkedArgumentBuffer args;
160 args.append(value);
161
162 // If this is WebCore's global object then we need to substitute the shell.
163 call(exec, setterFunc, callType, callData, *this, args);
164 return;
165 }
166
167 // If there's an existing property on the object or one of its
168 // prototypes it should be replaced, so break here.
169 break;
170 }
171
172 prototype = obj->prototype();
173 if (prototype.isNull())
174 break;
175 }
176
177 if (slot.isStrictMode())
178 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
179 return;
ba379fdc
A
180}
181
93a37866 182void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
ba379fdc 183{
93a37866
A
184 if (propertyName > MAX_ARRAY_INDEX) {
185 PutPropertySlot slot(shouldThrow);
186 putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
187 return;
188 }
189
190 if (synthesizePrototype(exec)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, *this, propertyName, value, shouldThrow))
191 return;
192
193 if (shouldThrow)
194 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
195}
f9bf01c6 196
93a37866
A
197void JSValue::dump(PrintStream& out) const
198{
f9bf01c6 199 if (!*this)
93a37866 200 out.print("<JSValue()>");
f9bf01c6 201 else if (isInt32())
93a37866 202 out.printf("Int32: %d", asInt32());
6fe7ccc8
A
203 else if (isDouble()) {
204#if USE(JSVALUE64)
93a37866 205 out.printf("Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble());
6fe7ccc8
A
206#else
207 union {
208 double asDouble;
209 uint32_t asTwoInt32s[2];
210 } u;
211 u.asDouble = asDouble();
93a37866 212 out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
6fe7ccc8 213#endif
93a37866
A
214 } else if (isCell()) {
215 if (asCell()->inherits(&JSString::s_info)) {
216 JSString* string = jsCast<JSString*>(asCell());
217 out.print("String: ");
218 if (string->isRope())
219 out.print("(rope) ");
220 out.print(string->tryGetValue());
221 } else if (asCell()->inherits(&Structure::s_info)) {
222 Structure* structure = jsCast<Structure*>(asCell());
223 out.print(
224 "Structure: ", RawPointer(structure), ": ", structure->classInfo()->className,
225 ", ", IndexingTypeDump(structure->indexingTypeIncludingHistory()));
226 } else {
227 out.print("Cell: ", RawPointer(asCell()));
228 if (isObject() && asObject(*this)->butterfly())
229 out.print("->", RawPointer(asObject(*this)->butterfly()));
230 out.print(
231 " (", RawPointer(asCell()->structure()), ": ", asCell()->structure()->classInfo()->className,
232 ", ", IndexingTypeDump(asCell()->structure()->indexingTypeIncludingHistory()), ")");
233 }
234 } else if (isTrue())
235 out.print("True");
ba379fdc 236 else if (isFalse())
93a37866 237 out.print("False");
ba379fdc 238 else if (isNull())
93a37866 239 out.print("Null");
14957cd0 240 else if (isUndefined())
93a37866 241 out.print("Undefined");
14957cd0 242 else
93a37866 243 out.print("INVALID");
ba379fdc 244}
ba379fdc 245
14957cd0
A
246// This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
247// Note that this operation is identical to ToUInt32 other than to interpretation
248// of the resulting bit-pattern (as such this metod is also called to implement
249// ToUInt32).
250//
251// The operation can be descibed as round towards zero, then select the 32 least
252// bits of the resulting value in 2s-complement representation.
253int32_t toInt32(double number)
9dae56ea 254{
14957cd0
A
255 int64_t bits = WTF::bitwise_cast<int64_t>(number);
256 int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
257
258 // If exponent < 0 there will be no bits to the left of the decimal point
259 // after rounding; if the exponent is > 83 then no bits of precision can be
260 // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
261 // of fractional precision).
262 // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
263 if (exp < 0 || exp > 83)
9dae56ea 264 return 0;
9dae56ea 265
14957cd0
A
266 // Select the appropriate 32-bits from the floating point mantissa. If the
267 // exponent is 52 then the bits we need to select are already aligned to the
268 // lowest bits of the 64-bit integer representation of tghe number, no need
269 // to shift. If the exponent is greater than 52 we need to shift the value
270 // left by (exp - 52), if the value is less than 52 we need to shift right
271 // accordingly.
272 int32_t result = (exp > 52)
273 ? static_cast<int32_t>(bits << (exp - 52))
274 : static_cast<int32_t>(bits >> (52 - exp));
275
276 // IEEE-754 double precision values are stored omitting an implicit 1 before
277 // the decimal point; we need to reinsert this now. We may also the shifted
278 // invalid bits into the result that are not a part of the mantissa (the sign
279 // and exponent bits from the floatingpoint representation); mask these out.
280 if (exp < 32) {
281 int32_t missingOne = 1 << exp;
282 result &= missingOne - 1;
283 result += missingOne;
9dae56ea
A
284 }
285
14957cd0
A
286 // If the input value was negative (we could test either 'number' or 'bits',
287 // but testing 'bits' is likely faster) invert the result appropriately.
288 return bits < 0 ? -result : result;
9dae56ea
A
289}
290
6fe7ccc8 291bool JSValue::isValidCallee()
ba379fdc 292{
6fe7ccc8 293 return asObject(asCell())->globalObject();
ba379fdc
A
294}
295
6fe7ccc8
A
296JSString* JSValue::toStringSlowCase(ExecState* exec) const
297{
93a37866 298 VM& vm = exec->vm();
6fe7ccc8
A
299 ASSERT(!isString());
300 if (isInt32())
93a37866 301 return jsString(&vm, vm.numericStrings.add(asInt32()));
6fe7ccc8 302 if (isDouble())
93a37866 303 return jsString(&vm, vm.numericStrings.add(asDouble()));
6fe7ccc8 304 if (isTrue())
93a37866 305 return vm.smallStrings.trueString();
6fe7ccc8 306 if (isFalse())
93a37866 307 return vm.smallStrings.falseString();
6fe7ccc8 308 if (isNull())
93a37866 309 return vm.smallStrings.nullString();
6fe7ccc8 310 if (isUndefined())
93a37866 311 return vm.smallStrings.undefinedString();
6fe7ccc8
A
312
313 ASSERT(isCell());
314 JSValue value = asCell()->toPrimitive(exec, PreferString);
315 if (exec->hadException())
316 return jsEmptyString(exec);
317 ASSERT(!value.isObject());
318 return value.toString(exec);
319}
320
93a37866 321String JSValue::toWTFStringSlowCase(ExecState* exec) const
14957cd0 322{
93a37866 323 return inlineJSValueNotStringtoString(*this, exec);
14957cd0
A
324}
325
9dae56ea 326} // namespace JSC