diff options
author | Liang Qi <liang.qi@qt.io> | 2016-05-19 13:04:54 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-05-19 20:41:34 +0200 |
commit | 63ec33e79cf86c4312c58bea12a2aab400890c70 (patch) | |
tree | 5c9b5cd51276ea0a3ca42567666a09e70efa11cc /src/qml/jsruntime | |
parent | b9e4a4df577959579b2322fb6077bde82d9ffce3 (diff) | |
parent | afc84775efdc6e13e2e210bb94e115b378d90134 (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts:
src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
src/qml/jsruntime/qv4engine.cpp
src/qml/jsruntime/qv4engine_p.h
Change-Id: I89ffccd699bee675732758d039e22224b275d60d
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4context_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 109 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 35 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 6 |
4 files changed, 39 insertions, 113 deletions
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index f51f677636..2e6773a927 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -247,7 +247,7 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; -struct QmlContext : public ExecutionContext +struct Q_QML_EXPORT QmlContext : public ExecutionContext { V4_MANAGED(QmlContext, ExecutionContext) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index bc64bbfe06..b42dc37b0f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -111,84 +111,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 { @@ -200,9 +122,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) @@ -219,6 +144,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) { @@ -267,9 +201,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); @@ -1103,22 +1034,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 7da4a1c3c1..73d506c4d2 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -81,15 +81,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; @@ -98,6 +94,7 @@ public: Value *jsStackTop; quint32 hasException; + qint32 callDepth; MemoryManager *memoryManager; ExecutableAllocator *executableAllocator; @@ -107,7 +104,6 @@ public: ExecutionContext *currentContext; Value *jsStackLimit; - quintptr cStackLimit; WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. @@ -437,8 +433,6 @@ public: InternalClass *newClass(const InternalClass &other); - bool recheckCStackLimits(); - // Exception handling Value *exceptionValue; StackTrace exceptionStackTrace; @@ -471,6 +465,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) @@ -516,7 +512,7 @@ inline Heap::QmlContext *ExecutionEngine::qmlContext() const if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) ctx = parentContext(currentContext)->d(); - if (!ctx->outer) + if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) return 0; while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) @@ -552,7 +548,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 514bdafb48..a8d9b0fa71 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -56,11 +56,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 |