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