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. 
   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. 
  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. 
  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. 
  26 #include "BooleanConstructor.h" 
  27 #include "BooleanPrototype.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> 
  40 static const double D32 
= 4294967296.0; 
  43 double JSValue::toInteger(ExecState
* exec
) const 
  47     double d 
= toNumber(exec
); 
  48     return isnan(d
) ? 0.0 : trunc(d
); 
  51 double JSValue::toIntegerPreserveNaN(ExecState
* exec
) const 
  55     return trunc(toNumber(exec
)); 
  58 double JSValue::toNumberSlowCase(ExecState
* exec
) const 
  60     ASSERT(!isInt32() && !isDouble()); 
  62         return asCell()->toNumber(exec
); 
  65     return isUndefined() ? std::numeric_limits
<double>::quiet_NaN() : 0; // null and false both convert to 0. 
  68 JSObject
* JSValue::toObjectSlowCase(ExecState
* exec
, JSGlobalObject
* globalObject
) const 
  72     if (isInt32() || isDouble()) 
  73         return constructNumber(exec
, globalObject
, asValue()); 
  74     if (isTrue() || isFalse()) 
  75         return constructBooleanFromImmediateBoolean(exec
, globalObject
, asValue()); 
  77     ASSERT(isUndefinedOrNull()); 
  78     throwError(exec
, createNotAnObjectError(exec
, *this)); 
  79     return JSNotAnObject::create(exec
); 
  82 JSObject
* JSValue::toThisObjectSlowCase(ExecState
* exec
) const 
  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(); 
  94 JSObject
* JSValue::synthesizePrototype(ExecState
* exec
) const 
  98         return exec
->lexicalGlobalObject()->stringPrototype(); 
 102         return exec
->lexicalGlobalObject()->numberPrototype(); 
 104         return exec
->lexicalGlobalObject()->booleanPrototype(); 
 106     ASSERT(isUndefinedOrNull()); 
 107     throwError(exec
, createNotAnObjectError(exec
, *this)); 
 108     return JSNotAnObject::create(exec
); 
 112 void JSValue::putToPrimitive(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
) 
 114     JSGlobalData
& globalData 
= exec
->globalData(); 
 116     // Check if there are any setters or getters in the prototype chain 
 117     JSObject
* obj 
= synthesizePrototype(exec
); 
 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
); 
 130     for (; ; obj 
= asObject(prototype
)) { 
 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
)); 
 141             JSValue gs 
= obj
->getDirectOffset(offset
); 
 142             if (gs
.isGetterSetter()) { 
 143                 JSObject
* setterFunc 
= asGetterSetter(gs
)->setter();         
 145                     if (slot
.isStrictMode()) 
 146                         throwError(exec
, createTypeError(exec
, "setting a property that has only a getter")); 
 151                 CallType callType 
= setterFunc
->methodTable()->getCallData(setterFunc
, callData
); 
 152                 MarkedArgumentBuffer args
; 
 155                 // If this is WebCore's global object then we need to substitute the shell. 
 156                 call(exec
, setterFunc
, callType
, callData
, *this, args
); 
 160             // If there's an existing property on the object or one of its  
 161             // prototypes it should be replaced, so break here. 
 165         prototype 
= obj
->prototype(); 
 166         if (prototype
.isNull()) 
 170     if (slot
.isStrictMode()) 
 171         throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
); 
 175 char* JSValue::description() 
 177     static const size_t size 
= 128; 
 178     static char description
[size
]; 
 181         snprintf(description
, size
, "<JSValue()>"); 
 183         snprintf(description
, size
, "Int32: %d", asInt32()); 
 184     else if (isDouble()) { 
 186         snprintf(description
, size
, "Double: %lx, %lf", reinterpretDoubleToIntptr(asDouble()), asDouble()); 
 190             uint32_t asTwoInt32s
[2]; 
 192         u
.asDouble 
= asDouble(); 
 193         snprintf(description
, size
, "Double: %08x:%08x, %lf", u
.asTwoInt32s
[1], u
.asTwoInt32s
[0], asDouble()); 
 196         snprintf(description
, size
, "Cell: %p", asCell()); 
 198         snprintf(description
, size
, "True"); 
 200         snprintf(description
, size
, "False"); 
 202         snprintf(description
, size
, "Null"); 
 203     else if (isUndefined()) 
 204         snprintf(description
, size
, "Undefined"); 
 206         snprintf(description
, size
, "INVALID"); 
 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 
 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
) 
 220     int64_t bits 
= WTF::bitwise_cast
<int64_t>(number
); 
 221     int32_t exp 
= (static_cast<int32_t>(bits 
>> 52) & 0x7ff) - 0x3ff; 
 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) 
 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 
 237     int32_t result 
= (exp 
> 52) 
 238         ? static_cast<int32_t>(bits 
<< (exp 
- 52)) 
 239         : static_cast<int32_t>(bits 
>> (52 - exp
)); 
 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. 
 246         int32_t missingOne 
= 1 << exp
; 
 247         result 
&= missingOne 
- 1; 
 248         result 
+= missingOne
; 
 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
; 
 256 bool JSValue::isValidCallee() 
 258     return asObject(asCell())->globalObject(); 
 261 JSString
* JSValue::toStringSlowCase(ExecState
* exec
) const 
 263     JSGlobalData
& globalData 
= exec
->globalData(); 
 266         return jsString(&globalData
, globalData
.numericStrings
.add(asInt32())); 
 268         return jsString(&globalData
, globalData
.numericStrings
.add(asDouble())); 
 270         return globalData
.smallStrings
.trueString(&globalData
); 
 272         return globalData
.smallStrings
.falseString(&globalData
); 
 274         return globalData
.smallStrings
.nullString(&globalData
); 
 276         return globalData
.smallStrings
.undefinedString(&globalData
); 
 279     JSValue value 
= asCell()->toPrimitive(exec
, PreferString
); 
 280     if (exec
->hadException()) 
 281         return jsEmptyString(exec
); 
 282     ASSERT(!value
.isObject()); 
 283     return value
.toString(exec
); 
 286 UString 
JSValue::toUStringSlowCase(ExecState
* exec
) const 
 288     return inlineJSValueNotStringtoUString(*this, exec
);