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 SourceMgr.getSLocEntry(SourceMgr.getFileID(BufferStartLoc)) 41 .getFile() 42 .getContentCache() 43 .SourceLineCache = SrcMgr::LineOffsetMapping(); 44 } 45 46 // Prefix the token with a \n, so that it looks like it is the first thing on 47 // its own virtual line in caret diagnostics. 48 CurBuffer[BytesUsed++] = '\n'; 49 50 // Return a pointer to the character data. 51 DestPtr = CurBuffer+BytesUsed; 52 53 // Copy the token data into the buffer. 54 memcpy(CurBuffer+BytesUsed, Buf, Len); 55 56 // Remember that we used these bytes. 57 BytesUsed += Len+1; 58 59 // Add a NUL terminator to the token. This keeps the tokens separated, in 60 // case they get relexed, and puts them on their own virtual lines in case a 61 // diagnostic points to one. 62 CurBuffer[BytesUsed-1] = '\0'; 63 64 return BufferStartLoc.getLocWithOffset(BytesUsed-Len-1); 65 } 66 67 void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) { 68 // Only pay attention to the requested length if it is larger than our default 69 // page size. If it is, we allocate an entire chunk for it. This is to 70 // support gigantic tokens, which almost certainly won't happen. :) 71 if (RequestLen < ScratchBufSize) 72 RequestLen = ScratchBufSize; 73 74 // Get scratch buffer. Zero-initialize it so it can be dumped into a PCH file 75 // deterministically. 76 std::unique_ptr<llvm::WritableMemoryBuffer> OwnBuf = 77 llvm::WritableMemoryBuffer::getNewMemBuffer(RequestLen, 78 "<scratch space>"); 79 CurBuffer = OwnBuf->getBufferStart(); 80 FileID FID = SourceMgr.createFileID(std::move(OwnBuf)); 81 BufferStartLoc = SourceMgr.getLocForStartOfFile(FID); 82 BytesUsed = 0; 83 } 84