diff options
Diffstat (limited to 'kjs/value.cpp')
-rw-r--r-- | kjs/value.cpp | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/kjs/value.cpp b/kjs/value.cpp new file mode 100644 index 000000000..e95756c48 --- /dev/null +++ b/kjs/value.cpp @@ -0,0 +1,412 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "value.h" +#include "object.h" +#include "types.h" +#include "interpreter.h" + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +#include "internal.h" +#include "collector.h" +#include "operations.h" +#include "error_object.h" +#include "nodes.h" +#include "simple_number.h" + +using namespace KJS; + +// ----------------------------- ValueImp ------------------------------------- + +ValueImp::ValueImp() : + refcount(0), + // Tell the garbage collector that this memory block corresponds to a real object now + _flags(VI_CREATED) +{ + //fprintf(stderr,"ValueImp::ValueImp %p\n",(void*)this); +} + +ValueImp::~ValueImp() +{ + //fprintf(stderr,"ValueImp::~ValueImp %p\n",(void*)this); + _flags |= VI_DESTRUCTED; +} + +void ValueImp::mark() +{ + //fprintf(stderr,"ValueImp::mark %p\n",(void*)this); + _flags |= VI_MARKED; +} + +bool ValueImp::marked() const +{ + // Simple numbers are always considered marked. + return SimpleNumber::is(this) || (_flags & VI_MARKED); +} + +void ValueImp::setGcAllowed() +{ + //fprintf(stderr,"ValueImp::setGcAllowed %p\n",(void*)this); + // simple numbers are never seen by the collector so setting this + // flag is irrelevant + if (!SimpleNumber::is(this)) + _flags |= VI_GCALLOWED; +} + +void* ValueImp::operator new(size_t s) +{ + return Collector::allocate(s); +} + +void ValueImp::operator delete(void*) +{ + // Do nothing. So far. +} + +bool ValueImp::toUInt32(unsigned&) const +{ + return false; +} + +// ECMA 9.4 +int ValueImp::toInteger(ExecState *exec) const +{ + unsigned i; + if (dispatchToUInt32(i)) + return static_cast<int>(i); + double d = roundValue(exec, Value(const_cast<ValueImp*>(this))); + if (isInf(d)) + return INT_MAX; + return static_cast<int>(d); +} + +int ValueImp::toInt32(ExecState *exec) const +{ + unsigned i; + if (dispatchToUInt32(i)) + return (int)i; + + double d = roundValue(exec, Value(const_cast<ValueImp*>(this))); + if (isNaN(d) || isInf(d) || d == 0.0) + return 0; + double d32 = fmod(d, D32); + + //Make sure we use the positive remainder. This matters since this may be + //less than MIN_INT (but still < 2^32), and we don't want the cast to clamp. + if (d32 < 0) + d32 += D32; + + if (d32 >= D32 / 2.0) + d32 -= D32; + + return static_cast<int>(d32); +} + +unsigned int ValueImp::toUInt32(ExecState *exec) const +{ + unsigned i; + if (dispatchToUInt32(i)) + return i; + + double d = roundValue(exec, Value(const_cast<ValueImp*>(this))); + if (isNaN(d) || isInf(d) || d == 0.0) + return 0; + double d32 = fmod(d, D32); + + if (d32 < 0) + d32 += D32; + + //6.3.1.4 Real floating and integer + // 50) The remaindering operation performed when a value of integer type is + // converted to unsigned type need not be performed when a value of real + // floating type is converted to unsigned type. Thus, the range of + // portable real floating values is (-1, Utype_MAX+1). + return static_cast<unsigned int>(d32); +} + +unsigned short ValueImp::toUInt16(ExecState *exec) const +{ + unsigned i; + if (dispatchToUInt32(i)) + return (unsigned short)i; + + double d = roundValue(exec, Value(const_cast<ValueImp*>(this))); + double d16 = fmod(d, D16); + + // look at toUInt32 to see why this is necesary + int t_int = static_cast<int>(d16); + return static_cast<unsigned short>(t_int); +} + +// Dispatchers for virtual functions, to special-case simple numbers which +// won't be real pointers. + +Type ValueImp::dispatchType() const +{ + if (SimpleNumber::is(this)) + return NumberType; + return type(); +} + +Value ValueImp::dispatchToPrimitive(ExecState *exec, Type preferredType) const +{ + if (SimpleNumber::is(this)) + return Value(const_cast<ValueImp *>(this)); + return toPrimitive(exec, preferredType); +} + +bool ValueImp::dispatchToBoolean(ExecState *exec) const +{ + if (SimpleNumber::is(this)) + return SimpleNumber::value(this); + return toBoolean(exec); +} + +double ValueImp::dispatchToNumber(ExecState *exec) const +{ + if (SimpleNumber::is(this)) + return SimpleNumber::value(this); + return toNumber(exec); +} + +UString ValueImp::dispatchToString(ExecState *exec) const +{ + if (SimpleNumber::is(this)) + return UString::from(SimpleNumber::value(this)); + return toString(exec); +} + +Object ValueImp::dispatchToObject(ExecState *exec) const +{ + if (SimpleNumber::is(this)) + return static_cast<const NumberImp *>(this)->NumberImp::toObject(exec); + return toObject(exec); +} + +bool ValueImp::dispatchToUInt32(unsigned& result) const +{ + if (SimpleNumber::is(this)) { + long i = SimpleNumber::value(this); + if (i < 0) + return false; + result = (unsigned)i; + return true; + } + return toUInt32(result); +} + +// ------------------------------ Value ---------------------------------------- + +Value::Value(ValueImp *v) +{ + rep = v; +#ifdef DEBUG_COLLECTOR + assert (!(rep && !SimpleNumber::is(rep) && *((uint32_t *)rep) == 0 )); + assert (!(rep && !SimpleNumber::is(rep) && rep->_flags & ValueImp::VI_MARKED)); +#endif + if (v) + { + v->ref(); + //fprintf(stderr, "Value::Value(%p) imp=%p ref=%d\n", this, rep, rep->refcount); + v->setGcAllowed(); + } +} + +Value::Value(const Value &v) +{ + rep = v.imp(); +#ifdef DEBUG_COLLECTOR + assert (!(rep && !SimpleNumber::is(rep) && *((uint32_t *)rep) == 0 )); + assert (!(rep && !SimpleNumber::is(rep) && rep->_flags & ValueImp::VI_MARKED)); +#endif + if (rep) + { + rep->ref(); + //fprintf(stderr, "Value::Value(%p)(copying %p) imp=%p ref=%d\n", this, &v, rep, rep->refcount); + } +} + +Value::~Value() +{ + if (rep) + { + rep->deref(); + //fprintf(stderr, "Value::~Value(%p) imp=%p ref=%d\n", this, rep, rep->refcount); + } +} + +Value& Value::operator=(const Value &v) +{ + ValueImp *tmpRep = v.imp(); + + //Avoid the destruction of the object underneath us by + //incrementing the reference on it first + if (tmpRep) { + tmpRep->ref(); + //fprintf(stderr, "Value::operator=(%p)(copying %p) imp=%p ref=%d\n", this, &v, tmpRep, tmpRep->refcount); + } + + if (rep) { + rep->deref(); + //fprintf(stderr, "Value::operator=(%p)(copying %p) old imp=%p ref=%d\n", this, &v, rep, rep->refcount); + } + rep = tmpRep; + + return *this; +} + +// ------------------------------ Undefined ------------------------------------ + +Undefined::Undefined() : Value(UndefinedImp::staticUndefined) +{ +} + +Undefined Undefined::dynamicCast(const Value &v) +{ + if (!v.isValid() || v.type() != UndefinedType) + return Undefined(0); + + return Undefined(); +} + +// ------------------------------ Null ----------------------------------------- + +Null::Null() : Value(NullImp::staticNull) +{ +} + +Null Null::dynamicCast(const Value &v) +{ + if (!v.isValid() || v.type() != NullType) + return Null(0); + + return Null(); +} + +// ------------------------------ Boolean -------------------------------------- + +Boolean::Boolean(bool b) + : Value(b ? BooleanImp::staticTrue : BooleanImp::staticFalse) +{ +} + +bool Boolean::value() const +{ + assert(rep); + return ((BooleanImp*)rep)->value(); +} + +Boolean Boolean::dynamicCast(const Value &v) +{ + if (!v.isValid() || v.type() != BooleanType) + return static_cast<BooleanImp*>(0); + + return static_cast<BooleanImp*>(v.imp()); +} + +// ------------------------------ String --------------------------------------- + +String::String(const UString &s) : Value(new StringImp(s)) +{ +#ifndef NDEBUG + if (s.isNull()) + fprintf(stderr, "WARNING: KJS::String constructed from null string\n"); +#endif +} + +UString String::value() const +{ + assert(rep); + return ((StringImp*)rep)->value(); +} + +String String::dynamicCast(const Value &v) +{ + if (!v.isValid() || v.type() != StringType) + return String(0); + + return String(static_cast<StringImp*>(v.imp())); +} + +// ------------------------------ Number --------------------------------------- + +Number::Number(int i) + : Value(SimpleNumber::fits(i) ? SimpleNumber::make(i) : new NumberImp(static_cast<double>(i))) { } + +Number::Number(unsigned int u) + : Value(SimpleNumber::fits(u) ? SimpleNumber::make(u) : new NumberImp(static_cast<double>(u))) { } + +Number::Number(double d) +#if defined(__alpha) && !defined(_IEEE_FP) + // check for NaN first if we werent't compiled with -mieee on Alpha + : Value(KJS::isNaN(d) ? NumberImp::staticNaN : (SimpleNumber::fits(d) ? SimpleNumber::make((long)d) : new NumberImp(d))) { } +#else + : Value(SimpleNumber::fits(d) ? SimpleNumber::make((long)d) : (KJS::isNaN(d) ? NumberImp::staticNaN : new NumberImp(d))) { } +#endif + +Number::Number(long int l) + : Value(SimpleNumber::fits(l) ? SimpleNumber::make(l) : new NumberImp(static_cast<double>(l))) { } + +Number::Number(long unsigned int l) + : Value(SimpleNumber::fits(l) ? SimpleNumber::make(l) : new NumberImp(static_cast<double>(l))) { } + +Number Number::dynamicCast(const Value &v) +{ + if (!v.isValid() || v.type() != NumberType) + return Number((NumberImp*)0); + + return Number(static_cast<NumberImp*>(v.imp())); +} + +double Number::value() const +{ + if (SimpleNumber::is(rep)) + return (double)SimpleNumber::value(rep); + assert(rep); + return ((NumberImp*)rep)->value(); +} + +int Number::intValue() const +{ + if (SimpleNumber::is(rep)) + return SimpleNumber::value(rep); + return (int)((NumberImp*)rep)->value(); +} + +bool Number::isNaN() const +{ + return rep == NumberImp::staticNaN; +} + +bool Number::isInf() const +{ + if (SimpleNumber::is(rep)) + return false; + return KJS::isInf(((NumberImp*)rep)->value()); +} |