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 <simon.hausmann@qt.io>
This commit is contained in:
parent
9ff4c5c216
commit
6cbc287c06
|
@ -110,7 +110,7 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
|
||||||
uint nLocals = compiledFunction->nLocals;
|
uint nLocals = compiledFunction->nLocals;
|
||||||
c->locals.size = nLocals;
|
c->locals.size = nLocals;
|
||||||
c->locals.alloc = localsAndFormals;
|
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);
|
Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0);
|
||||||
|
|
||||||
Value *args = c->locals.values + nLocals;
|
Value *args = c->locals.values + nLocals;
|
||||||
|
|
|
@ -193,6 +193,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
|
||||||
}
|
}
|
||||||
|
|
||||||
exceptionValue = jsAlloca(1);
|
exceptionValue = jsAlloca(1);
|
||||||
|
*exceptionValue = Encode::undefined();
|
||||||
globalObject = static_cast<Object *>(jsAlloca(1));
|
globalObject = static_cast<Object *>(jsAlloca(1));
|
||||||
jsObjects = jsAlloca(NJSObjects);
|
jsObjects = jsAlloca(NJSObjects);
|
||||||
typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes));
|
typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes));
|
||||||
|
|
|
@ -142,8 +142,6 @@ public:
|
||||||
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
|
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
|
||||||
Value *ptr = jsStackTop;
|
Value *ptr = jsStackTop;
|
||||||
jsStackTop = ptr + nValues;
|
jsStackTop = ptr + nValues;
|
||||||
for (int i = 0; i < nValues; ++i)
|
|
||||||
ptr[i] = Primitive::undefinedValue();
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -344,7 +344,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
|
||||||
uint len = arr->getLength();
|
uint len = arr->getLength();
|
||||||
|
|
||||||
Scope scope(v4);
|
Scope scope(v4);
|
||||||
Value *arguments = v4->jsAlloca(len);
|
Value *arguments = scope.alloc(len);
|
||||||
if (len) {
|
if (len) {
|
||||||
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
|
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
|
||||||
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
|
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct JSCallData {
|
||||||
if (thisObject)
|
if (thisObject)
|
||||||
this->thisObject = const_cast<Value *>(thisObject);
|
this->thisObject = const_cast<Value *>(thisObject);
|
||||||
else
|
else
|
||||||
this->thisObject = scope.alloc(1);
|
this->thisObject = scope.alloc();
|
||||||
if (argv)
|
if (argv)
|
||||||
this->args = const_cast<Value *>(argv);
|
this->args = const_cast<Value *>(argv);
|
||||||
else
|
else
|
||||||
|
@ -80,8 +80,7 @@ struct JSCallData {
|
||||||
|
|
||||||
CallData *callData(const FunctionObject *f = nullptr) const {
|
CallData *callData(const FunctionObject *f = nullptr) const {
|
||||||
int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
|
int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
|
||||||
CallData *ptr = reinterpret_cast<CallData *>(scope.engine->jsStackTop);
|
CallData *ptr = reinterpret_cast<CallData *>(scope.alloc<Scope::Uninitialized>(size));
|
||||||
scope.engine->jsStackTop += size;
|
|
||||||
ptr->function = Encode::undefined();
|
ptr->function = Encode::undefined();
|
||||||
ptr->context = Encode::undefined();
|
ptr->context = Encode::undefined();
|
||||||
ptr->accumulator = Encode::undefined();
|
ptr->accumulator = Encode::undefined();
|
||||||
|
|
|
@ -92,8 +92,8 @@ struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData
|
||||||
ObjectIterator(Scope &scope, const Object *o, uint flags)
|
ObjectIterator(Scope &scope, const Object *o, uint flags)
|
||||||
{
|
{
|
||||||
engine = scope.engine;
|
engine = scope.engine;
|
||||||
object = scope.alloc(1);
|
object = scope.alloc();
|
||||||
current = scope.alloc(1);
|
current = scope.alloc();
|
||||||
arrayNode = nullptr;
|
arrayNode = nullptr;
|
||||||
arrayIndex = 0;
|
arrayIndex = 0;
|
||||||
memberIndex = 0;
|
memberIndex = 0;
|
||||||
|
|
|
@ -117,8 +117,45 @@ struct Scope {
|
||||||
engine->jsStackTop = mark;
|
engine->jsStackTop = mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const {
|
enum AllocMode {
|
||||||
return engine->jsAlloca(nValues);
|
Undefined,
|
||||||
|
Empty,
|
||||||
|
/* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */
|
||||||
|
Uninitialized
|
||||||
|
};
|
||||||
|
template <AllocMode mode = Undefined>
|
||||||
|
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 <AllocMode mode = Undefined>
|
||||||
|
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 {
|
bool hasException() const {
|
||||||
|
@ -136,31 +173,31 @@ struct ScopedValue
|
||||||
{
|
{
|
||||||
ScopedValue(const Scope &scope)
|
ScopedValue(const Scope &scope)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsStackTop++;
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
ptr->setRawValue(0);
|
ptr->setRawValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedValue(const Scope &scope, const Value &v)
|
ScopedValue(const Scope &scope, const Value &v)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsStackTop++;
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
*ptr = v;
|
*ptr = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedValue(const Scope &scope, Heap::Base *o)
|
ScopedValue(const Scope &scope, Heap::Base *o)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsStackTop++;
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
ptr->setM(o);
|
ptr->setM(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedValue(const Scope &scope, Managed *m)
|
ScopedValue(const Scope &scope, Managed *m)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsStackTop++;
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
ptr->setRawValue(m->asReturnedValue());
|
ptr->setRawValue(m->asReturnedValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedValue(const Scope &scope, const ReturnedValue &v)
|
ScopedValue(const Scope &scope, const ReturnedValue &v)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsStackTop++;
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
ptr->setRawValue(v);
|
ptr->setRawValue(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,66 +251,66 @@ struct Scoped
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Undefined>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(v.as<T>());
|
setPointer(v.as<T>());
|
||||||
}
|
}
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o)
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
v = o;
|
v = o;
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(v.as<T>());
|
setPointer(v.as<T>());
|
||||||
}
|
}
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(v.ptr->as<T>());
|
setPointer(v.ptr->as<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
ptr->setRawValue(value_convert<T>(scope.engine, v));
|
ptr->setRawValue(value_convert<T>(scope.engine, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(v ? v->as<T>() : nullptr);
|
setPointer(v ? v->as<T>() : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(t);
|
setPointer(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(t);
|
setPointer(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
*ptr = t;
|
*ptr = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
setPointer(QV4::Value::fromReturnedValue(v).as<T>());
|
setPointer(QV4::Value::fromReturnedValue(v).as<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
|
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
|
||||||
{
|
{
|
||||||
ptr = scope.engine->jsAlloca(1);
|
ptr = scope.alloc<Scope::Uninitialized>();
|
||||||
ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)));
|
ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::
|
||||||
Q_ASSERT(!sharedState->allJavaScriptObjects);
|
Q_ASSERT(!sharedState->allJavaScriptObjects);
|
||||||
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
|
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
|
||||||
|
|
||||||
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
|
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
|
||||||
|
|
||||||
qSwap(_qmlContext, qmlContext);
|
qSwap(_qmlContext, qmlContext);
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
|
||||||
if (!sharedState->allJavaScriptObjects)
|
if (!sharedState->allJavaScriptObjects)
|
||||||
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
|
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
|
||||||
|
|
||||||
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
|
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
|
||||||
|
|
||||||
qSwap(_qmlContext, qmlContext);
|
qSwap(_qmlContext, qmlContext);
|
||||||
|
|
||||||
|
@ -1292,7 +1292,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
|
||||||
++sharedState->allJavaScriptObjects;
|
++sharedState->allJavaScriptObjects;
|
||||||
|
|
||||||
QV4::Scope valueScope(v4);
|
QV4::Scope valueScope(v4);
|
||||||
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
|
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
|
||||||
|
|
||||||
qSwap(_qmlContext, qmlContext);
|
qSwap(_qmlContext, qmlContext);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue