qtdeclarative/qmljs_runtime.h

870 lines
30 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
#include <qmljs_value.h>
#include <QtCore/QString>
#include <QtCore/qnumeric.h>
#include <QtCore/QDebug>
#include <cmath>
#include <cassert>
#ifdef DO_TRACE_INSTR
# define TRACE1(x) fprintf(stderr, " %s\n", __FUNCTION__);
# define TRACE2(x, y) fprintf(stderr, " %s\n", __FUNCTION__);
#else
# define TRACE1(x)
# define TRACE2(x, y)
#endif // TRACE1
namespace QQmlJS {
namespace IR {
struct Function;
}
namespace VM {
enum TypeHint {
PREFERREDTYPE_HINT,
NUMBER_HINT,
STRING_HINT
};
struct Object;
struct String;
struct PropertyDescriptor;
struct ExecutionContext;
struct FunctionObject;
struct BooleanObject;
struct NumberObject;
struct StringObject;
struct DateObject;
struct RegExpObject;
struct ArrayObject;
struct ErrorObject;
struct ActivationObject;
struct ExecutionEngine;
extern "C" {
// context
Value __qmljs_call_activation_property(ExecutionContext *, String *name, Value *args, int argc);
Value __qmljs_call_property(ExecutionContext *context, Value base, String *name, Value *args, int argc);
Value __qmljs_call_value(ExecutionContext *context, Value thisObject, Value func, Value *args, int argc);
Value __qmljs_construct_activation_property(ExecutionContext *, String *name, Value *args, int argc);
Value __qmljs_construct_property(ExecutionContext *context, Value base, String *name, Value *args, int argc);
Value __qmljs_construct_value(ExecutionContext *context, Value func, Value *args, int argc);
Value __qmljs_builtin_typeof(Value val, ExecutionContext *context);
void __qmljs_builtin_throw(Value val, ExecutionContext *context);
// constructors
Value __qmljs_init_closure(IR::Function *clos, ExecutionContext *ctx);
Value __qmljs_init_native_function(void (*code)(ExecutionContext *), ExecutionContext *ctx);
Bool __qmljs_is_function(Value value);
// string literals
Value __qmljs_string_literal_undefined(ExecutionContext *ctx);
Value __qmljs_string_literal_null(ExecutionContext *ctx);
Value __qmljs_string_literal_true(ExecutionContext *ctx);
Value __qmljs_string_literal_false(ExecutionContext *ctx);
Value __qmljs_string_literal_object(ExecutionContext *ctx);
Value __qmljs_string_literal_boolean(ExecutionContext *ctx);
Value __qmljs_string_literal_number(ExecutionContext *ctx);
Value __qmljs_string_literal_string(ExecutionContext *ctx);
Value __qmljs_string_literal_function(ExecutionContext *ctx);
// strings
String *__qmljs_string_from_utf8(ExecutionContext *ctx, const char *s);
int __qmljs_string_length(ExecutionContext *ctx, String *string);
double __qmljs_string_to_number(ExecutionContext *ctx, String *string);
Value __qmljs_string_from_number(ExecutionContext *ctx, double number);
Bool __qmljs_string_compare(ExecutionContext *ctx, String *left, String *right);
Bool __qmljs_string_equal(String *left, String *right);
String *__qmljs_string_concat(ExecutionContext *ctx, String *first, String *second);
String *__qmljs_identifier_from_utf8(ExecutionContext *ctx, const char *s);
// objects
Value __qmljs_object_default_value(ExecutionContext *ctx, Value object, int typeHint);
Value __qmljs_throw_type_error(ExecutionContext *ctx);
Value __qmljs_new_object(ExecutionContext *ctx);
Value __qmljs_new_boolean_object(ExecutionContext *ctx, bool boolean);
Value __qmljs_new_number_object(ExecutionContext *ctx, double n);
Value __qmljs_new_string_object(ExecutionContext *ctx, String *string);
void __qmljs_set_activation_property(ExecutionContext *ctx, String *name, Value value);
void __qmljs_set_property(ExecutionContext *ctx, Value object, String *name, Value value);
Value __qmljs_get_property(ExecutionContext *ctx, Value object, String *name);
Value __qmljs_get_activation_property(ExecutionContext *ctx, String *name);
Value __qmljs_get_element(ExecutionContext *ctx, Value object, Value index);
void __qmljs_set_element(ExecutionContext *ctx, Value object, Value index, Value value);
// For each
Value __qmljs_foreach_iterator_object(Value in, ExecutionContext *ctx);
Value __qmljs_foreach_next_property_name(Value foreach_iterator);
// context
Value __qmljs_get_thisObject(ExecutionContext *ctx);
// type conversion and testing
Value __qmljs_to_primitive(Value value, ExecutionContext *ctx, int typeHint);
Bool __qmljs_to_boolean(Value value, ExecutionContext *ctx);
double __qmljs_to_number(Value value, ExecutionContext *ctx);
double __qmljs_to_integer(Value value, ExecutionContext *ctx);
int __qmljs_to_int32(Value value, ExecutionContext *ctx);
unsigned short __qmljs_to_uint16(Value value, ExecutionContext *ctx);
Value __qmljs_to_string(Value value, ExecutionContext *ctx);
Value __qmljs_to_object(Value value, ExecutionContext *ctx);
//uint __qmljs_check_object_coercible(Context *ctx, Value *result, Value *value);
Bool __qmljs_is_callable(Value value, ExecutionContext *ctx);
Value __qmljs_default_value(Value value, ExecutionContext *ctx, int typeHint);
Bool __qmljs_equal(Value x, Value y, ExecutionContext *ctx);
Bool __qmljs_strict_equal(Value x, Value y);
// unary operators
Value __qmljs_uplus(Value value, ExecutionContext *ctx);
Value __qmljs_uminus(Value value, ExecutionContext *ctx);
Value __qmljs_compl(Value value, ExecutionContext *ctx);
Value __qmljs_not(Value value, ExecutionContext *ctx);
Value __qmljs_delete_subscript(ExecutionContext *ctx, Value base, Value index);
Value __qmljs_delete_member(ExecutionContext *ctx, Value base, String *name);
Value __qmljs_delete_property(ExecutionContext *ctx, String *name);
Value __qmljs_delete_value(ExecutionContext *ctx, Value value);
Value __qmljs_typeof(Value value, ExecutionContext *ctx);
void __qmljs_throw(Value value, ExecutionContext *context);
// actually returns a jmp_buf *
void *__qmljs_create_exception_handler(ExecutionContext *context);
void __qmljs_delete_exception_handler(ExecutionContext *context);
Value __qmljs_get_exception(ExecutionContext *context);
// binary operators
typedef Value (*BinOp)(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_instanceof(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_in(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_bit_or(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_bit_xor(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_bit_and(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_add(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_sub(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_mul(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_div(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_mod(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_shl(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_shr(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_ushr(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_gt(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_lt(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_ge(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_le(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_eq(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_ne(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_se(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_sne(Value left, Value right, ExecutionContext *ctx);
Value __qmljs_add_helper(Value left, Value right, ExecutionContext *ctx);
void __qmljs_inplace_bit_and_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_bit_or_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_bit_xor_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_add_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_sub_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_mul_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_div_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_mod_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_shl_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_shr_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_ushr_name(Value value, String *name, ExecutionContext *ctx);
void __qmljs_inplace_bit_and_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_bit_or_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_bit_xor_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_add_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_sub_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_mul_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_div_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_mod_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_shl_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_shr_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_ushr_element(Value base, Value index, Value value, ExecutionContext *ctx);
void __qmljs_inplace_bit_and_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_bit_or_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_bit_xor_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_add_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_sub_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_mul_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_div_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_mod_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_shl_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_shr_member(Value value, Value base, String *name, ExecutionContext *ctx);
void __qmljs_inplace_ushr_member(Value value, Value base, String *name, ExecutionContext *ctx);
Bool __qmljs_cmp_gt(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_lt(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_ge(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_le(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_eq(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_ne(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_se(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_sne(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_instanceof(Value left, Value right, ExecutionContext *ctx);
Bool __qmljs_cmp_in(Value left, Value right, ExecutionContext *ctx);
} // extern "C"
#include <qmljs_math.h>
extern "C" {
// type conversion and testing
inline Value __qmljs_to_primitive(Value value, ExecutionContext *ctx, int typeHint)
{
if (!value.isObject())
return value;
return __qmljs_default_value(value, ctx, typeHint);
}
inline Bool __qmljs_to_boolean(Value value, ExecutionContext *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() || std::isnan(value.doubleValue()))
return false;
return true;
}
}
inline double __qmljs_to_number(Value value, ExecutionContext *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(value, ctx, NUMBER_HINT);
return __qmljs_to_number(prim, ctx);
}
default: // double
return value.doubleValue();
}
}
inline double __qmljs_to_integer(Value value, ExecutionContext *ctx)
{
if (value.isConvertibleToInt())
return value.int_32;
return Value::toInteger(__qmljs_to_number(value, ctx));
}
inline int __qmljs_to_int32(Value value, ExecutionContext *ctx)
{
if (value.isConvertibleToInt())
return value.int_32;
return Value::toInt32(__qmljs_to_number(value, ctx));
}
inline unsigned short __qmljs_to_uint16(Value value, ExecutionContext *ctx)
{
if (value.isConvertibleToInt())
return (ushort)(uint)value.integerValue();
double number = __qmljs_to_number(value, ctx);
double D16 = 65536.0;
if ((number >= 0 && number < D16))
return static_cast<ushort>(number);
if (!std::isfinite(number))
return +0;
double d = ::floor(::fabs(number));
if (std::signbit(number))
d = -d;
number = ::fmod(d , D16);
if (number < 0)
number += D16;
return (unsigned short)number;
}
inline Value __qmljs_to_string(Value value, ExecutionContext *ctx)
{
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(value, ctx, STRING_HINT);
if (prim.isPrimitive())
return __qmljs_to_string(prim, ctx);
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(Value value, ExecutionContext *ctx)
{
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, 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(Value value, ExecutionContext * /*ctx*/)
{
if (value.isObject())
return __qmljs_is_function(value);
else
return false;
}
inline Value __qmljs_default_value(Value value, ExecutionContext *ctx, int typeHint)
{
if (value.isObject())
return __qmljs_object_default_value(ctx, value, typeHint);
return Value::undefinedValue();
}
// unary operators
inline Value __qmljs_typeof(Value value, ExecutionContext *ctx)
{
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(value, ctx))
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(Value value, ExecutionContext *ctx)
{
TRACE1(value);
if (value.tryIntegerConversion())
return value;
double n = __qmljs_to_number(value, ctx);
return Value::fromDouble(n);
}
inline Value __qmljs_uminus(Value value, ExecutionContext *ctx)
{
TRACE1(value);
if (value.isInteger())
return Value::fromInt32(-value.integerValue());
double n = __qmljs_to_number(value, ctx);
return Value::fromDouble(-n);
}
inline Value __qmljs_compl(Value value, ExecutionContext *ctx)
{
TRACE1(value);
int n;
if (value.isConvertibleToInt())
n = ~value.int_32;
else
n = Value::toInteger(__qmljs_to_number(value, ctx));
return Value::fromInt32(~n);
}
inline Value __qmljs_not(Value value, ExecutionContext *ctx)
{
TRACE1(value);
bool b = __qmljs_to_boolean(value, ctx);
return Value::fromBoolean(!b);
}
// binary operators
inline Value __qmljs_bit_or(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(left.integerValue() | right.integerValue());
int lval = Value::toInt32(__qmljs_to_number(left, ctx));
int rval = Value::toInt32(__qmljs_to_number(right, ctx));
return Value::fromInt32(lval | rval);
}
inline Value __qmljs_bit_xor(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(left.integerValue() ^ right.integerValue());
int lval = Value::toInt32(__qmljs_to_number(left, ctx));
int rval = Value::toInt32(__qmljs_to_number(right, ctx));
return Value::fromInt32(lval ^ rval);
}
inline Value __qmljs_bit_and(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(left.integerValue() & right.integerValue());
int lval = Value::toInt32(__qmljs_to_number(left, ctx));
int rval = Value::toInt32(__qmljs_to_number(right, ctx));
return Value::fromInt32(lval & rval);
}
inline Value __qmljs_add(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
#ifndef QMLJS_LLVM_RUNTIME
if (Value::integerCompatible(left, right))
return add_int32(left.integerValue(), right.integerValue());
#endif // QMLJS_LLVM_RUNTIME
if (Value::bothDouble(left, right))
return Value::fromDouble(left.doubleValue() + right.doubleValue());
return __qmljs_add_helper(left, right, ctx);
}
inline Value __qmljs_sub(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
#ifndef QMLJS_LLVM_RUNTIME
if (Value::integerCompatible(left, right))
return sub_int32(left.integerValue(), right.integerValue());
#endif // QMLJS_LLVM_RUNTIME
double lval = __qmljs_to_number(left, ctx);
double rval = __qmljs_to_number(right, ctx);
return Value::fromDouble(lval - rval);
}
inline Value __qmljs_mul(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
#ifndef QMLJS_LLVM_RUNTIME
if (Value::integerCompatible(left, right))
return mul_int32(left.integerValue(), right.integerValue());
#endif // QMLJS_LLVM_RUNTIME
double lval = __qmljs_to_number(left, ctx);
double rval = __qmljs_to_number(right, ctx);
return Value::fromDouble(lval * rval);
}
inline Value __qmljs_div(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
double lval = __qmljs_to_number(left, ctx);
double rval = __qmljs_to_number(right, ctx);
return Value::fromDouble(lval / rval);
}
inline Value __qmljs_mod(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(left.integerValue() % right.integerValue());
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(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(left.integerValue() << ((uint(right.integerValue()) & 0x1f)));
int lval = Value::toInt32(__qmljs_to_number(left, ctx));
unsigned rval = Value::toUInt32(__qmljs_to_number(right, ctx)) & 0x1f;
return Value::fromInt32(lval << rval);
}
inline Value __qmljs_shr(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(left.integerValue() >> ((uint(right.integerValue()) & 0x1f)));
int lval = Value::toInt32(__qmljs_to_number(left, ctx));
unsigned rval = Value::toUInt32(__qmljs_to_number(right, ctx)) & 0x1f;
return Value::fromInt32(lval >> rval);
}
inline Value __qmljs_ushr(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right))
return Value::fromInt32(uint(left.integerValue()) >> ((uint(right.integerValue()) & 0x1f)));
unsigned lval = Value::toUInt32(__qmljs_to_number(left, ctx));
unsigned rval = Value::toUInt32(__qmljs_to_number(right, ctx)) & 0x1f;
return Value::fromInt32(lval >> rval);
}
inline Value __qmljs_gt(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return Value::fromBoolean(__qmljs_cmp_gt(left, right, ctx));
}
inline Value __qmljs_lt(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return Value::fromBoolean(__qmljs_cmp_lt(left, right, ctx));
}
inline Value __qmljs_ge(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return Value::fromBoolean(__qmljs_cmp_ge(left, right, ctx));
}
inline Value __qmljs_le(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return Value::fromBoolean(__qmljs_cmp_le(left, right, ctx));
}
inline Value __qmljs_eq(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return Value::fromBoolean(__qmljs_cmp_eq(left, right, ctx));
}
inline Value __qmljs_ne(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return Value::fromBoolean(!__qmljs_cmp_eq(left, right, ctx));
}
inline Value __qmljs_se(Value left, Value right, ExecutionContext *)
{
TRACE2(left, right);
bool r = __qmljs_strict_equal(left, right);
return Value::fromBoolean(r);
}
inline Value __qmljs_sne(Value left, Value right, ExecutionContext *)
{
TRACE2(left, right);
bool r = ! __qmljs_strict_equal(left, right);
return Value::fromBoolean(r);
}
inline Bool __qmljs_cmp_gt(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
left = __qmljs_to_primitive(left, ctx, NUMBER_HINT);
right = __qmljs_to_primitive(right, ctx, NUMBER_HINT);
if (Value::integerCompatible(left, right))
return left.integerValue() > right.integerValue();
if (Value::bothDouble(left, right)) {
return left.doubleValue() > right.doubleValue();
} else if (left.isString() && right.isString()) {
return __qmljs_string_compare(ctx, right.stringValue(), left.stringValue());
} else {
double l = __qmljs_to_number(left, ctx);
double r = __qmljs_to_number(right, ctx);
return l > r;
}
}
inline Bool __qmljs_cmp_lt(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
left = __qmljs_to_primitive(left, ctx, NUMBER_HINT);
right = __qmljs_to_primitive(right, ctx, NUMBER_HINT);
if (Value::integerCompatible(left, right))
return left.integerValue() < right.integerValue();
if (Value::bothDouble(left, right)) {
return left.doubleValue() < right.doubleValue();
} else if (left.isString() && right.isString()) {
return __qmljs_string_compare(ctx, left.stringValue(), right.stringValue());
} else {
double l = __qmljs_to_number(left, ctx);
double r = __qmljs_to_number(right, ctx);
return l < r;
}
}
inline Bool __qmljs_cmp_ge(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
left = __qmljs_to_primitive(left, ctx, NUMBER_HINT);
right = __qmljs_to_primitive(right, ctx, NUMBER_HINT);
if (Value::integerCompatible(left, right))
return left.integerValue() >= right.integerValue();
if (Value::bothDouble(left, right)) {
return left.doubleValue() >= right.doubleValue();
} else if (left.isString() && right.isString()) {
return !__qmljs_string_compare(ctx, left.stringValue(), right.stringValue());
} else {
double l = __qmljs_to_number(left, ctx);
double r = __qmljs_to_number(right, ctx);
return l >= r;
}
}
inline Bool __qmljs_cmp_le(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
left = __qmljs_to_primitive(left, ctx, NUMBER_HINT);
right = __qmljs_to_primitive(right, ctx, NUMBER_HINT);
if (Value::integerCompatible(left, right))
return left.integerValue() <= right.integerValue();
if (Value::bothDouble(left, right)) {
return left.doubleValue() <= right.doubleValue();
} else if (left.isString() && right.isString()) {
return !__qmljs_string_compare(ctx, right.stringValue(), left.stringValue());
} else {
double l = __qmljs_to_number(left, ctx);
double r = __qmljs_to_number(right, ctx);
return l <= r;
}
}
inline Bool __qmljs_cmp_eq(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
// need to test for doubles first as NaN != NaN
if (Value::bothDouble(left, right))
return left.doubleValue() == right.doubleValue();
if (left.val == right.val)
return true;
if (left.isString() && right.isString())
return __qmljs_string_equal(left.stringValue(), right.stringValue());
return __qmljs_equal(left, right, ctx);
}
inline Bool __qmljs_cmp_ne(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
return !__qmljs_cmp_eq(left, right, ctx);
}
inline Bool __qmljs_cmp_se(Value left, Value right, ExecutionContext *)
{
TRACE2(left, right);
return __qmljs_strict_equal(left, right);
}
inline Bool __qmljs_cmp_sne(Value left, Value right, ExecutionContext *)
{
TRACE2(left, right);
return ! __qmljs_strict_equal(left, right);
}
inline Bool __qmljs_cmp_instanceof(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
Value v = __qmljs_instanceof(left, right, ctx);
return v.booleanValue();
}
inline uint __qmljs_cmp_in(Value left, Value right, ExecutionContext *ctx)
{
TRACE2(left, right);
Value v = __qmljs_in(left, right, ctx);
return v.booleanValue();
}
inline Bool __qmljs_strict_equal(Value x, Value y)
{
TRACE2(x, y);
if (x.isDouble() || y.isDouble())
return x.asDouble() == y.asDouble();
if (x.rawValue() == y.rawValue())
return true;
if (x.isString() && y.isString())
return __qmljs_string_equal(x.stringValue(), y.stringValue());
return false;
}
} // extern "C"
} // namespace VM
} // namespace QQmlJS
#endif // QMLJS_RUNTIME_H