diff options
author | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2016-05-12 11:17:52 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2016-05-12 11:17:52 +0200 |
commit | c49baa34d710b94d451d3f1165a442d3cb080ad8 (patch) | |
tree | d51a38beee14615e22c98e2277f793c9908412fa /src/qml | |
parent | 2b9693bfa5241c96a0b20861d9700fc5e0b826df (diff) | |
parent | 6bed1d55b38effa5ccee69423c104dfad374b484 (diff) |
Merge 5.6 into 5.6.1
Change-Id: If83c0d59fccf0620446a5da8d271a5037c9be106
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 109 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 33 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 7 |
4 files changed, 41 insertions, 114 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 2560f065cf..49b6dce697 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -105,84 +105,6 @@ static ReturnedValue throwTypeError(CallContext *ctx) return ctx->engine()->throwTypeError(); } -const int MinimumStackSize = 256; // in kbytes - -QT_WARNING_PUSH -QT_WARNING_DISABLE_MSVC(4172) // MSVC 2015: warning C4172: returning address of local variable or temporary: dummy - -quintptr getStackLimit() -{ - quintptr stackLimit; -#if USE(PTHREADS) && !OS(QNX) -# if OS(DARWIN) - pthread_t thread_self = pthread_self(); - void *stackTop = pthread_get_stackaddr_np(thread_self); - stackLimit = reinterpret_cast<quintptr>(stackTop); - quintptr size = 0; - if (pthread_main_np()) { - rlimit limit; - getrlimit(RLIMIT_STACK, &limit); - size = limit.rlim_cur; - } else - size = pthread_get_stacksize_np(thread_self); - stackLimit -= size; -# elif defined(__hppa) - // On some architectures the stack grows upwards. All of these are rather exotic, so simply assume - // everything is fine there. - // Known examples: - // -HP PA-RISC - stackLimit = 0; - -# else - pthread_attr_t attr; -#if HAVE(PTHREAD_NP_H) && OS(FREEBSD) - // on FreeBSD pthread_attr_init() must be called otherwise getting the attrs crashes - if (pthread_attr_init(&attr) == 0 && pthread_attr_get_np(pthread_self(), &attr) == 0) { -#else - if (pthread_getattr_np(pthread_self(), &attr) == 0) { -#endif - void *stackBottom = Q_NULLPTR; - size_t stackSize = 0; - - pthread_attr_getstack(&attr, &stackBottom, &stackSize); - pthread_attr_destroy(&attr); - -# if defined(Q_OS_ANDROID) - // Bionic pretends that the main thread has a tiny stack; work around it - if (gettid() == getpid()) { - rlimit limit; - getrlimit(RLIMIT_STACK, &limit); - stackBottom = reinterpret_cast<void*>(reinterpret_cast<quintptr>(stackBottom) + stackSize - limit.rlim_cur); - } -# endif - - stackLimit = reinterpret_cast<quintptr>(stackBottom); - } else { - int dummy; - // this is inexact, as part of the stack is used when being called here, - // but let's simply default to 1MB from where the stack is right now - stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024; - } - -# endif -// This is wrong. StackLimit is the currently committed stack size, not the real end. -// only way to get that limit is apparently by using VirtualQuery (Yuck) -//#elif OS(WINDOWS) -// PNT_TIB tib = (PNT_TIB)NtCurrentTeb(); -// stackLimit = static_cast<quintptr>(tib->StackLimit); -#else - int dummy; - // this is inexact, as part of the stack is used when being called here, - // but let's simply default to 1MB from where the stack is right now - // (Note: triggers warning C4172 as of MSVC 2015, returning address of local variable) - stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024; -#endif - - // 256k slack - return stackLimit + MinimumStackSize*1024; -} - -QT_WARNING_POP QJSEngine *ExecutionEngine::jsEngine() const { @@ -194,9 +116,12 @@ QQmlEngine *ExecutionEngine::qmlEngine() const return v8Engine->engine(); } +qint32 ExecutionEngine::maxCallDepth = -1; + ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : current(0) , hasException(false) + , callDepth(0) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -213,6 +138,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , regExpCache(0) , m_multiplyWrappedQObjects(0) { + if (maxCallDepth == -1) { + bool ok = false; + maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok); + if (!ok || maxCallDepth <= 0) { + maxCallDepth = 1234; + } + } + Q_ASSERT(maxCallDepth > 0); + MemoryManager::GCBlocker gcBlocker(memoryManager); if (!factory) { @@ -251,9 +185,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // set up stack limits jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value); - cStackLimit = getStackLimit(); - if (!recheckCStackLimits()) - qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize); identifierTable = new IdentifierTable(this); @@ -1117,22 +1048,6 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError() return error; } -bool ExecutionEngine::recheckCStackLimits() -{ - int dummy; -#ifdef Q_OS_WIN - // ### this is only required on windows, where we currently use heuristics to get the stack limit - if (cStackLimit - reinterpret_cast<quintptr>(&dummy) > 128*1024) - // we're more then 128k away from our stack limit, assume the thread has changed, and - // call getStackLimit -#endif - // this can happen after a thread change - cStackLimit = getStackLimit(); - - return (reinterpret_cast<quintptr>(&dummy) >= cStackLimit); -} - - // Variant conversion code typedef QSet<QV4::Heap::Object *> V4ObjectSet; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 4640f3f4cc..7fc880023f 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -75,15 +75,11 @@ namespace CompiledData { struct CompilationUnit; } -#define CHECK_STACK_LIMITS(v4) \ - if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \ - else \ - return v4->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) - - struct Q_QML_EXPORT ExecutionEngine { private: + static qint32 maxCallDepth; + friend struct ExecutionContextSaver; friend struct ExecutionContext; friend struct Heap::ExecutionContext; @@ -92,6 +88,7 @@ public: Value *jsStackTop; quint32 hasException; + qint32 callDepth; MemoryManager *memoryManager; ExecutableAllocator *executableAllocator; @@ -101,7 +98,6 @@ public: ExecutionContext *currentContext; Value *jsStackLimit; - quintptr cStackLimit; WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. @@ -431,8 +427,6 @@ public: InternalClass *newClass(const InternalClass &other); - bool recheckCStackLimits(); - // Exception handling Value *exceptionValue; StackTrace exceptionStackTrace; @@ -465,6 +459,8 @@ public: QV4::ReturnedValue metaTypeToJS(int type, const void *data); void assertObjectBelongsToEngine(const Heap::Base &baseObject); + + bool checkStackLimits(ReturnedValue &exception); }; inline void ExecutionEngine::pushContext(Heap::ExecutionContext *context) @@ -517,7 +513,26 @@ inline void Value::mark(ExecutionEngine *e) o->mark(e); } +#define CHECK_STACK_LIMITS(v4) { ReturnedValue e; if ((v4)->checkStackLimits(e)) return e; } \ + ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); + +struct ExecutionEngineCallDepthRecorder +{ + ExecutionEngine *ee; + ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; } + ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; } +}; + +inline bool ExecutionEngine::checkStackLimits(ReturnedValue &exception) +{ + if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) { + exception = throwRangeError(QStringLiteral("Maximum call stack size exceeded.")); + return true; + } + + return false; +} } // namespace QV4 diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 723afcab54..6bd39355c5 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -50,11 +50,7 @@ #include "qv4global_p.h" #include <private/qv4heap_p.h> -/* We cannot rely on QT_POINTER_SIZE to be set correctly on host builds. In qmldevtools the Value objects - are only used to store primitives, never object pointers. So we can use the 64-bit encoding. */ -#ifdef V4_BOOTSTRAP -#define QV4_USE_64_BIT_VALUE_ENCODING -#elif QT_POINTER_SIZE == 8 +#if QT_POINTER_SIZE == 8 #define QV4_USE_64_BIT_VALUE_ENCODING #endif diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index e85b3dc82c..aed5f5af35 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -665,9 +665,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * } else { QV4::MemberData *md = propertiesAsMemberData(); if (md) { - QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); - if (v) - QQml_valueTypeProvider()->readValueType(v->d()->data, a[0], t); + QVariant propertyAsVariant; + if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) + propertyAsVariant = v->d()->data; + QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], t); } } break; |