Commit 61a504c4 authored by Roberto Raggi's avatar Roberto Raggi

Ensure that the memory pool can be reused after a rewind and get rid of the segmented array.

parent 1e2af0a7
......@@ -304,6 +304,11 @@ Namespace *Document::globalNamespace() const
return _globalNamespace;
}
void Document::setGlobalNamespace(Namespace *globalNamespace)
{
_globalNamespace = globalNamespace;
}
Symbol *Document::findSymbolAt(unsigned line, unsigned column) const
{
return findSymbolAt(line, column, globalSymbols());
......
......@@ -86,7 +86,9 @@ public:
unsigned globalSymbolCount() const;
Symbol *globalSymbolAt(unsigned index) const;
Scope *globalSymbols() const; // ### deprecate?
Namespace *globalNamespace() const;
void setGlobalNamespace(Namespace *globalNamespace); // ### internal
QList<Macro> definedMacros() const
{ return _definedMacros; }
......
......@@ -74,6 +74,8 @@
#include <ASTVisitor.h>
#include <Lexer.h>
#include <Token.h>
#include <Parser.h>
#include <Control.h>
#include <cplusplus/LookupContext.h>
......@@ -261,18 +263,49 @@ public:
if (_workingCopy.contains(doc->fileName()))
mode = Document::FullCheck;
doc->parse();
doc->check(mode);
if (doc->isParsed() && mode == Document::FastCheck) {
TranslationUnit *unit = doc->translationUnit();
MemoryPool *pool = unit->memoryPool();
if (mode == Document::FullCheck) {
// run the binding pass
NamespaceBindingPtr ns = bind(doc, _snapshot);
Parser parser(unit);
Semantic semantic(unit);
// check for undefined symbols.
CheckUndefinedSymbols checkUndefinedSymbols(doc);
checkUndefinedSymbols.setGlobalNamespaceBinding(ns);
Namespace *globalNamespace = doc->control()->newNamespace(0);
doc->setGlobalNamespace(globalNamespace);
checkUndefinedSymbols(doc->translationUnit()->ast()); // ### FIXME
Scope *globals = globalNamespace->members();
while (parser.LA()) {
unsigned start_declaration = parser.cursor();
DeclarationAST *declaration = 0;
if (parser.parseDeclaration(declaration)) {
semantic.check(declaration, globals);
} else {
doc->translationUnit()->error(start_declaration, "expected a declaration");
parser.rewind(start_declaration + 1);
parser.skipUntilDeclaration();
}
parser.clearTemplateArgumentList();
pool->reset();
}
} else {
doc->parse();
doc->check(mode);
if (mode == Document::FullCheck) {
// run the binding pass
NamespaceBindingPtr ns = bind(doc, _snapshot);
// check for undefined symbols.
CheckUndefinedSymbols checkUndefinedSymbols(doc);
checkUndefinedSymbols.setGlobalNamespaceBinding(ns);
checkUndefinedSymbols(doc->translationUnit()->ast()); // ### FIXME
}
}
doc->releaseTranslationUnit();
......
......@@ -38,13 +38,12 @@ namespace CPlusPlus {
class CPLUSPLUS_EXPORT ASTPatternBuilder
{
MemoryPool pool;
MemoryPool::State state;
public:
ASTPatternBuilder(): state(pool.state()) {}
ASTPatternBuilder() {}
~ASTPatternBuilder() {}
void reset() { pool.rewind(state); }
void reset() { pool.reset(); }
SimpleSpecifierAST *SimpleSpecifier()
{
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "Array.h"
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CPLUSPLUS_ARRAY_H
#define CPLUSPLUS_ARRAY_H
#include "CPlusPlusForwardDeclarations.h"
#include <new>
namespace CPlusPlus {
template <typename _Tp, int SEGMENT_SHIFT = 4>
class CPLUSPLUS_EXPORT Array
{
Array(const Array &other);
void operator =(const Array &other);
public:
Array()
: _segments(0),
_allocatedSegments(0),
_segmentCount(-1),
_allocatedElements(0),
_count(-1)
{ }
~Array()
{
if (_segments) {
for (int index = 0; index <= _segmentCount; ++index) {
delete[] (_segments[index] + (index << SEGMENT_SHIFT));
}
std::free(_segments);
}
}
inline unsigned size() const
{ return _count + 1; }
inline unsigned count() const
{ return _count + 1; }
inline const _Tp &at(unsigned index) const
{ return _segments[index >> SEGMENT_SHIFT][index]; }
inline const _Tp &operator[](unsigned index) const
{ return _segments[index >> SEGMENT_SHIFT][index]; }
inline _Tp &operator[](unsigned index)
{ return _segments[index >> SEGMENT_SHIFT][index]; }
void push_back(const _Tp &value)
{
if (++_count == _allocatedElements) {
if (++_segmentCount == _allocatedSegments) {
_allocatedSegments += 4;
_segments = (_Tp **) std::realloc(_segments, _allocatedSegments * sizeof(_Tp *));
}
_Tp *segment = new _Tp[SEGMENT_SIZE];
_segments[_segmentCount] = segment - (_segmentCount << SEGMENT_SHIFT);
_allocatedElements += SEGMENT_SIZE;
}
_segments[_count >> SEGMENT_SHIFT][_count] = value;
}
private:
enum {
SEGMENT_SIZE = 1 << SEGMENT_SHIFT
};
_Tp **_segments;
int _allocatedSegments;
int _segmentCount;
int _allocatedElements;
int _count;
};
} // end of namespace CPlusPlus
#endif // CPLUSPLUS_ARRAY_H
......@@ -53,7 +53,6 @@
#include "CoreTypes.h"
#include "Symbols.h"
#include "Names.h"
#include "Array.h"
#include "TypeMatcher.h"
#include <map>
#include <set>
......
......@@ -57,20 +57,26 @@ MemoryPool::MemoryPool()
_blocks(0),
_allocatedBlocks(0),
_blockCount(-1),
ptr(0),
end(0)
_ptr(0),
_end(0)
{ }
MemoryPool::~MemoryPool()
{
if (_blockCount != -1) {
for (int i = 0; i < _blockCount + 1; ++i) {
std::free(_blocks[i]);
if (_blocks) {
for (int i = 0; i < _allocatedBlocks; ++i) {
if (char *b = _blocks[i])
std::free(b);
}
}
if (_blocks)
std::free(_blocks);
}
}
void MemoryPool::reset()
{
_blockCount = -1;
_ptr = _end = 0;
}
bool MemoryPool::initializeAllocatedMemory() const
......@@ -85,39 +91,47 @@ void *MemoryPool::allocate_helper(size_t size)
if (++_blockCount == _allocatedBlocks) {
if (! _allocatedBlocks)
_allocatedBlocks = 8;
_allocatedBlocks = DEFAULT_BLOCK_COUNT;
else
_allocatedBlocks *= 2;
_blocks = (char **) realloc(_blocks, sizeof(char *) * _allocatedBlocks);
for (int index = _blockCount; index < _allocatedBlocks; ++index)
_blocks[index] = 0;
}
char *&block = _blocks[_blockCount];
if (_initializeAllocatedMemory)
block = (char *) std::calloc(1, BLOCK_SIZE);
else
if (! block)
block = (char *) std::malloc(BLOCK_SIZE);
ptr = block;
end = ptr + BLOCK_SIZE;
if (_initializeAllocatedMemory)
std::memset(block, '\0', BLOCK_SIZE);
_ptr = block;
_end = _ptr + BLOCK_SIZE;
void *addr = ptr;
ptr += size;
void *addr = _ptr;
_ptr += size;
return addr;
}
MemoryPool::State MemoryPool::state() const
{ return State(ptr, _blockCount); }
RecursiveMemoryPool::RecursiveMemoryPool(MemoryPool *pool)
: _pool(pool),
_blockCount(pool->_blockCount),
_ptr(pool->_ptr),
_end(pool->_end)
{
}
void MemoryPool::rewind(const State &state)
RecursiveMemoryPool::~RecursiveMemoryPool()
{
if (_blockCount == state.blockCount && state.ptr < ptr) {
if (_initializeAllocatedMemory)
std::memset(state.ptr, '\0', ptr - state.ptr);
_pool->_blockCount = _blockCount;
_pool->_ptr = _ptr;
_pool->_end = _end;
ptr = state.ptr;
}
std::memset(_pool->_ptr, 0, _pool->_end - _pool->_ptr);
}
Managed::Managed()
......@@ -135,4 +149,3 @@ void Managed::operator delete(void *)
void Managed::operator delete(void *, MemoryPool *)
{ }
......@@ -54,6 +54,9 @@
namespace CPlusPlus {
class MemoryPool;
class RecursiveMemoryPool;
class CPLUSPLUS_EXPORT MemoryPool
{
MemoryPool(const MemoryPool &other);
......@@ -66,33 +69,19 @@ public:
bool initializeAllocatedMemory() const;
void setInitializeAllocatedMemory(bool initializeAllocatedMemory);
void reset();
inline void *allocate(size_t size)
{
size = (size + 7) & ~7;
if (ptr && (ptr + size < end)) {
void *addr = ptr;
ptr += size;
if (_ptr && (_ptr + size < _end)) {
void *addr = _ptr;
_ptr += size;
return addr;
}
return allocate_helper(size);
}
struct State
{
char *ptr;
char *end;
int blockCount;
inline bool isValid() const
{ return ptr != 0; }
inline State(char *ptr = 0, int blockCount = 0)
: ptr(ptr), blockCount(blockCount) {}
};
State state() const;
void rewind(const State &state);
private:
void *allocate_helper(size_t size);
......@@ -101,13 +90,29 @@ private:
char **_blocks;
int _allocatedBlocks;
int _blockCount;
char *ptr, *end;
char *_ptr;
char *_end;
int _ccc;
enum
{
BLOCK_SIZE = 8 * 1024,
DEFAULT_BLOCK_COUNT = 8
};
friend class RecursiveMemoryPool;
};
class CPLUSPLUS_EXPORT RecursiveMemoryPool
{
MemoryPool *_pool;
int _blockCount;
char *_ptr;
char *_end;
public:
RecursiveMemoryPool(MemoryPool *pool);
~RecursiveMemoryPool();
};
class CPLUSPLUS_EXPORT Managed
......
......@@ -190,30 +190,6 @@ inline bool isRightAssociative(int tokenKind)
return true; \
}
class Parser::Rewind
{
Parser *_parser;
MemoryPool::State _state;
public:
inline Rewind(Parser *parser)
: _parser(parser) {}
inline void operator()(unsigned tokenIndex)
{ rewind(tokenIndex); }
inline void mark()
{ _state = _parser->_pool->state(); }
inline void rewind(unsigned tokenIndex)
{
_parser->rewind(tokenIndex);
if (_state.isValid())
_parser->_pool->rewind(_state);
}
};
Parser::Parser(TranslationUnit *unit)
: _translationUnit(unit),
_control(_translationUnit->control()),
......@@ -2476,8 +2452,8 @@ bool Parser::parseExpressionStatement(StatementAST *&node)
ExpressionAST *expression = 0;
MemoryPool *oldPool = _pool;
MemoryPool tmp;
_pool = &tmp;
_pool = &_tempPool;
RecursiveMemoryPool rec(&_tempPool);
if (parseExpression(expression)) {
ExpressionStatementAST *ast = new (oldPool) ExpressionStatementAST;
ast->expression = expression->clone(oldPool);
......
......@@ -53,6 +53,7 @@
#include "ASTfwd.h"
#include "Token.h"
#include "TranslationUnit.h"
#include "MemoryPool.h"
#include <map>
namespace CPlusPlus {
......@@ -274,7 +275,6 @@ public:
int peekAtQtContextKeyword() const;
private:
bool switchTemplateArguments(bool templateArguments);
bool blockErrors(bool block);
......@@ -303,6 +303,7 @@ private:
};
TemplateArgumentListEntry *templateArgumentListEntry(unsigned tokenIndex);
void clearTemplateArgumentList() { _templateArgumentList.clear(); }
private:
TranslationUnit *_translationUnit;
......@@ -316,6 +317,7 @@ private:
bool _inObjCImplementationContext: 1;
int _expressionDepth;
MemoryPool _tempPool;
std::map<unsigned, TemplateArgumentListEntry> _templateArgumentList;
class Rewind;
......
......@@ -624,7 +624,7 @@ bool Class::matchType0(const Type *otherType, TypeMatcher *matcher) const
}
unsigned Class::baseClassCount() const
{ return _baseClasses.count(); }
{ return _baseClasses.size(); }
BaseClass *Class::baseClassAt(unsigned index) const
{ return _baseClasses.at(index); }
......
......@@ -53,8 +53,7 @@
#include "Symbol.h"
#include "Type.h"
#include "FullySpecifiedType.h"
#include "Array.h"
#include <vector>
namespace CPlusPlus {
......@@ -511,7 +510,7 @@ protected:
private:
Key _key;
TemplateParameters *_templateParameters;
Array<BaseClass *> _baseClasses;
std::vector<BaseClass *> _baseClasses;
};
class CPLUSPLUS_EXPORT ObjCBaseClass: public Symbol
......@@ -593,7 +592,7 @@ public:
virtual ~ObjCProtocol();
unsigned protocolCount() const
{ return _protocols.count(); }
{ return _protocols.size(); }
ObjCBaseProtocol *protocolAt(unsigned index) const
{ return _protocols.at(index); }
......@@ -625,7 +624,7 @@ protected:
virtual bool matchType0(const Type *otherType, TypeMatcher *matcher) const;
private:
Array<ObjCBaseProtocol *> _protocols;
std::vector<ObjCBaseProtocol *> _protocols;
};
class CPLUSPLUS_EXPORT ObjCForwardClassDeclaration: public Symbol, public Type
......@@ -677,7 +676,7 @@ public:
{ _baseClass = baseClass; }
unsigned protocolCount() const
{ return _protocols.count(); }
{ return _protocols.size(); }
ObjCBaseProtocol *protocolAt(unsigned index) const
{ return _protocols.at(index); }
......@@ -712,7 +711,7 @@ private:
bool _isInterface;
const Name *_categoryName;
ObjCBaseClass * _baseClass;
Array<ObjCBaseProtocol *> _protocols;
std::vector<ObjCBaseProtocol *> _protocols;
};
class CPLUSPLUS_EXPORT ObjCMethod: public ScopedSymbol, public Type
......
......@@ -69,7 +69,7 @@ TranslationUnit::TranslationUnit(Control *control, const StringLiteral *fileId)
_ast(0),
_flags(0)
{
_tokens = new Array<Token, 8>();
_tokens = new std::vector<Token>();
_previousTranslationUnit = control->switchTranslationUnit(this);
_pool = new MemoryPool();
}
......
......@@ -52,9 +52,8 @@
#include "CPlusPlusForwardDeclarations.h"
#include "ASTfwd.h"
#include "Token.h"
#include "Array.h"
#include <stdio.h> // for FILE*
#include <vector> // ### remove me
#include <cstdio>