aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-03-01 11:54:30 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-03-01 11:54:35 +0100
commit87aebe39ae80c0752695b21b5b7508d220035b85 (patch)
treea60bd61dd81b5e79532762ae014cb7612d619da2 /src/qml/jsruntime
parenta48244d5aa1d14c286b7cd39afebcfff9c9dcb60 (diff)
parentafec9016d0fd51345ea93a1bbadb99b5c3fdf629 (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/jsruntime.pri4
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp19
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp51
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp37
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h2
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h3
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp1
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp56
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4object.cpp117
-rw-r--r--src/qml/jsruntime/qv4object_p.h72
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp120
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h1
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp27
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp35
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp42
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp20
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp7
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h2
-rw-r--r--src/qml/jsruntime/qv4value_p.h47
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
33 files changed, 505 insertions, 203 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 919524d1ed..955cf585e4 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -35,7 +35,6 @@ SOURCES += \
$$PWD/qv4regexp.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
- $$PWD/qv4executableallocator.cpp \
$$PWD/qv4sequenceobject.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
@@ -113,7 +112,8 @@ HEADERS += \
SOURCES += \
$$PWD/qv4runtime.cpp \
$$PWD/qv4string.cpp \
- $$PWD/qv4value.cpp
+ $$PWD/qv4value.cpp \
+ $$PWD/qv4executableallocator.cpp
valgrind {
DEFINES += V4_USE_VALGRIND
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 5a190d6690..7c1cc92a13 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -88,10 +88,12 @@ void ArgumentsObject::fullyCreate()
Scope scope(engine());
Scoped<MemberData> md(scope, d()->mappedArguments);
- d()->mappedArguments = md->allocate(engine(), numAccessors);
- for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
- arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ if (numAccessors) {
+ d()->mappedArguments = md->allocate(engine(), numAccessors);
+ for (uint i = 0; i < numAccessors; ++i) {
+ d()->mappedArguments->data[i] = context()->callData->args[i];
+ arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ }
}
arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
for (uint i = numAccessors; i < argCount; ++i)
@@ -164,18 +166,17 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha
return Encode::undefined();
}
-void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
+bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
args->fullyCreate();
- if (args->fullyCreated()) {
- Object::putIndexed(m, index, value);
- return;
- }
+ if (args->fullyCreated())
+ return Object::putIndexed(m, index, value);
args->context()->callData->args[index] = value;
+ return true;
}
bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 0a2ea3b42a..f80ade9611 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -128,7 +128,7 @@ struct ArgumentsObject: Object {
bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 60b90e4bf0..740ebbe359 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -155,7 +155,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
ctx = ctx->d()->outer;
}
- if (activation->hasProperty(name))
+ if (activation->hasOwnProperty(name))
return;
ScopedProperty desc(scope);
PropertyAttributes attrs(Attr_Data);
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index b90c335b1c..c56d007028 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -340,7 +340,9 @@ static inline double TimeClip(double t)
{
if (! qt_is_finite(t) || fabs(t) > 8.64e15)
return qt_qnan();
- return Primitive::toInteger(t);
+
+ // +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0.
+ return Primitive::toInteger(t) + 0;
}
static inline double ParseString(const QString &s)
@@ -724,7 +726,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(7));
LocalTZA = getLocalTZA();
ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1);
@@ -774,8 +776,21 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setYear"), method_setYear, 1);
defineDefaultProperty(QStringLiteral("setFullYear"), method_setFullYear, 3);
defineDefaultProperty(QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3);
- defineDefaultProperty(QStringLiteral("toUTCString"), method_toUTCString, 0);
- defineDefaultProperty(QStringLiteral("toGMTString"), method_toUTCString, 0);
+
+ // ES6: B.2.4.3 & 20.3.4.43:
+ // We have to use the *same object* for toUTCString and toGMTString
+ {
+ QString toUtcString(QStringLiteral("toUTCString"));
+ QString toGmtString(QStringLiteral("toGMTString"));
+ ScopedString us(scope, engine->newIdentifier(toUtcString));
+ ScopedString gs(scope, engine->newIdentifier(toGmtString));
+ ExecutionContext *global = engine->rootContext();
+ ScopedFunctionObject toUtcGmtStringFn(scope, BuiltinFunction::create(global, us, method_toUTCString));
+ toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineDefaultProperty(us, toUtcGmtStringFn);
+ defineDefaultProperty(gs, toUtcGmtStringFn);
+ }
+
defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0);
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
@@ -1025,6 +1040,7 @@ void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(t));
scope.result = Encode(self->date());
}
@@ -1036,7 +1052,9 @@ void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
scope.result = Encode(self->date());
}
@@ -1048,7 +1066,9 @@ void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &sc
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
scope.result = Encode(self->date());
}
@@ -1060,8 +1080,11 @@ void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1088,9 +1111,13 @@ void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1118,10 +1145,15 @@ void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1150,7 +1182,9 @@ void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1163,7 +1197,9 @@ void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1176,8 +1212,11 @@ void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1245,11 +1284,15 @@ void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, Ca
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
if (std::isnan(t))
t = 0;
double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index a56d17f9b1..b32b2c3f66 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -112,7 +112,7 @@ struct DateCtor: FunctionObject
static void call(const Managed *that, Scope &scope, CallData *);
};
-struct DatePrototype: DateObject
+struct DatePrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a11f7f0875..39b433e5f9 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -91,7 +91,9 @@
#if USE(PTHREADS)
# include <pthread.h>
+#if !defined(Q_OS_INTEGRITY)
# include <sys/resource.h>
+#endif
#if HAVE(PTHREAD_NP_H)
# include <pthread_np.h>
#endif
@@ -168,7 +170,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
if (forceMoth) {
factory = new Moth::ISelFactory;
} else {
- factory = new JIT::ISelFactory;
+ factory = new JIT::ISelFactory<>;
jitDisabled = false;
}
#else // !V4_ENABLE_JIT
@@ -256,6 +258,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, objectPrototype());
+ jsObjects[PropertyListProto] = memoryManager->allocObject<PropertyListPrototype>();
InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable);
argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
@@ -358,6 +361,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
+ static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
@@ -400,7 +404,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
- globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor());
+ FunctionObject *numberObject = numberCtor();
+ globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
@@ -430,8 +435,26 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
- globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
- globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
+ // ES6: 20.1.2.12 & 20.1.2.13:
+ // parseInt and parseFloat must be the same FunctionObject on the global &
+ // Number object.
+ {
+ QString piString(QStringLiteral("parseInt"));
+ QString pfString(QStringLiteral("parseFloat"));
+ Scope scope(this);
+ ScopedString pi(scope, newIdentifier(piString));
+ ScopedString pf(scope, newIdentifier(pfString));
+ ExecutionContext *global = rootContext();
+ ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt));
+ ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat));
+ parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2));
+ parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1));
+ globalObject->defineDefaultProperty(piString, parseIntFn);
+ globalObject->defineDefaultProperty(pfString, parseFloatFn);
+ numberObject->defineDefaultProperty(piString, parseIntFn);
+ numberObject->defineDefaultProperty(pfString, parseFloatFn);
+ }
+
globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
@@ -1109,7 +1132,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (typeHint == qMetaTypeId<QJSValue>())
return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
- if (value.as<Object>()) {
+ if (value.as<QV4::Object>()) {
QV4::ScopedObject object(scope, value);
if (typeHint == QMetaType::QJsonObject
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
@@ -1755,7 +1778,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
return false;
}
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value, const QByteArray &targetType, void **result)
+static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
return false;
@@ -1770,7 +1793,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value,
return false;
}
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const Value &value)
+static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (!value.isObject())
return 0;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 1c20ad30aa..69aa389c44 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -157,6 +157,7 @@ public:
IntegerNull, // Has to come after the RootContext to make the context stack safe
ObjectProto,
ArrayProto,
+ PropertyListProto,
StringProto,
NumberProto,
BooleanProto,
@@ -225,6 +226,7 @@ public:
Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
+ Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); }
Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index b2d89220ea..e9431ed25e 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -131,7 +131,7 @@ void FunctionObject::init(String *n, bool createProto)
}
if (n)
- defineReadonlyProperty(s.engine->id_name(), *n);
+ defineReadonlyConfigurableProperty(s.engine->id_name(), *n);
}
ReturnedValue FunctionObject::name() const
@@ -258,10 +258,10 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
@@ -557,7 +557,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(s.engine->id_length(), Primitive::fromInt32(len));
ScopedProperty pd(s);
pd->value = s.engine->thrower();
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 66861bf697..b0d14fc2b4 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -258,6 +258,7 @@ enum PropertyFlag {
Attr_NotEnumerable = 0x4,
Attr_NotConfigurable = 0x8,
Attr_ReadOnly = Attr_NotWritable|Attr_NotEnumerable|Attr_NotConfigurable,
+ Attr_ReadOnly_ButConfigurable = Attr_NotWritable|Attr_NotEnumerable,
Attr_Invalid = 0xff
};
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index dcda949c97..1d8ef4b0fb 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -234,7 +234,7 @@ struct InternalClassTransition
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id; }
+ { return id < other.id || (id == other.id && flags < other.flags); }
};
struct InternalClass : public QQmlJS::Managed {
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 1d571f53f3..0f021c8bd0 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -705,7 +705,7 @@ QString Stringify::Str(const QString &key, const Value &v)
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine, QString(), scope.result);
+ holder->put(scope.engine->id_empty(), scope.result);
ScopedCallData callData(scope, 2);
callData->args[0] = v4->newString(key);
callData->args[1] = scope.result;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 52f54e25f5..c5ee92fedd 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -54,8 +54,11 @@
#include "qv4runtime_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
+
+#if !defined(V4_BOOTSTRAP)
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index f2a24f8179..db45c77472 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -55,6 +55,7 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(n);
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 09644c161d..8cfa930888 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -102,6 +102,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon()));
+ ctor->defineReadonlyProperty(QStringLiteral("MAX_SAFE_INTEGER"), Primitive::fromDouble(9007199254740991));
+ ctor->defineReadonlyProperty(QStringLiteral("MIN_SAFE_INTEGER"), Primitive::fromDouble(-9007199254740991));
QT_WARNING_PUSH
QT_WARNING_DISABLE_INTEL(239)
@@ -109,15 +111,17 @@ QT_WARNING_DISABLE_INTEL(239)
QT_WARNING_POP
ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isInteger"), method_isInteger, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isSafeInteger"), method_isSafeInteger, 1);
ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
- defineDefaultProperty(engine->id_toString(), method_toString);
+ defineDefaultProperty(engine->id_toString(), method_toString, 1);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1);
- defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential);
- defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
+ defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential, 1);
+ defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision, 1);
}
inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
@@ -155,6 +159,52 @@ void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, Cal
scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
}
+void NumberPrototype::method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv);
+}
+
+void NumberPrototype::method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+}
+
void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
if (!callData->argc) {
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 364b866a16..e18267c50c 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -88,6 +88,8 @@ struct NumberPrototype: NumberObject
void init(ExecutionEngine *engine, Object *ctor);
static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 5d6c479477..dd3bbccde3 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,7 +61,8 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
- if (!d()->memberData || (d()->memberData->size < ic->size))
+ bool hasMD = d()->memberData != nullptr;
+ if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size))
d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
}
@@ -92,13 +93,6 @@ bool Object::setPrototype(Object *proto)
return true;
}
-void Object::put(ExecutionEngine *engine, const QString &name, const Value &value)
-{
- Scope scope(engine);
- ScopedString n(scope, engine->newString(name));
- put(n, value);
-}
-
ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs)
{
if (!attrs.isAccessor())
@@ -114,11 +108,11 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
return scope.result.asReturnedValue();
}
-void Object::putValue(uint memberIndex, const Value &value)
+bool Object::putValue(uint memberIndex, const Value &value)
{
QV4::InternalClass *ic = internalClass();
if (ic->engine->hasException)
- return;
+ return false;
PropertyAttributes attrs = ic->propertyData[memberIndex];
@@ -131,7 +125,7 @@ void Object::putValue(uint memberIndex, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !ic->engine->hasException;
}
goto reject;
}
@@ -140,11 +134,12 @@ void Object::putValue(uint memberIndex, const Value &value)
goto reject;
*propertyData(memberIndex) = value;
- return;
+ return true;
reject:
if (engine()->current->strictMode)
engine()->throwTypeError();
+ return false;
}
void Object::defineDefaultProperty(const QString &name, const Value &value)
@@ -162,7 +157,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca
ScopedString s(scope, e->newIdentifier(name));
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(s, function);
}
@@ -173,7 +168,7 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built
ScopedString s(scope, e->newIdentifier(name));
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(s, function);
}
@@ -183,7 +178,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte
Scope scope(e);
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -193,7 +188,7 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct
Scope scope(e);
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -250,6 +245,19 @@ void Object::defineReadonlyProperty(String *name, const Value &value)
insertMember(name, value, Attr_ReadOnly);
}
+void Object::defineReadonlyConfigurableProperty(const QString &name, const Value &value)
+{
+ QV4::ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ defineReadonlyConfigurableProperty(s, value);
+}
+
+void Object::defineReadonlyConfigurableProperty(String *name, const Value &value)
+{
+ insertMember(name, value, Attr_ReadOnly_ButConfigurable);
+}
+
void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
{
Heap::Object *o = static_cast<Heap::Object *>(that);
@@ -440,14 +448,14 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty
return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty);
}
-void Object::put(Managed *m, String *name, const Value &value)
+bool Object::put(Managed *m, String *name, const Value &value)
{
- static_cast<Object *>(m)->internalPut(name, value);
+ return static_cast<Object *>(m)->internalPut(name, value);
}
-void Object::putIndexed(Managed *m, uint index, const Value &value)
+bool Object::putIndexed(Managed *m, uint index, const Value &value)
{
- static_cast<Object *>(m)->internalPutIndexed(index, value);
+ return static_cast<Object *>(m)->internalPutIndexed(index, value);
}
PropertyAttributes Object::query(const Managed *m, String *name)
@@ -705,10 +713,10 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
// Section 8.12.5
-void Object::internalPut(String *name, const Value &value)
+bool Object::internalPut(String *name, const Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -737,7 +745,7 @@ void Object::internalPut(String *name, const Value &value)
uint l = value.asArrayLength(&ok);
if (!ok) {
engine()->throwRangeError(value);
- return;
+ return false;
}
ok = setArrayLength(l);
if (!ok)
@@ -745,7 +753,7 @@ void Object::internalPut(String *name, const Value &value)
} else {
*v = value;
}
- return;
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
@@ -776,24 +784,26 @@ void Object::internalPut(String *name, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
insertMember(name, value);
- return;
+ return true;
reject:
+ // ### this should be removed once everything is ported to use Object::set()
if (engine()->current->strictMode) {
QString message = QLatin1String("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
engine()->throwTypeError(message);
}
+ return false;
}
-void Object::internalPutIndexed(uint index, const Value &value)
+bool Object::internalPutIndexed(uint index, const Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
PropertyAttributes attrs;
@@ -815,7 +825,7 @@ void Object::internalPutIndexed(uint index, const Value &value)
goto reject;
else
*v = value;
- return;
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
@@ -846,15 +856,17 @@ void Object::internalPutIndexed(uint index, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
arraySet(index, value);
- return;
+ return true;
reject:
+ // ### this should be removed once everything is ported to use Object::setIndexed()
if (engine()->current->strictMode)
engine()->throwTypeError();
+ return false;
}
// Section 8.12.7
@@ -1155,6 +1167,49 @@ uint Object::getLength(const Managed *m)
return v->toUInt32();
}
+// 'var' is 'V' in 15.3.5.3.
+ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var)
+{
+ QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
+
+ // 15.3.5.3, Assume F is a Function object.
+ const FunctionObject *function = typeObject->as<FunctionObject>();
+ if (!function)
+ return engine->throwTypeError();
+
+ Heap::FunctionObject *f = function->d();
+ if (function->isBoundFunction())
+ f = function->cast<BoundFunction>()->target();
+
+ // 15.3.5.3, 1: HasInstance can only be used on an object
+ const Object *lhs = var.as<Object>();
+ if (!lhs)
+ return Encode(false);
+
+ // 15.3.5.3, 2
+ const Object *o = f->protoProperty();
+ if (!o) // 15.3.5.3, 3
+ return engine->throwTypeError();
+
+ Heap::Object *v = lhs->d();
+
+ // 15.3.5.3, 4
+ while (v) {
+ // 15.3.5.3, 4, a
+ v = v->prototype;
+
+ // 15.3.5.3, 4, b
+ if (!v)
+ break; // will return false
+
+ // 15.3.5.3, 4, c
+ else if (o->d() == v)
+ return Encode(true);
+ }
+
+ return Encode(false);
+}
+
bool Object::setArrayLength(uint newLen)
{
Q_ASSERT(isArrayObject());
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 4a78690f47..0d17afbf41 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -130,8 +130,8 @@ struct ObjectVTable
void (*construct)(const Managed *, Scope &scope, CallData *data);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
- void (*put)(Managed *, String *name, const Value &value);
- void (*putIndexed)(Managed *, uint index, const Value &value);
+ bool (*put)(Managed *, String *name, const Value &value);
+ bool (*putIndexed)(Managed *, uint index, const Value &value);
PropertyAttributes (*query)(const Managed *, String *name);
PropertyAttributes (*queryIndexed)(const Managed *, uint index);
bool (*deleteProperty)(Managed *m, String *name);
@@ -140,6 +140,7 @@ struct ObjectVTable
void (*setLookup)(Managed *m, Lookup *l, const Value &v);
uint (*getLength)(const Managed *m);
void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
+ ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var);
};
#define DEFINE_OBJECT_VTABLE_BASE(classname) \
@@ -159,7 +160,8 @@ const QV4::ObjectVTable classname::static_vtbl = \
getLookup, \
setLookup, \
getLength, \
- advanceIterator \
+ advanceIterator, \
+ instanceOf \
}
#define DEFINE_OBJECT_VTABLE(classname) \
@@ -221,8 +223,6 @@ struct Q_QML_EXPORT Object: Managed {
//
// helpers
//
- void put(ExecutionEngine *engine, const QString &name, const Value &value);
-
static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs);
ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const {
Scope scope(this->engine());
@@ -230,7 +230,7 @@ struct Q_QML_EXPORT Object: Managed {
return getValue(t, v, attrs);
}
- void putValue(uint memberIndex, const Value &value);
+ bool putValue(uint memberIndex, const Value &value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
void defineDefaultProperty(String *name, const Value &value) {
@@ -251,6 +251,10 @@ struct Q_QML_EXPORT Object: Managed {
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
+ /* Fixed: Writable: false, Enumerable: false, Configurable: true */
+ void defineReadonlyConfigurableProperty(const QString &name, const Value &value);
+ void defineReadonlyConfigurableProperty(String *name, const Value &value);
+
void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
Scope scope(engine());
ScopedProperty p(scope);
@@ -332,10 +336,47 @@ public:
{ return vtable()->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const
{ return vtable()->getIndexed(this, idx, hasProperty); }
- inline void put(String *name, const Value &v)
- { vtable()->put(this, name, v); }
- inline void putIndexed(uint idx, const Value &v)
- { vtable()->putIndexed(this, idx, v); }
+
+ // use the set variants instead, to customize throw behavior
+ inline bool put(String *name, const Value &v)
+ { return vtable()->put(this, name, v); }
+ inline bool putIndexed(uint idx, const Value &v)
+ { return vtable()->putIndexed(this, idx, v); }
+
+ enum ThrowOnFailure {
+ DoThrowOnRejection,
+ DoNotThrow
+ };
+
+ // ES6: 7.3.3 Set (O, P, V, Throw)
+ inline bool set(String *name, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->put(this, name, v);
+ // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
+ name->toQString() + QLatin1Char('\"');
+ e->throwTypeError(message);
+ }
+ }
+ return ret;
+ }
+
+ inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->putIndexed(this, idx, v);
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ e->throwTypeError();
+ }
+ }
+ return ret;
+ }
+
+
PropertyAttributes query(String *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
@@ -351,6 +392,8 @@ public:
void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
+ ReturnedValue instanceOf(const Value &var) const
+ { return vtable()->instanceOf(this, var); }
inline void construct(Scope &scope, CallData *d) const
{ return vtable()->construct(this, scope, d); }
@@ -362,8 +405,8 @@ protected:
static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static PropertyAttributes query(const Managed *m, String *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static bool deleteProperty(Managed *m, String *name);
@@ -372,12 +415,13 @@ protected:
static void setLookup(Managed *m, Lookup *l, const Value &v);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
+ static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const;
- void internalPut(String *name, const Value &value);
- void internalPutIndexed(uint index, const Value &value);
+ bool internalPut(String *name, const Value &value);
+ bool internalPutIndexed(uint index, const Value &value);
bool internalDeleteProperty(String *name);
bool internalDeleteIndexedProperty(uint index);
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 97dbe24339..f650ffc7b1 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -89,10 +90,11 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
ScopedObject o(scope, this);
ctor->defineReadonlyProperty(v4->id_prototype(), o);
- ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(v4->id_length(), Primitive::fromInt32(1));
ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
+ ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2);
ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2);
ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3);
ctor->defineDefaultProperty(QStringLiteral("defineProperties"), method_defineProperties, 2);
@@ -123,9 +125,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedObject p(scope, o->prototype());
scope.result = !!p ? p->asReturnedValue() : Encode::null();
@@ -133,11 +134,8 @@ void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scop
void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
@@ -154,13 +152,54 @@ void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, S
void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+}
+
+// 19.1.2.1
+void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ ScopedObject to(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ if (callData->argc == 1) {
+ scope.result = to;
return;
}
- scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+ for (int i = 1; i < callData->argc; ++i) {
+ if (callData->args[i].isUndefined() || callData->args[i].isNull())
+ continue;
+
+ ScopedObject from(scope, callData->args[i].toObject(scope.engine));
+ CHECK_EXCEPTION();
+ QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
+ quint32 length = keys->getLength();
+
+ ScopedString nextKey(scope);
+ ScopedValue propValue(scope);
+ for (quint32 i = 0; i < length; ++i) {
+ nextKey = Value::fromReturnedValue(keys->getIndexed(i)).toString(scope.engine);
+
+ PropertyAttributes attrs;
+ ScopedProperty prop(scope);
+ from->getOwnProperty(nextKey, &attrs, prop);
+
+ if (attrs == PropertyFlag::Attr_Invalid)
+ continue;
+
+ if (!attrs.isEnumerable())
+ continue;
+
+ propValue = from->get(nextKey);
+ to->set(nextKey, propValue, Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+ }
+
+ scope.result = to;
}
void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
@@ -246,8 +285,11 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc
void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.17, 1
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->sealed());
@@ -265,8 +307,11 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.5, 1
+ scope.result = callData->argument(0);
+ return;
+ }
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -287,9 +332,11 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->nonExtensible());
scope.result = o;
@@ -297,9 +344,11 @@ void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &s
void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -335,9 +384,11 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -373,18 +424,19 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(false);
+ return;
+ }
scope.result = Encode((bool)o->isExtensible());
}
void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -670,12 +722,12 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, c
return o.asReturnedValue();
}
-
+// es6: GetOwnPropertyKeys
Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
{
Scope scope(v4);
ScopedArrayObject array(scope, v4->newArrayObject());
- ScopedObject O(scope, o);
+ ScopedObject O(scope, o.toObject(v4));
if (O) {
ObjectIterator it(scope, O, ObjectIterator::NoFlags);
ScopedValue name(scope);
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 1db8615511..44b54267f3 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -81,6 +81,7 @@ struct ObjectPrototype: Object
static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_assign(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 889f4ea288..cdc29c8b9c 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -225,21 +225,19 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
return Encode::undefined();
}
-void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
+bool QmlContextWrapper::put(Managed *m, String *name, const Value &value)
{
Q_ASSERT(m->as<QmlContextWrapper>());
QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m);
ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
if (scope.hasException())
- return;
+ return false;
QV4::Scoped<QmlContextWrapper> wrapper(scope, resource);
uint member = wrapper->internalClass()->find(name);
- if (member < UINT_MAX) {
- wrapper->putValue(member, value);
- return;
- }
+ if (member < UINT_MAX)
+ return wrapper->putValue(member, value);
if (wrapper->d()->isNullWrapper) {
if (wrapper && wrapper->d()->readOnly) {
@@ -247,11 +245,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QLatin1Char('"');
ScopedString e(scope, v4->newString(error));
v4->throwError(e);
- return;
+ return false;
}
- Object::put(m, name, value);
- return;
+ return Object::put(m, name, value);
}
// Its possible we could delay the calculation of the "actual" context (in the case
@@ -260,7 +257,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QQmlContextData *expressionContext = context;
if (!context)
- return;
+ return false;
// See QV8ContextWrapper::Getter for resolution order
@@ -270,18 +267,18 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
const QV4::IdentifierHash<int> &properties = context->propertyNames();
// Search context properties
if (properties.count() && properties.value(name) != -1)
- return;
+ return false;
// Search scope object
if (scopeObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
scopeObject = 0;
// Search context object
if (context->contextObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
context = context->parent;
}
@@ -292,10 +289,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
v4->throwError(error);
- return;
+ return false;
}
- Object::put(m, name, value);
+ return Object::put(m, name, value);
}
void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 9aec7467da..6e5e743609 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -100,7 +100,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
void setReadOnly(bool b) { d()->readOnly = b; }
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 7260e71fab..c9b4b433bd 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -625,13 +625,13 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *has
return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
}
-void QObjectWrapper::put(Managed *m, String *name, const Value &value)
+bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
{
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = that->engine();
if (v4->hasException || QQmlData::wasDeleted(that->d()->object()))
- return;
+ return false;
QQmlContextData *qmlContext = v4->callingQmlContext();
if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) {
@@ -642,10 +642,13 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Cannot assign to non-existent property \"") +
name->toQString() + QLatin1Char('\"');
v4->throwError(error);
+ return false;
} else {
- QV4::Object::put(m, name, value);
+ return QV4::Object::put(m, name, value);
}
}
+
+ return true;
}
PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
@@ -673,18 +676,24 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
- if (that->d()->object()) {
- const QMetaObject *mo = that->d()->object()->metaObject();
+ QObject *thatObject = that->d()->object();
+ if (thatObject && !QQmlData::wasDeleted(thatObject)) {
+ const QMetaObject *mo = thatObject->metaObject();
// These indices don't apply to gadgets, so don't block them.
const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject;
const int propertyCount = mo->propertyCount();
if (it->arrayIndex < static_cast<uint>(propertyCount)) {
- Scope scope(that->engine());
- ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name())));
+ ExecutionEngine *thatEngine = that->engine();
+ Scope scope(thatEngine);
+ const QMetaProperty property = mo->property(it->arrayIndex);
+ ScopedString propName(scope, thatEngine->newString(QString::fromUtf8(property.name())));
name->setM(propName->d());
++it->arrayIndex;
*attributes = QV4::Attr_Data;
- p->value = that->get(propName);
+
+ QQmlPropertyData local;
+ local.load(property);
+ p->value = that->getProperty(thatEngine, thatObject, &local);
return;
}
const int methodCount = mo->methodCount();
@@ -694,11 +703,15 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
++it->arrayIndex;
if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2)))
continue;
- Scope scope(that->engine());
- ScopedString methodName(scope, that->engine()->newString(QString::fromUtf8(method.name())));
+ ExecutionEngine *thatEngine = that->engine();
+ Scope scope(thatEngine);
+ ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name())));
name->setM(methodName->d());
*attributes = QV4::Attr_Data;
- p->value = that->get(methodName);
+
+ QQmlPropertyData local;
+ local.load(method);
+ p->value = that->getProperty(thatEngine, thatObject, &local);
return;
}
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index b09e06cec5..d81ef2a680 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -192,7 +192,7 @@ protected:
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 40682aaa4b..0894d0c25b 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -367,7 +367,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
RETURN_RESULT(Encode::null());
}
- uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint));
+ Q_ALLOCA_VAR(uint, matchOffsets, r->value()->captureCount() * 2 * sizeof(uint));
const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 023a739e33..6590054bf3 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -343,35 +343,15 @@ ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
return Encode(engine->currentContext->deleteProperty(name));
}
-QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
- const FunctionObject *function = right.as<FunctionObject>();
- if (!function)
- return engine->throwTypeError();
-
- Heap::FunctionObject *f = function->d();
- if (function->isBoundFunction())
- f = function->cast<BoundFunction>()->target();
-
- const Object *o = left.as<Object>();
- if (!o)
- return Encode(false);
- Heap::Object *v = o->d();
-
- o = f->protoProperty();
- if (!o)
- return engine->throwTypeError();
-
- while (v) {
- v = v->prototype;
-
- if (!v)
- break;
- else if (o->d() == v)
- return Encode(true);
- }
+ // 11.8.6, 5: rval must be an Object
+ const Object *rhs = rval.as<Object>();
+ if (!rhs)
+ return engine->throwTypeError();
- return Encode(false);
+ // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
+ return rhs->instanceOf(lval);
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -1284,12 +1264,16 @@ ReturnedValue Runtime::method_unwindException(ExecutionEngine *engine)
*/
void Runtime::method_pushWithScope(const Value &o, NoThrowEngine *engine)
{
- engine->pushContext(engine->currentContext->newWithContext(o.toObject(engine)));
+ QV4::Value *v = engine->jsAlloca(1);
+ Heap::Object *withObject = o.toObject(engine);
+ *v = withObject;
+ engine->pushContext(engine->currentContext->newWithContext(withObject));
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
}
void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
{
+ engine->jsAlloca(1); // keep this symmetric with pushWithScope
ExecutionContext *c = engine->currentContext;
engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
@@ -1299,7 +1283,7 @@ void Runtime::method_popScope(NoThrowEngine *engine)
{
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
engine->popContext();
- engine->jsStackTop -= 2;
+ engine->jsStackTop -= 3;
}
void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 8ce10e326d..6d3110771e 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -274,20 +274,20 @@ public:
return Encode::undefined();
}
- void containerPutIndexed(uint index, const QV4::Value &value)
+ bool containerPutIndexed(uint index, const QV4::Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
- return;
+ return false;
}
if (d()->isReference) {
if (!d()->object)
- return;
+ return false;
loadReference();
}
@@ -313,6 +313,7 @@ public:
if (d()->isReference)
storeReference();
+ return true;
}
QV4::PropertyAttributes containerQueryIndexed(uint index) const
@@ -540,8 +541,8 @@ public:
static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); }
- static void putIndexed(Managed *that, uint index, const QV4::Value &value)
- { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
+ static bool putIndexed(Managed *that, uint index, const QV4::Value &value)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); }
static bool deleteIndexedProperty(QV4::Managed *that, uint index)
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 3c6a24e035..72be11eca0 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -200,6 +200,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1);
defineDefaultProperty(QStringLiteral("match"), method_match, 1);
+ defineDefaultProperty(QStringLiteral("repeat"), method_repeat, 1);
defineDefaultProperty(QStringLiteral("replace"), method_replace, 2);
defineDefaultProperty(QStringLiteral("search"), method_search, 1);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
@@ -458,6 +459,21 @@ void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallDa
scope.result = a;
}
+void StringPrototype::method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ double repeats = callData->args[0].toInteger();
+
+ if (repeats < 0 || qIsInf(repeats)) {
+ scope.result = scope.engine->throwRangeError(QLatin1String("Invalid count value"));
+ return;
+ }
+
+ scope.result = scope.engine->newString(value.repeated(int(repeats)));
+}
+
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
{
result->reserve(result->length() + replaceValue.length());
@@ -634,7 +650,7 @@ void StringPrototype::method_search(const BuiltinFunction *, Scope &scope, CallD
Q_ASSERT(regExp);
}
Scoped<RegExp> re(scope, regExp->value());
- uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint));
+ Q_ALLOCA_VAR(uint, matchOffsets, regExp->value()->captureCount() * 2 * sizeof(uint));
uint result = re->match(string, /*offset*/0, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
scope.result = Encode(-1);
@@ -705,7 +721,7 @@ void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallDa
ScopedString s(scope);
if (re) {
uint offset = 0;
- uint* matchOffsets = (uint*)alloca(re->value()->captureCount() * 2 * sizeof(uint));
+ Q_ALLOCA_VAR(uint, matchOffsets, re->value()->captureCount() * 2 * sizeof(uint));
while (true) {
Scoped<RegExp> regexp(scope, re->value());
uint result = regexp->match(text, offset, matchOffsets);
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 0ee7a6ece9..aed3bc1e28 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -121,6 +121,7 @@ struct StringPrototype: StringObject
static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index cecd1e6958..5573a2e57f 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -398,11 +398,11 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp
return a->d()->type->read(a->d()->buffer->data->data(), byteOffset);
}
-void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
+bool TypedArray::putIndexed(Managed *m, uint index, const Value &value)
{
ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
if (v4->hasException)
- return;
+ return false;
Scope scope(v4);
Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
@@ -413,11 +413,12 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
goto reject;
a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value);
- return;
+ return true;
reject:
if (scope.engine->current->strictMode)
scope.engine->throwTypeError();
+ return false;
}
void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index eefed2db4b..fbf13c9815 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -133,7 +133,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
static void markObjects(Heap::Base *that, ExecutionEngine *e);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 816b8fb11b..4ff0565f9b 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -254,34 +254,47 @@ public:
Q_ASSERT(isDouble()); return Double_Type;
}
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-16,
+ IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
+ Managed_Type_Internal_64 = 0
+ };
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ // Used only by 32-bit encoding
enum Masks {
SilentNaNBit = 0x00040000,
- NaN_Mask = 0x7ff80000,
NotDouble_Mask = 0x7ffa0000,
- Immediate_Mask = NotDouble_Mask | 0x00020000u | SilentNaNBit,
- Tag_Shift = 32
};
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
enum {
- Managed_Type_Internal = NotDouble_Mask
+ Managed_Type_Internal_32 = NotDouble_Mask
};
-#else
- static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
- static const quint64 Immediate_Mask = 0x00020000u; // bit 49
- enum Masks {
- NaN_Mask = 0x7ff80000,
+#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+ enum {
+ Managed_Type_Internal = Managed_Type_Internal_64
};
+ static const quint64 Immediate_Mask = Immediate_Mask_64;
+#else
enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-16,
- Tag_Shift = 32,
- IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
- Managed_Type_Internal = 0
+ Managed_Type_Internal = Managed_Type_Internal_32
};
+ static const quint64 Immediate_Mask = Immediate_Mask_32;
#endif
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
enum ValueTypeInternal {
Empty_Type_Internal = Immediate_Mask | 0,
ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48
@@ -544,7 +557,7 @@ inline bool Value::asArrayIndex(uint &idx) const
}
double d = doubleValue();
idx = (uint)d;
- return (idx == d);
+ return (idx == d && idx != UINT_MAX);
}
#endif
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index b9183313cd..be2772c23f 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -402,7 +402,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
}
}
- QV4::Value **scopes = static_cast<QV4::Value **>(alloca(sizeof(QV4::Value *)*(2 + 2*scopeDepth)));
+ Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth));
{
scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->constants);
// stack gets setup in push instruction
@@ -957,8 +957,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
return QV4::Encode::undefined();
code = exceptionHandler;
}
-
-
}
#ifdef MOTH_THREADED_INTERPRETER