summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-04-03 15:59:17 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2013-04-03 19:55:03 +0200
commit9da722e2a73afe0cc28328580ba53b2d77fc6ba4 (patch)
tree3451493f8f3a229fe810bbf37cd03ac66a7a1b59
parent8fefb79a8d09fce5beeeca6e88573fd0278fbf52 (diff)
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 <simon.hausmann@digia.com>
-rw-r--r--src/v4/qv4argumentsobject.cpp1
-rw-r--r--src/v4/qv4context.cpp132
-rw-r--r--src/v4/qv4context.h39
-rw-r--r--src/v4/qv4engine.cpp29
-rw-r--r--src/v4/qv4managed.h1
-rw-r--r--src/v4/qv4mm.cpp17
-rw-r--r--src/v4/qv4mm.h14
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<ArgumentsObject *>(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<ExecutionContext *>(that);
- if (ctx->locals)
- delete [] ctx->locals;
- ctx->_data = 0;
- ctx->vtbl = 0;
-}
-
-void ExecutionContext::markObjects(Managed *that)
-{
- ExecutionContext *ctx = static_cast<ExecutionContext *>(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 <qv4runtime.h>
-#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<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
freedCount += sweep(reinterpret_cast<char*>(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 <QScopedPointer>
@@ -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<Data> 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