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