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 }