Add a MemoryManager, which does GC for the interpreter.
Todo: - stack walking for MASM - fix all TODOs/FIXMEs and hidden treasures (bugs). Change-Id: I36f8cdc3a545df7287ce1df17b3570a9c017865e Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
parent
3b3f3bebcd
commit
5f22fbd7fc
23
main.cpp
23
main.cpp
|
@ -53,6 +53,7 @@
|
|||
#include "qv4syntaxchecker_p.h"
|
||||
#include "qv4ecmaobjects_p.h"
|
||||
#include "qv4isel_p.h"
|
||||
#include "qv4mm_moth.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <private/qqmljsengine_p.h>
|
||||
|
@ -144,12 +145,12 @@ int executeLLVMCode(void *codePtr)
|
|||
void (*code)(VM::ExecutionContext *) = (void (*)(VM::ExecutionContext *)) codePtr;
|
||||
|
||||
QScopedPointer<QQmlJS::EvalISelFactory> iSelFactory(new QQmlJS::Moth::ISelFactory);
|
||||
VM::ExecutionEngine vm(iSelFactory.data());
|
||||
VM::ExecutionEngine vm(0, iSelFactory.data());
|
||||
VM::ExecutionContext *ctx = vm.rootContext;
|
||||
|
||||
QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue();
|
||||
globalObject->__put__(ctx, vm.identifier(QStringLiteral("print")),
|
||||
QQmlJS::VM::Value::fromObject(new builtins::Print(ctx)));
|
||||
QQmlJS::VM::Value::fromObject(new (ctx->engine->memoryManager) builtins::Print(ctx)));
|
||||
|
||||
void * buf = __qmljs_create_exception_handler(ctx);
|
||||
if (setjmp(*(jmp_buf *)buf)) {
|
||||
|
@ -318,13 +319,17 @@ int main(int argc, char *argv[])
|
|||
#endif // QMLJS_NO_LLVM
|
||||
case use_masm:
|
||||
case use_moth: {
|
||||
QScopedPointer<QQmlJS::VM::MemoryManager> mm;
|
||||
QScopedPointer<QQmlJS::EvalISelFactory> iSelFactory;
|
||||
if (mode == use_moth)
|
||||
if (mode == use_moth) {
|
||||
mm.reset(new QQmlJS::Moth::MemoryManager);
|
||||
iSelFactory.reset(new QQmlJS::Moth::ISelFactory);
|
||||
else
|
||||
} else {
|
||||
mm.reset(new QQmlJS::VM::MemoryManagerWithoutGC);
|
||||
iSelFactory.reset(new QQmlJS::MASM::ISelFactory);
|
||||
}
|
||||
|
||||
QQmlJS::VM::ExecutionEngine vm(iSelFactory.data());
|
||||
QQmlJS::VM::ExecutionEngine vm(mm.data(), iSelFactory.data());
|
||||
|
||||
QScopedPointer<QQmlJS::Debugging::Debugger> debugger;
|
||||
if (enableDebugging)
|
||||
|
@ -335,12 +340,12 @@ int main(int argc, char *argv[])
|
|||
|
||||
QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue();
|
||||
globalObject->__put__(ctx, vm.identifier(QStringLiteral("print")),
|
||||
QQmlJS::VM::Value::fromObject(new builtins::Print(ctx)));
|
||||
QQmlJS::VM::Value::fromObject(new (ctx->engine->memoryManager) builtins::Print(ctx)));
|
||||
|
||||
bool errorInTestHarness = false;
|
||||
if (!qgetenv("IN_TEST_HARNESS").isEmpty())
|
||||
globalObject->__put__(ctx, vm.identifier(QStringLiteral("$ERROR")),
|
||||
QQmlJS::VM::Value::fromObject(new builtins::TestHarnessError(ctx, errorInTestHarness)));
|
||||
QQmlJS::VM::Value::fromObject(new (ctx->engine->memoryManager) builtins::TestHarnessError(ctx, errorInTestHarness)));
|
||||
|
||||
foreach (const QString &fn, args) {
|
||||
QFile file(fn);
|
||||
|
@ -354,7 +359,7 @@ int main(int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QQmlJS::IR::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode);
|
||||
QScopedPointer<QQmlJS::IR::Function> f(QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode));
|
||||
if (!f)
|
||||
continue;
|
||||
|
||||
|
@ -376,6 +381,8 @@ int main(int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
mm->dumpStats();
|
||||
} return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ HEADERS += \
|
|||
$$PWD/qv4isel_moth_p.h \
|
||||
$$PWD/qv4instr_moth_p.h \
|
||||
$$PWD/qv4vme_moth_p.h \
|
||||
$$PWD/qv4mm_moth.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qv4isel_moth.cpp \
|
||||
$$PWD/qv4instr_moth.cpp \
|
||||
$$PWD/qv4vme_moth.cpp \
|
||||
$$PWD/qv4mm_moth.cpp
|
||||
|
||||
#DEFINES += DO_TRACE_INSTR
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmljs_engine.h"
|
||||
#include "qv4mm_moth.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
using namespace QQmlJS;
|
||||
using namespace QQmlJS::Moth;
|
||||
|
||||
MemoryManager::MemoryManager()
|
||||
{
|
||||
stackFrames.reserve(64);
|
||||
}
|
||||
|
||||
MemoryManager::~MemoryManager()
|
||||
{
|
||||
}
|
||||
|
||||
VM::Value *MemoryManager::allocStackFrame(std::size_t frameSize)
|
||||
{
|
||||
std::size_t size = frameSize * sizeof(VM::Value);
|
||||
MMObject *m = alloc(align(size));
|
||||
stackFrames.append(m);
|
||||
return reinterpret_cast<VM::Value *>(&m->data);
|
||||
}
|
||||
|
||||
void MemoryManager::deallocStackFrame(VM::Value *stackFrame)
|
||||
{
|
||||
MMObject *o = toObject(stackFrame);
|
||||
for (int i = stackFrames.size() - 1; i >= 0; --i) {
|
||||
if (stackFrames[i] == o) {
|
||||
stackFrames.remove(i);
|
||||
dealloc(o);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
void MemoryManager::collectRootsOnStack(QVector<VM::Object *> &roots) const
|
||||
{
|
||||
for (int i = 0, ei = stackFrames.size(); i < ei; ++i) {
|
||||
MMObject *m = stackFrames[i];
|
||||
VM::Value *frame = reinterpret_cast<VM::Value *>(&m->data);
|
||||
std::size_t frameSize = (m->info.size - align(sizeof(MMInfo))) / sizeof(VM::Value);
|
||||
for (std::size_t j = 0; j < frameSize; ++j) {
|
||||
if (VM::Object *o = frame[j].asObject()) {
|
||||
roots.append(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QV4GC_MOTH_H
|
||||
#define QV4GC_MOTH_H
|
||||
|
||||
#include "qv4mm.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
namespace QQmlJS {
|
||||
namespace Moth {
|
||||
|
||||
class MemoryManager: public QQmlJS::VM::MemoryManager
|
||||
{
|
||||
public:
|
||||
MemoryManager();
|
||||
~MemoryManager();
|
||||
|
||||
VM::Value *allocStackFrame(std::size_t frameSize);
|
||||
void deallocStackFrame(VM::Value *stackFrame);
|
||||
|
||||
protected:
|
||||
virtual void collectRootsOnStack(QVector<VM::Object *> &roots) const;
|
||||
|
||||
private:
|
||||
QVector<MMObject *> stackFrames;
|
||||
};
|
||||
|
||||
} // namespace Moth
|
||||
} // namespace QQmlJS
|
||||
|
||||
#endif // QV4GC_MOTH_H
|
|
@ -2,6 +2,7 @@
|
|||
#include "qv4instr_moth_p.h"
|
||||
#include "qmljs_value.h"
|
||||
#include "debugging.h"
|
||||
#include "qv4mm_moth.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -51,7 +52,7 @@ using namespace QQmlJS::Moth;
|
|||
|
||||
#endif
|
||||
|
||||
static inline VM::Value *tempValue(QQmlJS::VM::ExecutionContext *context, QVector<VM::Value> &stack, int index)
|
||||
static inline VM::Value *tempValue(QQmlJS::VM::ExecutionContext *context, VM::Value* stack, int index)
|
||||
{
|
||||
#ifdef DO_TRACE_INSTR
|
||||
const char *kind;
|
||||
|
@ -87,25 +88,32 @@ static inline VM::Value *tempValue(QQmlJS::VM::ExecutionContext *context, QVecto
|
|||
int off = index - context->variableCount();
|
||||
|
||||
Q_ASSERT(off >= 0);
|
||||
Q_ASSERT(off < stack.size());
|
||||
|
||||
return stack.data() + off;
|
||||
return stack + off;
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionState: public Debugging::FunctionState
|
||||
{
|
||||
public:
|
||||
FunctionState(QQmlJS::VM::ExecutionContext *context, QVector<VM::Value> *stack, const uchar **code)
|
||||
FunctionState(QQmlJS::VM::ExecutionContext *context, const uchar **code)
|
||||
: Debugging::FunctionState(context)
|
||||
, stack(stack)
|
||||
, stack(0)
|
||||
, stackSize(0)
|
||||
, code(code)
|
||||
{}
|
||||
|
||||
virtual VM::Value *temp(unsigned idx) { return stack->data() + idx; }
|
||||
~FunctionState()
|
||||
{ if (stack) static_cast<MemoryManager *>(context()->engine->memoryManager)->deallocStackFrame(stack); }
|
||||
|
||||
virtual VM::Value *temp(unsigned idx) { return stack + idx; }
|
||||
|
||||
void setStack(VM::Value *stack, unsigned stackSize)
|
||||
{ this->stack = stack; this->stackSize = stackSize; }
|
||||
|
||||
private:
|
||||
QVector<VM::Value> *stack;
|
||||
VM::Value *stack;
|
||||
unsigned stackSize;
|
||||
const uchar **code;
|
||||
};
|
||||
|
||||
|
@ -130,8 +138,9 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
|
|||
}
|
||||
#endif
|
||||
|
||||
QVector<VM::Value> stack;
|
||||
FunctionState state(context, &stack, &code);
|
||||
VM::Value *stack = 0;
|
||||
unsigned stackSize = 0;
|
||||
FunctionState state(context, &code);
|
||||
|
||||
#ifdef MOTH_THREADED_INTERPRETER
|
||||
const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
|
||||
|
@ -191,7 +200,9 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
|
|||
|
||||
MOTH_BEGIN_INSTR(Push)
|
||||
TRACE(inline, "stack size: %u", instr.value);
|
||||
stack.resize(instr.value);
|
||||
stackSize = instr.value;
|
||||
stack = static_cast<MemoryManager *>(context->engine->memoryManager)->allocStackFrame(stackSize);
|
||||
state.setStack(stack, stackSize);
|
||||
MOTH_END_INSTR(Push)
|
||||
|
||||
MOTH_BEGIN_INSTR(CallValue)
|
||||
|
@ -207,20 +218,20 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
|
|||
#endif // DO_TRACE_INSTR
|
||||
quint32 argStart = instr.args - context->variableCount();
|
||||
TRACE(Call, "value index = %d, argStart = %d, argc = %d, result temp index = %d", instr.destIndex, argStart, instr.argc, instr.targetTempIndex);
|
||||
VM::Value *args = stack.data() + argStart;
|
||||
VM::Value *args = stack + argStart;
|
||||
TEMP(instr.targetTempIndex) = __qmljs_call_value(context, VM::Value::undefinedValue(), TEMP(instr.destIndex), args, instr.argc);
|
||||
MOTH_END_INSTR(CallValue)
|
||||
|
||||
MOTH_BEGIN_INSTR(CallProperty)
|
||||
quint32 argStart = instr.args - context->variableCount();
|
||||
VM::Value *args = stack.data() + argStart;
|
||||
VM::Value *args = stack + argStart;
|
||||
VM::Value base = TEMP(instr.baseTemp);
|
||||
TEMP(instr.targetTempIndex) = __qmljs_call_property(context, base, instr.name, args, instr.argc);
|
||||
MOTH_END_INSTR(CallProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(CallBuiltin)
|
||||
quint32 argStart = instr.args - context->variableCount();
|
||||
VM::Value *args = stack.data() + argStart;
|
||||
VM::Value *args = stack + argStart;
|
||||
void *buf;
|
||||
switch (instr.builtin) {
|
||||
case Instr::instr_callBuiltin::builtin_typeof:
|
||||
|
@ -300,20 +311,20 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
|
|||
|
||||
MOTH_BEGIN_INSTR(CreateValue)
|
||||
quint32 argStart = instr.args - context->variableCount();
|
||||
VM::Value *args = stack.data() + argStart;
|
||||
VM::Value *args = stack + argStart;
|
||||
TEMP(instr.targetTempIndex) = __qmljs_construct_value(context, TEMP(instr.func), args, instr.argc);
|
||||
MOTH_END_INSTR(CreateValue)
|
||||
|
||||
MOTH_BEGIN_INSTR(CreateProperty)
|
||||
quint32 argStart = instr.args - context->variableCount();
|
||||
VM::Value *args = stack.data() + argStart;
|
||||
VM::Value *args = stack + argStart;
|
||||
TEMP(instr.targetTempIndex) = __qmljs_construct_property(context, TEMP(instr.base), instr.name, args, instr.argc);
|
||||
MOTH_END_INSTR(CreateProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(CreateActivationProperty)
|
||||
TRACE(inline, "property name = %s, argc = %d", instr.name->toQString().toUtf8().constData(), instr.argc);
|
||||
quint32 argStart = instr.args - context->variableCount();
|
||||
VM::Value *args = stack.data() + argStart;
|
||||
VM::Value *args = stack + argStart;
|
||||
TEMP(instr.targetTempIndex) = __qmljs_construct_activation_property(context, instr.name, args, instr.argc);
|
||||
MOTH_END_INSTR(CreateActivationProperty)
|
||||
|
||||
|
|
136
qmljs_engine.cpp
136
qmljs_engine.cpp
|
@ -41,6 +41,7 @@
|
|||
#include <qmljs_engine.h>
|
||||
#include <qmljs_objects.h>
|
||||
#include <qv4ecmaobjects_p.h>
|
||||
#include "qv4mm.h"
|
||||
|
||||
namespace QQmlJS {
|
||||
namespace VM {
|
||||
|
@ -49,6 +50,9 @@ struct StringPool
|
|||
{
|
||||
QHash<QString, String*> strings;
|
||||
|
||||
~StringPool()
|
||||
{ qDeleteAll(strings.values()); }
|
||||
|
||||
String *newString(const QString &s)
|
||||
{
|
||||
QHash<QString, String*>::const_iterator it = strings.find(s);
|
||||
|
@ -60,11 +64,18 @@ struct StringPool
|
|||
}
|
||||
};
|
||||
|
||||
ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
||||
: iselFactory(factory)
|
||||
ExecutionEngine::ExecutionEngine(MemoryManager *memoryManager, EvalISelFactory *factory)
|
||||
: memoryManager(memoryManager)
|
||||
, iselFactory(factory)
|
||||
, debugger(0)
|
||||
, globalObject(Value::nullValue())
|
||||
, exception(Value::nullValue())
|
||||
{
|
||||
MemoryManager::GCBlocker gcBlocker(memoryManager);
|
||||
|
||||
stringPool = new StringPool;
|
||||
memoryManager->setStringPool(stringPool);
|
||||
memoryManager->setExecutionEngine(this);
|
||||
|
||||
rootContext = newContext();
|
||||
rootContext->init(this);
|
||||
|
@ -75,21 +86,21 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
|||
id_arguments = identifier(QStringLiteral("arguments"));
|
||||
id___proto__ = identifier(QStringLiteral("__proto__"));
|
||||
|
||||
objectPrototype = new ObjectPrototype();
|
||||
stringPrototype = new StringPrototype(rootContext);
|
||||
numberPrototype = new NumberPrototype();
|
||||
booleanPrototype = new BooleanPrototype();
|
||||
arrayPrototype = new ArrayPrototype();
|
||||
datePrototype = new DatePrototype();
|
||||
functionPrototype = new FunctionPrototype(rootContext);
|
||||
regExpPrototype = new RegExpPrototype();
|
||||
errorPrototype = new ErrorPrototype();
|
||||
evalErrorPrototype = new EvalErrorPrototype(rootContext);
|
||||
rangeErrorPrototype = new RangeErrorPrototype(rootContext);
|
||||
referenceErrorPrototype = new ReferenceErrorPrototype(rootContext);
|
||||
syntaxErrorPrototype = new SyntaxErrorPrototype(rootContext);
|
||||
typeErrorPrototype = new TypeErrorPrototype(rootContext);
|
||||
uRIErrorPrototype = new URIErrorPrototype(rootContext);
|
||||
objectPrototype = new (memoryManager) ObjectPrototype();
|
||||
stringPrototype = new (memoryManager) StringPrototype(rootContext);
|
||||
numberPrototype = new (memoryManager) NumberPrototype();
|
||||
booleanPrototype = new (memoryManager) BooleanPrototype();
|
||||
arrayPrototype = new (memoryManager) ArrayPrototype();
|
||||
datePrototype = new (memoryManager) DatePrototype();
|
||||
functionPrototype = new (memoryManager) FunctionPrototype(rootContext);
|
||||
regExpPrototype = new (memoryManager) RegExpPrototype();
|
||||
errorPrototype = new (memoryManager) ErrorPrototype();
|
||||
evalErrorPrototype = new (memoryManager) EvalErrorPrototype(rootContext);
|
||||
rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(rootContext);
|
||||
referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(rootContext);
|
||||
syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(rootContext);
|
||||
typeErrorPrototype = new (memoryManager) TypeErrorPrototype(rootContext);
|
||||
uRIErrorPrototype = new (memoryManager) URIErrorPrototype(rootContext);
|
||||
|
||||
stringPrototype->prototype = objectPrototype;
|
||||
numberPrototype->prototype = objectPrototype;
|
||||
|
@ -106,21 +117,21 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
|||
typeErrorPrototype->prototype = errorPrototype;
|
||||
uRIErrorPrototype->prototype = errorPrototype;
|
||||
|
||||
objectCtor = Value::fromObject(new ObjectCtor(rootContext));
|
||||
stringCtor = Value::fromObject(new StringCtor(rootContext));
|
||||
numberCtor = Value::fromObject(new NumberCtor(rootContext));
|
||||
booleanCtor = Value::fromObject(new BooleanCtor(rootContext));
|
||||
arrayCtor = Value::fromObject(new ArrayCtor(rootContext));
|
||||
functionCtor = Value::fromObject(new FunctionCtor(rootContext));
|
||||
dateCtor = Value::fromObject(new DateCtor(rootContext));
|
||||
regExpCtor = Value::fromObject(new RegExpCtor(rootContext));
|
||||
errorCtor = Value::fromObject(new ErrorCtor(rootContext));
|
||||
evalErrorCtor = Value::fromObject(new EvalErrorCtor(rootContext));
|
||||
rangeErrorCtor = Value::fromObject(new RangeErrorCtor(rootContext));
|
||||
referenceErrorCtor = Value::fromObject(new ReferenceErrorCtor(rootContext));
|
||||
syntaxErrorCtor = Value::fromObject(new SyntaxErrorCtor(rootContext));
|
||||
typeErrorCtor = Value::fromObject(new TypeErrorCtor(rootContext));
|
||||
uRIErrorCtor = Value::fromObject(new URIErrorCtor(rootContext));
|
||||
objectCtor = Value::fromObject(new (memoryManager) ObjectCtor(rootContext));
|
||||
stringCtor = Value::fromObject(new (memoryManager) StringCtor(rootContext));
|
||||
numberCtor = Value::fromObject(new (memoryManager) NumberCtor(rootContext));
|
||||
booleanCtor = Value::fromObject(new (memoryManager) BooleanCtor(rootContext));
|
||||
arrayCtor = Value::fromObject(new (memoryManager) ArrayCtor(rootContext));
|
||||
functionCtor = Value::fromObject(new (memoryManager) FunctionCtor(rootContext));
|
||||
dateCtor = Value::fromObject(new (memoryManager) DateCtor(rootContext));
|
||||
regExpCtor = Value::fromObject(new (memoryManager) RegExpCtor(rootContext));
|
||||
errorCtor = Value::fromObject(new (memoryManager) ErrorCtor(rootContext));
|
||||
evalErrorCtor = Value::fromObject(new (memoryManager) EvalErrorCtor(rootContext));
|
||||
rangeErrorCtor = Value::fromObject(new (memoryManager) RangeErrorCtor(rootContext));
|
||||
referenceErrorCtor = Value::fromObject(new (memoryManager) ReferenceErrorCtor(rootContext));
|
||||
syntaxErrorCtor = Value::fromObject(new (memoryManager) SyntaxErrorCtor(rootContext));
|
||||
typeErrorCtor = Value::fromObject(new (memoryManager) TypeErrorCtor(rootContext));
|
||||
uRIErrorCtor = Value::fromObject(new (memoryManager) URIErrorCtor(rootContext));
|
||||
|
||||
stringCtor.objectValue()->prototype = functionPrototype;
|
||||
numberCtor.objectValue()->prototype = functionPrototype;
|
||||
|
@ -190,19 +201,19 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
|||
pd.value = Value::fromDouble(INFINITY);
|
||||
glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("Infinity")), &pd);
|
||||
|
||||
glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new EvalFunction(rootContext)));
|
||||
glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new (memoryManager) EvalFunction(rootContext)));
|
||||
|
||||
// TODO: parseInt [15.1.2.2]
|
||||
// TODO: parseFloat [15.1.2.3]
|
||||
glo->__put__(rootContext, identifier(QStringLiteral("isNaN")), Value::fromObject(new IsNaNFunction(rootContext))); // isNaN [15.1.2.4]
|
||||
glo->__put__(rootContext, identifier(QStringLiteral("isFinite")), Value::fromObject(new IsFiniteFunction(rootContext))); // isFinite [15.1.2.5]
|
||||
glo->__put__(rootContext, identifier(QStringLiteral("isNaN")), Value::fromObject(new (memoryManager) IsNaNFunction(rootContext))); // isNaN [15.1.2.4]
|
||||
glo->__put__(rootContext, identifier(QStringLiteral("isFinite")), Value::fromObject(new (memoryManager) IsFiniteFunction(rootContext))); // isFinite [15.1.2.5]
|
||||
}
|
||||
|
||||
ExecutionEngine::~ExecutionEngine()
|
||||
{
|
||||
delete globalObject.asObject();
|
||||
delete rootContext;
|
||||
delete stringPool; // the String pointers should get GC-ed.
|
||||
delete stringPool;
|
||||
}
|
||||
|
||||
ExecutionContext *ExecutionEngine::newContext()
|
||||
|
@ -220,14 +231,16 @@ String *ExecutionEngine::identifier(const QString &s)
|
|||
|
||||
FunctionObject *ExecutionEngine::newNativeFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *))
|
||||
{
|
||||
NativeFunction *f = new NativeFunction(scope, name, code);
|
||||
NativeFunction *f = new (memoryManager) NativeFunction(scope, name, code);
|
||||
f->prototype = scope->engine->functionPrototype;
|
||||
return f;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, IR::Function *function)
|
||||
{
|
||||
ScriptFunction *f = new ScriptFunction(scope, function);
|
||||
MemoryManager::GCBlocker gcBlocker(memoryManager);
|
||||
|
||||
ScriptFunction *f = new (memoryManager) ScriptFunction(scope, function);
|
||||
Object *proto = scope->engine->newObject();
|
||||
proto->__put__(scope, scope->engine->id_constructor, Value::fromObject(f));
|
||||
f->__put__(scope, scope->engine->id_prototype, Value::fromObject(proto));
|
||||
|
@ -237,14 +250,14 @@ FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, IR::
|
|||
|
||||
Object *ExecutionEngine::newObject()
|
||||
{
|
||||
Object *object = new Object();
|
||||
Object *object = new (memoryManager) Object();
|
||||
object->prototype = objectPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newObjectCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new ObjectCtor(ctx);
|
||||
return new (memoryManager) ObjectCtor(ctx);
|
||||
}
|
||||
|
||||
String *ExecutionEngine::newString(const QString &s)
|
||||
|
@ -254,76 +267,76 @@ String *ExecutionEngine::newString(const QString &s)
|
|||
|
||||
Object *ExecutionEngine::newStringObject(const Value &value)
|
||||
{
|
||||
StringObject *object = new StringObject(value);
|
||||
StringObject *object = new (memoryManager) StringObject(value);
|
||||
object->prototype = stringPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newStringCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new StringCtor(ctx);
|
||||
return new (memoryManager) StringCtor(ctx);
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newNumberObject(const Value &value)
|
||||
{
|
||||
NumberObject *object = new NumberObject(value);
|
||||
NumberObject *object = new (memoryManager) NumberObject(value);
|
||||
object->prototype = numberPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newNumberCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new NumberCtor(ctx);
|
||||
return new (memoryManager) NumberCtor(ctx);
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newBooleanObject(const Value &value)
|
||||
{
|
||||
Object *object = new BooleanObject(value);
|
||||
Object *object = new (memoryManager) BooleanObject(value);
|
||||
object->prototype = booleanPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newBooleanCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new BooleanCtor(ctx);
|
||||
return new (memoryManager) BooleanCtor(ctx);
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newFunctionObject(ExecutionContext *ctx)
|
||||
{
|
||||
Object *object = new FunctionObject(ctx);
|
||||
Object *object = new (memoryManager) FunctionObject(ctx);
|
||||
object->prototype = functionPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
ArrayObject *ExecutionEngine::newArrayObject()
|
||||
{
|
||||
ArrayObject *object = new ArrayObject();
|
||||
ArrayObject *object = new (memoryManager) ArrayObject();
|
||||
object->prototype = arrayPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
ArrayObject *ExecutionEngine::newArrayObject(const Array &value)
|
||||
{
|
||||
ArrayObject *object = new ArrayObject(value);
|
||||
ArrayObject *object = new (memoryManager) ArrayObject(value);
|
||||
object->prototype = arrayPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newArrayCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new ArrayCtor(ctx);
|
||||
return new (memoryManager) ArrayCtor(ctx);
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newDateObject(const Value &value)
|
||||
{
|
||||
Object *object = new DateObject(value);
|
||||
Object *object = new (memoryManager) DateObject(value);
|
||||
object->prototype = datePrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newDateCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new DateCtor(ctx);
|
||||
return new (memoryManager) DateCtor(ctx);
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
|
||||
|
@ -335,61 +348,60 @@ Object *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
|
|||
if (flags & IR::RegExp::RegExp_Multiline)
|
||||
options |= QRegularExpression::MultilineOption;
|
||||
|
||||
Object *object = new RegExpObject(QRegularExpression(pattern, options), global);
|
||||
Object *object = new (memoryManager) RegExpObject(QRegularExpression(pattern, options), global);
|
||||
object->prototype = regExpPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
FunctionObject *ExecutionEngine::newRegExpCtor(ExecutionContext *ctx)
|
||||
{
|
||||
return new RegExpCtor(ctx);
|
||||
return new (memoryManager) RegExpCtor(ctx);
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newErrorObject(const Value &value)
|
||||
{
|
||||
ErrorObject *object = new ErrorObject(value);
|
||||
ErrorObject *object = new (memoryManager) ErrorObject(value);
|
||||
object->prototype = errorPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message)
|
||||
{
|
||||
SyntaxErrorObject *object = new SyntaxErrorObject(ctx, message);
|
||||
SyntaxErrorObject *object = new (memoryManager) SyntaxErrorObject(ctx, message);
|
||||
object->prototype = syntaxErrorPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newReferenceErrorObject(ExecutionContext *ctx, const QString &message)
|
||||
{
|
||||
ReferenceErrorObject *object = new ReferenceErrorObject(ctx, message);
|
||||
ReferenceErrorObject *object = new (memoryManager) ReferenceErrorObject(ctx, message);
|
||||
object->prototype = referenceErrorPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newTypeErrorObject(ExecutionContext *ctx, const QString &message)
|
||||
{
|
||||
TypeErrorObject *object = new TypeErrorObject(ctx, message);
|
||||
TypeErrorObject *object = new (memoryManager) TypeErrorObject(ctx, message);
|
||||
object->prototype = typeErrorPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newMathObject(ExecutionContext *ctx)
|
||||
{
|
||||
MathObject *object = new MathObject(ctx);
|
||||
MathObject *object = new (memoryManager) MathObject(ctx);
|
||||
object->prototype = objectPrototype;
|
||||
return object;
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newActivationObject()
|
||||
{
|
||||
return new Object();
|
||||
return new (memoryManager) Object();
|
||||
}
|
||||
|
||||
Object *ExecutionEngine::newForEachIteratorObject(Object *o)
|
||||
{
|
||||
return new ForEachIteratorObject(o);
|
||||
return new (memoryManager) ForEachIteratorObject(o);
|
||||
}
|
||||
|
||||
|
||||
} // namespace VM
|
||||
} // namespace QQmlJS
|
||||
|
|
|
@ -68,6 +68,7 @@ struct ErrorObject;
|
|||
struct ArgumentsObject;
|
||||
struct ExecutionContext;
|
||||
struct ExecutionEngine;
|
||||
class MemoryManager;
|
||||
|
||||
struct ObjectPrototype;
|
||||
struct StringPrototype;
|
||||
|
@ -87,6 +88,7 @@ struct URIErrorPrototype;
|
|||
|
||||
struct ExecutionEngine
|
||||
{
|
||||
MemoryManager *memoryManager;
|
||||
EvalISelFactory *iselFactory;
|
||||
ExecutionContext *current;
|
||||
ExecutionContext *rootContext;
|
||||
|
@ -148,7 +150,7 @@ struct ExecutionEngine
|
|||
|
||||
struct StringPool *stringPool;
|
||||
|
||||
ExecutionEngine(EvalISelFactory *iselFactory);
|
||||
ExecutionEngine(MemoryManager *memoryManager, EvalISelFactory *iselFactory);
|
||||
~ExecutionEngine();
|
||||
|
||||
ExecutionContext *newContext();
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <qmljs_environment.h>
|
||||
#include <qmljs_objects.h>
|
||||
#include <qv4ecmaobjects_p.h>
|
||||
#include "qv4mm.h"
|
||||
|
||||
namespace QQmlJS {
|
||||
namespace VM {
|
||||
|
@ -266,7 +267,6 @@ void ExecutionContext::setProperty(String *name, Value value)
|
|||
|
||||
Value ExecutionContext::getProperty(String *name)
|
||||
{
|
||||
PropertyDescriptor tmp;
|
||||
for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
|
||||
if (ctx->withObject) {
|
||||
With *w = ctx->withObject;
|
||||
|
@ -286,7 +286,7 @@ Value ExecutionContext::getProperty(String *name)
|
|||
if (ctx->activation && ctx->activation->__hasProperty__(ctx, name))
|
||||
return ctx->activation->__get__(ctx, name);
|
||||
if (name->isEqualTo(ctx->engine->id_arguments)) {
|
||||
Value arguments = Value::fromObject(new ArgumentsObject(this));
|
||||
Value arguments = Value::fromObject(new (engine->memoryManager) ArgumentsObject(this));
|
||||
createMutableBinding(ctx->engine->id_arguments, false);
|
||||
setMutableBinding(this, ctx->engine->id_arguments, arguments);
|
||||
return arguments;
|
||||
|
@ -345,6 +345,8 @@ void ExecutionContext::throwReferenceError(Value value)
|
|||
|
||||
void ExecutionContext::initCallContext(ExecutionContext *parent, const Value that, FunctionObject *f, Value *args, unsigned argc)
|
||||
{
|
||||
MemoryManager::GCBlocker blockGC(parent->engine->memoryManager);
|
||||
|
||||
engine = parent->engine;
|
||||
this->parent = parent;
|
||||
thisObject = that;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "qv4ir_p.h"
|
||||
#include "qv4isel_p.h"
|
||||
#include "qv4ecmaobjects_p.h"
|
||||
#include "qv4mm.h"
|
||||
|
||||
#include <private/qqmljsengine_p.h>
|
||||
#include <private/qqmljslexer_p.h>
|
||||
|
@ -59,6 +60,28 @@
|
|||
|
||||
using namespace QQmlJS::VM;
|
||||
|
||||
|
||||
Managed::~Managed()
|
||||
{
|
||||
}
|
||||
|
||||
void *Managed::operator new(size_t size, MemoryManager *mm)
|
||||
{
|
||||
assert(mm);
|
||||
|
||||
return mm->allocManaged(size);
|
||||
}
|
||||
|
||||
void Managed::operator delete(void *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
Managed *m = reinterpret_cast<Managed *>(ptr);
|
||||
assert(m->mm);
|
||||
m->mm->deallocManaged(m);
|
||||
}
|
||||
|
||||
//
|
||||
// Object
|
||||
//
|
||||
|
@ -107,6 +130,20 @@ bool Object::inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContext *ct
|
|||
return inplaceBinOp(rhs, name, op, ctx);
|
||||
}
|
||||
|
||||
void Object::getCollectables(QVector<Object *> &objects)
|
||||
{
|
||||
if (prototype)
|
||||
objects.append(prototype);
|
||||
|
||||
if (members) {
|
||||
for (PropertyTable::iterator it = members->begin(), eit = members->end(); it < eit; ++it) {
|
||||
if ((*it)->descriptor.isData())
|
||||
if (Object *o = (*it)->descriptor.value.asObject())
|
||||
objects.append(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 8.12.1
|
||||
PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *, String *name)
|
||||
{
|
||||
|
@ -349,6 +386,15 @@ String *ForEachIteratorObject::nextPropertyName()
|
|||
}
|
||||
}
|
||||
|
||||
void ForEachIteratorObject::getCollectables(QVector<Object *> &objects)
|
||||
{
|
||||
Object::getCollectables(objects);
|
||||
if (object)
|
||||
objects.append(object);
|
||||
if (current)
|
||||
objects.append(current);
|
||||
}
|
||||
|
||||
Value ArrayObject::__get__(ExecutionContext *ctx, String *name)
|
||||
{
|
||||
if (name->isEqualTo(ctx->engine->id_length))
|
||||
|
@ -368,6 +414,12 @@ bool ArrayObject::inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContex
|
|||
return Object::inplaceBinOp(rhs, index, op, ctx);
|
||||
}
|
||||
|
||||
void ArrayObject::getCollectables(QVector<Object *> &objects)
|
||||
{
|
||||
Object::getCollectables(objects);
|
||||
value.getCollectables(objects);
|
||||
}
|
||||
|
||||
bool FunctionObject::hasInstance(ExecutionContext *ctx, const Value &value)
|
||||
{
|
||||
if (! value.isObject()) {
|
||||
|
@ -490,7 +542,7 @@ Value EvalFunction::call(ExecutionContext *context, Value /*thisObject*/, Value
|
|||
bool directCall = true;
|
||||
|
||||
const QString code = args[0].stringValue()->toQString();
|
||||
QQmlJS::IR::Function *f = parseSource(context, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode);
|
||||
QScopedPointer<QQmlJS::IR::Function> f(parseSource(context, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode));
|
||||
if (!f)
|
||||
return Value::undefinedValue();
|
||||
|
||||
|
@ -534,6 +586,8 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
|
|||
{
|
||||
using namespace QQmlJS;
|
||||
|
||||
MemoryManager::GCBlocker gcBlocker(ctx->engine->memoryManager);
|
||||
|
||||
VM::ExecutionEngine *vm = ctx->engine;
|
||||
IR::Module module;
|
||||
IR::Function *globalCode = 0;
|
||||
|
@ -654,6 +708,13 @@ void ErrorObject::setNameProperty(ExecutionContext *ctx)
|
|||
__put__(ctx, QLatin1String("name"), Value::fromString(ctx, className()));
|
||||
}
|
||||
|
||||
void ErrorObject::getCollectables(QVector<Object *> &objects)
|
||||
{
|
||||
Object::getCollectables(objects);
|
||||
if (Object *o = value.asObject())
|
||||
objects.append(o);
|
||||
}
|
||||
|
||||
SyntaxErrorObject::SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message)
|
||||
: ErrorObject(ctx->argument(0))
|
||||
, msg(message)
|
||||
|
@ -675,7 +736,6 @@ Value ScriptFunction::construct(VM::ExecutionContext *ctx)
|
|||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
|
||||
Value ArgumentsObject::__get__(ExecutionContext *ctx, String *name)
|
||||
{
|
||||
if (name->isEqualTo(ctx->engine->id_length))
|
||||
|
@ -698,7 +758,6 @@ PropertyDescriptor *ArgumentsObject::__getPropertyDescriptor__(ExecutionContext
|
|||
return Object::__getPropertyDescriptor__(ctx, name, to_fill);
|
||||
}
|
||||
|
||||
|
||||
NativeFunction::NativeFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *))
|
||||
: FunctionObject(scope)
|
||||
, code(code)
|
||||
|
|
|
@ -75,6 +75,7 @@ struct ErrorObject;
|
|||
struct ArgumentsObject;
|
||||
struct ExecutionContext;
|
||||
struct ExecutionEngine;
|
||||
class MemoryManager;
|
||||
|
||||
struct ObjectPrototype;
|
||||
struct StringPrototype;
|
||||
|
@ -92,6 +93,29 @@ struct SyntaxErrorPrototype;
|
|||
struct TypeErrorPrototype;
|
||||
struct URIErrorPrototype;
|
||||
|
||||
struct Managed
|
||||
{
|
||||
private:
|
||||
Managed(const Managed &other);
|
||||
void operator = (const Managed &other);
|
||||
|
||||
protected:
|
||||
Managed() {}
|
||||
|
||||
public:
|
||||
virtual ~Managed();
|
||||
|
||||
void *operator new(size_t size, MemoryManager *mm);
|
||||
void operator delete(void *ptr);
|
||||
|
||||
protected:
|
||||
virtual void getCollectables(QVector<Object *> &objects) = 0;
|
||||
|
||||
private:
|
||||
friend class MemoryManager;
|
||||
MemoryManager *mm;
|
||||
};
|
||||
|
||||
struct String {
|
||||
inline bool isEqualTo(const String *other) const {
|
||||
if (this == other)
|
||||
|
@ -395,7 +419,7 @@ private:
|
|||
int _allocated: 27;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
struct Object: Managed {
|
||||
Object *prototype;
|
||||
String *klass;
|
||||
PropertyTable *members;
|
||||
|
@ -440,6 +464,9 @@ struct Object {
|
|||
Value getValue(ExecutionContext *ctx, PropertyDescriptor *p) const;
|
||||
bool inplaceBinOp(Value rhs, String *name, BinOp op, ExecutionContext *ctx);
|
||||
virtual bool inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContext *ctx);
|
||||
|
||||
protected:
|
||||
virtual void getCollectables(QVector<Object *> &objects);
|
||||
};
|
||||
|
||||
struct ForEachIteratorObject: Object {
|
||||
|
@ -450,6 +477,9 @@ struct ForEachIteratorObject: Object {
|
|||
virtual QString className() { return QStringLiteral("__ForEachIteratorObject"); }
|
||||
|
||||
String *nextPropertyName();
|
||||
|
||||
protected:
|
||||
virtual void getCollectables(QVector<Object *> &objects);
|
||||
};
|
||||
|
||||
struct BooleanObject: Object {
|
||||
|
@ -489,6 +519,9 @@ struct ArrayObject: Object {
|
|||
virtual Value __get__(ExecutionContext *ctx, String *name);
|
||||
|
||||
virtual bool inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContext *ctx);
|
||||
|
||||
protected:
|
||||
virtual void getCollectables(QVector<Object *> &objects);
|
||||
};
|
||||
|
||||
struct FunctionObject: Object {
|
||||
|
@ -591,6 +624,7 @@ struct ErrorObject: Object {
|
|||
|
||||
protected:
|
||||
void setNameProperty(ExecutionContext *ctx);
|
||||
virtual void getCollectables(QVector<Object *> &objects);
|
||||
};
|
||||
|
||||
struct EvalErrorObject: ErrorObject {
|
||||
|
|
13
qv4array_p.h
13
qv4array_p.h
|
@ -74,8 +74,11 @@ public:
|
|||
Array &other);
|
||||
inline void push(const Value &value);
|
||||
|
||||
void getCollectables(QVector<Object *> &objects);
|
||||
|
||||
private:
|
||||
std::deque<Value> *to_vector;
|
||||
typedef std::deque<Value> ToVectorType;
|
||||
ToVectorType *to_vector;
|
||||
};
|
||||
|
||||
class ArrayElementLessThan
|
||||
|
@ -194,6 +197,14 @@ inline void Array::push(const Value &value)
|
|||
to_vector->push_back(value);
|
||||
}
|
||||
|
||||
inline void Array::getCollectables(QVector<Object *> &objects)
|
||||
{
|
||||
for (ToVectorType::const_iterator it = to_vector->begin(), eit = to_vector->end(); it != eit; ++it) {
|
||||
if (Object *o = it->asObject())
|
||||
objects.append(o);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Array::splice(double start, double deleteCount,
|
||||
const QVector<Value> &items,
|
||||
Array &other)
|
||||
|
|
|
@ -151,7 +151,7 @@ void liveness(IR::Function *function)
|
|||
computeUseDef(s);
|
||||
}
|
||||
|
||||
dfs(function->basicBlocks.first(), &V, &blocks);
|
||||
dfs(function->basicBlocks.at(0), &V, &blocks);
|
||||
|
||||
bool changed;
|
||||
do {
|
||||
|
@ -1471,6 +1471,9 @@ void Codegen::linearize(IR::Function *function)
|
|||
exitBlock->index = trace.size();
|
||||
trace.append(exitBlock);
|
||||
|
||||
foreach (IR::BasicBlock *b, function->basicBlocks)
|
||||
if (!trace.contains(b))
|
||||
delete b;
|
||||
function->basicBlocks = trace;
|
||||
|
||||
#ifndef QV4_NO_LIVENESS
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "qv4ecmaobjects_p.h"
|
||||
#include "qv4array_p.h"
|
||||
#include "qv4mm.h"
|
||||
#include <QtCore/qnumeric.h>
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QtCore/QDateTime>
|
||||
|
@ -1860,6 +1861,8 @@ FunctionCtor::FunctionCtor(ExecutionContext *scope)
|
|||
// 15.3.2
|
||||
Value FunctionCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
MemoryManager::GCBlocker gcBlocker(ctx->engine->memoryManager);
|
||||
|
||||
QString args;
|
||||
QString body;
|
||||
if (ctx->argumentCount > 0)
|
||||
|
@ -1899,7 +1902,7 @@ Value FunctionCtor::construct(ExecutionContext *ctx)
|
|||
isel->run(irf);
|
||||
delete isel;
|
||||
|
||||
ctx->thisObject = Value::fromObject(new ScriptFunction(ctx->engine->rootContext, irf));
|
||||
ctx->thisObject = Value::fromObject(ctx->engine->newScriptFunction(ctx->engine->rootContext, irf));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
|
@ -2593,7 +2596,7 @@ Value RegExpCtor::construct(ExecutionContext *ctx)
|
|||
if (!f.isUndefined())
|
||||
ctx->throwTypeError();
|
||||
|
||||
return Value::fromObject(new RegExpObject(re->value, false));
|
||||
return Value::fromObject(new (ctx->engine->memoryManager) RegExpObject(re->value, false));
|
||||
}
|
||||
|
||||
if (r.isUndefined())
|
||||
|
@ -2623,7 +2626,7 @@ Value RegExpCtor::construct(ExecutionContext *ctx)
|
|||
if (!re.isValid())
|
||||
ctx->throwTypeError();
|
||||
|
||||
ctx->thisObject = Value::fromObject(new RegExpObject(re, global));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) RegExpObject(re, global));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
|
@ -2715,7 +2718,7 @@ ErrorCtor::ErrorCtor(ExecutionContext *scope)
|
|||
|
||||
Value ErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new ErrorObject(ctx->argument(0)));
|
||||
ctx->thisObject = Value::fromObject(ctx->engine->newErrorObject(ctx->argument(0)));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
|
@ -2732,37 +2735,37 @@ Value ErrorCtor::call(ExecutionContext *ctx)
|
|||
|
||||
Value EvalErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new EvalErrorObject(ctx));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) EvalErrorObject(ctx));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
Value RangeErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new RangeErrorObject(ctx));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) RangeErrorObject(ctx));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
Value ReferenceErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new ReferenceErrorObject(ctx));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) ReferenceErrorObject(ctx));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
Value SyntaxErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new SyntaxErrorObject(ctx, 0));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) SyntaxErrorObject(ctx, 0));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
Value TypeErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new TypeErrorObject(ctx));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) TypeErrorObject(ctx));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
Value URIErrorCtor::construct(ExecutionContext *ctx)
|
||||
{
|
||||
ctx->thisObject = Value::fromObject(new URIErrorObject(ctx));
|
||||
ctx->thisObject = Value::fromObject(new (ctx->engine->memoryManager) URIErrorObject(ctx));
|
||||
return ctx->thisObject;
|
||||
}
|
||||
|
||||
|
|
16
qv4ir.cpp
16
qv4ir.cpp
|
@ -391,7 +391,19 @@ Function *Module::newFunction(const QString &name)
|
|||
return f;
|
||||
}
|
||||
|
||||
Module::~Module()
|
||||
{
|
||||
foreach (Function *f, functions)
|
||||
f->releaseModuleManagedData();
|
||||
}
|
||||
|
||||
Function::~Function()
|
||||
{
|
||||
delete[] codeData;
|
||||
}
|
||||
|
||||
|
||||
void Function::releaseModuleManagedData()
|
||||
{
|
||||
// destroy the Stmt::Data blocks manually, because memory pool cleanup won't
|
||||
// call the Stmt destructors.
|
||||
|
@ -400,9 +412,11 @@ Function::~Function()
|
|||
s->destroyData();
|
||||
|
||||
qDeleteAll(basicBlocks);
|
||||
delete[] codeData;
|
||||
pool = 0;
|
||||
module = 0;
|
||||
}
|
||||
|
||||
|
||||
const QString *Function::newString(const QString &text)
|
||||
{
|
||||
return &*strings.insert(text);
|
||||
|
|
|
@ -587,6 +587,8 @@ struct Module {
|
|||
QVector<Function *> functions;
|
||||
|
||||
Function *newFunction(const QString &name);
|
||||
|
||||
~Module();
|
||||
};
|
||||
|
||||
struct Function {
|
||||
|
@ -626,6 +628,7 @@ struct Function {
|
|||
{ this->name = newString(name); }
|
||||
|
||||
~Function();
|
||||
void releaseModuleManagedData();
|
||||
|
||||
enum BasicBlockInsertMode {
|
||||
InsertBlock,
|
||||
|
|
|
@ -0,0 +1,375 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmljs_engine.h"
|
||||
#include "qmljs_objects.h"
|
||||
#include "qv4ecmaobjects_p.h"
|
||||
#include "qv4mm.h"
|
||||
|
||||
#include <QTime>
|
||||
#include <QVector>
|
||||
#include <QLinkedList>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace QQmlJS::VM;
|
||||
|
||||
static const std::size_t CHUNK_SIZE = 65536;
|
||||
|
||||
struct MemoryManager::Data
|
||||
{
|
||||
bool enableGC;
|
||||
bool gcBlocked;
|
||||
bool scribble;
|
||||
bool aggressiveGC;
|
||||
ExecutionEngine *engine;
|
||||
StringPool *stringPool;
|
||||
|
||||
// FIXME: this freeList will get out of hand if there is one allocation+deallocation of, say, 16M.
|
||||
// TODO: turn the freeList into a fixed length array which can hold the most common sizes (e.g. up to 64K), then use a tree for anything afterwards.
|
||||
// TODO: this requires that the interaction with the freeList is factored out first into separate methods.
|
||||
QVector<MMObject *> freeList;
|
||||
QLinkedList<QPair<char *, std::size_t> > heapChunks;
|
||||
|
||||
// statistics:
|
||||
#ifdef DETAILED_MM_STATS
|
||||
QVector<unsigned> allocSizeCounters;
|
||||
#endif // DETAILED_MM_STATS
|
||||
|
||||
Data(bool enableGC)
|
||||
: enableGC(enableGC)
|
||||
, gcBlocked(false)
|
||||
, engine(0)
|
||||
, stringPool(0)
|
||||
, freeList(0)
|
||||
{
|
||||
scribble = qgetenv("MM_NO_SCRIBBLE").isEmpty();
|
||||
aggressiveGC = !qgetenv("MM_AGGRESSIVE_GC").isEmpty();
|
||||
}
|
||||
|
||||
~Data()
|
||||
{
|
||||
for (QLinkedList<QPair<char *, std::size_t> >::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i)
|
||||
delete[] i->first;
|
||||
}
|
||||
};
|
||||
|
||||
MemoryManager::MemoryManager()
|
||||
: m_d(new Data(true))
|
||||
{
|
||||
}
|
||||
|
||||
MemoryManager::MMObject *MemoryManager::alloc(std::size_t size)
|
||||
{
|
||||
if (m_d->aggressiveGC)
|
||||
runGC();
|
||||
#ifdef DETAILED_MM_STATS
|
||||
willAllocate(size);
|
||||
#endif // DETAILED_MM_STATS
|
||||
|
||||
size += sizeof(MMInfo);
|
||||
assert(size >= 16);
|
||||
assert(size % 16 == 0);
|
||||
|
||||
for (std::size_t s = size / 16, es = m_d->freeList.size(); s < es; ++s) {
|
||||
if (MMObject *m = m_d->freeList.at(s)) {
|
||||
m_d->freeList[s] = m->info.next;
|
||||
|
||||
if (s != size / 16) {
|
||||
MMObject *tail = reinterpret_cast<MMObject *>(reinterpret_cast<char *>(m) + size);
|
||||
assert(m->info.size == s * 16);
|
||||
tail->info.inUse = 0;
|
||||
tail->info.markBit = 0;
|
||||
tail->info.size = m->info.size - size;
|
||||
MMObject *&f = m_d->freeList[tail->info.size / 16];
|
||||
tail->info.next = f;
|
||||
f = tail;
|
||||
m->info.size = size;
|
||||
}
|
||||
|
||||
m->info.inUse = 1;
|
||||
m->info.markBit = 0;
|
||||
scribble(m, 0xaa);
|
||||
// qDebug("alloc(%lu) -> %p", size, m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_d->aggressiveGC)
|
||||
if (runGC() >= size)
|
||||
return alloc(size - sizeof(MMInfo));
|
||||
|
||||
std::size_t allocSize = std::max(size, CHUNK_SIZE);
|
||||
char *ptr = new char[allocSize];
|
||||
m_d->heapChunks.append(qMakePair(ptr, allocSize));
|
||||
// qDebug("Allocated new chunk of %lu bytes @ %p", allocSize, ptr);
|
||||
|
||||
if (allocSize > size) {
|
||||
MMObject *m = reinterpret_cast<MMObject *>(ptr + size);
|
||||
m->info.size = allocSize - size;
|
||||
std::size_t off = m->info.size / 16;
|
||||
if (((std::size_t) m_d->freeList.size()) <= off)
|
||||
m_d->freeList.resize(off + 1);
|
||||
MMObject *&f = m_d->freeList[off];
|
||||
m->info.next = f;
|
||||
f = m;
|
||||
}
|
||||
|
||||
MMObject *m = reinterpret_cast<MMObject *>(ptr);
|
||||
m->info.inUse = 1;
|
||||
m->info.markBit = 0;
|
||||
m->info.size = size;
|
||||
scribble(m, 0xaa);
|
||||
// qDebug("alloc(%lu) -> %p", size, ptr);
|
||||
return m;
|
||||
}
|
||||
|
||||
void MemoryManager::dealloc(MMObject *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
assert(ptr->info.size >= 16);
|
||||
assert(ptr->info.size % 16 == 0);
|
||||
|
||||
// qDebug("dealloc %p (%lu)", ptr, ptr->info.size);
|
||||
|
||||
std::size_t off = ptr->info.size / 16;
|
||||
if (((std::size_t) m_d->freeList.size()) <= off)
|
||||
m_d->freeList.resize(off + 1);
|
||||
MMObject *&f = m_d->freeList[off];
|
||||
ptr->info.next = f;
|
||||
ptr->info.inUse = 0;
|
||||
ptr->info.markBit = 0;
|
||||
ptr->info.needsManagedDestructorCall = 0;
|
||||
f = ptr;
|
||||
scribble(ptr, 0x55);
|
||||
}
|
||||
|
||||
void MemoryManager::scribble(MemoryManager::MMObject *obj, int c) const
|
||||
{
|
||||
if (m_d->scribble)
|
||||
::memset(&obj->data, c, obj->info.size - sizeof(MMInfo));
|
||||
}
|
||||
|
||||
std::size_t MemoryManager::mark(const QVector<Object *> &objects)
|
||||
{
|
||||
std::size_t marks = 0;
|
||||
|
||||
QVector<Object *> kids;
|
||||
kids.reserve(32);
|
||||
|
||||
foreach (Object *o, objects) {
|
||||
if (!o)
|
||||
continue;
|
||||
|
||||
MMObject *obj = toObject(o);
|
||||
assert(obj->info.inUse);
|
||||
if (obj->info.markBit == 0) {
|
||||
obj->info.markBit = 1;
|
||||
++marks;
|
||||
static_cast<Managed *>(o)->getCollectables(kids);
|
||||
marks += mark(kids);
|
||||
kids.resize(0);
|
||||
}
|
||||
}
|
||||
|
||||
return marks;
|
||||
}
|
||||
|
||||
std::size_t MemoryManager::sweep(std::size_t &largestFreedBlock)
|
||||
{
|
||||
std::size_t freedCount = 0;
|
||||
|
||||
for (QLinkedList<QPair<char *, std::size_t> >::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
|
||||
freedCount += sweep(i->first, i->second, largestFreedBlock);
|
||||
|
||||
return freedCount;
|
||||
}
|
||||
|
||||
std::size_t MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, std::size_t &largestFreedBlock)
|
||||
{
|
||||
// qDebug("chunkStart @ %p", chunkStart);
|
||||
std::size_t freedCount = 0;
|
||||
|
||||
for (char *chunk = chunkStart, *chunkEnd = chunk + chunkSize; chunk < chunkEnd; ) {
|
||||
MMObject *m = reinterpret_cast<MMObject *>(chunk);
|
||||
// qDebug("chunk @ %p, size = %lu, in use: %s, mark bit: %s",
|
||||
// chunk, m->info.size, (m->info.inUse ? "yes" : "no"), (m->info.markBit ? "true" : "false"));
|
||||
|
||||
assert((intptr_t) chunk % 16 == 0);
|
||||
assert(m->info.size >= 16);
|
||||
assert(m->info.size % 16 == 0);
|
||||
|
||||
chunk = chunk + m->info.size;
|
||||
if (m->info.inUse) {
|
||||
if (m->info.markBit) {
|
||||
m->info.markBit = 0;
|
||||
} else {
|
||||
// qDebug("-- collecting it.");
|
||||
if (m->info.needsManagedDestructorCall)
|
||||
reinterpret_cast<VM::Managed *>(&m->data)->~Managed();
|
||||
dealloc(m);
|
||||
largestFreedBlock = std::max(largestFreedBlock, m->info.size);
|
||||
++freedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return freedCount;
|
||||
}
|
||||
|
||||
bool MemoryManager::isGCBlocked() const
|
||||
{
|
||||
return m_d->gcBlocked;
|
||||
}
|
||||
|
||||
void MemoryManager::setGCBlocked(bool blockGC)
|
||||
{
|
||||
m_d->gcBlocked = blockGC;
|
||||
}
|
||||
|
||||
std::size_t MemoryManager::runGC()
|
||||
{
|
||||
if (!m_d->enableGC || m_d->gcBlocked) {
|
||||
// qDebug() << "Not running GC.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// QTime t; t.start();
|
||||
|
||||
QVector<Object *> roots;
|
||||
collectRoots(roots);
|
||||
// std::cerr << "GC: found " << roots.size()
|
||||
// << " roots in " << t.elapsed()
|
||||
// << "ms" << std::endl;
|
||||
|
||||
// t.restart();
|
||||
/*std::size_t marks =*/ mark(roots);
|
||||
// std::cerr << "GC: marked " << marks
|
||||
// << " objects in " << t.elapsed()
|
||||
// << "ms" << std::endl;
|
||||
|
||||
// t.restart();
|
||||
std::size_t freedCount = 0, largestFreedBlock = 0;
|
||||
freedCount = sweep(largestFreedBlock);
|
||||
// std::cerr << "GC: sweep freed " << freedCount
|
||||
// << " objects in " << t.elapsed()
|
||||
// << "ms" << std::endl;
|
||||
|
||||
return largestFreedBlock;
|
||||
}
|
||||
|
||||
void MemoryManager::setEnableGC(bool enableGC)
|
||||
{
|
||||
m_d->enableGC = enableGC;
|
||||
}
|
||||
|
||||
MemoryManager::~MemoryManager()
|
||||
{
|
||||
std::size_t dummy = 0;
|
||||
sweep(dummy);
|
||||
}
|
||||
|
||||
static inline void add(QVector<Object *> &values, const Value &v)
|
||||
{
|
||||
if (Object *o = v.asObject())
|
||||
values.append(o);
|
||||
}
|
||||
|
||||
void MemoryManager::setExecutionEngine(ExecutionEngine *engine)
|
||||
{
|
||||
m_d->engine = engine;
|
||||
}
|
||||
|
||||
void MemoryManager::setStringPool(StringPool *stringPool)
|
||||
{
|
||||
m_d->stringPool = stringPool;
|
||||
}
|
||||
|
||||
void MemoryManager::dumpStats() const
|
||||
{
|
||||
std::cerr << "=================" << std::endl;
|
||||
std::cerr << "Allocation stats:" << std::endl;
|
||||
#ifdef DETAILED_MM_STATS
|
||||
std::cerr << "Requests for each chunk size:" << std::endl;
|
||||
for (int i = 0; i < m_d->allocSizeCounters.size(); ++i) {
|
||||
if (unsigned count = m_d->allocSizeCounters[i]) {
|
||||
std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl;
|
||||
}
|
||||
}
|
||||
#endif // DETAILED_MM_STATS
|
||||
}
|
||||
|
||||
ExecutionEngine *MemoryManager::engine() const
|
||||
{
|
||||
return m_d->engine;
|
||||
}
|
||||
|
||||
#ifdef DETAILED_MM_STATS
|
||||
void MemoryManager::willAllocate(std::size_t size)
|
||||
{
|
||||
unsigned alignedSize = (size + 15) >> 4;
|
||||
QVector<unsigned> &counters = m_d->allocSizeCounters;
|
||||
if ((unsigned) counters.size() < alignedSize + 1)
|
||||
counters.resize(alignedSize + 1);
|
||||
counters[alignedSize]++;
|
||||
}
|
||||
#endif // DETAILED_MM_STATS
|
||||
|
||||
void MemoryManager::collectRoots(QVector<VM::Object *> &roots) const
|
||||
{
|
||||
add(roots, m_d->engine->globalObject);
|
||||
add(roots, m_d->engine->exception);
|
||||
|
||||
for (ExecutionContext *ctxt = engine()->current; ctxt; ctxt = ctxt->parent) {
|
||||
add(roots, ctxt->thisObject);
|
||||
if (ctxt->function)
|
||||
roots.append(ctxt->function);
|
||||
for (unsigned arg = 0, lastArg = ctxt->formalCount(); arg < lastArg; ++arg)
|
||||
add(roots, ctxt->arguments[arg]);
|
||||
for (unsigned local = 0, lastLocal = ctxt->variableCount(); local < lastLocal; ++local)
|
||||
add(roots, ctxt->locals[local]);
|
||||
if (ctxt->activation)
|
||||
roots.append(ctxt->activation);
|
||||
for (ExecutionContext::With *it = ctxt->withObject; it; it = it->next)
|
||||
if (it->object)
|
||||
roots.append(it->object);
|
||||
}
|
||||
|
||||
collectRootsOnStack(roots);
|
||||
}
|
||||
|
||||
MemoryManagerWithoutGC::~MemoryManagerWithoutGC()
|
||||
{}
|
||||
|
||||
void MemoryManagerWithoutGC::collectRootsOnStack(QVector<VM::Object *> &roots) const
|
||||
{
|
||||
Q_UNUSED(roots);
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QV4GC_H
|
||||
#define QV4GC_H
|
||||
|
||||
#include "qmljs_objects.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
|
||||
#define DETAILED_MM_STATS
|
||||
|
||||
namespace QQmlJS {
|
||||
namespace VM {
|
||||
|
||||
class MemoryManager
|
||||
{
|
||||
MemoryManager(const MemoryManager &);
|
||||
MemoryManager &operator=(const MemoryManager&);
|
||||
|
||||
struct Data;
|
||||
|
||||
public:
|
||||
class GCBlocker
|
||||
{
|
||||
public:
|
||||
GCBlocker(MemoryManager *mm)
|
||||
: mm(mm)
|
||||
, wasBlocked(mm->isGCBlocked())
|
||||
{
|
||||
mm->setGCBlocked(true);
|
||||
}
|
||||
|
||||
~GCBlocker()
|
||||
{
|
||||
mm->setGCBlocked(wasBlocked);
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryManager *mm;
|
||||
bool wasBlocked;
|
||||
};
|
||||
|
||||
public:
|
||||
MemoryManager();
|
||||
virtual ~MemoryManager() = 0;
|
||||
|
||||
// TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries).
|
||||
// Note: all occurances of "16" in alloc/dealloc are also due to the alignment.
|
||||
static inline std::size_t align(std::size_t size)
|
||||
{ return (size + 15) & ~0xf; }
|
||||
|
||||
inline Managed *allocManaged(std::size_t size)
|
||||
{
|
||||
size = align(size);
|
||||
MMObject *o = alloc(size);
|
||||
o->info.needsManagedDestructorCall = 1;
|
||||
Managed *ptr = reinterpret_cast<Managed *>(&o->data);
|
||||
ptr->mm = this;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
inline void deallocManaged(Managed *m)
|
||||
{
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
assert(m->mm == this);
|
||||
dealloc(toObject(m));
|
||||
}
|
||||
|
||||
bool isGCBlocked() const;
|
||||
void setGCBlocked(bool blockGC);
|
||||
std::size_t runGC();
|
||||
|
||||
void setEnableGC(bool enableGC);
|
||||
void setExecutionEngine(ExecutionEngine *engine);
|
||||
void setStringPool(StringPool *stringPool);
|
||||
|
||||
void dumpStats() const;
|
||||
|
||||
protected:
|
||||
#if 1 // 64bit and x86:
|
||||
struct MMObject;
|
||||
struct MMInfo {
|
||||
std::size_t inUse : 1;
|
||||
std::size_t markBit : 1;
|
||||
std::size_t needsManagedDestructorCall : 1;
|
||||
std::size_t size : 61;
|
||||
MMObject *next;
|
||||
};
|
||||
struct MMObject {
|
||||
MMInfo info;
|
||||
std::size_t data;
|
||||
};
|
||||
#endif
|
||||
#if 0 // for 32bits:
|
||||
// untested!
|
||||
struct MMInfo {
|
||||
std::size_t inUse : 1;
|
||||
std::size_t markBit : 1;
|
||||
std::size_t size : 30;
|
||||
};
|
||||
struct MMObject {
|
||||
MMInfo info;
|
||||
union {
|
||||
struct MMObject *next;
|
||||
char data[1];
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static inline MMObject *toObject(void *ptr) { return reinterpret_cast<MMObject *>(reinterpret_cast<char *>(ptr) - sizeof(MMInfo)); }
|
||||
|
||||
/// expects size to be aligned
|
||||
// TODO: try to inline
|
||||
MMObject *alloc(std::size_t size);
|
||||
|
||||
// TODO: try to inline
|
||||
void dealloc(MMObject *ptr);
|
||||
|
||||
void scribble(MMObject *obj, int c) const;
|
||||
|
||||
virtual void collectRootsOnStack(QVector<VM::Object *> &roots) const = 0;
|
||||
|
||||
ExecutionEngine *engine() const;
|
||||
|
||||
#ifdef DETAILED_MM_STATS
|
||||
void willAllocate(std::size_t size);
|
||||
#endif // DETAILED_MM_STATS
|
||||
|
||||
private:
|
||||
void collectRoots(QVector<VM::Object *> &roots) const;
|
||||
static std::size_t mark(const QVector<Object *> &objects);
|
||||
std::size_t sweep(std::size_t &largestFreedBlock);
|
||||
std::size_t sweep(char *chunkStart, std::size_t chunkSize, std::size_t &largestFreedBlock);
|
||||
|
||||
private:
|
||||
QScopedPointer<Data> m_d;
|
||||
};
|
||||
|
||||
class MemoryManagerWithoutGC: public MemoryManager
|
||||
{
|
||||
public:
|
||||
MemoryManagerWithoutGC()
|
||||
{ setEnableGC(false); }
|
||||
|
||||
virtual ~MemoryManagerWithoutGC();
|
||||
|
||||
protected:
|
||||
virtual void collectRootsOnStack(QVector<VM::Object *> &roots) const;
|
||||
};
|
||||
|
||||
} // namespace VM
|
||||
} // namespace QQmlJS
|
||||
|
||||
#endif // QV4GC_H
|
6
v4.pro
6
v4.pro
|
@ -24,7 +24,8 @@ SOURCES += main.cpp \
|
|||
qv4isel_masm.cpp \
|
||||
llvm_runtime.cpp \
|
||||
qv4isel_p.cpp \
|
||||
debugging.cpp
|
||||
debugging.cpp \
|
||||
qv4mm.cpp
|
||||
|
||||
HEADERS += \
|
||||
qv4codegen_p.h \
|
||||
|
@ -41,7 +42,8 @@ HEADERS += \
|
|||
qv4isel_masm_p.h \
|
||||
qv4isel_p.h \
|
||||
qv4isel_util_p.h \
|
||||
debugging.h
|
||||
debugging.h \
|
||||
qv4mm.h
|
||||
|
||||
llvm {
|
||||
|
||||
|
|
Loading…
Reference in New Issue