File indexing completed on 2024-05-12 15:43:23
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) 0004 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 0005 * Copyright (C) 2004 Apple Computer, Inc. 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 0024 #include "internal.h" 0025 0026 #include "array_object.h" 0027 #include "bool_object.h" 0028 #include "collector.h" 0029 #include "date_object.h" 0030 #include "debugger.h" 0031 #include "error_object.h" 0032 #include "function_object.h" 0033 #include "lexer.h" 0034 #include "math_object.h" 0035 #include "nodes.h" 0036 #include "number_object.h" 0037 #include "object_object.h" 0038 #include "operations.h" 0039 #include "regexp_object.h" 0040 #include "string_object.h" 0041 #include <assert.h> 0042 #include <wtf/HashMap.h> 0043 #include <wtf/HashSet.h> 0044 #include <wtf/Vector.h> 0045 #include <math.h> 0046 #include <stdio.h> 0047 0048 namespace KJS 0049 { 0050 0051 #if defined(WTF_COMPILER_MSVC) 0052 #define copysign _copysign 0053 #endif 0054 0055 static const double D16 = 65536.0; 0056 static const double D32 = 4294967296.0; 0057 0058 // ------------------------------ StringImp ------------------------------------ 0059 0060 JSValue *StringImp::toPrimitive(ExecState *, JSType) const 0061 { 0062 return const_cast<StringImp *>(this); 0063 } 0064 0065 bool GetterSetterImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value) 0066 { 0067 ASSERT_NOT_REACHED(); 0068 number = 0; 0069 value = nullptr; 0070 return true; 0071 } 0072 0073 bool StringImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value) 0074 { 0075 value = this; 0076 number = val.toDouble(); 0077 return false; 0078 } 0079 0080 bool StringImp::toBoolean(ExecState *) const 0081 { 0082 return (val.size() > 0); 0083 } 0084 0085 double StringImp::toNumber(ExecState *) const 0086 { 0087 return val.toDouble(); 0088 } 0089 0090 UString StringImp::toString(ExecState *) const 0091 { 0092 return val; 0093 } 0094 0095 JSObject *StringImp::toObject(ExecState *exec) const 0096 { 0097 return new StringInstance(exec->lexicalInterpreter()->builtinStringPrototype(), const_cast<StringImp *>(this)); 0098 } 0099 0100 // ------------------------------ NumberImp ------------------------------------ 0101 0102 JSValue *NumberImp::toPrimitive(ExecState *, JSType) const 0103 { 0104 return const_cast<NumberImp *>(this); 0105 } 0106 0107 bool NumberImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value) 0108 { 0109 number = val; 0110 value = this; 0111 return true; 0112 } 0113 0114 bool NumberImp::toBoolean(ExecState *) const 0115 { 0116 return val < 0.0 || val > 0.0; // false for NaN 0117 } 0118 0119 double NumberImp::toNumber(ExecState *) const 0120 { 0121 return val; 0122 } 0123 0124 UString NumberImp::toString(ExecState *) const 0125 { 0126 if (val == 0.0) { // +0.0 or -0.0 0127 return "0"; 0128 } 0129 return UString::from(val); 0130 } 0131 0132 JSObject *NumberImp::toObject(ExecState *exec) const 0133 { 0134 List args; 0135 args.append(const_cast<NumberImp *>(this)); 0136 return static_cast<JSObject *>(exec->lexicalInterpreter()->builtinNumber()->construct(exec, args)); 0137 } 0138 0139 bool NumberImp::getUInt32(uint32_t &uint32) const 0140 { 0141 uint32 = static_cast<uint32_t>(val); 0142 return uint32 == val; 0143 } 0144 0145 bool NumberImp::getTruncatedInt32(int32_t &int32) const 0146 { 0147 if (!(val >= -2147483648.0 && val < 2147483648.0)) { 0148 return false; 0149 } 0150 int32 = static_cast<int32_t>(val); 0151 return true; 0152 } 0153 0154 bool NumberImp::getTruncatedUInt32(uint32_t &uint32) const 0155 { 0156 if (!(val >= 0.0 && val < 4294967296.0)) { 0157 return false; 0158 } 0159 uint32 = static_cast<uint32_t>(val); 0160 return true; 0161 } 0162 0163 // --------------------------- GetterSetterImp --------------------------------- 0164 void GetterSetterImp::mark() 0165 { 0166 JSCell::mark(); 0167 0168 if (getter && !getter->marked()) { 0169 getter->mark(); 0170 } 0171 if (setter && !setter->marked()) { 0172 setter->mark(); 0173 } 0174 } 0175 0176 JSValue *GetterSetterImp::toPrimitive(ExecState *, JSType) const 0177 { 0178 assert(false); 0179 return jsNull(); 0180 } 0181 0182 bool GetterSetterImp::toBoolean(ExecState *) const 0183 { 0184 assert(false); 0185 return false; 0186 } 0187 0188 double GetterSetterImp::toNumber(ExecState *) const 0189 { 0190 assert(false); 0191 return 0.0; 0192 } 0193 0194 UString GetterSetterImp::toString(ExecState *) const 0195 { 0196 assert(false); 0197 return UString::null(); 0198 } 0199 0200 JSObject *GetterSetterImp::toObject(ExecState *exec) const 0201 { 0202 assert(false); 0203 return JSValue::toObject(jsNull(), exec); 0204 } 0205 0206 // ------------------------------ InternalFunctionImp -------------------------- 0207 0208 const ClassInfo InternalFunctionImp::info = {"Function", nullptr, nullptr, nullptr}; 0209 0210 InternalFunctionImp::InternalFunctionImp() 0211 { 0212 } 0213 0214 InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto) 0215 : JSObject(funcProto) 0216 { 0217 } 0218 0219 InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto, const Identifier &name) 0220 : JSObject(funcProto) 0221 , m_name(name) 0222 { 0223 } 0224 0225 bool InternalFunctionImp::implementsCall() const 0226 { 0227 return true; 0228 } 0229 0230 bool InternalFunctionImp::implementsHasInstance() const 0231 { 0232 return true; 0233 } 0234 0235 // ------------------------------ global functions ----------------------------- 0236 0237 double roundValue(double d) 0238 { 0239 double ad = fabs(d); 0240 if (ad == 0 || isNaN(d) || isInf(d)) { 0241 return d; 0242 } 0243 return copysign(floor(ad), d); 0244 } 0245 0246 int32_t toInt32(double d) 0247 { 0248 if (isNaN(d) || isInf(d)) { 0249 return 0; 0250 } 0251 double d32 = fmod(roundValue(d), D32); 0252 0253 if (d32 >= D32 / 2) { 0254 d32 -= D32; 0255 } else if (d32 < -D32 / 2) { 0256 d32 += D32; 0257 } 0258 0259 return static_cast<int32_t>(d32); 0260 } 0261 0262 int32_t toInt32(double d, bool &ok) 0263 { 0264 ok = true; 0265 if (isNaN(d) || isInf(d)) { 0266 ok = false; 0267 return 0; 0268 } 0269 return toInt32(d); 0270 } 0271 0272 uint32_t toUInt32(double dd) 0273 { 0274 double d = roundValue(dd); 0275 if (isNaN(d) || isInf(d)) { 0276 return 0; 0277 } 0278 double d32 = fmod(d, D32); 0279 0280 if (d32 < 0) { 0281 d32 += D32; 0282 } 0283 0284 return static_cast<uint32_t>(d32); 0285 } 0286 0287 uint16_t toUInt16(double dd) 0288 { 0289 double d = roundValue(dd); 0290 if (isNaN(d) || isInf(d)) { 0291 return 0; 0292 } 0293 double d16 = fmod(d, D16); 0294 0295 if (d16 < 0) { 0296 d16 += D16; 0297 } 0298 0299 return static_cast<uint16_t>(d16); 0300 } 0301 0302 //#ifndef NDEBUG 0303 void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno) 0304 { 0305 UString vString; 0306 if (!o) { 0307 fprintf(stderr, "KJS: %s: (null)", s); 0308 } else { 0309 JSValue *v = o; 0310 0311 unsigned int arrayLength = 0; 0312 bool hadExcep = exec->hadException(); 0313 0314 UString name; 0315 switch (JSValue::type(v)) { 0316 case UnspecifiedType: 0317 name = "Unspecified"; 0318 break; 0319 case UndefinedType: 0320 name = "Undefined"; 0321 break; 0322 case NullType: 0323 name = "Null"; 0324 break; 0325 case BooleanType: 0326 name = "Boolean"; 0327 break; 0328 case StringType: 0329 name = "String"; 0330 break; 0331 case NumberType: 0332 name = "Number"; 0333 break; 0334 case ObjectType: { 0335 JSObject *obj = static_cast<JSObject *>(v); 0336 name = obj->className(); 0337 if (name.isNull()) { 0338 name = "(unknown class)"; 0339 } 0340 0341 if (obj->inherits(&ArrayInstance::info)) { 0342 arrayLength = JSValue::toUInt32(obj->get(exec, exec->propertyNames().length), exec); 0343 } 0344 vString = "[object " + name + "]"; // krazy:exclude=doublequote_chars 0345 break; 0346 } 0347 case GetterSetterType: 0348 name = "GetterSetter"; 0349 break; 0350 } 0351 0352 // Avoid calling toString on a huge array (e.g. 4 billion elements, in mozilla/js/js1_5/Array/array-001.js) 0353 if (arrayLength > 100) { 0354 vString = UString("[ Array with ") + UString::from(arrayLength) + " elements ]"; 0355 } else if (JSValue::type(v) != ObjectType) { // Don't want to call a user toString function! 0356 vString = JSValue::toString(v, exec); 0357 } 0358 if (!hadExcep) { 0359 exec->clearException(); 0360 } 0361 0362 if (vString.size() > 350) { 0363 vString = vString.substr(0, 350) + "..."; 0364 } 0365 0366 // Can't use two UString::ascii() in the same fprintf call 0367 CString tempString(vString.cstring()); 0368 0369 fprintf(stderr, "KJS: %s: %s : %s (%p)", 0370 s, tempString.c_str(), name.ascii(), (void *)v); 0371 0372 if (lineno >= 0) { 0373 fprintf(stderr, ", line %d\n", lineno); 0374 } else { 0375 fprintf(stderr, "\n"); 0376 } 0377 } 0378 } 0379 //#endif 0380 0381 }