source: webkit/trunk/JavaScriptCore/kjs/value.cpp@ 1825

Last change on this file since 1825 was 1825, checked in by mjs, 23 years ago

Phase 2 of fixnum optimization. Store any integral number that
will fit in two bits less than a long inside the ValueImp *
itself, thus avoiding the need to deal with the garbage collector
at all for these types. Such numbers comprised .5 million of the
1.7 million ValueImps created during the cvs-js-performance test,
so traffic through the garbage collector should be

20% improvement on cvs-js-performance. This may also show up on
cvs-base, but I did not compare and I am too lazy to make clean in
WebCore yet again.

This also significantly reduces memory footprint on
JavaScript-heavy pages. Size after going through
cvs-js-performance suite is now down from 22 MB to 17.5 MB.

  • JavaScriptCore.pbproj/project.pbxproj:
  • kjs/simple_number.h: Added. Some inline static methods for handling simple numbers that are stored in the pointer.
  • kjs/ustring.h:
  • kjs/ustring.cpp: (UString::from): Added new overload for long.
  • kjs/value.cpp: (ValueImp::marked): Add special case for simple numbers. (ValueImp::setGcAllowed): Likewise. (ValueImp::toInteger): Call dispatch version of toUInt32(unsigned&), not the real method. (ValueImp::toInt32): Likewise. (ValueImp::toUInt32): Likewise. (ValueImp::toUInt16): Likewise. (ValueImp::dispatchType): Add special case for simple numbers. (ValueImp::dispatchToPrimitive): Likewise. (ValueImp::dispatchToBoolean): Likewise. (ValueImp::dispatchToNumber): Likewise. (ValueImp::dispatchToString): Likewise. (ValueImp::dispatchToObject): Likewise. (ValueImp::dispatchToUInt32): Likewise. (ValueImp::dispatchGetBase): Likewise. (ValueImp::dispatchGetPropertyName): Likewise. (ValueImp::dispatchPutValue): Likewise. (ValueImp::dispatchDeleteValue): Likewise. (Number::Number): Create a simple number instead of a full-blown ValueImp when possible. (Number::value): Likewise.
  • kjs/value.h:
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 */
23
24#include "value.h"
25#include "object.h"
26#include "types.h"
27#include "interpreter.h"
28
29#include <assert.h>
30#include <math.h>
31#include <stdio.h>
32#include <string.h>
33
34#include "internal.h"
35#include "collector.h"
36#include "operations.h"
37#include "error_object.h"
38#include "nodes.h"
39#include "simple_number.h"
40
41using namespace KJS;
42
43// ----------------------------- ValueImp -------------------------------------
44
45ValueImp::ValueImp() :
46 refcount(0),
47 // Tell the garbage collector that this memory block corresponds to a real object now
48 _flags(VI_CREATED)
49{
50 //fprintf(stderr,"ValueImp::ValueImp %p\n",(void*)this);
51}
52
53ValueImp::~ValueImp()
54{
55 //fprintf(stderr,"ValueImp::~ValueImp %p\n",(void*)this);
56 _flags |= VI_DESTRUCTED;
57}
58
59void ValueImp::mark()
60{
61 //fprintf(stderr,"ValueImp::mark %p\n",(void*)this);
62 _flags |= VI_MARKED;
63}
64
65bool ValueImp::marked() const
66{
67 // simple numbers are always considered marked
68 return SimpleNumber::isSimpleNumber(this) || (_flags & VI_MARKED);
69}
70
71void ValueImp::setGcAllowed()
72{
73 // simple numbers are never seen by the collector so setting this
74 // flag is irrelevant
75 if (!SimpleNumber::isSimpleNumber(this)) {
76 //fprintf(stderr,"ValueImp::setGcAllowed %p\n",(void*)this);
77 _flags |= VI_GCALLOWED;
78 }
79}
80
81void* ValueImp::operator new(size_t s)
82{
83 return Collector::allocate(s);
84}
85
86void ValueImp::operator delete(void*)
87{
88 // Do nothing. So far.
89}
90
91bool ValueImp::toUInt32(unsigned&) const
92{
93 return false;
94}
95
96// ECMA 9.4
97int ValueImp::toInteger(ExecState *exec) const
98{
99 unsigned i;
100 if (dispatchToUInt32(i))
101 return (int)i;
102 return int(roundValue(exec, Value(const_cast<ValueImp*>(this))));
103}
104
105int ValueImp::toInt32(ExecState *exec) const
106{
107 unsigned i;
108 if (dispatchToUInt32(i))
109 return (int)i;
110
111 double d = roundValue(exec, Value(const_cast<ValueImp*>(this)));
112 double d32 = fmod(d, D32);
113
114 if (d32 >= D32 / 2.0)
115 d32 -= D32;
116
117 return static_cast<int>(d32);
118}
119
120unsigned int ValueImp::toUInt32(ExecState *exec) const
121{
122 unsigned i;
123 if (dispatchToUInt32(i))
124 return i;
125
126 double d = roundValue(exec, Value(const_cast<ValueImp*>(this)));
127 double d32 = fmod(d, D32);
128
129 return static_cast<unsigned int>(d32);
130}
131
132unsigned short ValueImp::toUInt16(ExecState *exec) const
133{
134 unsigned i;
135 if (dispatchToUInt32(i))
136 return (unsigned short)i;
137
138 double d = roundValue(exec, Value(const_cast<ValueImp*>(this)));
139 double d16 = fmod(d, D16);
140
141 return static_cast<unsigned short>(d16);
142}
143
144// ECMA 8.7.1
145Value ValueImp::getBase(ExecState *exec) const
146{
147 Object err = Error::create(exec, ReferenceError, I18N_NOOP("Invalid reference base"));
148 exec->setException(err);
149 return err;
150}
151
152// ECMA 8.7.2
153UString ValueImp::getPropertyName(ExecState * /*exec*/) const
154{
155 // the spec wants a runtime error here. But getValue() and putValue()
156 // will catch this case on their own earlier. When returning a Null
157 // string we should be on the safe side.
158 return UString();
159}
160
161// ECMA 8.7.1
162Value ValueImp::getValue(ExecState *exec) const
163{
164 return Value(const_cast<ValueImp*>(this));
165}
166
167void ValueImp::putValue(ExecState *exec, const Value& w)
168{
169 Object err = Error::create(exec,ReferenceError);
170 exec->setException(err);
171}
172
173bool ValueImp::deleteValue(ExecState *exec)
174{
175 Object err = Error::create(exec,ReferenceError);
176 exec->setException(err);
177 return false;
178}
179
180
181// Dispatchers for virtual functions, to special-case fixnums which
182// won't be real pointers
183
184Type ValueImp::dispatchType() const
185{
186 if (SimpleNumber::isSimpleNumber(this)) {
187 return NumberType;
188 } else {
189 return this->type();
190 }
191}
192
193Value ValueImp::dispatchToPrimitive(ExecState *exec, Type preferredType) const
194{
195 if (SimpleNumber::isSimpleNumber(this)) {
196 return Number((NumberImp*)this);
197 } else {
198 return this->toPrimitive(exec, preferredType);
199 }
200}
201
202bool ValueImp::dispatchToBoolean(ExecState *exec) const
203{
204 if (SimpleNumber::isSimpleNumber(this)) {
205 return SimpleNumber::longValue(this);
206 } else {
207 return this->toBoolean(exec);
208 }
209}
210
211double ValueImp::dispatchToNumber(ExecState *exec) const
212{
213 if (SimpleNumber::isSimpleNumber(this)) {
214 return SimpleNumber::longValue(this);
215 } else {
216 return this->toNumber(exec);
217 }
218}
219
220UString ValueImp::dispatchToString(ExecState *exec) const
221{
222 if (SimpleNumber::isSimpleNumber(this)) {
223 return UString::from(SimpleNumber::longValue(this));
224 } else {
225 return this->toString(exec);
226 }
227}
228
229Object ValueImp::dispatchToObject(ExecState *exec) const
230{
231 if (SimpleNumber::isSimpleNumber(this)) {
232 List args;
233 args.append(Number(static_cast<NumberImp*>(const_cast<ValueImp *>(this))));
234 return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
235 } else {
236 return this->toObject(exec);
237 }
238}
239
240bool ValueImp::dispatchToUInt32(unsigned& result) const
241{
242 if (SimpleNumber::isSimpleNumber(this)) {
243 result = SimpleNumber::longValue(this);
244 return true;
245 } else {
246 return this->toUInt32(result);
247 }
248}
249
250Value ValueImp::dispatchGetBase(ExecState *exec) const
251{
252 if (SimpleNumber::isSimpleNumber(this)) {
253 Object err = Error::create(exec, ReferenceError, I18N_NOOP("Invalid reference base"));
254 exec->setException(err);
255 return err;
256 } else {
257 return this->getBase(exec);
258 }
259}
260
261UString ValueImp::dispatchGetPropertyName(ExecState *exec) const
262{
263 if (SimpleNumber::isSimpleNumber(this)) {
264 return UString();
265 } else {
266 return this->getPropertyName(exec);
267 }
268}
269
270void ValueImp::dispatchPutValue(ExecState *exec, const Value& w)
271{
272 if (SimpleNumber::isSimpleNumber(this)) {
273 Object err = Error::create(exec,ReferenceError);
274 exec->setException(err);
275 } else {
276 return this->putValue(exec, w);
277 }
278}
279
280bool ValueImp::dispatchDeleteValue(ExecState *exec)
281{
282 if (SimpleNumber::isSimpleNumber(this)) {
283 Object err = Error::create(exec,ReferenceError);
284 exec->setException(err);
285 return false;
286 } else {
287 return this->deleteValue(exec);
288 }
289}
290
291
292// ------------------------------ Value ----------------------------------------
293
294Value::Value(ValueImp *v)
295{
296 rep = v;
297 if (rep)
298 {
299 rep->ref();
300 //fprintf(stderr, "Value::Value(%p) imp=%p ref=%d\n", this, rep, rep->refcount);
301 v->setGcAllowed();
302 }
303}
304
305Value::Value(const Value &v)
306{
307 rep = v.imp();
308 if (rep)
309 {
310 rep->ref();
311 //fprintf(stderr, "Value::Value(%p)(copying %p) imp=%p ref=%d\n", this, &v, rep, rep->refcount);
312 }
313}
314
315Value::~Value()
316{
317 if (rep)
318 {
319 rep->deref();
320 //fprintf(stderr, "Value::~Value(%p) imp=%p ref=%d\n", this, rep, rep->refcount);
321 }
322}
323
324Value& Value::operator=(const Value &v)
325{
326 if (rep) {
327 rep->deref();
328 //fprintf(stderr, "Value::operator=(%p)(copying %p) old imp=%p ref=%d\n", this, &v, rep, rep->refcount);
329 }
330 rep = v.imp();
331 if (rep)
332 {
333 rep->ref();
334 //fprintf(stderr, "Value::operator=(%p)(copying %p) imp=%p ref=%d\n", this, &v, rep, rep->refcount);
335 }
336 return *this;
337}
338
339// ------------------------------ Undefined ------------------------------------
340
341Undefined::Undefined() : Value(UndefinedImp::staticUndefined)
342{
343}
344
345Undefined Undefined::dynamicCast(const Value &v)
346{
347 if (v.isNull() || v.type() != UndefinedType)
348 return Undefined(0);
349
350 return Undefined();
351}
352
353// ------------------------------ Null -----------------------------------------
354
355Null::Null() : Value(NullImp::staticNull)
356{
357}
358
359Null Null::dynamicCast(const Value &v)
360{
361 if (v.isNull() || v.type() != NullType)
362 return Null(0);
363
364 return Null();
365}
366
367// ------------------------------ Boolean --------------------------------------
368
369Boolean::Boolean(bool b)
370 : Value(b ? BooleanImp::staticTrue : BooleanImp::staticFalse)
371{
372}
373
374bool Boolean::value() const
375{
376 assert(rep);
377 return ((BooleanImp*)rep)->value();
378}
379
380Boolean Boolean::dynamicCast(const Value &v)
381{
382 if (v.isNull() || v.type() != BooleanType)
383 return static_cast<BooleanImp*>(0);
384
385 return static_cast<BooleanImp*>(v.imp());
386}
387
388// ------------------------------ String ---------------------------------------
389
390String::String(const UString &s) : Value(new StringImp(UString(s)))
391{
392}
393
394UString String::value() const
395{
396 assert(rep);
397 return ((StringImp*)rep)->value();
398}
399
400String String::dynamicCast(const Value &v)
401{
402 if (v.isNull() || v.type() != StringType)
403 return String(0);
404
405 return String(static_cast<StringImp*>(v.imp()));
406}
407
408// ------------------------------ Number ---------------------------------------
409
410Number::Number(int i)
411 : Value(SimpleNumber::fitsInSimpleNumber(i) ? SimpleNumber::makeSimpleNumber(i) : new NumberImp(static_cast<double>(i))) { }
412
413Number::Number(unsigned int u)
414 : Value(SimpleNumber::fitsInSimpleNumber(u) ? SimpleNumber::makeSimpleNumber(u) : new NumberImp(static_cast<double>(u))) { }
415
416Number::Number(double d)
417 : Value(SimpleNumber::fitsInSimpleNumber((long)d) ? SimpleNumber::makeSimpleNumber((long)d) : new NumberImp(d)) { }
418
419Number::Number(long int l)
420 : Value(SimpleNumber::fitsInSimpleNumber(l) ? SimpleNumber::makeSimpleNumber(l) : new NumberImp(static_cast<double>(l))) { }
421
422Number::Number(long unsigned int l)
423 : Value(SimpleNumber::fitsInSimpleNumber(l) ? SimpleNumber::makeSimpleNumber(l) : new NumberImp(static_cast<double>(l))) { }
424
425Number Number::dynamicCast(const Value &v)
426{
427 if (v.isNull() || v.type() != NumberType)
428 return Number((NumberImp*)0);
429
430 return Number(static_cast<NumberImp*>(v.imp()));
431}
432
433double Number::value() const
434{
435 if (SimpleNumber::isSimpleNumber(rep)) {
436 return (double)SimpleNumber::longValue(rep);
437 } else {
438 assert(rep);
439 return ((NumberImp*)rep)->value();
440 }
441}
442
443int Number::intValue() const
444{
445 return int(value());
446}
447
448bool Number::isNaN() const
449{
450 return KJS::isNaN(value());
451}
452
453bool Number::isInf() const
454{
455 return KJS::isInf(value());
456}
Note: See TracBrowser for help on using the repository browser.