1 //===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the ScratchBuffer interface. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Lex/ScratchBuffer.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "llvm/Support/MemoryBuffer.h" 17 #include <cstring> 18 using namespace clang; 19 20 // ScratchBufSize - The size of each chunk of scratch memory. Slightly less 21 //than a page, almost certainly enough for anything. :) 22 static const unsigned ScratchBufSize = 4060; 23 24 ScratchBuffer::ScratchBuffer(SourceManager &SM) 25 : SourceMgr(SM), CurBuffer(nullptr) { 26 // Set BytesUsed so that the first call to getToken will require an alloc. 27 BytesUsed = ScratchBufSize; 28 } 29 30 /// getToken - Splat the specified text into a temporary MemoryBuffer and 31 /// return a SourceLocation that refers to the token. This is just like the 32 /// method below, but returns a location that indicates the physloc of the 33 /// token. 34 SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len, 35 const char *&DestPtr) { 36 if (BytesUsed+Len+2 > ScratchBufSize) 37 AllocScratchBuffer(Len+2); 38 else { 39 // Clear out the source line cache if it's already been computed. 40 // FIXME: Allow this to be incrementally extended. 41 auto *ContentCache = const_cast<SrcMgr::ContentCache *>( 42 SourceMgr.getSLocEntry(SourceMgr.getFileID(BufferStartLoc)) 43 .getFile().getContentCache()); 44 ContentCache->SourceLineCache = nullptr; 45 } 46 47 // Prefix the token with a \n, so that it looks like it is the first thing on 48 // its own virtual line in caret diagnostics. 49 CurBuffer[BytesUsed++] = '\n'; 50 51 // Return a pointer to the character data. 52 DestPtr = CurBuffer+BytesUsed; 53 54 // Copy the token data into the buffer. 55 memcpy(CurBuffer+BytesUsed, Buf, Len); 56 57 // Remember that we used these bytes. 58 BytesUsed += Len+1; 59 60 // Add a NUL terminator to the token. This keeps the tokens separated, in 61 // case they get relexed, and puts them on their own virtual lines in case a 62 // diagnostic points to one. 63 CurBuffer[BytesUsed-1] = '\0'; 64 65 return BufferStartLoc.getLocWithOffset(BytesUsed-Len-1); 66 } 67 68 void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) { 69 // Only pay attention to the requested length if it is larger than our default 70 // page size. If it is, we allocate an entire chunk for it. This is to 71 // support gigantic tokens, which almost certainly won't happen. :) 72 if (RequestLen < ScratchBufSize) 73 RequestLen = ScratchBufSize; 74 75 // Get scratch buffer. Zero-initialize it so it can be dumped into a PCH file 76 // deterministically. 77 std::unique_ptr<llvm::WritableMemoryBuffer> OwnBuf = 78 llvm::WritableMemoryBuffer::getNewMemBuffer(RequestLen, 79 "<scratch space>"); 80 CurBuffer = OwnBuf->getBufferStart(); 81 FileID FID = SourceMgr.createFileID(std::move(OwnBuf)); 82 BufferStartLoc = SourceMgr.getLocForStartOfFile(FID); 83 BytesUsed = 0; 84 } 85