/**************************************************************************** ** ** 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_RUNTIME_H #define QMLJS_RUNTIME_H #ifndef QMLJS_LLVM_RUNTIME # include # include # include #endif #include #include namespace QQmlJS { namespace IR { struct Function; } namespace VM { enum TypeHint { PREFERREDTYPE_HINT, NUMBER_HINT, STRING_HINT }; enum PropertyAttributes { NoAttributes = 0, ValueAttribute = 1, WritableAttribute = 2, EnumerableAttribute = 4, ConfigurableAttribute = 8 }; struct Value; struct Object; struct String; struct Context; struct FunctionObject; struct BooleanObject; struct NumberObject; struct StringObject; struct DateObject; struct ArrayObject; struct ErrorObject; struct ActivationObject; struct ExecutionEngine; typedef uint Bool; extern "C" { // context Value __qmljs_call_activation_property(Context *, String *name, Value *args, int argc); Value __qmljs_call_property(Context *context, const Value base, String *name, Value *args, int argc); Value __qmljs_call_value(Context *context, const Value thisObject, const Value func, Value *args, int argc); Value __qmljs_construct_activation_property(Context *, String *name, Value *args, int argc); Value __qmljs_construct_property(Context *context, const Value base, String *name, Value *args, int argc); Value __qmljs_construct_value(Context *context, const Value func, Value *args, int argc); Value __qmljs_builtin_typeof(Context *context, Value *args, int argc); Value __qmljs_builtin_throw(Context *context, Value *args, int argc); Value __qmljs_builtin_rethrow(Context *context, Value *args, int argc); // constructors Value __qmljs_init_string(String *string); Value __qmljs_init_object(Object *object); Value __qmljs_init_closure(IR::Function *clos, Context *ctx); Value __qmljs_init_native_function(void (*code)(Context *), Context *ctx); Bool __qmljs_is_function(const Value value); // string literals Value __qmljs_string_literal_undefined(Context *ctx); Value __qmljs_string_literal_null(Context *ctx); Value __qmljs_string_literal_true(Context *ctx); Value __qmljs_string_literal_false(Context *ctx); Value __qmljs_string_literal_object(Context *ctx); Value __qmljs_string_literal_boolean(Context *ctx); Value __qmljs_string_literal_number(Context *ctx); Value __qmljs_string_literal_string(Context *ctx); Value __qmljs_string_literal_function(Context *ctx); // strings String *__qmljs_string_from_utf8(Context *ctx, const char *s); int __qmljs_string_length(Context *ctx, String *string); double __qmljs_string_to_number(Context *ctx, String *string); Value __qmljs_string_from_number(Context *ctx, double number); Bool __qmljs_string_compare(Context *ctx, String *left, String *right); Bool __qmljs_string_equal(Context *ctx, String *left, String *right); String *__qmljs_string_concat(Context *ctx, String *first, String *second); String *__qmljs_identifier_from_utf8(Context *ctx, const char *s); // objects Value __qmljs_object_default_value(Context *ctx, const Value object, int typeHint); Value __qmljs_throw_type_error(Context *ctx); Value __qmljs_new_object(Context *ctx); Value __qmljs_new_boolean_object(Context *ctx, bool boolean); Value __qmljs_new_number_object(Context *ctx, double n); Value __qmljs_new_string_object(Context *ctx, String *string); void __qmljs_set_activation_property(Context *ctx, String *name, Value value); void __qmljs_set_property(Context *ctx, Value object, String *name, Value value); Value __qmljs_get_property(Context *ctx, Value object, String *name); Value __qmljs_get_activation_property(Context *ctx, String *name); Value __qmljs_get_element(Context *ctx, Value object, Value index); void __qmljs_set_element(Context *ctx, Value object, Value index, Value value); // context Value __qmljs_get_thisObject(Context *ctx); // type conversion and testing Value __qmljs_to_primitive(Context *ctx, const Value value, int typeHint); Bool __qmljs_to_boolean(const Value value, Context *ctx); double __qmljs_to_number(const Value value, Context *ctx); double __qmljs_to_integer(const Value value, Context *ctx); int __qmljs_to_int32(const Value value, Context *ctx); unsigned __qmljs_to_uint32(const Value value, Context *ctx); unsigned short __qmljs_to_uint16(const Value value, Context *ctx); Value __qmljs_to_string(Context *ctx, const Value value); Value __qmljs_to_object(Context *ctx, const Value value); //uint __qmljs_check_object_coercible(Context *ctx, Value *result, const Value *value); Bool __qmljs_is_callable(Context *ctx, const Value value); Value __qmljs_default_value(Context *ctx, const Value value, int typeHint); Value __qmljs_compare(Context *ctx, const Value left, const Value right, bool leftFlag); Bool __qmljs_equal(Context *ctx, const Value x, const Value y); Bool __qmljs_strict_equal(Context *ctx, const Value x, const Value y); // unary operators Value __qmljs_uplus(const Value value, Context *ctx); Value __qmljs_uminus(const Value value, Context *ctx); Value __qmljs_compl(const Value value, Context *ctx); Value __qmljs_not(const Value value, Context *ctx); /* ### these 4 methods are apparently unused right now */ Value __qmljs_delete_subscript(Context *ctx, Value base, Value index); Value __qmljs_delete_member(Context *ctx, Value base, String *name); Value __qmljs_delete_property(Context *ctx, String *name); Value __qmljs_delete_value(Context *ctx, Value value); Value __qmljs_typeof(Context *ctx, const Value value); void __qmljs_throw(Context *context, Value value); Value __qmljs_rethrow(Context *context); // binary operators Value __qmljs_instanceof(const Value left, const Value right, Context *ctx); Value __qmljs_in(const Value left, const Value right, Context *ctx); Value __qmljs_bit_or(const Value left, const Value right, Context *ctx); Value __qmljs_bit_xor(const Value left, const Value right, Context *ctx); Value __qmljs_bit_and(const Value left, const Value right, Context *ctx); Value __qmljs_add(const Value left, const Value right, Context *ctx); Value __qmljs_sub(const Value left, const Value right, Context *ctx); Value __qmljs_mul(const Value left, const Value right, Context *ctx); Value __qmljs_div(const Value left, const Value right, Context *ctx); Value __qmljs_mod(const Value left, const Value right, Context *ctx); Value __qmljs_shl(const Value left, const Value right, Context *ctx); Value __qmljs_shr(const Value left, const Value right, Context *ctx); Value __qmljs_ushr(const Value left, const Value right, Context *ctx); Value __qmljs_gt(const Value left, const Value right, Context *ctx); Value __qmljs_lt(const Value left, const Value right, Context *ctx); Value __qmljs_ge(const Value left, const Value right, Context *ctx); Value __qmljs_le(const Value left, const Value right, Context *ctx); Value __qmljs_eq(const Value left, const Value right, Context *ctx); Value __qmljs_ne(const Value left, const Value right, Context *ctx); Value __qmljs_se(const Value left, const Value right, Context *ctx); Value __qmljs_sne(const Value left, const Value right, Context *ctx); Value __qmljs_add_helper(const Value left, const Value right, Context *ctx); void __qmljs_inplace_bit_and(Context *ctx, Value *result, Value *value); void __qmljs_inplace_bit_or(Context *ctx, Value *result, Value *value); void __qmljs_inplace_bit_xor(Context *ctx, Value *result, Value *value); void __qmljs_inplace_add(Context *ctx, Value *result, Value *value); void __qmljs_inplace_sub(Context *ctx, Value *result, Value *value); void __qmljs_inplace_mul(Context *ctx, Value *result, Value *value); void __qmljs_inplace_div(Context *ctx, Value *result, Value *value); void __qmljs_inplace_mod(Context *ctx, Value *result, Value *value); void __qmljs_inplace_shl(Context *ctx, Value *result, Value *value); void __qmljs_inplace_shr(Context *ctx, Value *result, Value *value); void __qmljs_inplace_ushr(Context *ctx, Value *result, Value *value); void __qmljs_inplace_bit_and_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_bit_or_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_bit_xor_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_add_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_sub_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_mul_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_div_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_mod_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_shl_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_shr_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_ushr_name(Context *ctx, String *name, Value *value); void __qmljs_inplace_bit_and_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_bit_or_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_bit_xor_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_add_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_sub_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_mul_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_div_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_mod_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_shl_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_shr_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_ushr_element(Context *ctx, Value *base, Value *index, Value *value); void __qmljs_inplace_bit_and_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_bit_or_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_bit_xor_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_add_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_sub_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_mul_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_div_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_mod_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_shl_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_shr_member(Context *ctx, Value *base, String *name, Value *value); void __qmljs_inplace_ushr_member(Context *ctx, Value *base, String *name, Value *value); Bool __qmljs_cmp_gt(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_lt(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_ge(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_le(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_eq(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_ne(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_se(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_sne(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_instanceof(Context *ctx, const Value left, const Value right); Bool __qmljs_cmp_in(Context *ctx, const Value left, const Value right); } // extern "C" struct ValueData { union { quint64 val; double dbl; struct { #if Q_BYTE_ORDER != Q_LITTLE_ENDIAN uint tag; #endif union { uint uint_32; int int_32; }; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN uint tag; #endif }; }; }; struct Value; template struct ValueBase; template <> struct ValueBase<4> : public ValueData { // we have all 4 bytes on 32 bit to specify the type enum Masks { NaN_Mask = 0xfff80000, Type_Mask = 0xffffffff }; enum ValueType { Undefined_Type = NaN_Mask | 0x7ffff, // all 1's Null_Type = NaN_Mask | 0x0, Boolean_Type = NaN_Mask | 0x1, Integer_Type = NaN_Mask | 0x2, Object_Type = NaN_Mask | 0x2d59b, // give it randomness to avoid accidental collisions (for gc) String_Type = NaN_Mask | 0x2d5ba, Double_Type = 0 }; inline bool is(ValueType type) const { if (type == Double_Type) return (tag & NaN_Mask) != NaN_Mask; return tag == type; } inline ValueType type() const { return (ValueType)tag; } 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; } double integerValue() const { return int_32; } String *stringValue() const { return (String *)(quintptr) uint_32; } Object *objectValue() const { return (Object *)(quintptr) uint_32; } quint64 rawValue() const { return val; } static inline Value undefinedValue(); static inline Value nullValue(); static inline Value fromBoolean(Bool b); static inline Value fromDouble(double d); static inline Value fromInt32(int i); static inline Value fromString(String *s); static inline Value fromObject(Object *o); }; template <> struct ValueBase<8> : public ValueData { enum Masks { NaN_Mask = 0x7ff80000, Type_Mask = 0x7fff0000, Tag_Shift = 32 }; enum ValueType { Undefined_Type = NaN_Mask | 0x70000, Null_Type = NaN_Mask | 0x00000, Boolean_Type = NaN_Mask | 0x10000, Integer_Type = NaN_Mask | 0x20000, Object_Type = NaN_Mask | 0x30000, String_Type = NaN_Mask | 0x40000, Double_Type = 0 }; inline bool is(ValueType type) const { if (type == Double_Type) return (tag & NaN_Mask) != NaN_Mask; return (tag & Type_Mask) == type; } inline bool isNot(ValueType type) { return !is(type); } inline ValueType type() const { return (ValueType)(tag & Type_Mask); } 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; } double integerValue() const { return int_32; } String *stringValue() const { return (String *)(val & ~(quint64(Type_Mask) << Tag_Shift)); } Object *objectValue() const { return (Object *)(val & ~(quint64(Type_Mask) << Tag_Shift)); } 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); }; struct Value : public ValueBase { #ifndef QMLJS_LLVM_RUNTIME static Value fromString(Context *ctx, const QString &fromString); using ValueBase::fromString; #endif static int toInteger(double fromNumber); static int toInt32(double value); static unsigned int toUInt32(double value); int toUInt16(Context *ctx); int toInt32(Context *ctx); unsigned int toUInt32(Context *ctx); Bool toBoolean(Context *ctx) const; double toInteger(Context *ctx) const; double toNumber(Context *ctx) const; String *toString(Context *ctx) const; Value toObject(Context *ctx) const; inline bool isUndefined() const { return is(Value::Undefined_Type); } inline bool isNull() const { return is(Value::Null_Type); } inline bool isString() const { return is(Value::String_Type); } inline bool isBoolean() const { return type() == Value::Boolean_Type; } inline bool isNumber() const { return is(Value::Integer_Type) || is(Value::Double_Type); } inline bool isDouble() const { return is(Value::Double_Type); } inline bool isInteger() const { return type() == Value::Integer_Type; } inline bool isObject() const { return type() == Value::Object_Type; } inline bool isPrimitive() const { return type() != Value::Object_Type; } bool isFunctionObject() const; bool isBooleanObject() const; bool isNumberObject() const; bool isStringObject() const; bool isDateObject() const; bool isArrayObject() const; bool isErrorObject() const; bool isArgumentsObject() const; Object *asObject() const; FunctionObject *asFunctionObject() const; BooleanObject *asBooleanObject() const; NumberObject *asNumberObject() const; StringObject *asStringObject() const; DateObject *asDateObject() const; ArrayObject *asArrayObject() const; ErrorObject *asErrorObject() const; ActivationObject *asArgumentsObject() const; Value property(Context *ctx, String *name) const; Value *getPropertyDescriptor(Context *ctx, String *name) const; }; inline Value ValueBase<4>::undefinedValue() { Value v; v.tag = Undefined_Type; v.uint_32 = 0; return v; } inline Value ValueBase<4>::nullValue() { Value v; v.tag = Null_Type; v.uint_32 = 0; return v; } inline Value ValueBase<4>::fromBoolean(Bool b) { Value v; v.tag = Boolean_Type; v.int_32 = (bool)b; return v; } inline Value ValueBase<4>::fromDouble(double d) { Value v; v.dbl = d; return v; } inline Value ValueBase<4>::fromInt32(int i) { Value v; v.tag = Integer_Type; v.int_32 = i; return v; } inline Value ValueBase<4>::fromString(String *s) { Value v; v.tag = String_Type; v.uint_32 = (quint32)(quintptr) s; return v; } inline Value ValueBase<4>::fromObject(Object *o) { Value v; v.tag = Object_Type; v.uint_32 = (quint32)(quintptr) o; return v; } inline Value ValueBase<8>::undefinedValue() { Value v; v.val = quint64(Undefined_Type) << Tag_Shift; return v; } inline Value ValueBase<8>::nullValue() { Value v; v.val = quint64(Null_Type) << Tag_Shift; return v; } inline Value ValueBase<8>::fromBoolean(Bool b) { Value v; v.tag = Boolean_Type; v.int_32 = (bool)b; return v; } inline Value ValueBase<8>::fromDouble(double d) { Value v; v.dbl = d; return v; } inline Value ValueBase<8>::fromInt32(int i) { Value v; v.tag = Integer_Type; v.int_32 = i; return v; } inline Value ValueBase<8>::fromString(String *s) { Value v; v.val = (quint64)s; v.val |= quint64(String_Type) << Tag_Shift; return v; } inline Value ValueBase<8>::fromObject(Object *o) { Value v; v.val = (quint64)o; v.val |= quint64(Object_Type) << Tag_Shift; return v; } template struct ValueOffsetHelper; template <> struct ValueOffsetHelper { enum { DataOffset = offsetof(ValueData, int_32) }; }; template <> struct ValueOffsetHelper { enum { DataOffset = offsetof(ValueData, uint_32) }; }; template <> struct ValueOffsetHelper { enum { DataOffset = offsetof(ValueData, uint_32) }; }; template <> struct ValueOffsetHelper { enum { DataOffset = offsetof(ValueData, uint_32) }; }; #include struct Context { ExecutionEngine *engine; Context *parent; Value activation; Value thisObject; Value *arguments; unsigned int argumentCount; Value *locals; Value result; String **formals; unsigned int formalCount; String **vars; unsigned int varCount; int calledAsConstructor; int hasUncaughtException; Value *lookupPropertyDescriptor(String *name); inline Value argument(unsigned int index = 0) { Value arg; getArgument(&arg, index); return arg; } inline void getArgument(Value *result, unsigned int index) { if (index < argumentCount) *result = arguments[index]; else *result = Value::undefinedValue(); } void init(ExecutionEngine *eng); void throwError(const Value &value); void throwTypeError(); void throwReferenceError(const Value &value); #ifndef QMLJS_LLVM_RUNTIME void throwError(const QString &message); void throwUnimplemented(const QString &message); #endif void initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, unsigned argc); void leaveCallContext(FunctionObject *f); void initConstructorContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, unsigned argc); void leaveConstructorContext(FunctionObject *f); }; extern "C" { // constructors inline Value __qmljs_init_string(String *value) { return Value::fromString(value); } inline Value __qmljs_init_object(Object *object) { return Value::fromObject(object); } // type conversion and testing inline Value __qmljs_to_primitive(Context *ctx, const Value value, int typeHint) { if (!value.isObject()) return value; return __qmljs_default_value(ctx, value, typeHint); } inline Bool __qmljs_to_boolean(const Value value, Context *ctx) { switch (value.type()) { case Value::Undefined_Type: case Value::Null_Type: return false; case Value::Boolean_Type: case Value::Integer_Type: return (bool)value.int_32; case Value::String_Type: return __qmljs_string_length(ctx, value.stringValue()) > 0; case Value::Object_Type: return true; default: // double if (! value.doubleValue() || qIsNaN(value.doubleValue())) return false; return true; } } inline double __qmljs_to_number(const Value value, Context *ctx) { switch (value.type()) { case Value::Undefined_Type: return nan(""); case Value::Null_Type: return 0; case Value::Boolean_Type: return (value.booleanValue() ? 1. : 0.); case Value::Integer_Type: return value.int_32; case Value::String_Type: return __qmljs_string_to_number(ctx, value.stringValue()); case Value::Object_Type: { Value prim = __qmljs_to_primitive(ctx, value, NUMBER_HINT); return __qmljs_to_number(prim, ctx); } default: // double return value.doubleValue(); } } inline double __qmljs_to_integer(const Value value, Context *ctx) { if (value.isInteger()) return value.int_32; const double number = __qmljs_to_number(value, ctx); if (qIsNaN(number)) return +0; else if (! number || isinf(number)) return number; const double v = floor(fabs(number)); return signbit(number) ? -v : v; } inline int __qmljs_to_int32(const Value value, Context *ctx) { if (value.isInteger()) return value.int_32; double number = __qmljs_to_number(value, ctx); if ((number >= -2147483648.0 && number < 2147483648.0)) { return static_cast(number); } if (! number || qIsNaN(number) || isinf(number)) return 0; double D32 = 4294967296.0; double sign = (number < 0) ? -1.0 : 1.0; double abs_n = fabs(number); number = ::fmod(sign * ::floor(abs_n), D32); const double D31 = D32 / 2.0; if (sign == -1 && number < -D31) number += D32; else if (sign != -1 && number >= D31) number -= D32; return int(number); } inline unsigned __qmljs_to_uint32(const Value value, Context *ctx) { if (value.isInteger()) return (unsigned) value.int_32; double number = __qmljs_to_number(value, ctx); if (! number || qIsNaN(number) || isinf(number)) return +0; double sign = (number < 0) ? -1.0 : 1.0; double abs_n = ::fabs(number); const double D32 = 4294967296.0; number = ::fmod(sign * ::floor(abs_n), D32); if (number < 0) number += D32; return unsigned(number); } inline unsigned short __qmljs_to_uint16(const Value value, Context *ctx) { double number = __qmljs_to_number(value, ctx); if (! number || qIsNaN(number) || isinf(number)) return +0; double sign = (number < 0) ? -1.0 : 1.0; double abs_n = ::fabs(number); double D16 = 65536.0; number = ::fmod(sign * ::floor(abs_n), D16); if (number < 0) number += D16; return (unsigned short)number; } inline Value __qmljs_to_string(Context *ctx, const Value value) { switch (value.type()) { case Value::Undefined_Type: return __qmljs_string_literal_undefined(ctx); break; case Value::Null_Type: return __qmljs_string_literal_null(ctx); break; case Value::Boolean_Type: if (value.booleanValue()) return __qmljs_string_literal_true(ctx); else return __qmljs_string_literal_false(ctx); break; case Value::String_Type: return value; break; case Value::Object_Type: { Value prim = __qmljs_to_primitive(ctx, value, STRING_HINT); if (prim.isPrimitive()) return __qmljs_to_string(ctx, prim); else return __qmljs_throw_type_error(ctx); break; } case Value::Integer_Type: return __qmljs_string_from_number(ctx, value.int_32); break; default: // double return __qmljs_string_from_number(ctx, value.doubleValue()); break; } // switch } inline Value __qmljs_to_object(Context *ctx, const Value value) { switch (value.type()) { case Value::Undefined_Type: case Value::Null_Type: return __qmljs_throw_type_error(ctx); break; case Value::Boolean_Type: return __qmljs_new_boolean_object(ctx, value.booleanValue()); break; case Value::String_Type: return __qmljs_new_string_object(ctx, value.stringValue()); break; case Value::Object_Type: return value; break; case Value::Integer_Type: return __qmljs_new_number_object(ctx, value.int_32); break; default: // double return __qmljs_new_number_object(ctx, value.doubleValue()); break; } } /* inline uint __qmljs_check_object_coercible(Context *ctx, Value *result, const Value *value) { switch (value->type()) { case Value::Undefined_Type: case Value::Null_Type: *result = __qmljs_throw_type_error(ctx); return false; default: return true; } } */ inline Bool __qmljs_is_callable(Context *ctx, const Value value) { if (value.isObject()) return __qmljs_is_function(value); else return false; } inline Value __qmljs_default_value(Context *ctx, const Value value, int typeHint) { if (value.isObject()) return __qmljs_object_default_value(ctx, value, typeHint); return Value::undefinedValue(); } // unary operators inline Value __qmljs_typeof(Context *ctx, const Value value) { switch (value.type()) { case Value::Undefined_Type: return __qmljs_string_literal_undefined(ctx); break; case Value::Null_Type: return __qmljs_string_literal_object(ctx); break; case Value::Boolean_Type: return __qmljs_string_literal_boolean(ctx); break; case Value::String_Type: return __qmljs_string_literal_string(ctx); break; case Value::Object_Type: if (__qmljs_is_callable(ctx, value)) return __qmljs_string_literal_function(ctx); else return __qmljs_string_literal_object(ctx); // ### implementation-defined break; default: return __qmljs_string_literal_number(ctx); break; } } inline Value __qmljs_uplus(const Value value, Context *ctx) { if (value.isInteger()) return value; double n = __qmljs_to_number(value, ctx); return Value::fromDouble(n); } inline Value __qmljs_uminus(const Value value, Context *ctx) { if (value.isInteger()) return Value::fromInt32(-value.integerValue()); double n = __qmljs_to_number(value, ctx); return Value::fromDouble(-n); } inline Value __qmljs_compl(const Value value, Context *ctx) { int n = __qmljs_to_int32(value, ctx); return Value::fromInt32(~n); } inline Value __qmljs_not(const Value value, Context *ctx) { bool b = __qmljs_to_boolean(value, ctx); return Value::fromBoolean(!b); } // binary operators inline Value __qmljs_bit_or(const Value left, const Value right, Context *ctx) { int lval = __qmljs_to_int32(left, ctx); int rval = __qmljs_to_int32(right, ctx); // ### changing this to fromInt32() breaks crypto.js return Value::fromDouble(lval | rval); } inline Value __qmljs_bit_xor(const Value left, const Value right, Context *ctx) { int lval = __qmljs_to_int32(left, ctx); int rval = __qmljs_to_int32(right, ctx); return Value::fromInt32(lval ^ rval); } inline Value __qmljs_bit_and(const Value left, const Value right, Context *ctx) { int lval = __qmljs_to_int32(left, ctx); int rval = __qmljs_to_int32(right, ctx); return Value::fromInt32(lval & rval); } inline void __qmljs_inplace_bit_and(Context *ctx, Value *result, Value *value) { *result = __qmljs_bit_and(*result, *value, ctx); } inline void __qmljs_inplace_bit_or(Context *ctx, Value *result, Value *value) { *result = __qmljs_bit_or(*result, *value, ctx); } inline void __qmljs_inplace_bit_xor(Context *ctx, Value *result, Value *value) { *result = __qmljs_bit_xor(*result, *value, ctx); } inline void __qmljs_inplace_add(Context *ctx, Value *result, Value *value) { *result = __qmljs_add(*result, *value, ctx); } inline void __qmljs_inplace_sub(Context *ctx, Value *result, Value *value) { *result = __qmljs_sub(*result, *value, ctx); } inline void __qmljs_inplace_mul(Context *ctx, Value *result, Value *value) { *result = __qmljs_mul(*result, *value, ctx); } inline void __qmljs_inplace_div(Context *ctx, Value *result, Value *value) { *result = __qmljs_div(*result, *value, ctx); } inline void __qmljs_inplace_mod(Context *ctx, Value *result, Value *value) { *result = __qmljs_mod(*result, *value, ctx); } inline void __qmljs_inplace_shl(Context *ctx, Value *result, Value *value) { *result = __qmljs_shl(*result, *value, ctx); } inline void __qmljs_inplace_shr(Context *ctx, Value *result, Value *value) { *result = __qmljs_shr(*result, *value, ctx); } inline void __qmljs_inplace_ushr(Context *ctx, Value *result, Value *value) { *result = __qmljs_ushr(*result, *value, ctx); } inline Value __qmljs_add(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return add_int32(left.integerValue(), right.integerValue()); if (left.isNumber() && right.isNumber()) return Value::fromDouble(left.asDouble() + right.asDouble()); else return __qmljs_add_helper(left, right, ctx); } inline Value __qmljs_sub(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return sub_int32(left.integerValue(), right.integerValue()); double lval = __qmljs_to_number(left, ctx); double rval = __qmljs_to_number(right, ctx); return Value::fromDouble(lval - rval); } inline Value __qmljs_mul(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return mul_int32(left.integerValue(), right.integerValue()); double lval = __qmljs_to_number(left, ctx); double rval = __qmljs_to_number(right, ctx); return Value::fromDouble(lval * rval); } inline Value __qmljs_div(const Value left, const Value right, Context *ctx) { double lval = __qmljs_to_number(left, ctx); double rval = __qmljs_to_number(right, ctx); return Value::fromDouble(lval / rval); } inline Value __qmljs_mod(const Value left, const Value right, Context *ctx) { double lval = __qmljs_to_number(left, ctx); double rval = __qmljs_to_number(right, ctx); return Value::fromDouble(fmod(lval, rval)); } // ### unsigned shl missing? inline Value __qmljs_shl(const Value left, const Value right, Context *ctx) { int lval = __qmljs_to_int32(left, ctx); unsigned rval = __qmljs_to_uint32(right, ctx); return Value::fromInt32(lval << rval); } inline Value __qmljs_shr(const Value left, const Value right, Context *ctx) { int lval = __qmljs_to_int32(left, ctx); unsigned rval = __qmljs_to_uint32(right, ctx); return Value::fromInt32(lval >> rval); } inline Value __qmljs_ushr(const Value left, const Value right, Context *ctx) { unsigned lval = __qmljs_to_uint32(left, ctx); unsigned rval = __qmljs_to_uint32(right, ctx); return Value::fromInt32(lval >> rval); } inline Value __qmljs_gt(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return Value::fromBoolean(left.integerValue() > right.integerValue()); if (left.isNumber() && right.isNumber()) { return Value::fromBoolean(left.asDouble() > right.asDouble()); } else { Value result = __qmljs_compare(ctx, left, right, false); if (result.isUndefined()) result = Value::fromBoolean(false); return result; } } inline Value __qmljs_lt(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return Value::fromBoolean(left.integerValue() < right.integerValue()); if (left.isNumber() && right.isNumber()) { return Value::fromBoolean(left.asDouble() < right.asDouble()); } else { Value result = __qmljs_compare(ctx, left, right, true); if (result.isUndefined()) result = Value::fromBoolean(false); return result; } } inline Value __qmljs_ge(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return Value::fromBoolean(left.integerValue() >= right.integerValue()); if (left.isNumber() && right.isNumber()) { return Value::fromBoolean(left.asDouble() >= right.asDouble()); } else { Value result = __qmljs_compare(ctx, right, left, false); bool r = ! (result.isUndefined() || (result.isBoolean() && result.booleanValue())); return Value::fromBoolean(r); } } inline Value __qmljs_le(const Value left, const Value right, Context *ctx) { if (left.isInteger() && right.isInteger()) return Value::fromBoolean(left.integerValue() <= right.integerValue()); if (left.isNumber() && right.isNumber()) { return Value::fromBoolean(left.asDouble() <= right.asDouble()); } else { Value result = __qmljs_compare(ctx, right, left, true); bool r = ! (result.isUndefined() || (result.isBoolean() && result.booleanValue())); return Value::fromBoolean(r); } } inline Value __qmljs_eq(const Value left, const Value right, Context *ctx) { if (left.val == right.val) return Value::fromBoolean(true); if (left.isNumber() && right.isNumber()) { return Value::fromBoolean(left.asDouble() == right.asDouble()); } else if (left.isString() && right.isString()) { return Value::fromBoolean(__qmljs_string_equal(ctx, left.stringValue(), right.stringValue())); } else { bool r = __qmljs_equal(ctx, left, right); return Value::fromBoolean(r); } } inline Value __qmljs_ne(const Value left, const Value right, Context *ctx) { Value result = __qmljs_eq(left, right, ctx); result.int_32 = !(bool)result.int_32; return result; } inline Value __qmljs_se(const Value left, const Value right, Context *ctx) { bool r = __qmljs_strict_equal(ctx, left, right); return Value::fromBoolean(r); } inline Value __qmljs_sne(const Value left, const Value right, Context *ctx) { bool r = ! __qmljs_strict_equal(ctx, left, right); return Value::fromBoolean(r); } inline Bool __qmljs_cmp_gt(Context *ctx, const Value left, const Value right) { Value v = __qmljs_gt(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_cmp_lt(Context *ctx, const Value left, const Value right) { Value v = __qmljs_lt(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_cmp_ge(Context *ctx, const Value left, const Value right) { Value v = __qmljs_ge(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_cmp_le(Context *ctx, const Value left, const Value right) { Value v = __qmljs_le(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_cmp_eq(Context *ctx, const Value left, const Value right) { Value v = __qmljs_eq(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_cmp_ne(Context *ctx, const Value left, const Value right) { Value v = __qmljs_ne(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_cmp_se(Context *ctx, const Value left, const Value right) { return __qmljs_strict_equal(ctx, left, right); } inline Bool __qmljs_cmp_sne(Context *ctx, const Value left, const Value right) { return ! __qmljs_strict_equal(ctx, left, right); } inline Bool __qmljs_cmp_instanceof(Context *ctx, const Value left, const Value right) { Value v = __qmljs_instanceof(left, right, ctx); return v.booleanValue(); } inline uint __qmljs_cmp_in(Context *ctx, const Value left, const Value right) { Value v = __qmljs_in(left, right, ctx); return v.booleanValue(); } inline Bool __qmljs_strict_equal(Context *ctx, const Value x, const Value y) { if (x.rawValue() == y.rawValue()) return true; if (x.isString() && y.isString()) return __qmljs_string_equal(ctx, x.stringValue(), y.stringValue()); return false; } } // extern "C" } // namespace VM } // namespace QQmlJS #endif // QMLJS_RUNTIME_H