From 6cbc287c06dd61988f2d4f4de253d89103919d2e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 25 May 2018 09:03:51 +0200 Subject: Cleanup JS stack allocations Avoid double writes to the stack, and use scope.alloc() for most allocations on the stack. Change-Id: I8b89273c1b6796d955fc8eeb72c67cff208ef786 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 1 + src/qml/jsruntime/qv4engine_p.h | 2 - src/qml/jsruntime/qv4functionobject.cpp | 2 +- src/qml/jsruntime/qv4jscall_p.h | 5 +-- src/qml/jsruntime/qv4objectiterator_p.h | 4 +- src/qml/jsruntime/qv4scopedvalue_p.h | 73 +++++++++++++++++++++++++-------- src/qml/qml/qqmlobjectcreator.cpp | 6 +-- 8 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 59b88c3160..78cca8d525 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -110,7 +110,7 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame) uint nLocals = compiledFunction->nLocals; c->locals.size = nLocals; c->locals.alloc = localsAndFormals; - // memory allocated from the JS heap is 0 initialized, so check if undefined is 0 + // memory allocated from the JS heap is 0 initialized, so check if empty is 0 Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0); Value *args = c->locals.values + nLocals; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index acc650f9f5..fbe9db7075 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -193,6 +193,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) } exceptionValue = jsAlloca(1); + *exceptionValue = Encode::undefined(); globalObject = static_cast(jsAlloca(1)); jsObjects = jsAlloca(NJSObjects); typedArrayPrototype = static_cast(jsAlloca(NTypedArrayTypes)); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 86421c2ddc..9206fdc0bb 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -142,8 +142,6 @@ public: QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { Value *ptr = jsStackTop; jsStackTop = ptr + nValues; - for (int i = 0; i < nValues; ++i) - ptr[i] = Primitive::undefinedValue(); return ptr; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 78419719f0..e95f5108a9 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -344,7 +344,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons uint len = arr->getLength(); Scope scope(v4); - Value *arguments = v4->jsAlloca(len); + Value *arguments = scope.alloc(len); if (len) { if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast()->fullyCreated()) { QV4::ArgumentsObject *a = arr->cast(); diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h index c676b57c51..e186285025 100644 --- a/src/qml/jsruntime/qv4jscall_p.h +++ b/src/qml/jsruntime/qv4jscall_p.h @@ -67,7 +67,7 @@ struct JSCallData { if (thisObject) this->thisObject = const_cast(thisObject); else - this->thisObject = scope.alloc(1); + this->thisObject = scope.alloc(); if (argv) this->args = const_cast(argv); else @@ -80,8 +80,7 @@ struct JSCallData { CallData *callData(const FunctionObject *f = nullptr) const { int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc; - CallData *ptr = reinterpret_cast(scope.engine->jsStackTop); - scope.engine->jsStackTop += size; + CallData *ptr = reinterpret_cast(scope.alloc(size)); ptr->function = Encode::undefined(); ptr->context = Encode::undefined(); ptr->accumulator = Encode::undefined(); diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 462bd9a114..1e7000ad1f 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -92,8 +92,8 @@ struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData ObjectIterator(Scope &scope, const Object *o, uint flags) { engine = scope.engine; - object = scope.alloc(1); - current = scope.alloc(1); + object = scope.alloc(); + current = scope.alloc(); arrayNode = nullptr; arrayIndex = 0; memberIndex = 0; diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index bb20f384b3..73ee17cd40 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -117,8 +117,45 @@ struct Scope { engine->jsStackTop = mark; } - QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const { - return engine->jsAlloca(nValues); + enum AllocMode { + Undefined, + Empty, + /* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */ + Uninitialized + }; + template + QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const + { + Value *ptr = engine->jsAlloca(nValues); + switch (mode) { + case Undefined: + for (int i = 0; i < nValues; ++i) + ptr[i] = Primitive::undefinedValue(); + break; + case Empty: + for (int i = 0; i < nValues; ++i) + ptr[i] = Primitive::emptyValue(); + break; + case Uninitialized: + break; + } + return ptr; + } + template + QML_NEARLY_ALWAYS_INLINE Value *alloc() const + { + Value *ptr = engine->jsAlloca(1); + switch (mode) { + case Undefined: + *ptr = Primitive::undefinedValue(); + break; + case Empty: + *ptr = Primitive::emptyValue(); + break; + case Uninitialized: + break; + } + return ptr; } bool hasException() const { @@ -136,31 +173,31 @@ struct ScopedValue { ScopedValue(const Scope &scope) { - ptr = scope.engine->jsStackTop++; + ptr = scope.alloc(); ptr->setRawValue(0); } ScopedValue(const Scope &scope, const Value &v) { - ptr = scope.engine->jsStackTop++; + ptr = scope.alloc(); *ptr = v; } ScopedValue(const Scope &scope, Heap::Base *o) { - ptr = scope.engine->jsStackTop++; + ptr = scope.alloc(); ptr->setM(o); } ScopedValue(const Scope &scope, Managed *m) { - ptr = scope.engine->jsStackTop++; + ptr = scope.alloc(); ptr->setRawValue(m->asReturnedValue()); } ScopedValue(const Scope &scope, const ReturnedValue &v) { - ptr = scope.engine->jsStackTop++; + ptr = scope.alloc(); ptr->setRawValue(v); } @@ -214,66 +251,66 @@ struct Scoped QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(v.as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o) { Value v; v = o; - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(v.as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(v.ptr->as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); ptr->setRawValue(value_convert(scope.engine, v)); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(v ? v->as() : nullptr); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(t); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(t); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); *ptr = t; } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); setPointer(QV4::Value::fromReturnedValue(v).as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) { - ptr = scope.engine->jsAlloca(1); + ptr = scope.alloc(); ptr->setRawValue(value_convert(scope.engine, QV4::Value::fromReturnedValue(v))); } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index bec9c9840f..f6f18ab35f 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -252,7 +252,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData:: Q_ASSERT(!sharedState->allJavaScriptObjects); sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); - QV4::QmlContext *qmlContext = static_cast(valueScope.alloc(1)); + QV4::QmlContext *qmlContext = static_cast(valueScope.alloc()); qSwap(_qmlContext, qmlContext); @@ -312,7 +312,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, if (!sharedState->allJavaScriptObjects) sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); - QV4::QmlContext *qmlContext = static_cast(valueScope.alloc(1)); + QV4::QmlContext *qmlContext = static_cast(valueScope.alloc()); qSwap(_qmlContext, qmlContext); @@ -1292,7 +1292,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo ++sharedState->allJavaScriptObjects; QV4::Scope valueScope(v4); - QV4::QmlContext *qmlContext = static_cast(valueScope.alloc(1)); + QV4::QmlContext *qmlContext = static_cast(valueScope.alloc()); qSwap(_qmlContext, qmlContext); -- cgit v1.2.3