From 87b61295d3cfc629bb01b516ba6d86b313424d9d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 29 Jan 2013 13:23:32 +0100 Subject: [PATCH] Allocate execution context and local variables in one chunk This avoids a few mallocs and in addition memory leaks where the local variables or arguments array wasn't destroyed before. crypto.js seems to run without a mem leak now :) Change-Id: Icca74c5dba764fadabd7a77f233bdf5883046c86 Reviewed-by: Simon Hausmann --- qmljs_environment.cpp | 13 ++++++------- qmljs_environment.h | 4 ++++ qv4functionobject.cpp | 9 +++++---- qv4globalobject.cpp | 6 ++++-- tests/fact.2.js | 2 +- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/qmljs_environment.cpp b/qmljs_environment.cpp index 007928c..9042a43 100644 --- a/qmljs_environment.cpp +++ b/qmljs_environment.cpp @@ -507,20 +507,21 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha thisObject = thisObject.toObject(this); } + locals = function->varCount ? reinterpret_cast(this + 1) : 0; + if (locals) + std::fill(locals, locals + function->varCount, Value::undefinedValue()); + arguments = args; argumentCount = argc; if (function->needsActivation || argc < function->formalParameterCount){ argumentCount = qMax(argc, function->formalParameterCount); - arguments = new Value[argumentCount]; + arguments = reinterpret_cast(this + 1) + function->varCount; if (argc) std::copy(args, args + argc, arguments); if (argc < function->formalParameterCount) std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue()); } - locals = function->varCount ? new Value[function->varCount] : 0; - if (locals) - std::fill(locals, locals + function->varCount, Value::undefinedValue()); activation = 0; withObject = 0; @@ -539,10 +540,8 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha void ExecutionContext::leaveCallContext() { - if (!function->needsActivation) { - delete[] locals; + if (!function->needsActivation) locals = 0; - } engine->current = parent; parent = 0; diff --git a/qmljs_environment.h b/qmljs_environment.h index ec135a4..c21cab5 100644 --- a/qmljs_environment.h +++ b/qmljs_environment.h @@ -135,8 +135,12 @@ struct ExecutionContext } void mark(); + }; +/* Function *f, int argc */ +#define requiredMemoryForExecutionContect(f, argc) \ + sizeof(ExecutionContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) } // namespace VM diff --git a/qv4functionobject.cpp b/qv4functionobject.cpp index e463550..34cdbb5 100644 --- a/qv4functionobject.cpp +++ b/qv4functionobject.cpp @@ -131,8 +131,8 @@ Value FunctionObject::construct(ExecutionContext *context, Value *args, int argc if (proto.isObject()) obj->prototype = proto.objectValue(); - ExecutionContext k; - ExecutionContext *ctx = needsActivation ? context->engine->newContext() : &k; + uint size = requiredMemoryForExecutionContect(this, argc); + ExecutionContext *ctx = static_cast(needsActivation ? malloc(size) : alloca(size)); ctx->initCallContext(context, Value::fromObject(obj), this, args, argc); Value result = construct(ctx); @@ -145,8 +145,9 @@ Value FunctionObject::construct(ExecutionContext *context, Value *args, int argc Value FunctionObject::call(ExecutionContext *context, Value thisObject, Value *args, int argc) { - ExecutionContext k; - ExecutionContext *ctx = needsActivation ? context->engine->newContext() : &k; + uint size = requiredMemoryForExecutionContect(this, argc); + ExecutionContext *ctx = static_cast(needsActivation ? malloc(size) : alloca(size)); + ctx->initCallContext(context, thisObject, this, args, argc); if (isBuiltinFunction) { diff --git a/qv4globalobject.cpp b/qv4globalobject.cpp index a446f6f..bdf010f 100644 --- a/qv4globalobject.cpp +++ b/qv4globalobject.cpp @@ -55,6 +55,7 @@ #include #include #include +#include using namespace QQmlJS::VM; @@ -342,10 +343,11 @@ Value EvalFunction::evalCall(ExecutionContext *context, Value /*thisObject*/, Va bool strict = f->isStrict || (directCall && context->strictMode); - ExecutionContext k; + uint size = requiredMemoryForExecutionContect(this, argc); + ExecutionContext *k = static_cast(alloca(size)); if (strict) { - ctx = &k; + ctx = k; ctx->initCallContext(context, context->thisObject, this, args, argc); } diff --git a/tests/fact.2.js b/tests/fact.2.js index d8f750b..c0f087e 100644 --- a/tests/fact.2.js +++ b/tests/fact.2.js @@ -3,6 +3,6 @@ function fact(n) { return n > 1 ? n * fact(n - 1) : 1 } -for (var i = 0; i < 1000000; i = i + 1) +for (var i = 0; i < 10000; i = i + 1) fact(12) -- 2.7.4