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(RequestLen: 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(FID: SourceMgr.getFileID(SpellingLoc: 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(dest: CurBuffer+BytesUsed, src: Buf, n: 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(Offset: 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(Size: RequestLen, |
78 | BufferName: "<scratch space>" ); |
79 | CurBuffer = OwnBuf->getBufferStart(); |
80 | FileID FID = SourceMgr.createFileID(Buffer: std::move(OwnBuf)); |
81 | BufferStartLoc = SourceMgr.getLocForStartOfFile(FID); |
82 | BytesUsed = 0; |
83 | } |
84 | |