From ef9751ee246ca77a75ece557326311ac1436db0c Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 19 Jul 2011 15:12:40 +0200 Subject: [PATCH] Change the V4 IR so it can be stored in a memory pool. That is, remove members with a non-trivial destructor from IR::Stmt and IR::Expr (that's because we don't destroy the objects allocated in the pool). Added the method MemoryPool::reset() so we can clear the pool without disposing the allocated memory. Change-Id: I126332be387c016578c086db8b3aa8098b2507f6 Reviewed-on: http://codereview.qt.nokia.com/3758 Reviewed-by: Roberto Raggi Reviewed-by: Qt Sanity Bot --- .../qml/parser/qdeclarativejsmemorypool_p.h | 111 ++++++++++++-------- src/declarative/qml/v4/qdeclarativev4compiler.cpp | 19 ++-- .../qml/v4/qdeclarativev4compiler_p_p.h | 3 +- src/declarative/qml/v4/qdeclarativev4ir.cpp | 85 +++++++++++----- src/declarative/qml/v4/qdeclarativev4ir_p.h | 65 +++++++----- src/declarative/qml/v4/qdeclarativev4irbuilder.cpp | 11 ++- 6 files changed, 188 insertions(+), 106 deletions(-) diff --git a/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h index e921ac6..043331d 100644 --- a/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h +++ b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h @@ -57,8 +57,9 @@ #include #include +#include -#include +#include QT_QML_BEGIN_NAMESPACE @@ -66,63 +67,89 @@ namespace QDeclarativeJS { class QML_PARSER_EXPORT MemoryPool : public QSharedData { + MemoryPool(const MemoryPool &other); + void operator =(const MemoryPool &other); + public: - enum { maxBlockCount = -1 }; - enum { defaultBlockSize = 1 << 12 }; - - MemoryPool() { - m_blockIndex = maxBlockCount; - m_currentIndex = 0; - m_storage = 0; - m_currentBlock = 0; - m_currentBlockSize = 0; + MemoryPool() + : _blocks(0), + _allocatedBlocks(0), + _blockCount(-1), + _ptr(0), + _end(0) + { } + + ~MemoryPool() + { + if (_blocks) { + for (int i = 0; i < _allocatedBlocks; ++i) { + if (char *b = _blocks[i]) + qFree(b); + } + + qFree(_blocks); + } } - virtual ~MemoryPool() { - for (int index = 0; index < m_blockIndex + 1; ++index) - qFree(m_storage[index]); + inline void *allocate(size_t size) + { + size = (size + 7) & ~7; + if (_ptr && (_ptr + size < _end)) { + void *addr = _ptr; + _ptr += size; + return addr; + } + return allocate_helper(size); + } - qFree(m_storage); + void reset() + { + _blockCount = -1; + _ptr = _end = 0; } - char *allocate(int bytes) { - bytes += (8 - bytes) & 7; // ensure multiple of 8 bytes (maintain alignment) - if (m_currentBlock == 0 || m_currentBlockSize < m_currentIndex + bytes) { - ++m_blockIndex; - m_currentBlockSize = defaultBlockSize << m_blockIndex; +private: + void *allocate_helper(size_t size) + { + Q_ASSERT(size < BLOCK_SIZE); - m_storage = reinterpret_cast(qRealloc(m_storage, sizeof(char*) * (1 + m_blockIndex))); - m_currentBlock = m_storage[m_blockIndex] = reinterpret_cast(qMalloc(m_currentBlockSize)); + if (++_blockCount == _allocatedBlocks) { + if (! _allocatedBlocks) + _allocatedBlocks = DEFAULT_BLOCK_COUNT; + else + _allocatedBlocks *= 2; - m_currentIndex = (8 - quintptr(m_currentBlock)) & 7; // ensure first chunk is 64-bit aligned - Q_ASSERT(m_currentIndex + bytes <= m_currentBlockSize); + _blocks = (char **) qRealloc(_blocks, sizeof(char *) * _allocatedBlocks); + + for (int index = _blockCount; index < _allocatedBlocks; ++index) + _blocks[index] = 0; } - char *p = reinterpret_cast - (m_currentBlock + m_currentIndex); + char *&block = _blocks[_blockCount]; - m_currentIndex += bytes; + if (! block) + block = (char *) qMalloc(BLOCK_SIZE); - return p; - } + _ptr = block; + _end = _ptr + BLOCK_SIZE; - int bytesAllocated() const { - int bytes = 0; - for (int index = 0; index < m_blockIndex; ++index) - bytes += (defaultBlockSize << index); - bytes += m_currentIndex; - return bytes; + void *addr = _ptr; + _ptr += size; + return addr; } private: - int m_blockIndex; - int m_currentIndex; - char *m_currentBlock; - int m_currentBlockSize; - char **m_storage; - -private: - Q_DISABLE_COPY(MemoryPool) + char **_blocks; + int _allocatedBlocks; + int _blockCount; + char *_ptr; + char *_end; + + enum + { + BLOCK_SIZE = 8 * 1024, + DEFAULT_BLOCK_COUNT = 8 + }; }; class QML_PARSER_EXPORT Managed diff --git a/src/declarative/qml/v4/qdeclarativev4compiler.cpp b/src/declarative/qml/v4/qdeclarativev4compiler.cpp index 371edda..332ce03 100644 --- a/src/declarative/qml/v4/qdeclarativev4compiler.cpp +++ b/src/declarative/qml/v4/qdeclarativev4compiler.cpp @@ -91,11 +91,11 @@ void QDeclarativeV4CompilerPrivate::trace(int line, int column) if (IR::Stmt *terminator = block->terminator()) { if (IR::CJump *cj = terminator->asCJump()) { if (cj->iffalse != next) { - block->i(new IR::Jump(cj->iffalse)); + block->i(new (_function->module->pool) IR::Jump(cj->iffalse)); } } else if (IR::Jump *j = terminator->asJump()) { if (j->target == next) { - delete block->statements.back(); + delete block->statements.at(block->statements.size() - 1); block->statements.resize(block->statements.size() - 1); } } @@ -174,9 +174,8 @@ void QDeclarativeV4CompilerPrivate::trace(int line, int column) void QDeclarativeV4CompilerPrivate::trace(QVector *blocks) { - QList todo = QList::fromVector(_function->basicBlocks); - while (! todo.isEmpty()) { - IR::BasicBlock *block = todo.takeFirst(); + for (int i = 0; i < _function->basicBlocks.size(); ++i) { + IR::BasicBlock *block = _function->basicBlocks.at(i); while (! blocks->contains(block)) { blocks->append(block); @@ -763,8 +762,9 @@ void QDeclarativeV4CompilerPrivate::visitBinop(IR::Binop *e) void QDeclarativeV4CompilerPrivate::visitCall(IR::Call *call) { if (IR::Name *name = call->base->asName()) { - if (call->args.size() == 1 && call->args.at(0)->type == IR::RealType) { - traceExpression(call->args.at(0), currentReg); + IR::Expr *arg = call->onlyArgument(); + if (arg != 0 && arg->type == IR::RealType) { + traceExpression(arg, currentReg); Instr instr; instr.common.type = Instr::Noop; @@ -989,6 +989,7 @@ void QDeclarativeV4CompilerPrivate::resetInstanceState() registeredStrings = committed.registeredStrings; bytecode.clear(); patches.clear(); + pool.reset(); // reset the memory pool without disposing the allocated memory currentReg = 0; } @@ -1032,7 +1033,7 @@ bool QDeclarativeV4CompilerPrivate::compile(QDeclarativeJS::AST::Node *node) return false; } - IR::Module module; + IR::Module module(&pool); IR::Function *function = 0; QDeclarativeV4IRBuilder irBuilder(expression, engine); @@ -1067,7 +1068,7 @@ bool QDeclarativeV4CompilerPrivate::compile(QDeclarativeJS::AST::Node *node) } // Returns a reg -int QDeclarativeV4CompilerPrivate::registerLiteralString(quint8 reg, const QString &str) +int QDeclarativeV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str) { // ### string cleanup diff --git a/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h index 1d9414d..e2c85f4 100644 --- a/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h +++ b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h @@ -111,7 +111,7 @@ public: QHash > registerCleanups; - int registerLiteralString(quint8 reg, const QString &); + int registerLiteralString(quint8 reg, const QStringRef &); int registerString(const QString &); QHash > registeredStrings; QByteArray data; @@ -137,6 +137,7 @@ public: : block(block), offset(index) {} }; QVector patches; + QDeclarativeJS::MemoryPool pool; // Committed binding data struct { diff --git a/src/declarative/qml/v4/qdeclarativev4ir.cpp b/src/declarative/qml/v4/qdeclarativev4ir.cpp index c9c2c08..bc2cc62 100644 --- a/src/declarative/qml/v4/qdeclarativev4ir.cpp +++ b/src/declarative/qml/v4/qdeclarativev4ir.cpp @@ -165,10 +165,11 @@ void String::dump(QTextStream &out) out << '"' << escape(value) << '"'; } -QString String::escape(const QString &s) +QString String::escape(const QStringRef &s) { QString r; - foreach (const QChar &ch, s) { + for (int i = 0; i < s.length(); ++i) { + const QChar ch = s.at(i); if (ch == QLatin1Char('\n')) r += QLatin1String("\\n"); else if (ch == QLatin1Char('\r')) @@ -185,7 +186,7 @@ QString String::escape(const QString &s) return r; } -Name::Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column) +Name::Name(Name *base, Type type, QString &id, Symbol symbol, quint32 line, quint32 column) : Expr(type) , base(base) , id(id) @@ -318,10 +319,10 @@ void Call::dump(QTextStream &out) { base->dump(out); out << '('; - for (int i = 0; i < args.size(); ++i) { - if (i) + for (ExprList *it = args; it; it = it->next) { + if (it != args) out << ", "; - args.at(i)->dump(out); + it->expr->dump(out); } out << ')'; } @@ -396,7 +397,6 @@ void Ret::dump(QTextStream &out, Mode) Function::~Function() { qDeleteAll(basicBlocks); - qDeleteAll(temps); } BasicBlock *Function::newBasicBlock() @@ -419,7 +419,7 @@ void Function::dump(QTextStream &out) Temp *BasicBlock::TEMP(Type type, int index) { - return function->e(new Temp(type, index)); + return function->e(new (function->module->pool) Temp(type, index)); } Temp *BasicBlock::TEMP(Type type) @@ -434,12 +434,12 @@ Expr *BasicBlock::CONST(double value) Expr *BasicBlock::CONST(Type type, double value) { - return function->e(new Const(type, value)); + return function->e(new (function->module->pool) Const(type, value)); } -Expr *BasicBlock::STRING(const QString &value) +Expr *BasicBlock::STRING(const QStringRef &value) { - return function->e(new String(value)); + return function->e(new (function->module->pool) String(value)); } Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) @@ -449,7 +449,9 @@ Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column) { - return function->e(new Name(base, InvalidType, id, Name::Unbound, line, column)); + return function->e(new (function->module->pool) Name(base, InvalidType, + function->module->newIdentifier(id), + Name::Unbound, line, column)); } Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, @@ -463,7 +465,9 @@ Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, quint32 line, quint32 column) { - Name *name = new Name(base, type, id, Name::Property, line, column); + Name *name = new (function->module->pool) Name(base, type, + function->module->newIdentifier(id), + Name::Property, line, column); name->meta = meta; name->index = index; name->storage = storage; @@ -473,7 +477,9 @@ Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaOb Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, quint32 line, quint32 column) { - Name *name = new Name(base, type, id, Name::Property, line, column); + Name *name = new (function->module->pool) Name(base, type, + function->module->newIdentifier(id), + Name::Property, line, column); name->meta = meta; name->index = index; return function->e(name); @@ -481,7 +487,9 @@ Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaOb Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column) { - Name *name = new Name(/*base = */ 0, IR::ObjectType, id, Name::IdObject, line, column); + Name *name = new (function->module->pool) Name(/*base = */ 0, IR::ObjectType, + function->module->newIdentifier(id), + Name::IdObject, line, column); name->idObject = object; name->index = object->idIndex; name->storage = Name::IdStorage; @@ -491,7 +499,9 @@ Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage, quint32 line, quint32 column) { - Name *name = new Name(/*base = */ 0, IR::AttachType, id, Name::AttachType, line, column); + Name *name = new (function->module->pool) Name(/*base = */ 0, IR::AttachType, + function->module->newIdentifier(id), + Name::AttachType, line, column); name->declarativeType = attachType; name->storage = storage; return function->e(name); @@ -500,7 +510,7 @@ Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachT Expr *BasicBlock::UNOP(AluOp op, Expr *expr) { - return function->e(new Unop(op, expr)); + return function->e(new (function->module->pool) Unop(op, expr)); } Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) @@ -543,22 +553,22 @@ Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) } } - return function->e(new Binop(op, left, right)); + return function->e(new (function->module->pool) Binop(op, left, right)); } -Expr *BasicBlock::CALL(Expr *base, const QVector &args) +Expr *BasicBlock::CALL(Expr *base, ExprList *args) { - return function->e(new Call(base, args)); + return function->e(new (function->module->pool) Call(base, args)); } Stmt *BasicBlock::EXP(Expr *expr) { - return i(new Exp(expr)); + return i(new (function->module->pool) Exp(expr)); } Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn) { - return i(new Move(target, source, isMoveForReturn)); + return i(new (function->module->pool) Move(target, source, isMoveForReturn)); } Stmt *BasicBlock::JUMP(BasicBlock *target) @@ -566,14 +576,14 @@ Stmt *BasicBlock::JUMP(BasicBlock *target) if (isTerminated()) return 0; else - return i(new Jump(target)); + return i(new (function->module->pool) Jump(target)); } Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) { if (isTerminated()) return 0; - return i(new CJump(cond, iftrue, iffalse)); + return i(new (function->module->pool) CJump(cond, iftrue, iffalse)); } Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column) @@ -581,7 +591,7 @@ Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column) if (isTerminated()) return 0; else - return i(new Ret(expr, type, line, column)); + return i(new (function->module->pool) Ret(expr, type, line, column)); } void BasicBlock::dump(QTextStream &out) @@ -594,6 +604,31 @@ void BasicBlock::dump(QTextStream &out) } } +Module::Module(MemoryPool *pool) + : pool(pool) +{ +} + +Module::~Module() +{ + qDeleteAll(functions); + qDeleteAll(strings); +} + +QString &Module::newIdentifier(const QString &text) +{ + QString *s = new QString(text); + strings.append(s); + return *s; +} + +Function *Module::newFunction(const QString &name) +{ + Function *f = new Function(this, name); + functions.append(f); + return f; +} + void Module::dump(QTextStream &out) { foreach (Function *fun, functions) { diff --git a/src/declarative/qml/v4/qdeclarativev4ir_p.h b/src/declarative/qml/v4/qdeclarativev4ir_p.h index e8fde4f..a27b8d8 100644 --- a/src/declarative/qml/v4/qdeclarativev4ir_p.h +++ b/src/declarative/qml/v4/qdeclarativev4ir_p.h @@ -60,7 +60,8 @@ #include #include -#include +#include +#include .h> // #define DEBUG_IR_STRUCTURE @@ -175,7 +176,7 @@ struct StmtVisitor { virtual void visitRet(Ret *) {} }; -struct Expr { +struct Expr: Managed { Type type; Expr(Type type): type(type) {} @@ -191,6 +192,14 @@ struct Expr { virtual void dump(QTextStream &out) = 0; }; +struct ExprList: Managed { + Expr *expr; + ExprList *next; + + ExprList(Expr *expr, ExprList *next = 0) + : expr(expr), next(next) {} +}; + struct Const: Expr { double value; Const(Type type, double value): Expr(type), value(value) {} @@ -202,14 +211,14 @@ struct Const: Expr { }; struct String: Expr { - QString value; - String(const QString &value): Expr(StringType), value(value) {} + QStringRef value; + String(const QStringRef &value): Expr(StringType), value(value) {} virtual void accept(ExprVisitor *v) { v->visitString(this); } virtual String *asString() { return this; } virtual void dump(QTextStream &out); - static QString escape(const QString &s); + static QString escape(const QStringRef &s); }; enum BuiltinSymbol { @@ -240,7 +249,7 @@ struct Name: Expr { }; Name *base; - QString id; + QString &id; Symbol symbol; union { void *ptr; @@ -254,7 +263,7 @@ struct Name: Expr { quint32 line; quint32 column; - Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column); + Name(Name *base, Type type, QString &id, Symbol symbol, quint32 line, quint32 column); inline bool is(Symbol s) const { return s == symbol; } inline bool isNot(Symbol s) const { return s != symbol; } @@ -309,11 +318,17 @@ private: struct Call: Expr { Expr *base; - QVector args; + ExprList *args; - Call(Expr *base, const QVector &args) + Call(Expr *base, ExprList *args) : Expr(typeForFunction(base)), base(base), args(args) {} + Expr *onlyArgument() const { + if (args && ! args->next) + return args->expr; + return 0; + } + virtual void accept(ExprVisitor *v) { v->visitCall(this); } virtual Call *asCall() { return this; } @@ -323,7 +338,7 @@ private: static Type typeForFunction(Expr *base); }; -struct Stmt { +struct Stmt: Managed { enum Mode { HIR, MIR @@ -409,11 +424,10 @@ struct Function { Module *module; QString name; int tempCount; - QVector basicBlocks; - QVector temps; + QVarLengthArray basicBlocks; template inline BB i(BB i) { basicBlocks.append(i); return i; } - template inline E e(E e) { temps.append(e); return e; } + template inline E e(E e) { return e; } Function(Module *module, const QString &name): module(module), name(name), tempCount(0) {} ~Function(); @@ -426,11 +440,11 @@ struct Function { struct BasicBlock { Function *function; int index; - QVector statements; int offset; + QVarLengthArray statements; BasicBlock(Function *function, int index): function(function), index(index), offset(-1) {} - ~BasicBlock() { qDeleteAll(statements); } + ~BasicBlock() {} template inline Instr i(Instr i) { statements.append(i); return i; } @@ -439,8 +453,8 @@ struct BasicBlock { } inline Stmt *terminator() const { - if (! statements.isEmpty() && statements.last()->asTerminator() != 0) - return statements.last(); + if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0) + return statements.at(statements.size() - 1); return 0; } @@ -455,7 +469,7 @@ struct BasicBlock { Expr *CONST(double value); Expr *CONST(Type type, double value); - Expr *STRING(const QString &value); + Expr *STRING(const QStringRef &value); Name *NAME(const QString &id, quint32 line, quint32 column); Name *NAME(Name *base, const QString &id, quint32 line, quint32 column); @@ -467,7 +481,7 @@ struct BasicBlock { Expr *UNOP(AluOp op, Expr *expr); Expr *BINOP(AluOp op, Expr *left, Expr *right); - Expr *CALL(Expr *base, const QVector &args); + Expr *CALL(Expr *base, ExprList *args); Stmt *EXP(Expr *expr); Stmt *MOVE(Expr *target, Expr *source, bool = false); @@ -480,14 +494,15 @@ struct BasicBlock { }; struct Module { - QVector functions; - - Module() {} - ~Module() { qDeleteAll(functions); } + MemoryPool *pool; + QVarLengthArray functions; + QVarLengthArray strings; - template inline BB i(BB i) { functions.append(i); return i; } + Module(MemoryPool *pool); + ~Module(); - Function *newFunction(const QString &name = QString()) { return i(new Function(this, name)); } + QString &newIdentifier(const QString &text); + Function *newFunction(const QString &name = QString()); virtual void dump(QTextStream &out); }; diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp index 1b8abba..fa67f57 100644 --- a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp +++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp @@ -544,7 +544,7 @@ bool QDeclarativeV4IRBuilder::visit(AST::FalseLiteral *) bool QDeclarativeV4IRBuilder::visit(AST::StringLiteral *ast) { // ### TODO: cx format - _expr.code = _block->STRING(ast->value.toString()); + _expr.code = _block->STRING(ast->value); return false; } @@ -704,9 +704,12 @@ bool QDeclarativeV4IRBuilder::visit(AST::CallExpression *ast) const quint32 column = nameNodes.last()->firstSourceLocation().startColumn; IR::Expr *base = _block->NAME(id, line, column); - QVector args; - for (AST::ArgumentList *it = ast->arguments; it; it = it->next) - args.append(expression(it->expression)); + IR::ExprList *args = 0, **argsInserter = &args; + for (AST::ArgumentList *it = ast->arguments; it; it = it->next) { + IR::Expr *arg = expression(it->expression); + *argsInserter = new (_module->pool) IR::ExprList(arg); + argsInserter = &(*argsInserter)->next; + } IR::Temp *r = _block->TEMP(IR::InvalidType); IR::Expr *call = _block->CALL(base, args); -- 1.7.2.5