1 /*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2004 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24 #include "internal.h"
25
26 #include "array_object.h"
27 #include "bool_object.h"
28 #include "collector.h"
29 #include "date_object.h"
30 #include "debugger.h"
31 #include "error_object.h"
32 #include "function_object.h"
33 #include "lexer.h"
34 #include "math_object.h"
35 #include "nodes.h"
36 #include "number_object.h"
37 #include "object_object.h"
38 #include "operations.h"
39 #include "regexp_object.h"
40 #include "string_object.h"
41 #include <assert.h>
42 #include <wtf/HashMap.h>
43 #include <wtf/HashSet.h>
44 #include <wtf/Vector.h>
45 #include <math.h>
46 #include <stdio.h>
47
48 namespace KJS
49 {
50
51 #if defined(WTF_COMPILER_MSVC)
52 #define copysign _copysign
53 #endif
54
55 static const double D16 = 65536.0;
56 static const double D32 = 4294967296.0;
57
58 // ------------------------------ StringImp ------------------------------------
59
toPrimitive(ExecState *,JSType) const60 JSValue *StringImp::toPrimitive(ExecState *, JSType) const
61 {
62 return const_cast<StringImp *>(this);
63 }
64
getPrimitiveNumber(ExecState *,double & number,JSValue * & value)65 bool GetterSetterImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value)
66 {
67 ASSERT_NOT_REACHED();
68 number = 0;
69 value = nullptr;
70 return true;
71 }
72
getPrimitiveNumber(ExecState *,double & number,JSValue * & value)73 bool StringImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value)
74 {
75 value = this;
76 number = val.toDouble();
77 return false;
78 }
79
toBoolean(ExecState *) const80 bool StringImp::toBoolean(ExecState *) const
81 {
82 return (val.size() > 0);
83 }
84
toNumber(ExecState *) const85 double StringImp::toNumber(ExecState *) const
86 {
87 return val.toDouble();
88 }
89
toString(ExecState *) const90 UString StringImp::toString(ExecState *) const
91 {
92 return val;
93 }
94
toObject(ExecState * exec) const95 JSObject *StringImp::toObject(ExecState *exec) const
96 {
97 return new StringInstance(exec->lexicalInterpreter()->builtinStringPrototype(), const_cast<StringImp *>(this));
98 }
99
100 // ------------------------------ NumberImp ------------------------------------
101
toPrimitive(ExecState *,JSType) const102 JSValue *NumberImp::toPrimitive(ExecState *, JSType) const
103 {
104 return const_cast<NumberImp *>(this);
105 }
106
getPrimitiveNumber(ExecState *,double & number,JSValue * & value)107 bool NumberImp::getPrimitiveNumber(ExecState *, double &number, JSValue *&value)
108 {
109 number = val;
110 value = this;
111 return true;
112 }
113
toBoolean(ExecState *) const114 bool NumberImp::toBoolean(ExecState *) const
115 {
116 return val < 0.0 || val > 0.0; // false for NaN
117 }
118
toNumber(ExecState *) const119 double NumberImp::toNumber(ExecState *) const
120 {
121 return val;
122 }
123
toString(ExecState *) const124 UString NumberImp::toString(ExecState *) const
125 {
126 if (val == 0.0) { // +0.0 or -0.0
127 return "0";
128 }
129 return UString::from(val);
130 }
131
toObject(ExecState * exec) const132 JSObject *NumberImp::toObject(ExecState *exec) const
133 {
134 List args;
135 args.append(const_cast<NumberImp *>(this));
136 return static_cast<JSObject *>(exec->lexicalInterpreter()->builtinNumber()->construct(exec, args));
137 }
138
getUInt32(uint32_t & uint32) const139 bool NumberImp::getUInt32(uint32_t &uint32) const
140 {
141 uint32 = static_cast<uint32_t>(val);
142 return uint32 == val;
143 }
144
getTruncatedInt32(int32_t & int32) const145 bool NumberImp::getTruncatedInt32(int32_t &int32) const
146 {
147 if (!(val >= -2147483648.0 && val < 2147483648.0)) {
148 return false;
149 }
150 int32 = static_cast<int32_t>(val);
151 return true;
152 }
153
getTruncatedUInt32(uint32_t & uint32) const154 bool NumberImp::getTruncatedUInt32(uint32_t &uint32) const
155 {
156 if (!(val >= 0.0 && val < 4294967296.0)) {
157 return false;
158 }
159 uint32 = static_cast<uint32_t>(val);
160 return true;
161 }
162
163 // --------------------------- GetterSetterImp ---------------------------------
mark()164 void GetterSetterImp::mark()
165 {
166 JSCell::mark();
167
168 if (getter && !getter->marked()) {
169 getter->mark();
170 }
171 if (setter && !setter->marked()) {
172 setter->mark();
173 }
174 }
175
toPrimitive(ExecState *,JSType) const176 JSValue *GetterSetterImp::toPrimitive(ExecState *, JSType) const
177 {
178 assert(false);
179 return jsNull();
180 }
181
toBoolean(ExecState *) const182 bool GetterSetterImp::toBoolean(ExecState *) const
183 {
184 assert(false);
185 return false;
186 }
187
toNumber(ExecState *) const188 double GetterSetterImp::toNumber(ExecState *) const
189 {
190 assert(false);
191 return 0.0;
192 }
193
toString(ExecState *) const194 UString GetterSetterImp::toString(ExecState *) const
195 {
196 assert(false);
197 return UString::null();
198 }
199
toObject(ExecState * exec) const200 JSObject *GetterSetterImp::toObject(ExecState *exec) const
201 {
202 assert(false);
203 return JSValue::toObject(jsNull(), exec);
204 }
205
206 // ------------------------------ InternalFunctionImp --------------------------
207
208 const ClassInfo InternalFunctionImp::info = {"Function", nullptr, nullptr, nullptr};
209
InternalFunctionImp()210 InternalFunctionImp::InternalFunctionImp()
211 {
212 }
213
InternalFunctionImp(FunctionPrototype * funcProto)214 InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto)
215 : JSObject(funcProto)
216 {
217 }
218
InternalFunctionImp(FunctionPrototype * funcProto,const Identifier & name)219 InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto, const Identifier &name)
220 : JSObject(funcProto)
221 , m_name(name)
222 {
223 }
224
implementsCall() const225 bool InternalFunctionImp::implementsCall() const
226 {
227 return true;
228 }
229
implementsHasInstance() const230 bool InternalFunctionImp::implementsHasInstance() const
231 {
232 return true;
233 }
234
235 // ------------------------------ global functions -----------------------------
236
roundValue(double d)237 double roundValue(double d)
238 {
239 double ad = fabs(d);
240 if (ad == 0 || isNaN(d) || isInf(d)) {
241 return d;
242 }
243 return copysign(floor(ad), d);
244 }
245
toInt32(double d)246 int32_t toInt32(double d)
247 {
248 if (isNaN(d) || isInf(d)) {
249 return 0;
250 }
251 double d32 = fmod(roundValue(d), D32);
252
253 if (d32 >= D32 / 2) {
254 d32 -= D32;
255 } else if (d32 < -D32 / 2) {
256 d32 += D32;
257 }
258
259 return static_cast<int32_t>(d32);
260 }
261
toInt32(double d,bool & ok)262 int32_t toInt32(double d, bool &ok)
263 {
264 ok = true;
265 if (isNaN(d) || isInf(d)) {
266 ok = false;
267 return 0;
268 }
269 return toInt32(d);
270 }
271
toUInt32(double dd)272 uint32_t toUInt32(double dd)
273 {
274 double d = roundValue(dd);
275 if (isNaN(d) || isInf(d)) {
276 return 0;
277 }
278 double d32 = fmod(d, D32);
279
280 if (d32 < 0) {
281 d32 += D32;
282 }
283
284 return static_cast<uint32_t>(d32);
285 }
286
toUInt16(double dd)287 uint16_t toUInt16(double dd)
288 {
289 double d = roundValue(dd);
290 if (isNaN(d) || isInf(d)) {
291 return 0;
292 }
293 double d16 = fmod(d, D16);
294
295 if (d16 < 0) {
296 d16 += D16;
297 }
298
299 return static_cast<uint16_t>(d16);
300 }
301
302 //#ifndef NDEBUG
printInfo(ExecState * exec,const char * s,JSValue * o,int lineno)303 void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno)
304 {
305 UString vString;
306 if (!o) {
307 fprintf(stderr, "KJS: %s: (null)", s);
308 } else {
309 JSValue *v = o;
310
311 unsigned int arrayLength = 0;
312 bool hadExcep = exec->hadException();
313
314 UString name;
315 switch (JSValue::type(v)) {
316 case UnspecifiedType:
317 name = "Unspecified";
318 break;
319 case UndefinedType:
320 name = "Undefined";
321 break;
322 case NullType:
323 name = "Null";
324 break;
325 case BooleanType:
326 name = "Boolean";
327 break;
328 case StringType:
329 name = "String";
330 break;
331 case NumberType:
332 name = "Number";
333 break;
334 case ObjectType: {
335 JSObject *obj = static_cast<JSObject *>(v);
336 name = obj->className();
337 if (name.isNull()) {
338 name = "(unknown class)";
339 }
340
341 if (obj->inherits(&ArrayInstance::info)) {
342 arrayLength = JSValue::toUInt32(obj->get(exec, exec->propertyNames().length), exec);
343 }
344 vString = "[object " + name + "]"; // krazy:exclude=doublequote_chars
345 break;
346 }
347 case GetterSetterType:
348 name = "GetterSetter";
349 break;
350 }
351
352 // Avoid calling toString on a huge array (e.g. 4 billion elements, in mozilla/js/js1_5/Array/array-001.js)
353 if (arrayLength > 100) {
354 vString = UString("[ Array with ") + UString::from(arrayLength) + " elements ]";
355 } else if (JSValue::type(v) != ObjectType) { // Don't want to call a user toString function!
356 vString = JSValue::toString(v, exec);
357 }
358 if (!hadExcep) {
359 exec->clearException();
360 }
361
362 if (vString.size() > 350) {
363 vString = vString.substr(0, 350) + "...";
364 }
365
366 // Can't use two UString::ascii() in the same fprintf call
367 CString tempString(vString.cstring());
368
369 fprintf(stderr, "KJS: %s: %s : %s (%p)",
370 s, tempString.c_str(), name.ascii(), (void *)v);
371
372 if (lineno >= 0) {
373 fprintf(stderr, ", line %d\n", lineno);
374 } else {
375 fprintf(stderr, "\n");
376 }
377 }
378 }
379 //#endif
380
381 }
382