1267 lines
39 KiB
C++
1267 lines
39 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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 <QtCore/QString>
|
|
# include <QtCore/qnumeric.h>
|
|
# include <QtCore/QDebug>
|
|
#endif
|
|
|
|
#include <math.h>
|
|
#include <cassert>
|
|
|
|
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 <int> 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<sizeof(void *)>
|
|
{
|
|
|
|
#ifndef QMLJS_LLVM_RUNTIME
|
|
static Value fromString(Context *ctx, const QString &fromString);
|
|
using ValueBase<sizeof(void *)>::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 <Value::ValueType> struct ValueOffsetHelper;
|
|
template <> struct ValueOffsetHelper<Value::Boolean_Type>
|
|
{
|
|
enum { DataOffset = offsetof(ValueData, int_32) };
|
|
};
|
|
|
|
template <> struct ValueOffsetHelper<Value::Undefined_Type>
|
|
{
|
|
enum { DataOffset = offsetof(ValueData, uint_32) };
|
|
};
|
|
|
|
template <> struct ValueOffsetHelper<Value::Null_Type>
|
|
{
|
|
enum { DataOffset = offsetof(ValueData, uint_32) };
|
|
};
|
|
|
|
template <> struct ValueOffsetHelper<Value::Integer_Type>
|
|
{
|
|
enum { DataOffset = offsetof(ValueData, uint_32) };
|
|
};
|
|
|
|
#include <qmljs_math.h>
|
|
|
|
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<int>(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
|