/**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the V4VM module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QMLJS_VALUE_H #define QMLJS_VALUE_H #include #include #include #include namespace QQmlJS { namespace VM { class Array; struct String; struct Object; struct BooleanObject; struct NumberObject; struct StringObject; struct ArrayObject; struct DateObject; struct FunctionObject; struct RegExpObject; struct ErrorObject; struct ArgumentsObject; struct ExecutionContext; struct ExecutionEngine; struct Value; extern "C" { double __qmljs_to_number(Value value, ExecutionContext *ctx); } typedef uint Bool; struct Value { union { quint64 val; double dbl; struct { #if Q_BYTE_ORDER != Q_LITTLE_ENDIAN uint tag; #endif union { uint uint_32; int int_32; #if CPU(X86_64) #else Object *o; String *s; #endif }; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN uint tag; #endif }; }; enum Masks { NotDouble_Mask = 0xfff80000, Type_Mask = 0xffff0000, Immediate_Mask = NotDouble_Mask | 0x00040000, Tag_Shift = 32 }; enum ValueType { Undefined_Type = Immediate_Mask | 0x00000, Null_Type = Immediate_Mask | 0x10000, Boolean_Type = Immediate_Mask | 0x20000, Integer_Type = Immediate_Mask | 0x30000, Object_Type = NotDouble_Mask | 0x00000, String_Type = NotDouble_Mask | 0x10000 }; enum ImmediateFlags { ConvertibleToInt = Immediate_Mask | (0x1 << 15) }; enum ValueTypeInternal { _Undefined_Type = Undefined_Type, _Null_Type = Null_Type | ConvertibleToInt, _Boolean_Type = Boolean_Type | ConvertibleToInt, _Integer_Type = Integer_Type | ConvertibleToInt, _Object_Type = Object_Type, _String_Type = String_Type }; inline ValueType type() const { return (ValueType)(tag & Type_Mask); } inline bool isUndefined() const { return tag == _Undefined_Type; } inline bool isNull() const { return tag == _Null_Type; } inline bool isBoolean() const { return tag == _Boolean_Type; } inline bool isInteger() const { return tag == _Integer_Type; } inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; } inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; } #if CPU(X86_64) inline bool isString() const { return (tag & Type_Mask) == String_Type; } inline bool isObject() const { return (tag & Type_Mask) == Object_Type; } #else inline bool isString() const { return tag == String_Type; } inline bool isObject() const { return tag == Object_Type; } #endif inline bool isConvertibleToInt() const { return (tag & ConvertibleToInt) == ConvertibleToInt; } Bool booleanValue() const { return int_32; } double doubleValue() const { return dbl; } void setDouble(double d) { dbl = d; } double asDouble() const { if (tag == _Integer_Type) return int_32; return dbl; } int integerValue() const { return int_32; } #if CPU(X86_64) String *stringValue() const { return (String *)(val & ~(quint64(Type_Mask) << Tag_Shift)); } Object *objectValue() const { return (Object *)(val & ~(quint64(Type_Mask) << Tag_Shift)); } #else String *stringValue() const { return s; } Object *objectValue() const { return o; } #endif quint64 rawValue() const { return val; } static Value undefinedValue(); static Value nullValue(); static Value fromBoolean(Bool b); static Value fromDouble(double d); static Value fromInt32(int i); static Value fromString(String *s); static Value fromObject(Object *o); #ifndef QMLJS_LLVM_RUNTIME static Value fromString(ExecutionContext *ctx, const QString &fromString); #endif static double toInteger(double fromNumber); static int toInt32(double value); static unsigned int toUInt32(double value); int toUInt16(ExecutionContext *ctx); int toInt32(ExecutionContext *ctx); unsigned int toUInt32(ExecutionContext *ctx); Bool toBoolean(ExecutionContext *ctx) const; double toInteger(ExecutionContext *ctx) const; double toNumber(ExecutionContext *ctx) const; String *toString(ExecutionContext *ctx) const; Value toObject(ExecutionContext *ctx) const; inline bool isPrimitive() const { return !isObject(); } #if CPU(X86_64) inline bool integerCompatible() const { const quint64 mask = quint64(ConvertibleToInt) << 32; return (val & mask) == mask; } static inline bool integerCompatible(Value a, Value b) { const quint64 mask = quint64(ConvertibleToInt) << 32; return ((a.val & b.val) & mask) == mask; } static inline bool bothDouble(Value a, Value b) { const quint64 mask = quint64(NotDouble_Mask) << 32; return ((a.val | b.val) & mask) != mask; } #else inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; } static inline bool integerCompatible(Value a, Value b) { return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt; } static inline bool bothDouble(Value a, Value b) { return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask; } #endif inline bool tryIntegerConversion() { bool b = isConvertibleToInt(); if (b) tag = _Integer_Type; return b; } Object *asObject() const; FunctionObject *asFunctionObject() const; BooleanObject *asBooleanObject() const; NumberObject *asNumberObject() const; StringObject *asStringObject() const; DateObject *asDateObject() const; RegExpObject *asRegExpObject() const; ArrayObject *asArrayObject() const; ErrorObject *asErrorObject() const; Value property(ExecutionContext *ctx, String *name) const; // Section 9.12 bool sameValue(Value other); }; inline Value Value::undefinedValue() { Value v; #if CPU(X86_64) v.val = quint64(_Undefined_Type) << Tag_Shift; #else v.tag = _Undefined_Type; v.int_32 = 0; #endif return v; } inline Value Value::nullValue() { Value v; #if CPU(X86_64) v.val = quint64(_Null_Type) << Tag_Shift; #else v.tag = _Null_Type; v.int_32 = 0; #endif return v; } inline Value Value::fromBoolean(Bool b) { Value v; v.tag = _Boolean_Type; v.int_32 = (bool)b; return v; } inline Value Value::fromDouble(double d) { Value v; v.dbl = d; return v; } inline Value Value::fromInt32(int i) { Value v; v.tag = _Integer_Type; v.int_32 = i; return v; } inline Value Value::fromString(String *s) { Value v; #if CPU(X86_64) v.val = (quint64)s; v.val |= quint64(_String_Type) << Tag_Shift; #else v.tag = _String_Type; v.s = s; #endif return v; } inline Value Value::fromObject(Object *o) { Value v; #if CPU(X86_64) v.val = (quint64)o; v.val |= quint64(_Object_Type) << Tag_Shift; #else v.tag = _Object_Type; v.o = o; #endif return v; } inline int Value::toInt32(ExecutionContext *ctx) { if (isConvertibleToInt()) return int_32; double d; if (isDouble()) d = dbl; else d = __qmljs_to_number(*this, ctx); const double D32 = 4294967296.0; const double D31 = D32 / 2.0; if ((d >= -D31 && d < D31)) return static_cast(d); return Value::toInt32(__qmljs_to_number(*this, ctx)); } inline unsigned int Value::toUInt32(ExecutionContext *ctx) { if (isConvertibleToInt()) return (unsigned) int_32; double d; if (isDouble()) d = dbl; else d = __qmljs_to_number(*this, ctx); const double D32 = 4294967296.0; if (dbl >= 0 && dbl < D32) return static_cast(dbl); return toUInt32(d); } } // namespace VM } // namespace QQmlJS #endif