diff options
| author | Steven Wu <stevenwu@apple.com> | 2024-10-22 11:54:21 -0700 |
|---|---|---|
| committer | Steven Wu <stevenwu@apple.com> | 2024-10-22 11:54:21 -0700 |
| commit | 1b5b7ad620edd00dc84d631cd11bd548e35d648a (patch) | |
| tree | 6dd8e023b29f89a6d262d9ad45c76b69107af73d /llvm/lib/Support/VirtualOutputFile.cpp | |
| parent | e57548387000071562f44bfd66644480c8e6542d (diff) | |
[𝘀𝗽𝗿] changes to main this commit is based onusers/cachemeifyoucan/spr/main.address-review-feedback
Created using spr 1.3.5
[skip ci]
Diffstat (limited to 'llvm/lib/Support/VirtualOutputFile.cpp')
| -rw-r--r-- | llvm/lib/Support/VirtualOutputFile.cpp | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/llvm/lib/Support/VirtualOutputFile.cpp b/llvm/lib/Support/VirtualOutputFile.cpp new file mode 100644 index 000000000000..c043c0b455c5 --- /dev/null +++ b/llvm/lib/Support/VirtualOutputFile.cpp @@ -0,0 +1,106 @@ +//===- VirtualOutputFile.cpp - Output file virtualization -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/VirtualOutputFile.h" +#include "llvm/Support/VirtualOutputBackends.h" +#include "llvm/Support/VirtualOutputError.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/raw_ostream_proxy.h" + +using namespace llvm; +using namespace llvm::vfs; + +char OutputFileImpl::ID = 0; +char NullOutputFileImpl::ID = 0; + +void OutputFileImpl::anchor() {} +void NullOutputFileImpl::anchor() {} + +class OutputFile::TrackedProxy : public raw_pwrite_stream_proxy { +public: + void resetProxy() { + TrackingPointer = nullptr; + resetProxiedOS(); + } + + explicit TrackedProxy(TrackedProxy *&TrackingPointer, raw_pwrite_stream &OS) + : raw_pwrite_stream_proxy(OS), TrackingPointer(TrackingPointer) { + assert(!TrackingPointer && "Expected to add a proxy"); + TrackingPointer = this; + } + + ~TrackedProxy() override { resetProxy(); } + + TrackedProxy *&TrackingPointer; +}; + +Expected<std::unique_ptr<raw_pwrite_stream>> OutputFile::createProxy() { + if (OpenProxy) + return make_error<OutputError>(getPath(), OutputErrorCode::has_open_proxy); + + return std::make_unique<TrackedProxy>(OpenProxy, getOS()); +} + +Error OutputFile::keep() { + // Catch double-closing logic bugs. + if (LLVM_UNLIKELY(!Impl)) + report_fatal_error( + make_error<OutputError>(getPath(), OutputErrorCode::already_closed)); + + // Report a fatal error if there's an open proxy and the file is being kept. + // This is safer than relying on clients to remember to flush(). Also call + // OutputFile::discard() to give the backend a chance to clean up any + // side effects (such as temporaries). + if (LLVM_UNLIKELY(OpenProxy)) + report_fatal_error(joinErrors( + make_error<OutputError>(getPath(), OutputErrorCode::has_open_proxy), + discard())); + + Error E = Impl->keep(); + Impl = nullptr; + DiscardOnDestroyHandler = nullptr; + return E; +} + +Error OutputFile::discard() { + // Catch double-closing logic bugs. + if (LLVM_UNLIKELY(!Impl)) + report_fatal_error( + make_error<OutputError>(getPath(), OutputErrorCode::already_closed)); + + // Be lenient about open proxies since client teardown paths won't + // necessarily clean up in the right order. Reset the proxy to flush any + // current content; if there is another write, there should be quick crash on + // null dereference. + if (OpenProxy) + OpenProxy->resetProxy(); + + Error E = Impl->discard(); + Impl = nullptr; + DiscardOnDestroyHandler = nullptr; + return E; +} + +void OutputFile::destroy() { + if (!Impl) + return; + + // Clean up the file. Move the discard handler into a local since discard + // will reset it. + auto DiscardHandler = std::move(DiscardOnDestroyHandler); + Error E = discard(); + assert(!Impl && "Expected discard to destroy Impl"); + + // If there's no handler, report a fatal error. + if (LLVM_UNLIKELY(!DiscardHandler)) + llvm::report_fatal_error(joinErrors( + make_error<OutputError>(getPath(), OutputErrorCode::not_closed), + std::move(E))); + else if (E) + DiscardHandler(std::move(E)); +} |
