From 9da722e2a73afe0cc28328580ba53b2d77fc6ba4 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 3 Apr 2013 15:59:17 +0200 Subject: Speed up Context creation and handling Creating context and locals in two mallocs wasn't very good for performance. This allocates them in one go again, while still managing them through the garbage collector. This brings performance up by around 20%. Change-Id: I9b31d669e1a502c90a117bacf5fee5d23e9821b4 Reviewed-by: Simon Hausmann --- src/v4/qv4argumentsobject.cpp | 1 + src/v4/qv4context.cpp | 132 ++++++++++++++---------------------------- src/v4/qv4context.h | 39 ++++--------- src/v4/qv4engine.cpp | 29 +++++----- src/v4/qv4managed.h | 1 - src/v4/qv4mm.cpp | 17 +++++- src/v4/qv4mm.h | 14 +++++ 7 files changed, 101 insertions(+), 132 deletions(-) diff --git a/src/v4/qv4argumentsobject.cpp b/src/v4/qv4argumentsobject.cpp index 7667aaac..b891d029 100644 --- a/src/v4/qv4argumentsobject.cpp +++ b/src/v4/qv4argumentsobject.cpp @@ -168,6 +168,7 @@ Value ArgumentsSetterFunction::call(Managed *setter, ExecutionContext *ctx, cons void ArgumentsObject::markObjects(Managed *that) { ArgumentsObject *o = static_cast(that); + o->context->mark(); for (int i = 0; i < o->mappedArguments.size(); ++i) { Managed *m = o->mappedArguments.at(i).asManaged(); if (m) diff --git a/src/v4/qv4context.cpp b/src/v4/qv4context.cpp index 41b0b2ac..51a80f4a 100644 --- a/src/v4/qv4context.cpp +++ b/src/v4/qv4context.cpp @@ -79,8 +79,6 @@ String *DiagnosticMessage::buildFullMessage(ExecutionContext *ctx) const return ctx->engine->newString(msg); } -DEFINE_MANAGED_VTABLE(ExecutionContext); - void ExecutionContext::createMutableBinding(String *name, bool deletable) { if (!activation) @@ -177,6 +175,7 @@ unsigned int ExecutionContext::variableCount() const void ExecutionContext::init(ExecutionEngine *eng) { + marked = false; engine = eng; outer = 0; thisObject = eng->globalObject; @@ -184,6 +183,7 @@ void ExecutionContext::init(ExecutionEngine *eng) function = 0; lookups = 0; + locals = 0; arguments = 0; argumentCount = 0; locals = 0; @@ -197,6 +197,7 @@ void ExecutionContext::init(ExecutionEngine *eng) void ExecutionContext::init(ExecutionContext *p, Object *with) { + marked = false; engine = p->engine; outer = p; thisObject = p->thisObject; @@ -204,6 +205,7 @@ void ExecutionContext::init(ExecutionContext *p, Object *with) function = 0; lookups = p->lookups; + locals = 0; arguments = 0; argumentCount = 0; locals = 0; @@ -217,6 +219,7 @@ void ExecutionContext::init(ExecutionContext *p, Object *with) void ExecutionContext::initForCatch(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue) { + marked = false; engine = p->engine; outer = p; thisObject = p->thisObject; @@ -269,76 +272,29 @@ bool ExecutionContext::needsOwnArguments() const return function && (function->needsActivation || argumentCount < function->formalParameterCount); } -void ExecutionContext::destroy(Managed *that) -{ - ExecutionContext *ctx = static_cast(that); - if (ctx->locals) - delete [] ctx->locals; - ctx->_data = 0; - ctx->vtbl = 0; -} - -void ExecutionContext::markObjects(Managed *that) -{ - ExecutionContext *ctx = static_cast(that); - ctx->thisObject.mark(); - if (ctx->function) - ctx->function->mark(); - for (unsigned arg = 0, lastArg = ctx->argumentCount; arg < lastArg; ++arg) - ctx->arguments[arg].mark(); - for (unsigned local = 0, lastLocal = ctx->variableCount(); local < lastLocal; ++local) - ctx->locals[local].mark(); - if (ctx->activation) - ctx->activation->mark(); - if (ctx->withObject) - ctx->withObject->mark(); - if (ctx->exceptionVarName) - ctx->exceptionVarName->mark(); - ctx->exceptionValue.mark(); -} - -Value ExecutionContext::get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty) -{ - Q_UNIMPLEMENTED(); - Q_UNREACHABLE(); -} - -Value ExecutionContext::getIndexed(Managed *m, ExecutionContext *ctx, uint index, bool *hasProperty) -{ - Q_UNIMPLEMENTED(); - Q_UNREACHABLE(); -} - -void ExecutionContext::put(Managed *m, ExecutionContext *ctx, String *name, const Value &value) -{ -} - -void ExecutionContext::putIndexed(Managed *m, ExecutionContext *ctx, uint index, const Value &value) +void ExecutionContext::mark() { -} - -PropertyFlags ExecutionContext::query(Managed *m, ExecutionContext *ctx, String *name) -{ - Q_UNIMPLEMENTED(); - Q_UNREACHABLE(); -} - -PropertyFlags ExecutionContext::queryIndexed(Managed *m, ExecutionContext *ctx, uint index) -{ - Q_UNIMPLEMENTED(); - Q_UNREACHABLE(); -} - -bool ExecutionContext::deleteProperty(Managed *m, ExecutionContext *ctx, String *name) -{ - Q_UNIMPLEMENTED(); - Q_UNREACHABLE(); -} - -bool ExecutionContext::deleteIndexedProperty(Managed *m, ExecutionContext *ctx, uint index) -{ - Q_UNIMPLEMENTED(); - Q_UNREACHABLE(); + if (marked) + return; + marked = true; + + if (outer) + outer->mark(); + + thisObject.mark(); + if (function) + function->mark(); + for (unsigned arg = 0, lastArg = argumentCount; arg < lastArg; ++arg) + arguments[arg].mark(); + for (unsigned local = 0, lastLocal = variableCount(); local < lastLocal; ++local) + locals[local].mark(); + if (activation) + activation->mark(); + if (withObject) + withObject->mark(); + if (exceptionVarName) + exceptionVarName->mark(); + exceptionValue.mark(); } void ExecutionContext::setProperty(String *name, const Value& value) @@ -583,6 +539,7 @@ void ExecutionContext::throwURIError(Value msg) void ExecutionContext::initCallContext(ExecutionEngine *engine) { + marked = false; this->engine = engine; outer = function->scope; @@ -599,27 +556,22 @@ void ExecutionContext::initCallContext(ExecutionEngine *engine) lookups = function->function->lookups; uint argc = argumentCount; - uint valuesToAlloc = function->varCount; - bool copyArgs = needsOwnArguments(); - if (copyArgs) - valuesToAlloc += qMax(argc, function->formalParameterCount); - - if (valuesToAlloc) { - locals = new Value[valuesToAlloc]; - if (function->varCount) - std::fill(locals, locals + function->varCount, Value::undefinedValue()); - - if (copyArgs) { - Value *args = arguments; - argumentCount = qMax(argc, function->formalParameterCount); - arguments = locals + function->varCount; - if (argc) - ::memcpy(arguments, args, argc * sizeof(Value)); - if (argc < function->formalParameterCount) - std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue()); - } + locals = (Value *)(this + 1); + if (function->varCount) + std::fill(locals, locals + function->varCount, Value::undefinedValue()); + + if (needsOwnArguments()) { + Value *args = arguments; + argumentCount = qMax(argc, function->formalParameterCount); + arguments = locals + function->varCount; + if (argc) + ::memcpy(arguments, args, argc * sizeof(Value)); + if (argc < function->formalParameterCount) + std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue()); + } + if (function->usesArgumentsObject) { ArgumentsObject *args = new (engine->memoryManager) ArgumentsObject(this, function->formalParameterCount, argc); args->prototype = engine->objectPrototype; diff --git a/src/v4/qv4context.h b/src/v4/qv4context.h index 35c586f2..d2b05bbf 100644 --- a/src/v4/qv4context.h +++ b/src/v4/qv4context.h @@ -43,7 +43,6 @@ #include "qv4global.h" #include -#include "qv4managed.h" QT_BEGIN_NAMESPACE @@ -53,7 +52,6 @@ namespace VM { struct Value; struct Object; struct ExecutionEngine; -struct ExecutionContext; struct DeclarativeEnvironment; struct Lookup; @@ -75,8 +73,9 @@ struct Q_V4_EXPORT DiagnosticMessage String *buildFullMessage(ExecutionContext *ctx) const; }; -struct ExecutionContext : public Managed +struct ExecutionContext { + ExecutionContext *next; // used in the GC ExecutionEngine *engine; ExecutionContext *outer; Value thisObject; @@ -91,33 +90,28 @@ struct ExecutionContext : public Managed String *exceptionVarName; Value exceptionValue; - String * const *formals() const; - unsigned int formalCount() const; - String * const *variables() const; - unsigned int variableCount() const; - bool strictMode; bool qmlObject; // ## temporary until we do proper QML contexts + bool marked; Object *activation; Object *withObject; - ExecutionContext() - : Managed() - , locals(0) - { vtbl = &static_vtbl; } + String * const *formals() const; + unsigned int formalCount() const; + String * const *variables() const; + unsigned int variableCount() const; void init(ExecutionEngine *e); void init(ExecutionContext *p, Object *with); void initForCatch(ExecutionContext *p, String *exceptionVarName, const QQmlJS::VM::Value &exceptionValue); + void initCallContext(QQmlJS::VM::ExecutionEngine *engine); void createMutableBinding(String *name, bool deletable); bool setMutableBinding(ExecutionContext *scope, String *name, const Value &value); Value getBindingValue(ExecutionContext *scope, String *name, bool strict) const; bool deleteBinding(ExecutionContext *ctx, String *name); - void initCallContext(QQmlJS::VM::ExecutionEngine *engine); - void wireUpPrototype(); void Q_NORETURN throwError(const Value &value); @@ -145,21 +139,12 @@ struct ExecutionContext : public Managed bool needsOwnArguments() const; -protected: - static void destroy(Managed *that); - static void markObjects(Managed *that); - static Value get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty); - static Value getIndexed(Managed *m, ExecutionContext *ctx, uint index, bool *hasProperty); - static void put(Managed *m, ExecutionContext *ctx, String *name, const Value &value); - static void putIndexed(Managed *m, ExecutionContext *ctx, uint index, const Value &value); - static PropertyFlags query(Managed *m, ExecutionContext *ctx, String *name); - static PropertyFlags queryIndexed(Managed *m, ExecutionContext *ctx, uint index); - static bool deleteProperty(Managed *m, ExecutionContext *ctx, String *name); - static bool deleteIndexedProperty(Managed *m, ExecutionContext *ctx, uint index); - - static const ManagedVTable static_vtbl; + void mark(); }; +/* Function *f, int argc */ +#define requiredMemoryForExecutionContect(f, argc) \ + sizeof(ExecutionContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) } // namespace VM } // namespace QQmlJS diff --git a/src/v4/qv4engine.cpp b/src/v4/qv4engine.cpp index f7c0098c..d944de80 100644 --- a/src/v4/qv4engine.cpp +++ b/src/v4/qv4engine.cpp @@ -243,7 +243,6 @@ ExecutionEngine::~ExecutionEngine() { delete regExpCache; delete globalObject.asObject(); - delete rootContext; delete [] contextStack; UnwindHelper::deregisterFunctions(functions); qDeleteAll(functions); @@ -254,10 +253,10 @@ ExecutionEngine::~ExecutionEngine() void ExecutionEngine::initRootContext() { ensureContextStackSize(); - rootContext = new (memoryManager) ExecutionContext(); - rootContext->init(this); + rootContext = memoryManager->allocContext(sizeof(ExecutionContext)); current = rootContext; contextStack[0] = rootContext; + current->init(this); } void ExecutionEngine::ensureContextStackSize() @@ -270,6 +269,7 @@ void ExecutionEngine::ensureContextStackSize() if (contextStack) memcpy(newStack, contextStack, contextStackSize*sizeof(ExecutionContext *)); memset(newStack + contextStackSize, 0, (stackSize - contextStackSize)*sizeof(ExecutionContext *)); + delete [] contextStack; contextStackSize = stackSize; contextStack = newStack; } @@ -279,11 +279,11 @@ ExecutionContext *ExecutionEngine::newWithContext(Object *with) ensureContextStackSize(); assert(contextStack[contextStackPosition + 1] == 0); - ExecutionContext *ctx = new (memoryManager) ExecutionContext(); - ctx->init(current, with); - current = ctx; - + ExecutionContext *c = current; + current = memoryManager->allocContext(sizeof(ExecutionContext)); contextStack[++contextStackPosition] = current; + + current->init(c, with); return current; } @@ -292,11 +292,11 @@ ExecutionContext *ExecutionEngine::newCatchContext(String *exceptionVarName, con ensureContextStackSize(); assert(contextStack[contextStackPosition + 1] == 0); - ExecutionContext *ctx = new (memoryManager) ExecutionContext(); - ctx->initForCatch(current, exceptionVarName, exceptionValue); - current = ctx; - + ExecutionContext *c = current; + current = memoryManager->allocContext(sizeof(ExecutionContext)); contextStack[++contextStackPosition] = current; + + current->initForCatch(c, exceptionVarName, exceptionValue); return current; } @@ -305,14 +305,15 @@ ExecutionContext *ExecutionEngine::newCallContext(FunctionObject *f, const Value ensureContextStackSize(); assert(contextStack[contextStackPosition + 1] == 0); - current = new (memoryManager) ExecutionContext(); + current = memoryManager->allocContext(requiredMemoryForExecutionContect(f, argc)); + contextStack[++contextStackPosition] = current; + current->function = f; current->thisObject = thisObject; current->arguments = args; current->argumentCount = argc; current->initCallContext(this); - contextStack[++contextStackPosition] = current; return current; } @@ -530,6 +531,8 @@ void ExecutionEngine::markObjects() pd.set->mark(); } + for (int i = 0; i <= contextStackPosition; ++i) + contextStack[i]->mark(); for (int i = 0; i < functions.size(); ++i) functions.at(i)->mark(); diff --git a/src/v4/qv4managed.h b/src/v4/qv4managed.h index a69adf36..264c92c1 100644 --- a/src/v4/qv4managed.h +++ b/src/v4/qv4managed.h @@ -236,7 +236,6 @@ protected: private: friend class MemoryManager; - friend struct ExecutionContext; friend struct Identifiers; }; diff --git a/src/v4/qv4mm.cpp b/src/v4/qv4mm.cpp index 26c26c04..0281aeca 100644 --- a/src/v4/qv4mm.cpp +++ b/src/v4/qv4mm.cpp @@ -128,7 +128,8 @@ bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::C } } // namespace QQmlJS::VM MemoryManager::MemoryManager() - : m_d(new Data(true)) + : m_d(new Data(true))\ + , m_contextList(0) { setEnableGC(true); #ifdef V4_USE_VALGRIND @@ -280,6 +281,20 @@ std::size_t MemoryManager::sweep() for (QVector::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) freedCount += sweep(reinterpret_cast(i->memory.base()), i->memory.size(), i->chunkSize); + ExecutionContext *ctx = m_contextList; + ExecutionContext **n = &m_contextList; + while (ctx) { + ExecutionContext *next = ctx->next; + if (!ctx->marked) { + free(ctx); + *n = next; + } else { + ctx->marked = false; + n = &ctx->next; + } + ctx = next; + } + return freedCount; } diff --git a/src/v4/qv4mm.h b/src/v4/qv4mm.h index fdde7615..a41df835 100644 --- a/src/v4/qv4mm.h +++ b/src/v4/qv4mm.h @@ -43,6 +43,7 @@ #define QV4GC_H #include "qv4global.h" +#include "qv4context.h" #include @@ -54,6 +55,7 @@ namespace QQmlJS { namespace VM { struct ExecutionEngine; +struct ExecutionContext; struct Managed; class Q_V4_EXPORT MemoryManager @@ -103,6 +105,8 @@ public: return o; } + ExecutionContext *allocContext(uint size); + bool isGCBlocked() const; void setGCBlocked(bool blockGC); void runGC(); @@ -131,8 +135,18 @@ private: protected: QScopedPointer m_d; + ExecutionContext *m_contextList; }; +inline ExecutionContext *MemoryManager::allocContext(uint size) +{ + ExecutionContext *newContext = (ExecutionContext *)malloc(size); + newContext->next = m_contextList; + m_contextList = newContext; + return newContext; +} + + } // namespace VM } // namespace QQmlJS -- cgit v1.2.3