Allocate execution context and local variables in one chunk
authorLars Knoll <lars.knoll@digia.com>
Tue, 29 Jan 2013 12:23:32 +0000 (13:23 +0100)
committerLars Knoll <lars.knoll@digia.com>
Tue, 29 Jan 2013 19:16:56 +0000 (20:16 +0100)
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 <simon.hausmann@digia.com>
qmljs_environment.cpp
qmljs_environment.h
qv4functionobject.cpp
qv4globalobject.cpp
tests/fact.2.js

index 007928c..9042a43 100644 (file)
@@ -507,20 +507,21 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha
             thisObject = thisObject.toObject(this);
     }
 
+    locals = function->varCount ? reinterpret_cast<Value *>(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<Value *>(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;
 
index ec135a4..c21cab5 100644 (file)
@@ -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
index e463550..34cdbb5 100644 (file)
@@ -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<ExecutionContext *>(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<ExecutionContext *>(needsActivation ? malloc(size) : alloca(size));
+
 
     ctx->initCallContext(context, thisObject, this, args, argc);
     if (isBuiltinFunction) {
index a446f6f..bdf010f 100644 (file)
@@ -55,6 +55,7 @@
 #include <QtCore/QDebug>
 #include <QtCore/QString>
 #include <iostream>
+#include <alloca.h>
 
 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<ExecutionContext *>(alloca(size));
 
     if (strict) {
-        ctx = &k;
+        ctx = k;
         ctx->initCallContext(context, context->thisObject, this, args, argc);
     }
 
index d8f750b..c0f087e 100644 (file)
@@ -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)