17330f729Sjoerg //===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the ScratchBuffer interface.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Lex/ScratchBuffer.h"
147330f729Sjoerg #include "clang/Basic/SourceManager.h"
157330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
167330f729Sjoerg #include <cstring>
177330f729Sjoerg using namespace clang;
187330f729Sjoerg
197330f729Sjoerg // ScratchBufSize - The size of each chunk of scratch memory. Slightly less
207330f729Sjoerg //than a page, almost certainly enough for anything. :)
217330f729Sjoerg static const unsigned ScratchBufSize = 4060;
227330f729Sjoerg
ScratchBuffer(SourceManager & SM)237330f729Sjoerg ScratchBuffer::ScratchBuffer(SourceManager &SM)
247330f729Sjoerg : SourceMgr(SM), CurBuffer(nullptr) {
257330f729Sjoerg // Set BytesUsed so that the first call to getToken will require an alloc.
267330f729Sjoerg BytesUsed = ScratchBufSize;
277330f729Sjoerg }
287330f729Sjoerg
297330f729Sjoerg /// getToken - Splat the specified text into a temporary MemoryBuffer and
307330f729Sjoerg /// return a SourceLocation that refers to the token. This is just like the
317330f729Sjoerg /// method below, but returns a location that indicates the physloc of the
327330f729Sjoerg /// token.
getToken(const char * Buf,unsigned Len,const char * & DestPtr)337330f729Sjoerg SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
347330f729Sjoerg const char *&DestPtr) {
357330f729Sjoerg if (BytesUsed+Len+2 > ScratchBufSize)
367330f729Sjoerg AllocScratchBuffer(Len+2);
377330f729Sjoerg else {
387330f729Sjoerg // Clear out the source line cache if it's already been computed.
397330f729Sjoerg // FIXME: Allow this to be incrementally extended.
407330f729Sjoerg SourceMgr.getSLocEntry(SourceMgr.getFileID(BufferStartLoc))
41*e038c9c4Sjoerg .getFile()
42*e038c9c4Sjoerg .getContentCache()
43*e038c9c4Sjoerg .SourceLineCache = SrcMgr::LineOffsetMapping();
447330f729Sjoerg }
457330f729Sjoerg
467330f729Sjoerg // Prefix the token with a \n, so that it looks like it is the first thing on
477330f729Sjoerg // its own virtual line in caret diagnostics.
487330f729Sjoerg CurBuffer[BytesUsed++] = '\n';
497330f729Sjoerg
507330f729Sjoerg // Return a pointer to the character data.
517330f729Sjoerg DestPtr = CurBuffer+BytesUsed;
527330f729Sjoerg
537330f729Sjoerg // Copy the token data into the buffer.
547330f729Sjoerg memcpy(CurBuffer+BytesUsed, Buf, Len);
557330f729Sjoerg
567330f729Sjoerg // Remember that we used these bytes.
577330f729Sjoerg BytesUsed += Len+1;
587330f729Sjoerg
597330f729Sjoerg // Add a NUL terminator to the token. This keeps the tokens separated, in
607330f729Sjoerg // case they get relexed, and puts them on their own virtual lines in case a
617330f729Sjoerg // diagnostic points to one.
627330f729Sjoerg CurBuffer[BytesUsed-1] = '\0';
637330f729Sjoerg
647330f729Sjoerg return BufferStartLoc.getLocWithOffset(BytesUsed-Len-1);
657330f729Sjoerg }
667330f729Sjoerg
AllocScratchBuffer(unsigned RequestLen)677330f729Sjoerg void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
687330f729Sjoerg // Only pay attention to the requested length if it is larger than our default
697330f729Sjoerg // page size. If it is, we allocate an entire chunk for it. This is to
707330f729Sjoerg // support gigantic tokens, which almost certainly won't happen. :)
717330f729Sjoerg if (RequestLen < ScratchBufSize)
727330f729Sjoerg RequestLen = ScratchBufSize;
737330f729Sjoerg
747330f729Sjoerg // Get scratch buffer. Zero-initialize it so it can be dumped into a PCH file
757330f729Sjoerg // deterministically.
767330f729Sjoerg std::unique_ptr<llvm::WritableMemoryBuffer> OwnBuf =
777330f729Sjoerg llvm::WritableMemoryBuffer::getNewMemBuffer(RequestLen,
787330f729Sjoerg "<scratch space>");
797330f729Sjoerg CurBuffer = OwnBuf->getBufferStart();
807330f729Sjoerg FileID FID = SourceMgr.createFileID(std::move(OwnBuf));
817330f729Sjoerg BufferStartLoc = SourceMgr.getLocForStartOfFile(FID);
827330f729Sjoerg BytesUsed = 0;
837330f729Sjoerg }
84