1 //===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the ScratchBuffer interface. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Lex/ScratchBuffer.h" 14 #include "clang/Basic/SourceManager.h" 15 #include "llvm/Support/MemoryBuffer.h" 16 #include <cstring> 17 using namespace clang; 18 19 // ScratchBufSize - The size of each chunk of scratch memory. Slightly less 20 //than a page, almost certainly enough for anything. :) 21 static const unsigned ScratchBufSize = 4060; 22 23 ScratchBuffer::ScratchBuffer(SourceManager &SM) 24 : SourceMgr(SM), CurBuffer(nullptr) { 25 // Set BytesUsed so that the first call to getToken will require an alloc. 26 BytesUsed = ScratchBufSize; 27 } 28 29 /// getToken - Splat the specified text into a temporary MemoryBuffer and 30 /// return a SourceLocation that refers to the token. This is just like the 31 /// method below, but returns a location that indicates the physloc of the 32 /// token. 33 SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len, 34 const char *&DestPtr) { 35 if (BytesUsed+Len+2 > ScratchBufSize) 36 AllocScratchBuffer(Len+2); 37 else { 38 // Clear out the source line cache if it's already been computed. 39 // FIXME: Allow this to be incrementally extended. 40 auto *ContentCache = const_cast<SrcMgr::ContentCache *>( 41 &SourceMgr.getSLocEntry(SourceMgr.getFileID(BufferStartLoc)) 42 .getFile() 43 .getContentCache()); 44 ContentCache->SourceLineCache = SrcMgr::LineOffsetMapping(); 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