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