-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[5.9] Add support for an externally defined block list configuration file #66688
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
de424d9
382ff2a
8f26c8f
13efc5d
109586f
64b201d
606476f
5dd92d6
b19c45f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
//===--- BlockList.h ---------------------------------------------*- C++ -*-===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines some miscellaneous overloads of hash_value() and | ||
// simple_display(). | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef SWIFT_BASIC_BLOCKLIST_H | ||
#define SWIFT_BASIC_BLOCKLIST_H | ||
|
||
#include "swift/Basic/LLVM.h" | ||
#include "llvm/ADT/StringRef.h" | ||
|
||
namespace swift { | ||
|
||
enum class BlockListAction: uint8_t { | ||
Undefined = 0, | ||
#define BLOCKLIST_ACTION(NAME) NAME, | ||
#include "BlockListAction.def" | ||
}; | ||
|
||
enum class BlockListKeyKind: uint8_t { | ||
Undefined = 0, | ||
ModuleName, | ||
ProjectName | ||
}; | ||
|
||
class BlockListStore { | ||
public: | ||
struct Implementation; | ||
void addConfigureFilePath(StringRef path); | ||
bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, | ||
BlockListAction action); | ||
BlockListStore(); | ||
~BlockListStore(); | ||
private: | ||
Implementation &Impl; | ||
}; | ||
|
||
} // namespace swift | ||
|
||
#endif // SWIFT_BASIC_BLOCKLIST_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//===--- BlockListAction.def - Define all blocklist actions -----*- C++ -*-===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This definition file describes all block list actions for meta-programming | ||
// purposes. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef BLOCKLIST_ACTION | ||
#define BLOCKLIST_ACTION(NAME) | ||
#endif | ||
|
||
BLOCKLIST_ACTION(ShouldUseBinaryModule) | ||
BLOCKLIST_ACTION(ShouldUseTextualModule) | ||
BLOCKLIST_ACTION(DowngradeInterfaceVerificationFailure) | ||
|
||
#undef BLOCKLIST_ACTION |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
//===--- BlockList.cpp - BlockList utilities ------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/ADT/STLExtras.h" | ||
#include "llvm/ADT/StringSwitch.h" | ||
#include "llvm/Support/YAMLParser.h" | ||
#include "llvm/Support/YAMLTraits.h" | ||
#include "swift/Basic/BlockList.h" | ||
#include "swift/Basic/SourceManager.h" | ||
|
||
struct swift::BlockListStore::Implementation { | ||
SourceManager SM; | ||
llvm::StringMap<std::vector<BlockListAction>> ModuleActionDict; | ||
llvm::StringMap<std::vector<BlockListAction>> ProjectActionDict; | ||
void addConfigureFilePath(StringRef path); | ||
bool hasBlockListAction(StringRef key, BlockListKeyKind keyKind, | ||
BlockListAction action); | ||
void collectBlockList(llvm::yaml::Node *N, BlockListAction action); | ||
|
||
llvm::StringMap<std::vector<BlockListAction>> *getDictToUse(BlockListKeyKind kind) { | ||
switch (kind) { | ||
case BlockListKeyKind::ModuleName: | ||
return &ModuleActionDict; | ||
case BlockListKeyKind::ProjectName: | ||
return &ProjectActionDict; | ||
case BlockListKeyKind::Undefined: | ||
return nullptr; | ||
} | ||
} | ||
static std::string getScalaString(llvm::yaml::Node *N) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo on scalar? |
||
llvm::SmallString<64> Buffer; | ||
if (auto *scala = dyn_cast<llvm::yaml::ScalarNode>(N)) { | ||
return scala->getValue(Buffer).str(); | ||
} | ||
return std::string(); | ||
} | ||
}; | ||
|
||
swift::BlockListStore::BlockListStore(): Impl(*new Implementation()) {} | ||
|
||
swift::BlockListStore::~BlockListStore() { delete &Impl; } | ||
|
||
bool swift::BlockListStore::hasBlockListAction(StringRef key, | ||
BlockListKeyKind keyKind, BlockListAction action) { | ||
return Impl.hasBlockListAction(key, keyKind, action); | ||
} | ||
|
||
void swift::BlockListStore::addConfigureFilePath(StringRef path) { | ||
Impl.addConfigureFilePath(path); | ||
} | ||
|
||
bool swift::BlockListStore::Implementation::hasBlockListAction(StringRef key, | ||
BlockListKeyKind keyKind, BlockListAction action) { | ||
auto *dict = getDictToUse(keyKind); | ||
assert(dict); | ||
auto it = dict->find(key); | ||
if (it == dict->end()) | ||
return false; | ||
return llvm::is_contained(it->second, action); | ||
} | ||
|
||
void swift::BlockListStore::Implementation::collectBlockList(llvm::yaml::Node *N, | ||
BlockListAction action) { | ||
namespace yaml = llvm::yaml; | ||
auto *pair = dyn_cast<yaml::KeyValueNode>(N); | ||
if (!pair) | ||
return; | ||
std::string rawKey = getScalaString(pair->getKey()); | ||
auto keyKind = llvm::StringSwitch<BlockListKeyKind>(rawKey) | ||
#define CASE(X) .Case(#X, BlockListKeyKind::X) | ||
CASE(ModuleName) | ||
CASE(ProjectName) | ||
#undef CASE | ||
.Default(BlockListKeyKind::Undefined); | ||
if (keyKind == BlockListKeyKind::Undefined) | ||
return; | ||
auto *dictToUse = getDictToUse(keyKind); | ||
assert(dictToUse); | ||
auto *seq = dyn_cast<yaml::SequenceNode>(pair->getValue()); | ||
if (!seq) | ||
return; | ||
for (auto &node: *seq) { | ||
std::string name = getScalaString(&node); | ||
dictToUse->insert({name, std::vector<BlockListAction>()}) | ||
.first->second.push_back(action); | ||
} | ||
} | ||
|
||
void swift::BlockListStore::Implementation::addConfigureFilePath(StringRef path) { | ||
namespace yaml = llvm::yaml; | ||
|
||
// Load the input file. | ||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = | ||
vfs::getFileOrSTDIN(*SM.getFileSystem(), path, | ||
/*FileSize*/-1, /*RequiresNullTerminator*/true, | ||
/*IsVolatile*/false, /*RetryCount*/30); | ||
if (!FileBufOrErr) { | ||
return; | ||
} | ||
StringRef Buffer = FileBufOrErr->get()->getBuffer(); | ||
yaml::Stream Stream(llvm::MemoryBufferRef(Buffer, path), | ||
SM.getLLVMSourceMgr()); | ||
for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) { | ||
assert(DI != Stream.end() && "Failed to read a document"); | ||
yaml::Node *N = DI->getRoot(); | ||
for (auto &pair: *dyn_cast<yaml::MappingNode>(N)) { | ||
std::string key = getScalaString(pair.getKey()); | ||
auto action = llvm::StringSwitch<BlockListAction>(key) | ||
#define BLOCKLIST_ACTION(X) .Case(#X, BlockListAction::X) | ||
#include "swift/Basic/BlockListAction.def" | ||
.Default(BlockListAction::Undefined); | ||
if (action == BlockListAction::Undefined) | ||
continue; | ||
auto *map = dyn_cast<yaml::MappingNode>(pair.getValue()); | ||
if (!map) | ||
continue; | ||
for (auto &innerPair: *map) { | ||
collectBlockList(&innerPair, action); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,6 +159,31 @@ void CompilerInvocation::setDefaultPrebuiltCacheIfNecessary() { | |
(llvm::Twine(pair.first) + "preferred-interfaces" + pair.second).str(); | ||
} | ||
|
||
void CompilerInvocation::setDefaultBlocklistsIfNecessary() { | ||
if (!LangOpts.BlocklistConfigFilePaths.empty()) | ||
return; | ||
if (SearchPathOpts.RuntimeResourcePath.empty()) | ||
return; | ||
// XcodeDefault.xctoolchain/usr/lib/swift | ||
SmallString<64> blocklistDir{SearchPathOpts.RuntimeResourcePath}; | ||
// XcodeDefault.xctoolchain/usr/lib | ||
llvm::sys::path::remove_filename(blocklistDir); | ||
// XcodeDefault.xctoolchain/usr | ||
llvm::sys::path::remove_filename(blocklistDir); | ||
// XcodeDefault.xctoolchain/usr/local/lib/swift/blocklists | ||
llvm::sys::path::append(blocklistDir, "local", "lib", "swift", "blocklists"); | ||
std::error_code EC; | ||
if (llvm::sys::fs::is_directory(blocklistDir)) { | ||
for (llvm::sys::fs::directory_iterator F(blocklistDir, EC), FE; | ||
F != FE; F.increment(EC)) { | ||
StringRef ext = llvm::sys::path::extension(F->path()); | ||
if (ext == "yml" || ext == "yaml") { | ||
LangOpts.BlocklistConfigFilePaths.push_back(F->path()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the main advantage of supporting many blocklists like this? My first though would be that one blocklist would be enough, unless we want different owners of each blocklist? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for taking a look! The reasons for supporting multiple block lists are that (1) one single file may get too long over time, and (2) we could group similar actions into a single block list file, such as module loading related actions. |
||
} | ||
} | ||
} | ||
} | ||
|
||
static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts, | ||
llvm::Triple &Triple) { | ||
llvm::SmallString<128> LibPath(SearchPathOpts.RuntimeResourcePath); | ||
|
@@ -1211,6 +1236,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, | |
|
||
Opts.DumpTypeWitnessSystems = Args.hasArg(OPT_dump_type_witness_systems); | ||
|
||
for (auto &block: FrontendOpts.BlocklistConfigFilePaths) | ||
Opts.BlocklistConfigFilePaths.push_back(block); | ||
if (const Arg *A = Args.getLastArg(options::OPT_concurrency_model)) { | ||
Opts.ActiveConcurrencyModel = | ||
llvm::StringSwitch<ConcurrencyModel>(A->getValue()) | ||
|
@@ -2933,6 +2960,7 @@ bool CompilerInvocation::parseArgs( | |
|
||
updateRuntimeLibraryPaths(SearchPathOpts, LangOpts.Target); | ||
setDefaultPrebuiltCacheIfNecessary(); | ||
setDefaultBlocklistsIfNecessary(); | ||
|
||
// Now that we've parsed everything, setup some inter-option-dependent state. | ||
setIRGenOutputOptsFromFrontendOptions(IRGenOpts, FrontendOpts); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I understand correctly that only
DowngradeInterfaceVerificationFailure
is enforced by this PR, and notShouldUseBinaryModule
norShouldUseTextualModule
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. I suspect honoring
ShouldUseBinaryModule
andShouldUseTextualModule
here may cause a later merge conflict.