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, 2012 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 "JSCJSValue.h"
25
26#include "BooleanConstructor.h"
27#include "BooleanPrototype.h"
28#include "CustomGetterSetter.h"
29#include "Error.h"
30#include "ExceptionHelpers.h"
31#include "GetterSetter.h"
32#include "JSCJSValueInlines.h"
33#include "JSFunction.h"
34#include "JSGlobalObject.h"
35#include "JSNotAnObject.h"
36#include "NumberObject.h"
37#include "StructureInlines.h"
38#include <wtf/MathExtras.h>
39#include <wtf/StringExtras.h>
40
41namespace JSC {
42
43// ECMA 9.4
44double JSValue::toInteger(ExecState* exec) const
45{
46    if (isInt32())
47        return asInt32();
48    double d = toNumber(exec);
49    return std::isnan(d) ? 0.0 : trunc(d);
50}
51
52double JSValue::toIntegerPreserveNaN(ExecState* exec) const
53{
54    if (isInt32())
55        return asInt32();
56    return trunc(toNumber(exec));
57}
58
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;
66    return isUndefined() ? PNaN : 0; // null and false both convert to 0.
67}
68
69JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
70{
71    ASSERT(!isCell());
72
73    if (isInt32() || isDouble())
74        return constructNumber(exec, globalObject, asValue());
75    if (isTrue() || isFalse())
76        return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
77
78    ASSERT(isUndefinedOrNull());
79    VM& vm = exec->vm();
80    vm.throwException(exec, createNotAnObjectError(exec, *this));
81    return JSNotAnObject::create(vm);
82}
83
84JSValue JSValue::toThisSlowCase(ExecState* exec, ECMAMode ecmaMode) const
85{
86    ASSERT(!isCell());
87
88    if (ecmaMode == StrictMode)
89        return *this;
90
91    if (isInt32() || isDouble())
92        return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
93    if (isTrue() || isFalse())
94        return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
95    ASSERT(isUndefinedOrNull());
96    return exec->globalThisValue();
97}
98
99JSObject* JSValue::synthesizePrototype(ExecState* exec) const
100{
101    if (isCell()) {
102        ASSERT(isString());
103        return exec->lexicalGlobalObject()->stringPrototype();
104    }
105
106    if (isNumber())
107        return exec->lexicalGlobalObject()->numberPrototype();
108    if (isBoolean())
109        return exec->lexicalGlobalObject()->booleanPrototype();
110
111    ASSERT(isUndefinedOrNull());
112    VM& vm = exec->vm();
113    vm.throwException(exec, createNotAnObjectError(exec, *this));
114    return JSNotAnObject::create(vm);
115}
116
117// ECMA 8.7.2
118void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
119{
120    VM& vm = exec->vm();
121
122    unsigned index = propertyName.asIndex();
123    if (index != PropertyName::NotAnIndex) {
124        putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
125        return;
126    }
127
128    // Check if there are any setters or getters in the prototype chain
129    JSObject* obj = synthesizePrototype(exec);
130    JSValue prototype;
131    if (propertyName != exec->propertyNames().underscoreProto) {
132        for (; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
133            prototype = obj->prototype();
134            if (prototype.isNull()) {
135                if (slot.isStrictMode())
136                    throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
137                return;
138            }
139        }
140    }
141
142    for (; ; obj = asObject(prototype)) {
143        unsigned attributes;
144        JSCell* specificValue;
145        PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
146        if (offset != invalidOffset) {
147            if (attributes & ReadOnly) {
148                if (slot.isStrictMode())
149                    exec->vm().throwException(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
150                return;
151            }
152
153            JSValue gs = obj->getDirect(offset);
154            if (gs.isGetterSetter()) {
155                callSetter(exec, *this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
156                return;
157            }
158
159            if (gs.isCustomGetterSetter()) {
160                callCustomSetter(exec, gs, obj, slot.thisValue(), value);
161                return;
162            }
163
164            // If there's an existing property on the object or one of its
165            // prototypes it should be replaced, so break here.
166            break;
167        }
168
169        prototype = obj->prototype();
170        if (prototype.isNull())
171            break;
172    }
173
174    if (slot.isStrictMode())
175        throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
176    return;
177}
178
179void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
180{
181    if (propertyName > MAX_ARRAY_INDEX) {
182        PutPropertySlot slot(*this, shouldThrow);
183        putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
184        return;
185    }
186
187    if (synthesizePrototype(exec)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, *this, propertyName, value, shouldThrow))
188        return;
189
190    if (shouldThrow)
191        throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
192}
193
194void JSValue::dump(PrintStream& out) const
195{
196    dumpInContext(out, 0);
197}
198
199void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
200{
201    if (!*this)
202        out.print("<JSValue()>");
203    else if (isInt32())
204        out.printf("Int32: %d", asInt32());
205    else if (isDouble()) {
206#if USE(JSVALUE64)
207        out.printf("Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble());
208#else
209        union {
210            double asDouble;
211            uint32_t asTwoInt32s[2];
212        } u;
213        u.asDouble = asDouble();
214        out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
215#endif
216    } else if (isCell()) {
217        if (asCell()->inherits(JSString::info())) {
218            JSString* string = jsCast<JSString*>(asCell());
219            out.print("String");
220            if (string->isRope())
221                out.print(" (rope)");
222            const StringImpl* impl = string->tryGetValueImpl();
223            if (impl) {
224                if (impl->isAtomic())
225                    out.print(" (atomic)");
226                if (impl->isAtomic())
227                    out.print(" (identifier)");
228                if (impl->isEmptyUnique())
229                    out.print(" (unique)");
230            } else
231                out.print(" (unresolved)");
232            out.print(": ", impl);
233        } else if (asCell()->inherits(Structure::info()))
234            out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context));
235        else {
236            out.print("Cell: ", RawPointer(asCell()));
237            out.print(" (", inContext(*asCell()->structure(), context), ")");
238        }
239#if USE(JSVALUE64)
240        out.print(", ID: ", asCell()->structureID());
241#endif
242    } else if (isTrue())
243        out.print("True");
244    else if (isFalse())
245        out.print("False");
246    else if (isNull())
247        out.print("Null");
248    else if (isUndefined())
249        out.print("Undefined");
250    else
251        out.print("INVALID");
252}
253
254void JSValue::dumpForBacktrace(PrintStream& out) const
255{
256    if (!*this)
257        out.print("<JSValue()>");
258    else if (isInt32())
259        out.printf("%d", asInt32());
260    else if (isDouble())
261        out.printf("%lf", asDouble());
262    else if (isCell()) {
263        if (asCell()->inherits(JSString::info())) {
264            JSString* string = jsCast<JSString*>(asCell());
265            const StringImpl* impl = string->tryGetValueImpl();
266            if (impl)
267                out.print("\"", impl, "\"");
268            else
269                out.print("(unresolved string)");
270        } else if (asCell()->inherits(Structure::info())) {
271            out.print("Structure[ ", asCell()->structure()->classInfo()->className);
272#if USE(JSVALUE64)
273            out.print(" ID: ", asCell()->structureID());
274#endif
275            out.print("]: ", RawPointer(asCell()));
276        } else {
277            out.print("Cell[", asCell()->structure()->classInfo()->className);
278#if USE(JSVALUE64)
279            out.print(" ID: ", asCell()->structureID());
280#endif
281            out.print("]: ", RawPointer(asCell()));
282        }
283    } else if (isTrue())
284        out.print("True");
285    else if (isFalse())
286        out.print("False");
287    else if (isNull())
288        out.print("Null");
289    else if (isUndefined())
290        out.print("Undefined");
291    else
292        out.print("INVALID");
293}
294
295// This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
296// Note that this operation is identical to ToUInt32 other than to interpretation
297// of the resulting bit-pattern (as such this metod is also called to implement
298// ToUInt32).
299//
300// The operation can be descibed as round towards zero, then select the 32 least
301// bits of the resulting value in 2s-complement representation.
302int32_t toInt32(double number)
303{
304    int64_t bits = WTF::bitwise_cast<int64_t>(number);
305    int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
306
307    // If exponent < 0 there will be no bits to the left of the decimal point
308    // after rounding; if the exponent is > 83 then no bits of precision can be
309    // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
310    // of fractional precision).
311    // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
312    if (exp < 0 || exp > 83)
313        return 0;
314
315    // Select the appropriate 32-bits from the floating point mantissa.  If the
316    // exponent is 52 then the bits we need to select are already aligned to the
317    // lowest bits of the 64-bit integer representation of tghe number, no need
318    // to shift.  If the exponent is greater than 52 we need to shift the value
319    // left by (exp - 52), if the value is less than 52 we need to shift right
320    // accordingly.
321    int32_t result = (exp > 52)
322        ? static_cast<int32_t>(bits << (exp - 52))
323        : static_cast<int32_t>(bits >> (52 - exp));
324
325    // IEEE-754 double precision values are stored omitting an implicit 1 before
326    // the decimal point; we need to reinsert this now.  We may also the shifted
327    // invalid bits into the result that are not a part of the mantissa (the sign
328    // and exponent bits from the floatingpoint representation); mask these out.
329    if (exp < 32) {
330        int32_t missingOne = 1 << exp;
331        result &= missingOne - 1;
332        result += missingOne;
333    }
334
335    // If the input value was negative (we could test either 'number' or 'bits',
336    // but testing 'bits' is likely faster) invert the result appropriately.
337    return bits < 0 ? -result : result;
338}
339
340bool JSValue::isValidCallee()
341{
342    return asObject(asCell())->globalObject();
343}
344
345JSString* JSValue::toStringSlowCase(ExecState* exec) const
346{
347    VM& vm = exec->vm();
348    ASSERT(!isString());
349    if (isInt32())
350        return jsString(&vm, vm.numericStrings.add(asInt32()));
351    if (isDouble())
352        return jsString(&vm, vm.numericStrings.add(asDouble()));
353    if (isTrue())
354        return vm.smallStrings.trueString();
355    if (isFalse())
356        return vm.smallStrings.falseString();
357    if (isNull())
358        return vm.smallStrings.nullString();
359    if (isUndefined())
360        return vm.smallStrings.undefinedString();
361
362    ASSERT(isCell());
363    JSValue value = asCell()->toPrimitive(exec, PreferString);
364    if (exec->hadException())
365        return jsEmptyString(exec);
366    ASSERT(!value.isObject());
367    return value.toString(exec);
368}
369
370String JSValue::toWTFStringSlowCase(ExecState* exec) const
371{
372    return inlineJSValueNotStringtoString(*this, exec);
373}
374
375} // namespace JSC
376