From a885d10a0289da85b8c966d2fa40fb10edae4fd7 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 12 Mar 2014 16:55:06 +0100 Subject: Extend the QML bootstrap library by the IR builders This is among other things needed to fix the qml import scanner to detect dependencies from .js files correctly. The patch also fixes the use of Q_QML_EXPORT towards Q_QML_PRIVATE_EXPORT where appropriate and corrects the wrong include path for the double conversion code to actually be relative to the file it is included from. This worked by accident because of other include paths present in the build. Change-Id: I338583dad2f76300819af8ab0dae8e5724c84430 Reviewed-by: Lars Knoll --- src/qml/jsruntime/jsruntime.pri | 22 ++++++--- src/qml/jsruntime/qv4global_p.h | 5 ++ src/qml/jsruntime/qv4managed_p.h | 2 +- src/qml/jsruntime/qv4object_p.h | 2 + src/qml/jsruntime/qv4runtime.cpp | 94 ++++++++++++++++++++++++++++++-------- src/qml/jsruntime/qv4runtime_p.h | 16 ++++++- src/qml/jsruntime/qv4script.cpp | 4 +- src/qml/jsruntime/qv4string.cpp | 16 +++++-- src/qml/jsruntime/qv4string_p.h | 11 +++-- src/qml/jsruntime/qv4value.cpp | 10 ++++ src/qml/jsruntime/qv4value_inl_p.h | 7 +++ src/qml/jsruntime/qv4value_p.h | 4 +- 12 files changed, 154 insertions(+), 39 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 9d5757b5a0..72010d3fa8 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -1,11 +1,10 @@ INCLUDEPATH += $$PWD INCLUDEPATH += $$OUT_PWD +!qmldevtools_build { SOURCES += \ $$PWD/qv4engine.cpp \ $$PWD/qv4context.cpp \ - $$PWD/qv4runtime.cpp \ - $$PWD/qv4value.cpp \ $$PWD/qv4persistent.cpp \ $$PWD/qv4debugging.cpp \ $$PWD/qv4lookup.cpp \ @@ -33,7 +32,6 @@ SOURCES += \ $$PWD/qv4regexpobject.cpp \ $$PWD/qv4stringobject.cpp \ $$PWD/qv4variantobject.cpp \ - $$PWD/qv4string.cpp \ $$PWD/qv4objectiterator.cpp \ $$PWD/qv4regexp.cpp \ $$PWD/qv4serialize.cpp \ @@ -50,10 +48,7 @@ HEADERS += \ $$PWD/qv4global_p.h \ $$PWD/qv4engine_p.h \ $$PWD/qv4context_p.h \ - $$PWD/qv4runtime_p.h \ $$PWD/qv4math_p.h \ - $$PWD/qv4value_inl_p.h \ - $$PWD/qv4value_p.h \ $$PWD/qv4persistent_p.h \ $$PWD/qv4debugging_p.h \ $$PWD/qv4lookup_p.h \ @@ -81,7 +76,6 @@ HEADERS += \ $$PWD/qv4regexpobject_p.h \ $$PWD/qv4stringobject_p.h \ $$PWD/qv4variantobject_p.h \ - $$PWD/qv4string_p.h \ $$PWD/qv4property_p.h \ $$PWD/qv4objectiterator_p.h \ $$PWD/qv4regexp_p.h \ @@ -97,6 +91,20 @@ HEADERS += \ $$PWD/qv4vme_moth_p.h \ $$PWD/qv4profiling_p.h +} + + +HEADERS += \ + $$PWD/qv4runtime_p.h \ + $$PWD/qv4value_inl_p.h \ + $$PWD/qv4string_p.h \ + $$PWD/qv4value_p.h + +SOURCES += \ + $$PWD/qv4runtime.cpp \ + $$PWD/qv4string.cpp \ + $$PWD/qv4value.cpp + # Use SSE2 floating point math on 32 bit instead of the default # 387 to make test results pass on 32 and on 64 bit builds. linux-g++*:isEqual(QT_ARCH,i386) { diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 4e05bb81ab..b5dc6742f9 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -45,6 +45,7 @@ #include #include #include +#include #if defined(Q_CC_MSVC) #include @@ -66,6 +67,10 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #define qOffsetOf(s, m) ((size_t)((((char *)&(((s *)64)->m)) - 64))) +#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) +#define V4_BOOTSTRAP +#endif + // Decide whether to enable or disable the JIT // White list architectures diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 5ad4c28970..06d3e4884b 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -187,7 +187,7 @@ const QV4::ObjectVTable classname::static_vtbl = \ } -struct Q_QML_EXPORT Managed +struct Q_QML_PRIVATE_EXPORT Managed { V4_MANAGED enum { diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 0dfaffc132..40f38ee347 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -410,11 +410,13 @@ inline ArrayObject *value_cast(const Value &v) { return v.asArrayObject(); } +#ifndef V4_BOOTSTRAP template<> inline ReturnedValue value_convert(ExecutionEngine *e, const Value &v) { return v.toObject(e->currentContext())->asReturnedValue(); } +#endif struct ObjectRef : public ManagedRef { diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 4923c217b6..e44d1a07a6 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -41,6 +41,7 @@ #include "qv4global_p.h" #include "qv4runtime_p.h" +#ifndef V4_BOOTSTRAP #include "qv4object_p.h" #include "qv4jsir_p.h" #include "qv4objectproto_p.h" @@ -54,6 +55,7 @@ #include #include "qv4qobjectwrapper_p.h" #include +#endif #include #include @@ -63,7 +65,7 @@ #include #include -#include "../../../3rdparty/double-conversion/double-conversion.h" +#include "../../3rdparty/double-conversion/double-conversion.h" QT_BEGIN_NAMESPACE @@ -207,6 +209,7 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2) #endif // QV4_COUNT_RUNTIME_FUNCTIONS +#ifndef V4_BOOTSTRAP void RuntimeHelpers::numberToString(QString *result, double num, int radix) { Q_ASSERT(result); @@ -414,10 +417,7 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) return ctx->throwTypeError(); } -Bool Runtime::toBoolean(const ValueRef value) -{ - return value->toBoolean(); -} + Returned *RuntimeHelpers::convertToObject(ExecutionContext *ctx, const ValueRef value) { @@ -677,6 +677,8 @@ ReturnedValue Runtime::getActivationProperty(ExecutionContext *ctx, const String return ctx->getProperty(name); } +#endif // V4_BOOTSTRAP + uint RuntimeHelpers::equalHelper(const ValueRef x, const ValueRef y) { Q_ASSERT(x->type() != y->type() || (x->isManaged() && (x->isString() != y->isString()))); @@ -697,14 +699,20 @@ uint RuntimeHelpers::equalHelper(const ValueRef x, const ValueRef y) return Runtime::compareEqual(Primitive::fromDouble((double) x->booleanValue()), y); } else if (y->isBoolean()) { return Runtime::compareEqual(x, Primitive::fromDouble((double) y->booleanValue())); - } else if ((x->isNumber() || x->isString()) && y->isObject()) { - Scope scope(y->objectValue()->engine()); - ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT)); - return Runtime::compareEqual(x, py); - } else if (x->isObject() && (y->isNumber() || y->isString())) { - Scope scope(x->objectValue()->engine()); - ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT)); - return Runtime::compareEqual(px, y); + } else { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else + if ((x->isNumber() || x->isString()) && y->isObject()) { + Scope scope(y->objectValue()->engine()); + ScopedValue py(scope, RuntimeHelpers::toPrimitive(y, PREFERREDTYPE_HINT)); + return Runtime::compareEqual(x, py); + } else if (x->isObject() && (y->isNumber() || y->isString())) { + Scope scope(x->objectValue()->engine()); + ScopedValue px(scope, RuntimeHelpers::toPrimitive(x, PREFERREDTYPE_HINT)); + return Runtime::compareEqual(px, y); + } +#endif } return false; @@ -732,15 +740,25 @@ QV4::Bool Runtime::compareGreaterThan(const QV4::ValueRef l, const QV4::ValueRef return l->integerValue() > r->integerValue(); if (l->isNumber() && r->isNumber()) return l->asDouble() > r->asDouble(); - if (l->isString() && r->isString()) + if (l->isString() && r->isString()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); + return false; +#else return r->stringValue()->compare(l->stringValue()); +#endif + } if (l->isObject() || r->isObject()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine(); QV4::Scope scope(e); QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); return Runtime::compareGreaterThan(pl, pr); +#endif } double dl = RuntimeHelpers::toNumber(l); @@ -755,15 +773,25 @@ QV4::Bool Runtime::compareLessThan(const QV4::ValueRef l, const QV4::ValueRef r) return l->integerValue() < r->integerValue(); if (l->isNumber() && r->isNumber()) return l->asDouble() < r->asDouble(); - if (l->isString() && r->isString()) + if (l->isString() && r->isString()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); + return false; +#else return l->stringValue()->compare(r->stringValue()); +#endif + } if (l->isObject() || r->isObject()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine(); QV4::Scope scope(e); QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); return Runtime::compareLessThan(pl, pr); +#endif } double dl = RuntimeHelpers::toNumber(l); @@ -778,15 +806,25 @@ QV4::Bool Runtime::compareGreaterEqual(const QV4::ValueRef l, const QV4::ValueRe return l->integerValue() >= r->integerValue(); if (l->isNumber() && r->isNumber()) return l->asDouble() >= r->asDouble(); - if (l->isString() && r->isString()) + if (l->isString() && r->isString()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); + return false; +#else return !l->stringValue()->compare(r->stringValue()); +#endif + } if (l->isObject() || r->isObject()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine(); QV4::Scope scope(e); QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); return Runtime::compareGreaterEqual(pl, pr); +#endif } double dl = RuntimeHelpers::toNumber(l); @@ -801,15 +839,25 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r return l->integerValue() <= r->integerValue(); if (l->isNumber() && r->isNumber()) return l->asDouble() <= r->asDouble(); - if (l->isString() && r->isString()) + if (l->isString() && r->isString()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); + return false; +#else return !r->stringValue()->compare(l->stringValue()); +#endif + } if (l->isObject() || r->isObject()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else QV4::ExecutionEngine *e = (l->isObject() ? l->objectValue() : r->objectValue())->engine(); QV4::Scope scope(e); QV4::ScopedValue pl(scope, RuntimeHelpers::toPrimitive(l, QV4::NUMBER_HINT)); QV4::ScopedValue pr(scope, RuntimeHelpers::toPrimitive(r, QV4::NUMBER_HINT)); return Runtime::compareLessEqual(pl, pr); +#endif } double dl = RuntimeHelpers::toNumber(l); @@ -817,7 +865,7 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r return dl <= dr; } - +#ifndef V4_BOOTSTRAP ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData) { Scope scope(context); @@ -1144,6 +1192,8 @@ QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionContext *ctx) return (new (c->engine->memoryManager) ArgumentsObject(c))->asReturnedValue(); } +#endif // V4_BOOTSTRAP + QV4::ReturnedValue Runtime::increment(const QV4::ValueRef value) { TRACE1(value); @@ -1168,6 +1218,8 @@ QV4::ReturnedValue Runtime::decrement(const QV4::ValueRef value) } } +#ifndef V4_BOOTSTRAP + QV4::ReturnedValue RuntimeHelpers::toString(QV4::ExecutionContext *ctx, const QV4::ValueRef value) { if (value->isString()) @@ -1187,6 +1239,8 @@ QV4::ReturnedValue RuntimeHelpers::toObject(QV4::ExecutionContext *ctx, const QV return Encode(o); } +#endif // V4_BOOTSTRAP + ReturnedValue Runtime::toDouble(const ValueRef value) { TRACE1(value); @@ -1217,6 +1271,8 @@ unsigned Runtime::doubleToUInt(const double &d) return Primitive::toUInt32(d); } +#ifndef V4_BOOTSTRAP + ReturnedValue Runtime::regexpLiteral(ExecutionContext *ctx, int id) { return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); @@ -1301,6 +1357,8 @@ void Runtime::convertThisToObject(ExecutionContext *ctx) } } +#endif // V4_BOOTSTRAP + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index d00c579283..0979105680 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -103,7 +103,7 @@ struct NoThrowContext : public ExecutionContext { }; -struct Q_QML_EXPORT Runtime { +struct Q_QML_PRIVATE_EXPORT Runtime { // call static ReturnedValue callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData); static ReturnedValue callActivationProperty(ExecutionContext *, const StringRef name, CallDataRef callData); @@ -232,7 +232,7 @@ struct Q_QML_EXPORT Runtime { static void setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value); }; -struct Q_QML_EXPORT RuntimeHelpers { +struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static ReturnedValue objectDefaultValue(Object *object, int typeHint); static ReturnedValue toPrimitive(const ValueRef value, int typeHint); @@ -255,6 +255,7 @@ struct Q_QML_EXPORT RuntimeHelpers { // type conversion and testing +#ifndef V4_BOOTSTRAP inline ReturnedValue RuntimeHelpers::toPrimitive(const ValueRef value, int typeHint) { Object *o = value->asObject(); @@ -262,6 +263,7 @@ inline ReturnedValue RuntimeHelpers::toPrimitive(const ValueRef value, int typeH return value.asReturnedValue(); return RuntimeHelpers::objectDefaultValue(o, typeHint); } +#endif inline double RuntimeHelpers::toNumber(const ValueRef value) { @@ -338,6 +340,7 @@ inline ReturnedValue Runtime::bitAnd(const ValueRef left, const ValueRef right) return Encode(lval & rval); } +#ifndef V4_BOOTSTRAP inline ReturnedValue Runtime::add(ExecutionContext *ctx, const ValueRef left, const ValueRef right) { TRACE2(left, right); @@ -349,6 +352,7 @@ inline ReturnedValue Runtime::add(ExecutionContext *ctx, const ValueRef left, co return RuntimeHelpers::addHelper(ctx, left, right); } +#endif // V4_BOOTSTRAP inline ReturnedValue Runtime::sub(const ValueRef left, const ValueRef right) { @@ -532,6 +536,7 @@ inline Bool Runtime::compareStrictNotEqual(const ValueRef left, const ValueRef r return ! RuntimeHelpers::strictEqual(left, right); } +#ifndef V4_BOOTSTRAP inline Bool Runtime::compareInstanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) { TRACE2(left, right); @@ -550,6 +555,13 @@ inline uint Runtime::compareIn(ExecutionContext *ctx, const ValueRef left, const return v->booleanValue(); } +#endif // V4_BOOTSTRAP + +inline Bool Runtime::toBoolean(const ValueRef value) +{ + return value->toBoolean(); +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 33922684da..36f61a1df5 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -385,10 +385,10 @@ QV4::CompiledData::CompilationUnit *Script::precompile(IR::Module *module, Compi QQmlJS::Codegen cg(/*strict mode*/false); cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode); - errors = cg.errors(); + errors = cg.qmlErrors(); if (!errors.isEmpty()) { if (reportedErrors) - *reportedErrors << cg.errors(); + *reportedErrors << errors; return 0; } diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 575f605e45..d9aa881f21 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -40,10 +40,13 @@ ****************************************************************************/ #include "qv4string_p.h" +#include "qv4value_inl_p.h" +#ifndef V4_BOOTSTRAP #include "qv4identifiertable_p.h" #include "qv4runtime_p.h" #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" +#endif #include using namespace QV4; @@ -74,6 +77,8 @@ static uint toArrayIndex(const QChar *ch, const QChar *end, bool *ok) return i; } +#ifndef V4_BOOTSTRAP + static uint toArrayIndex(const char *ch, const char *end, bool *ok) { *ok = false; @@ -407,13 +412,16 @@ uint String::createHashValue(const char *ch, int length) return h; } +uint String::getLength(const Managed *m) +{ + return static_cast(m)->length(); +} + +#endif // V4_BOOTSTRAP + uint String::toArrayIndex(const QString &str) { bool ok; return ::toArrayIndex(str.constData(), str.constData() + str.length(), &ok); } -uint String::getLength(const Managed *m) -{ - return static_cast(m)->length(); -} diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index ade64d1352..ed2a4e3646 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -51,7 +51,8 @@ namespace QV4 { struct ExecutionEngine; struct Identifier; -struct Q_QML_EXPORT String : public Managed { +struct Q_QML_PRIVATE_EXPORT String : public Managed { +#ifndef V4_BOOTSTRAP // ### FIXME: Should this be a V4_OBJECT V4_OBJECT Q_MANAGED_TYPE(String) @@ -143,8 +144,6 @@ struct Q_QML_EXPORT String : public Managed { return len; } - static uint toArrayIndex(const QString &str); - union { mutable QStringData *_text; mutable String *left; @@ -174,8 +173,13 @@ protected: private: QChar *recursiveAppend(QChar *ch) const; +#endif + +public: + static uint toArrayIndex(const QString &str); }; +#ifndef V4_BOOTSTRAP template<> inline String *value_cast(const Value &v) { return v.asString(); @@ -188,6 +192,7 @@ inline ReturnedValue value_convert(ExecutionEngine *e, const Value &v) } DEFINE_REF(String, Managed); +#endif } diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index fa16662b46..e9246f7a14 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -39,9 +39,11 @@ ** ****************************************************************************/ #include +#ifndef V4_BOOTSTRAP #include #include #include "qv4mm_p.h" +#endif #include @@ -87,6 +89,9 @@ double Value::toNumberImpl() const case QV4::Value::Undefined_Type: return std::numeric_limits::quiet_NaN(); case QV4::Value::Managed_Type: +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else if (isString()) return RuntimeHelpers::stringToNumber(stringValue()->toQString()); { @@ -95,6 +100,7 @@ double Value::toNumberImpl() const ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ValueRef::fromRawValue(this), NUMBER_HINT)); return prim->toNumber(); } +#endif case QV4::Value::Null_Type: case QV4::Value::Boolean_Type: case QV4::Value::Integer_Type: @@ -104,6 +110,7 @@ double Value::toNumberImpl() const } } +#ifndef V4_BOOTSTRAP QString Value::toQStringNoThrow() const { switch (type()) { @@ -192,6 +199,7 @@ QString Value::toQString() const } } // switch } +#endif // V4_BOOTSTRAP bool Value::sameValue(Value other) const { if (val == other.val) @@ -263,6 +271,7 @@ double Primitive::toInteger(double number) return std::signbit(number) ? -v : v; } +#ifndef V4_BOOTSTRAP String *Value::toString(ExecutionEngine *e) const { return toString(e->currentContext()); @@ -282,3 +291,4 @@ Object *Value::toObject(ExecutionContext *ctx) const return RuntimeHelpers::convertToObject(ctx, ValueRef::fromRawValue(this))->getPointer(); } +#endif // V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h index 35508f442a..1fe9e1c165 100644 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ b/src/qml/jsruntime/qv4value_inl_p.h @@ -180,14 +180,19 @@ inline bool Value::toBoolean() const case Value::Integer_Type: return (bool)int_32; case Value::Managed_Type: +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); +#else if (isString()) return stringValue()->toQString().length() > 0; +#endif return true; default: // double return doubleValue() && !std::isnan(doubleValue()); } } +#ifndef V4_BOOTSTRAP inline uint Value::asArrayIndex() const { #if QT_POINTER_SIZE == 8 @@ -278,6 +283,8 @@ inline ErrorObject *Value::asErrorObject() const template inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as() : 0; } +#endif + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 27c81d59a5..2c780622dc 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -64,7 +64,7 @@ struct Returned : private T using T::asReturnedValue; }; -struct Q_QML_EXPORT Value +struct Q_QML_PRIVATE_EXPORT Value { /* We use two different ways of encoding JS values. One for 32bit and one for 64bit systems. @@ -372,7 +372,7 @@ inline String *Value::asString() const return 0; } -struct Q_QML_EXPORT Primitive : public Value +struct Q_QML_PRIVATE_EXPORT Primitive : public Value { inline static Primitive emptyValue(); static inline Primitive fromBoolean(bool b); -- cgit v1.2.3 From 52fcb218c379bb2008e24a2b5b00b613219ba7f6 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 16 Apr 2014 09:36:38 +0200 Subject: Fix marking of prototype objects in internal class pool As per reported bug, we have to protect ourselves against potential loops and can mark the internal classes much simpler by just walking through the memory pool they were allocated in. Task-number: QTBUG-38299 Change-Id: I3ae96e8082e76d06f4321c5aa6d2e9645d2830a0 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4engine.cpp | 9 ++++++--- src/qml/jsruntime/qv4engine_p.h | 3 ++- src/qml/jsruntime/qv4internalclass.cpp | 30 +++++++++++++++++++----------- src/qml/jsruntime/qv4internalclass_p.h | 9 +++++++-- 4 files changed, 34 insertions(+), 17 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index b95197e16b..8916cc597e 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -215,7 +215,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) identifierTable = new IdentifierTable(this); - emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this); + classPool = new InternalClassPool; + + emptyClass = new (classPool) InternalClass(this); executionContextClass = InternalClass::create(this, ExecutionContext::staticVTable(), 0); constructClass = InternalClass::create(this, Object::staticVTable(), 0); stringClass = InternalClass::create(this, String::staticVTable(), 0); @@ -429,6 +431,7 @@ ExecutionEngine::~ExecutionEngine() delete m_qmlExtensions; emptyClass->destroy(); + delete classPool; delete bumperPointerAllocator; delete regExpCache; delete regExpAllocator; @@ -464,7 +467,7 @@ void ExecutionEngine::initRootContext() InternalClass *ExecutionEngine::newClass(const InternalClass &other) { - return new (classPool.allocate(sizeof(InternalClass))) InternalClass(other); + return new (classPool) InternalClass(other); } ExecutionContext *ExecutionEngine::pushGlobalContext() @@ -897,7 +900,7 @@ void ExecutionEngine::markObjects() if (m_qmlExtensions) m_qmlExtensions->markObjects(this); - emptyClass->markObjects(); + classPool->markObjects(this); for (QSet::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); it != end; ++it) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index b93af514b1..d678d6595e 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -109,6 +109,7 @@ struct SequencePrototype; struct EvalFunction; struct IdentifierTable; struct InternalClass; +struct InternalClassPool; class MultiplyWrappedQObjectMap; class RegExp; class RegExpCache; @@ -197,7 +198,7 @@ public: Value uRIErrorCtor; Value sequencePrototype; - QQmlJS::MemoryPool classPool; + InternalClassPool *classPool; InternalClass *emptyClass; InternalClass *executionContextClass; InternalClass *constructClass; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index aacc5bf517..3dc20b8e76 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -129,7 +129,7 @@ uint PropertyHash::lookup(const Identifier *identifier) const InternalClass::InternalClass(ExecutionEngine *engine) : engine(engine) , prototype(0) - , vtable(&Managed::static_vtbl) + , vtable(&QV4::Managed::static_vtbl) , m_sealed(0) , m_frozen(0) , size(0) @@ -138,7 +138,8 @@ InternalClass::InternalClass(ExecutionEngine *engine) InternalClass::InternalClass(const QV4::InternalClass &other) - : engine(other.engine) + : QQmlJS::Managed() + , engine(other.engine) , prototype(other.prototype) , vtable(other.vtable) , propertyTable(other.propertyTable) @@ -455,17 +456,24 @@ void InternalClass::destroy() transitions.clear(); } -void InternalClass::markObjects() +struct InternalClassPoolVisitor { - // all prototype changes are done on the empty class - Q_ASSERT(!prototype || this != engine->emptyClass); - - if (prototype) - prototype->mark(engine); + ExecutionEngine *engine; + void operator()(InternalClass *klass) + { + // all prototype changes are done on the empty class + Q_ASSERT(!klass->prototype || klass != engine->emptyClass); + + if (klass->prototype) + klass->prototype->mark(engine); + } +}; - for (QHash::ConstIterator it = transitions.begin(), end = transitions.end(); - it != end; ++it) - it.value()->markObjects(); +void InternalClassPool::markObjects(ExecutionEngine *engine) +{ + InternalClassPoolVisitor v; + v.engine = engine; + visitManagedPool(v); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 91c6e264db..bd1828a146 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -44,6 +44,7 @@ #include #include #include "qv4global_p.h" +#include QT_BEGIN_NAMESPACE @@ -213,7 +214,7 @@ struct InternalClassTransition }; uint qHash(const QV4::InternalClassTransition &t, uint = 0); -struct InternalClass { +struct InternalClass : public QQmlJS::Managed { ExecutionEngine *engine; Object *prototype; const ManagedVTable *vtable; @@ -247,7 +248,6 @@ struct InternalClass { InternalClass *frozen(); void destroy(); - void markObjects(); private: InternalClass *addMemberImpl(String *string, PropertyAttributes data, uint *index); @@ -256,6 +256,11 @@ private: InternalClass(const InternalClass &other); }; +struct InternalClassPool : public QQmlJS::MemoryPool +{ + void markObjects(ExecutionEngine *engine); +}; + } QT_END_NAMESPACE -- cgit v1.2.3 From d59c6238abffb5a53342e4e4a23f122b135812e3 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Tue, 29 Apr 2014 12:13:08 +0200 Subject: v4: assert when an unsupported double value is stored in a value we assume that just few NaN values can be generated by the HW (currently 0x7ff800..00 and 0x7ffc00..00), and we use the other values to encode js values. If uninitialized memory is interpreted as double or another NaN is explicitly constructed and feed to the interpreter, it might crash (later when actually accessing that value). Adding an assertion to catch those values when assertions are active for the 32 bit encoding (64 bit already has it). Task-number: QTBUG-36859 Change-Id: I7ac7b2619f286ba19066729836af718014a515a6 Reviewed-by: Johannes Matokic Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4value_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 2c780622dc..3f83d7b25e 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -241,8 +241,8 @@ struct Q_QML_PRIVATE_EXPORT Value static inline bool bothDouble(Value a, Value b) { return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask; } - double doubleValue() const { return dbl; } - void setDouble(double d) { dbl = d; } + double doubleValue() const { Q_ASSERT(isDouble()); return dbl; } + void setDouble(double d) { dbl = d; Q_ASSERT(isDouble()); } bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; } #endif inline bool isString() const; -- cgit v1.2.3 From 7ea1f75fd877f312d70a90ab0405f3ca03914171 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Wed, 16 Apr 2014 00:42:40 +0200 Subject: v4: ignore quiet bit for NaNs in 32 bit value encoding on iOS x % 0 generates a NaN with the silent bit set, i.e. 0x7ffc_0000_0000_0000 which was interpreted as a null managed object which crashed the interpreter. Task-number: QTBUG-36859 Change-Id: Idf31ad9f0454f83d321b49b2f76bdbc2ee906189 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4value_p.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 3f83d7b25e..29cb8b42ed 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -119,20 +119,21 @@ struct Q_QML_PRIVATE_EXPORT Value #if QT_POINTER_SIZE == 4 enum Masks { - NaN_Mask = 0x7ff80000, - NotDouble_Mask = 0x7ffc0000, - Type_Mask = 0xffff8000, - Immediate_Mask = NotDouble_Mask | 0x00008000, - IsNullOrUndefined_Mask = Immediate_Mask | 0x20000, + SilentNaNBit = 0x00040000, + NaN_Mask = 0x7ff80000, + NotDouble_Mask = 0x7ffa0000, + Type_Mask = 0xffffc000, + Immediate_Mask = NotDouble_Mask | 0x00004000 | SilentNaNBit, + IsNullOrUndefined_Mask = Immediate_Mask | 0x08000, Tag_Shift = 32 }; enum ValueType { Undefined_Type = Immediate_Mask | 0x00000, - Null_Type = Immediate_Mask | 0x10000, - Boolean_Type = Immediate_Mask | 0x20000, - Integer_Type = Immediate_Mask | 0x30000, - Managed_Type = NotDouble_Mask | 0x00000, - Empty_Type = NotDouble_Mask | 0x30000 + Null_Type = Immediate_Mask | 0x10000, + Boolean_Type = Immediate_Mask | 0x08000, + Integer_Type = Immediate_Mask | 0x18000, + Managed_Type = NotDouble_Mask | 0x00000 | SilentNaNBit, + Empty_Type = NotDouble_Mask | 0x18000 | SilentNaNBit }; enum ImmediateFlags { -- cgit v1.2.3