blob: 65e590219520efb93bac4a9e896f354a738bd75d [file] [log] [blame]
//===--- SyntaxArena.cpp - SyntaxArena implementation -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Syntax/SyntaxArena.h"
#include "swift/Syntax/RawSyntax.h"
#include "llvm/ADT/FoldingSet.h"
using namespace swift;
using namespace swift::syntax;
namespace {
class RawSyntaxCacheNode;
}
/// Implementation detail of SyntaxArena.
struct SyntaxArena::Implementation {
/// Allocator.
llvm::BumpPtrAllocator Allocator;
/// List of pointers to the allocated RawSyntax
std::vector<RawSyntax *> AllocatedRawSyntaxList;
/// Cached Tokens.
llvm::FoldingSet<RawSyntaxCacheNode> CachedTokens;
Implementation() = default;
void *Allocate(size_t size, size_t alignment) {
return Allocator.Allocate(size, alignment);
}
void *AllocateRawSyntax(size_t size, size_t alignment) {
void *data = Allocator.Allocate(size, alignment);
/// Remember the allocated pointers so that we can destruct them.
AllocatedRawSyntaxList.push_back(static_cast<RawSyntax *>(data));
return data;
}
~Implementation() {
// Destruct all allocated RawSyntax. They might contain heap allocated
// propeties and/or children.
for (auto *N : AllocatedRawSyntaxList)
N->~RawSyntax();
}
};
SyntaxArena::SyntaxArena() : Impl(*new Implementation()){};
SyntaxArena::~SyntaxArena() { delete &Impl; }
llvm::BumpPtrAllocator &SyntaxArena::getAllocator() const {
return Impl.Allocator;
}
void *SyntaxArena::Allocate(size_t size, size_t alignment) {
return Impl.Allocate(size, alignment);
}
void *SyntaxArena::AllocateRawSyntax(size_t size, size_t alignment) {
return Impl.AllocateRawSyntax(size, alignment);
}
namespace {
/// Cache node for RawSyntax.
class RawSyntaxCacheNode : public llvm::FoldingSetNode {
friend llvm::FoldingSetTrait<RawSyntaxCacheNode>;
/// Associated RawSyntax.
RawSyntax *Obj;
/// FoldingSet node identifier of the associated RawSyntax.
llvm::FoldingSetNodeIDRef IDRef;
public:
RawSyntaxCacheNode(RawSyntax *Obj, const llvm::FoldingSetNodeIDRef IDRef)
: Obj(Obj), IDRef(IDRef) {}
/// Retrieve assciated RawSyntax.
RawSyntax *get() { return Obj; }
// Only allow allocation of Node using the allocator in SyntaxArena.
void *operator new(size_t Bytes, SyntaxArena &Arena,
unsigned Alignment = alignof(RawSyntaxCacheNode)) {
return Arena.Allocate(Bytes, Alignment);
}
void *operator new(size_t Bytes) throw() = delete;
void operator delete(void *Data) throw() = delete;
};
} // namespace
namespace llvm {
/// FoldingSet traits for RawSyntax wrapper.
template <> struct FoldingSetTrait<RawSyntaxCacheNode> {
static inline void Profile(RawSyntaxCacheNode &X, FoldingSetNodeID &ID) {
ID.AddNodeID(X.IDRef);
}
static inline bool Equals(RawSyntaxCacheNode &X, const FoldingSetNodeID &ID,
unsigned, FoldingSetNodeID &) {
return ID == X.IDRef;
}
static inline unsigned ComputeHash(RawSyntaxCacheNode &X,
FoldingSetNodeID &) {
return X.IDRef.ComputeHash();
}
};
} // namespace llvm
/// Retrive "token" RawSyntax from the given Arena.
RC<RawSyntax> RawSyntax::getToken(SyntaxArena &Arena, tok TokKind,
OwnedString Text,
llvm::ArrayRef<TriviaPiece> LeadingTrivia,
llvm::ArrayRef<TriviaPiece> TrailingTrivia) {
// Determine whether this token is worth to cache.
if (
// Is string_literal with >16 length.
(TokKind == tok::string_literal && Text.size() > 16) ||
// Has leading comment trivia et al.
any_of(LeadingTrivia,
[](const syntax::TriviaPiece &T) { return T.getText().size(); }) ||
// Has trailing comment trivia et al.
any_of(TrailingTrivia,
[](const syntax::TriviaPiece &T) { return T.getText().size(); })) {
// Do not use cache.
return RawSyntax::make(TokKind, Text, LeadingTrivia, TrailingTrivia,
SourcePresence::Present, &Arena);
}
// This node is cacheable. Get or create.
auto &CachedTokens = Arena.Impl.CachedTokens;
llvm::FoldingSetNodeID ID;
RawSyntax::Profile(ID, TokKind, Text, LeadingTrivia, TrailingTrivia);
void *insertPos = nullptr;
if (auto existing = CachedTokens.FindNodeOrInsertPos(ID, insertPos))
// Found in the cache. Just return it.
return existing->get();
// Could not found in the cache. Create it.
auto Raw = RawSyntax::make(TokKind, Text, LeadingTrivia, TrailingTrivia,
SourcePresence::Present, &Arena);
auto IDRef = ID.Intern(Arena.getAllocator());
auto CacheNode = new (Arena) RawSyntaxCacheNode(Raw.get(), IDRef);
CachedTokens.InsertNode(CacheNode, insertPos);
return Raw;
}