diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 2e06c5fd9028b..f54f40d028158 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -105,7 +105,6 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) endif() - option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON) option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF) diff --git a/clang/cmake/caches/Apple-stage2.cmake b/clang/cmake/caches/Apple-stage2.cmake index b24ec558c071d..ff9c612b98082 100644 --- a/clang/cmake/caches/Apple-stage2.cmake +++ b/clang/cmake/caches/Apple-stage2.cmake @@ -58,6 +58,13 @@ set(LLVM_TOOLCHAIN_TOOLS llvm-size CACHE STRING "") +set(LLVM_BUILD_UTILS ON CACHE BOOL "") +set(LLVM_INSTALL_UTILS ON CACHE BOOL "") +set(LLVM_TOOLCHAIN_UTILITIES + FileCheck + yaml2obj + CACHE STRING "") + set(LLVM_DISTRIBUTION_COMPONENTS clang LTO @@ -66,6 +73,7 @@ set(LLVM_DISTRIBUTION_COMPONENTS cxx-headers Remarks ${LLVM_TOOLCHAIN_TOOLS} + ${LLVM_TOOLCHAIN_UTILITIES} CACHE STRING "") # test args diff --git a/clang/docs/SourceBasedCodeCoverage.rst b/clang/docs/SourceBasedCodeCoverage.rst index 0e9c364fbf6bd..f5b3d05262e93 100644 --- a/clang/docs/SourceBasedCodeCoverage.rst +++ b/clang/docs/SourceBasedCodeCoverage.rst @@ -79,6 +79,9 @@ directory structure will be created. Additionally, the following special * "%h" expands out to the hostname of the machine running the program. +* "%t" expands out to the value of the ``TMPDIR`` environment variable. On + Darwin, this is typically set to a temporary scratch directory. + * "%Nm" expands out to the instrumented binary's signature. When this pattern is specified, the runtime creates a pool of N raw profiles which are used for on-line profile merging. The runtime takes care of selecting a raw profile diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index caa77b88abf97..1026f85cded06 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -393,6 +393,10 @@ CODEGENOPT(KeepStaticConsts, 1, 0) /// Whether to not follow the AAPCS that enforce at least one read before storing to a volatile bitfield CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0) +/// Assume that by-value parameters do not alias any other values. +CODEGENOPT(PassByValueIsNoAlias, 1, 0) + + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 5e0031335e1ce..6dc2e51b434ca 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -234,6 +234,7 @@ def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi, def GNUFlexibleArrayInitializer : DiagGroup<"gnu-flexible-array-initializer">; def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; +def FormatInsufficientArgs : DiagGroup<"format-insufficient-args">; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; @@ -840,7 +841,8 @@ def FormatPedantic : DiagGroup<"format-pedantic">; def FormatTypeConfusion : DiagGroup<"format-type-confusion">; def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull, - FormatSecurity, FormatY2K, FormatInvalidSpecifier]>, + FormatSecurity, FormatY2K, FormatInvalidSpecifier, + FormatInsufficientArgs]>, DiagCategory<"Format String Issue">; def FormatNonLiteral : DiagGroup<"format-nonliteral">; def Format2 : DiagGroup<"format=2", diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c8cc44b4feb35..685a735bd4518 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8945,7 +8945,7 @@ def note_array_declared_here : Note< "array %0 declared here">; def warn_printf_insufficient_data_args : Warning< - "more '%%' conversions than data arguments">, InGroup; + "more '%%' conversions than data arguments">, InGroup; def warn_printf_data_arg_not_used : Warning< "data argument not used by format string">, InGroup; def warn_format_invalid_conversion : Warning< diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index adacd107a092c..34c0386136070 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1457,11 +1457,11 @@ def fno_pch_validate_input_files_content: Group, Flags<[DriverOption]>; def fpch_instantiate_templates: Flag <["-"], "fpch-instantiate-templates">, - Group, Flags<[CC1Option]>, + Group, Flags<[CC1Option, CoreOption]>, HelpText<"Instantiate templates already while building a PCH">; def fno_pch_instantiate_templates: Flag <["-"], "fno-pch-instantiate-templates">, - Group, Flags<[CC1Option]>; + Group, Flags<[CC1Option, CoreOption]>; defm pch_codegen: OptInFFlag<"pch-codegen", "Generate ", "Do not generate ", "code for uses of this PCH that assumes an explicit object file will be built for the PCH">; defm pch_debuginfo: OptInFFlag<"pch-debuginfo", "Generate ", "Do not generate ", @@ -4339,6 +4339,9 @@ def fno_signed_wchar : Flag<["-"], "fno-signed-wchar">, def fcompatibility_qualified_id_block_param_type_checking : Flag<["-"], "fcompatibility-qualified-id-block-type-checking">, HelpText<"Allow using blocks with parameters of more specific type than " "the type system guarantees when a parameter is qualified id">; +def fpass_by_value_is_noalias: Flag<["-"], "fpass-by-value-is-noalias">, + HelpText<"Allows assuming by-value parameters do not alias any other value. " + "Has no effect on non-trivially-copyable classes in C++.">, Group; // FIXME: Remove these entirely once functionality/tests have been excised. def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group, diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index 2f91f66c24769..c8115b7919334 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -429,22 +429,6 @@ namespace llvm { } }; - template <> - struct ScalarTraits { - static void output(const VersionTuple &value, void*, - llvm::raw_ostream &out) { - out << value; - } - static StringRef input(StringRef scalar, void*, VersionTuple &value) { - if (value.tryParse(scalar)) - return "not a version number in the form XX.YY"; - - return StringRef(); - } - - static QuotingType mustQuote(StringRef) { return QuotingType::None; } - }; - template <> struct MappingTraits { static void mapping(IO &io, Param& p) { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index a0159388bbb5c..4a823659c4b55 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1743,12 +1743,28 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { Decl *ImportedDecl = *ImportedOrErr; FieldDecl *FieldTo = dyn_cast_or_null(ImportedDecl); if (FieldFrom && FieldTo) { - const RecordType *RecordFrom = FieldFrom->getType()->getAs(); - const RecordType *RecordTo = FieldTo->getType()->getAs(); - if (RecordFrom && RecordTo) { - RecordDecl *FromRecordDecl = RecordFrom->getDecl(); - RecordDecl *ToRecordDecl = RecordTo->getDecl(); + RecordDecl *FromRecordDecl = nullptr; + RecordDecl *ToRecordDecl = nullptr; + // If we have a field that is an ArrayType we need to check if the array + // element is a RecordDecl and if so we need to import the defintion. + if (FieldFrom->getType()->isArrayType()) { + // getBaseElementTypeUnsafe(...) handles multi-dimensonal arrays for us. + FromRecordDecl = FieldFrom->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl(); + ToRecordDecl = FieldTo->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl(); + } + + if (!FromRecordDecl || !ToRecordDecl) { + const RecordType *RecordFrom = + FieldFrom->getType()->getAs(); + const RecordType *RecordTo = FieldTo->getType()->getAs(); + + if (RecordFrom && RecordTo) { + FromRecordDecl = RecordFrom->getDecl(); + ToRecordDecl = RecordTo->getDecl(); + } + } + if (FromRecordDecl && ToRecordDecl) { if (FromRecordDecl->isCompleteDefinition() && !ToRecordDecl->isCompleteDefinition()) { Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl); diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 817b0ba4f062b..16c43aa4d72c5 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -949,7 +949,8 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() { if (!Redecl && isRedeclaration()) { // This is the last redeclaration, go back to the first method. return cast(CtxD)->getMethod(getSelector(), - isInstanceMethod()); + isInstanceMethod(), + /*AllowHidden=*/true); } return Redecl ? Redecl : this; @@ -982,7 +983,8 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { if (isRedeclaration()) { // It is possible that we have not done deserializing the ObjCMethod yet. ObjCMethodDecl *MD = - cast(CtxD)->getMethod(Sel, isInstanceMethod()); + cast(CtxD)->getMethod(Sel, isInstanceMethod(), + /*AllowHidden=*/true); return MD ? MD : this; } @@ -1299,8 +1301,9 @@ void ObjCMethodDecl::getOverriddenMethods( const ObjCMethodDecl *Method = this; if (Method->isRedeclaration()) { - Method = cast(Method->getDeclContext())-> - getMethod(Method->getSelector(), Method->isInstanceMethod()); + Method = cast(Method->getDeclContext()) + ->getMethod(Method->getSelector(), Method->isInstanceMethod(), + /*AllowHidden=*/true); } if (Method->isOverriding()) { diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 2a9e4f91d4780..c52da8c0e85e2 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -154,7 +154,8 @@ class LLVM_LIBRARY_VISIBILITY DarwinTargetInfo : public OSTargetInfo { MinVersion = llvm::VersionTuple(5U); break; default: - llvm_unreachable("Unexpected OS"); + // Conservatively return 8 bytes if OS is unknown. + return 64; } unsigned Major, Minor, Micro; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 69d4a60705718..84689697eb523 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2192,6 +2192,13 @@ void CodeGenModule::ConstructAttributeList( if (AI.getIndirectByVal()) Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); + auto *Decl = ParamType->getAsRecordDecl(); + if (CodeGenOpts.PassByValueIsNoAlias && Decl && + Decl->getArgPassingRestrictions() == RecordDecl::APK_CanPassInRegs) + // When calling the function, the pointer passed in will be the only + // reference to the underlying object. Mark it accordingly. + Attrs.addAttribute(llvm::Attribute::NoAlias); + CharUnits Align = AI.getIndirectAlign(); // In a byval argument, it is important that the required @@ -3746,10 +3753,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, } SanitizerScope SanScope(this); - assert(RV.isScalar()); - llvm::Value *V = RV.getScalarVal(); - llvm::Value *Cond = - Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType())); + llvm::Value *Cond = EmitNonNullRValueCheck(RV, ArgType); llvm::Constant *StaticData[] = { EmitCheckSourceLocation(ArgLoc), EmitCheckSourceLocation(AttrLoc), llvm::ConstantInt::get(Int32Ty, ArgNo + 1), diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index c6cfaf6fe9d6e..b0c44eda43515 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1170,6 +1170,13 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, return Address(EmitScalarExpr(E), Align); } +llvm::Value *CodeGenFunction::EmitNonNullRValueCheck(RValue RV, QualType T) { + llvm::Value *V = RV.getScalarVal(); + if (auto MPT = T->getAs()) + return CGM.getCXXABI().EmitMemberPointerIsNotNull(*this, V, MPT); + return Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType())); +} + RValue CodeGenFunction::GetUndefRValue(QualType Ty) { if (Ty->isVoidType()) return RValue::get(nullptr); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index d3b11618d5129..cb903a1f9d880 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3563,6 +3563,9 @@ class CodeGenFunction : public CodeGenTypeCache { // LValue Expression Emission //===--------------------------------------------------------------------===// + /// Create a check that a scalar RValue is non-null. + llvm::Value *EmitNonNullRValueCheck(RValue RV, QualType T); + /// GetUndefRValue - Get an appropriate 'undef' rvalue for the given type. RValue GetUndefRValue(QualType Ty); diff --git a/clang/lib/CodeGen/SwiftCallingConv.cpp b/clang/lib/CodeGen/SwiftCallingConv.cpp index 3d7421ac2e16c..1423d82896e74 100644 --- a/clang/lib/CodeGen/SwiftCallingConv.cpp +++ b/clang/lib/CodeGen/SwiftCallingConv.cpp @@ -93,11 +93,24 @@ void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) { // Just add it all as opaque. addOpaqueData(begin, begin + CGM.getContext().getTypeSizeInChars(type)); - // Everything else is scalar and should not convert as an LLVM aggregate. + // Atomic types. + } else if (const auto *atomicType = type->getAs()) { + auto valueType = atomicType->getValueType(); + auto atomicSize = CGM.getContext().getTypeSizeInChars(atomicType); + auto valueSize = CGM.getContext().getTypeSizeInChars(valueType); + + addTypedData(atomicType->getValueType(), begin); + + // Add atomic padding. + auto atomicPadding = atomicSize - valueSize; + if (atomicPadding > CharUnits::Zero()) + addOpaqueData(begin + valueSize, begin + atomicSize); + + // Everything else is scalar and should not convert as an LLVM aggregate. } else { // We intentionally convert as !ForMem because we want to preserve // that a type was an i1. - auto llvmType = CGM.getTypes().ConvertType(type); + auto *llvmType = CGM.getTypes().ConvertType(type); addTypedData(llvmType, begin); } } diff --git a/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp b/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp index 25cbcf536388a..8c2e64a87b79d 100644 --- a/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp +++ b/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp @@ -6,19 +6,12 @@ // //===----------------------------------------------------------------------===// -// TODO: This is not yet an implementation, but it will make it so Windows -// builds don't fail. - #include "DirectoryScanner.h" #include "clang/DirectoryWatcher/DirectoryWatcher.h" - #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/ScopeExit.h" -#include "llvm/Support/AlignOf.h" -#include "llvm/Support/Errno.h" -#include "llvm/Support/Mutex.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Path.h" -#include +#include "llvm/Support/Windows/WindowsSupport.h" #include #include #include @@ -28,23 +21,270 @@ namespace { +using DirectoryWatcherCallback = + std::function, bool)>; + using namespace llvm; using namespace clang; class DirectoryWatcherWindows : public clang::DirectoryWatcher { + OVERLAPPED Overlapped; + + std::vector Notifications; + + std::thread WatcherThread; + std::thread HandlerThread; + std::function, bool)> Callback; + SmallString Path; + HANDLE Terminate; + + class EventQueue { + std::mutex M; + std::queue Q; + std::condition_variable CV; + + public: + void emplace(DirectoryWatcher::Event::EventKind Kind, StringRef Path) { + { + std::unique_lock L(M); + Q.emplace(Kind, Path); + } + CV.notify_one(); + } + + DirectoryWatcher::Event pop_front() { + std::unique_lock L(M); + while (true) { + if (!Q.empty()) { + DirectoryWatcher::Event E = Q.front(); + Q.pop(); + return E; + } + CV.wait(L, [this]() { return !Q.empty(); }); + } + } + } Q; + public: - ~DirectoryWatcherWindows() override { } - void InitialScan() { } - void EventReceivingLoop() { } - void StopWork() { } + DirectoryWatcherWindows(HANDLE DirectoryHandle, bool WaitForInitialSync, + DirectoryWatcherCallback Receiver); + + ~DirectoryWatcherWindows() override; + + void InitialScan(); + void WatcherThreadProc(HANDLE DirectoryHandle); + void NotifierThreadProc(bool WaitForInitialSync); }; + +DirectoryWatcherWindows::DirectoryWatcherWindows( + HANDLE DirectoryHandle, bool WaitForInitialSync, + DirectoryWatcherCallback Receiver) + : Callback(Receiver), Terminate(INVALID_HANDLE_VALUE) { + // Pre-compute the real location as we will be handing over the directory + // handle to the watcher and performing synchronous operations. + { + DWORD Length = GetFinalPathNameByHandleW(DirectoryHandle, NULL, 0, 0); + + std::vector Buffer; + Buffer.resize(Length); + + Length = GetFinalPathNameByHandleW(DirectoryHandle, Buffer.data(), + Buffer.size(), 0); + Buffer.resize(Length); + + llvm::sys::windows::UTF16ToUTF8(Buffer.data(), Buffer.size(), Path); + } + + Notifications.resize(4 * (sizeof(FILE_NOTIFY_INFORMATION) + + MAX_PATH * sizeof(WCHAR))); + + memset(&Overlapped, 0, sizeof(Overlapped)); + Overlapped.hEvent = + CreateEventW(NULL, /*bManualReset=*/TRUE, /*bInitialState=*/FALSE, NULL); + assert(Overlapped.hEvent && "unable to create event"); + + Terminate = CreateEventW(NULL, /*bManualReset=*/TRUE, + /*bInitialState=*/FALSE, NULL); + + WatcherThread = std::thread([this, DirectoryHandle]() { + this->WatcherThreadProc(DirectoryHandle); + }); + + if (WaitForInitialSync) + InitialScan(); + + HandlerThread = std::thread([this, WaitForInitialSync]() { + this->NotifierThreadProc(WaitForInitialSync); + }); +} + +DirectoryWatcherWindows::~DirectoryWatcherWindows() { + // Signal the Watcher to exit. + SetEvent(Terminate); + HandlerThread.join(); + WatcherThread.join(); + CloseHandle(Terminate); + CloseHandle(Overlapped.hEvent); +} + +void DirectoryWatcherWindows::InitialScan() { + Callback(getAsFileEvents(scanDirectory(Path.data())), /*IsInitial=*/true); +} + +void DirectoryWatcherWindows::WatcherThreadProc(HANDLE DirectoryHandle) { + while (true) { + // We do not guarantee subdirectories, but macOS already provides + // subdirectories, might as well as ... + BOOL WatchSubtree = TRUE; + DWORD NotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_LAST_ACCESS + | FILE_NOTIFY_CHANGE_LAST_WRITE + | FILE_NOTIFY_CHANGE_CREATION; + + DWORD BytesTransferred; + if (!ReadDirectoryChangesW(DirectoryHandle, Notifications.data(), + Notifications.size(), WatchSubtree, + NotifyFilter, &BytesTransferred, &Overlapped, + NULL)) { + Q.emplace(DirectoryWatcher::Event::EventKind::WatcherGotInvalidated, + ""); + break; + } + + HANDLE Handles[2] = { Terminate, Overlapped.hEvent }; + switch (WaitForMultipleObjects(2, Handles, FALSE, INFINITE)) { + case WAIT_OBJECT_0: // Terminate Request + case WAIT_FAILED: // Failure + Q.emplace(DirectoryWatcher::Event::EventKind::WatcherGotInvalidated, + ""); + (void)CloseHandle(DirectoryHandle); + return; + case WAIT_TIMEOUT: // Spurious wakeup? + continue; + case WAIT_OBJECT_0 + 1: // Directory change + break; + } + + if (!GetOverlappedResult(DirectoryHandle, &Overlapped, &BytesTransferred, + FALSE)) { + Q.emplace(DirectoryWatcher::Event::EventKind::WatchedDirRemoved, + ""); + Q.emplace(DirectoryWatcher::Event::EventKind::WatcherGotInvalidated, + ""); + break; + } + + // There was a buffer underrun on the kernel side. We may have lost + // events, please re-synchronize. + if (BytesTransferred == 0) { + Q.emplace(DirectoryWatcher::Event::EventKind::WatcherGotInvalidated, + ""); + break; + } + + for (FILE_NOTIFY_INFORMATION *I = + (FILE_NOTIFY_INFORMATION *)Notifications.data(); + I; + I = I->NextEntryOffset + ? (FILE_NOTIFY_INFORMATION *)((CHAR *)I + I->NextEntryOffset) + : NULL) { + DirectoryWatcher::Event::EventKind Kind = + DirectoryWatcher::Event::EventKind::WatcherGotInvalidated; + switch (I->Action) { + case FILE_ACTION_MODIFIED: + Kind = DirectoryWatcher::Event::EventKind::Modified; + break; + case FILE_ACTION_ADDED: + Kind = DirectoryWatcher::Event::EventKind::Modified; + break; + case FILE_ACTION_REMOVED: + Kind = DirectoryWatcher::Event::EventKind::Removed; + break; + case FILE_ACTION_RENAMED_OLD_NAME: + Kind = DirectoryWatcher::Event::EventKind::Removed; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + Kind = DirectoryWatcher::Event::EventKind::Modified; + break; + } + + SmallString filename; + sys::windows::UTF16ToUTF8(I->FileName, I->FileNameLength / 2, + filename); + Q.emplace(Kind, filename); + } + } + + (void)CloseHandle(DirectoryHandle); +} + +void DirectoryWatcherWindows::NotifierThreadProc(bool WaitForInitialSync) { + // If we did not wait for the initial sync, then we should perform the + // scan when we enter the thread. + if (!WaitForInitialSync) + this->InitialScan(); + + while (true) { + DirectoryWatcher::Event E = Q.pop_front(); + Callback(E, /*IsInitial=*/false); + if (E.Kind == DirectoryWatcher::Event::EventKind::WatcherGotInvalidated) + break; + } +} + +auto error(DWORD ErrorCode) { + DWORD Flags = FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS; + + LPSTR Buffer; + if (!FormatMessageA(Flags, NULL, ErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&Buffer, + 0, NULL)) { + return make_error("error " + utostr(ErrorCode), + inconvertibleErrorCode()); + } + std::string Message{Buffer}; + LocalFree(Buffer); + return make_error(Message, inconvertibleErrorCode()); +} + } // namespace llvm::Expected> -clang::DirectoryWatcher::create( - StringRef Path, - std::function, bool)> Receiver, - bool WaitForInitialSync) { - return llvm::Expected>( - llvm::errorCodeToError(std::make_error_code(std::errc::not_supported))); +clang::DirectoryWatcher::create(StringRef Path, + DirectoryWatcherCallback Receiver, + bool WaitForInitialSync) { + if (Path.empty()) + llvm::report_fatal_error( + "DirectoryWatcher::create can not accept an empty Path."); + + if (!sys::fs::is_directory(Path)) + llvm::report_fatal_error( + "DirectoryWatcher::create can not accept a filepath."); + + SmallVector WidePath; + if (sys::windows::UTF8ToUTF16(Path, WidePath)) + return llvm::make_error( + "unable to convert path to UTF-16", llvm::inconvertibleErrorCode()); + + DWORD DesiredAccess = FILE_LIST_DIRECTORY; + DWORD ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + DWORD CreationDisposition = OPEN_EXISTING; + DWORD FlagsAndAttributes = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED; + + HANDLE DirectoryHandle = + CreateFileW(WidePath.data(), DesiredAccess, ShareMode, + /*lpSecurityAttributes=*/NULL, CreationDisposition, + FlagsAndAttributes, NULL); + if (DirectoryHandle == INVALID_HANDLE_VALUE) + return error(GetLastError()); + + // NOTE: We use the watcher instance as a RAII object to discard the handles + // for the directory and the IOCP in case of an error. Hence, this is early + // allocated, with the state being written directly to the watcher. + return std::make_unique( + DirectoryHandle, WaitForInitialSync, Receiver); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 26b031e59bf6a..bbeb99e354143 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1198,7 +1198,11 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, if (YcArg && JA.getKind() >= Action::PrecompileJobClass && JA.getKind() <= Action::AssembleJobClass) { CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); - CmdArgs.push_back(Args.MakeArgString("-fpch-instantiate-templates")); + // -fpch-instantiate-templates is the default when creating + // precomp using /Yc + if (Args.hasFlag(options::OPT_fpch_instantiate_templates, + options::OPT_fno_pch_instantiate_templates, true)) + CmdArgs.push_back(Args.MakeArgString("-fpch-instantiate-templates")); } if (YcArg || YuArg) { StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue(); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b937f54fff72b..0cc8ef65bf4e0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1539,6 +1539,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, std::string(Args.getLastArgValue(OPT_fsymbol_partition_EQ)); Opts.ForceAAPCSBitfieldLoad = Args.hasArg(OPT_ForceAAPCSBitfieldLoad); + + Opts.PassByValueIsNoAlias = Args.hasArg(OPT_fpass_by_value_is_noalias); return Success; } diff --git a/clang/lib/Index/IndexUnitReader.cpp b/clang/lib/Index/IndexUnitReader.cpp index 30e474d6d6165..a1f8ca7798407 100644 --- a/clang/lib/Index/IndexUnitReader.cpp +++ b/clang/lib/Index/IndexUnitReader.cpp @@ -378,10 +378,10 @@ void IndexUnitReaderImpl::constructFilePath(SmallVectorImpl &PathBuf, } StringRef IndexUnitReaderImpl::getModuleName(int ModuleIndex) { - if (ModuleIndex < 0) + if (ModuleIndex < 0 || ModuleNamesBuffer.empty()) return StringRef(); auto &ModInfo = Modules[ModuleIndex]; - return StringRef(ModuleNamesBuffer.data()+ModInfo.NameOffset, ModInfo.NameSize); + return ModuleNamesBuffer.substr(ModInfo.NameOffset, ModInfo.NameSize); } diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index b7c7e2693ef18..de7b9b73ddf7a 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -263,10 +263,12 @@ static void collectAllSubModulesWithUmbrellaHeader( } void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) { - assert(Mod.getUmbrellaHeader() && "Module must use umbrella header"); - SourceLocation StartLoc = - SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); - if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, StartLoc)) + const Module::Header &UmbrellaHeader = Mod.getUmbrellaHeader(); + assert(UmbrellaHeader.Entry && "Module must use umbrella header"); + const FileID &File = SourceMgr.translateFile(UmbrellaHeader.Entry); + SourceLocation ExpectedHeadersLoc = SourceMgr.getLocForEndOfFile(File); + if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, + ExpectedHeadersLoc)) return; ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap(); @@ -291,7 +293,7 @@ void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) { // Find the relative path that would access this header. SmallString<128> RelativePath; computeRelativePath(FileMgr, Dir, *Header, RelativePath); - Diag(StartLoc, diag::warn_uncovered_module_header) + Diag(ExpectedHeadersLoc, diag::warn_uncovered_module_header) << Mod.getFullModuleName() << RelativePath; } } diff --git a/clang/test/CodeGen/64bit-swiftcall.c b/clang/test/CodeGen/64bit-swiftcall.c index 51fb8545551f0..5843b8cde4dce 100644 --- a/clang/test/CodeGen/64bit-swiftcall.c +++ b/clang/test/CodeGen/64bit-swiftcall.c @@ -10,6 +10,9 @@ #define ERROR __attribute__((swift_error_result)) #define CONTEXT __attribute__((swift_context)) +// CHECK-DAG: %struct.atomic_padded = type { { %struct.packed, [7 x i8] } } +// CHECK-DAG: %struct.packed = type <{ i64, i8 }> +// // CHECK: [[STRUCT2_RESULT:@.*]] = private {{.*}} constant [[STRUCT2_TYPE:%.*]] { i32 0, i8 0, i8 undef, i8 0, i32 0, i32 0 } /*****************************************************************************/ @@ -1042,3 +1045,27 @@ void no_lifetime_markers() { // CHECK-NOT: call void @llvm.lifetime. take_int5(return_int5()); } + +typedef struct { + unsigned long long a; + unsigned long long b; +} double_word; + +typedef struct { + _Atomic(double_word) a; +} atomic_double_word; + +// CHECK-LABEL: use_atomic(i64 %0, i64 %1) +SWIFTCALL void use_atomic(atomic_double_word a) {} + +typedef struct { + unsigned long long a; + unsigned char b; +} __attribute__((packed)) packed; + +typedef struct { + _Atomic(packed) a; +} atomic_padded; + +// CHECK-LABEL: use_atomic_padded(i64 %0, i64 %1) +SWIFTCALL void use_atomic_padded(atomic_padded a) {} diff --git a/clang/test/CodeGen/pass-by-value-noalias.c b/clang/test/CodeGen/pass-by-value-noalias.c new file mode 100644 index 0000000000000..f77ce2b1e35bb --- /dev/null +++ b/clang/test/CodeGen/pass-by-value-noalias.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fpass-by-value-is-noalias -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=WITH_NOALIAS %s +// RUN: %clang_cc1 -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=NO_NOALIAS %s + +// A struct large enough so it is not passed in registers on ARM64. +struct Foo { + int a; + int b; + int c; + int d; + int e; + int f; +}; + +// WITH_NOALIAS: define void @take(%struct.Foo* noalias %arg) +// NO_NOALIAS: define void @take(%struct.Foo* %arg) +void take(struct Foo arg) {} diff --git a/clang/test/CodeGenCXX/pass-by-value-noalias.cpp b/clang/test/CodeGenCXX/pass-by-value-noalias.cpp new file mode 100644 index 0000000000000..fd96a36d3d6e5 --- /dev/null +++ b/clang/test/CodeGenCXX/pass-by-value-noalias.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -fpass-by-value-is-noalias -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=WITH_NOALIAS %s +// RUN: %clang_cc1 -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=NO_NOALIAS %s + +// A trivial struct large enough so it is not passed in registers on ARM64. +struct Foo { + int a; + int b; + int c; + int d; + int e; + int f; +}; + +// Make sure noalias is added to indirect arguments with trivially copyable types +// if -fpass-by-value-is-noalias is provided. + +// WITH_NOALIAS: define void @_Z4take3Foo(%struct.Foo* noalias %arg) +// NO_NOALIAS: define void @_Z4take3Foo(%struct.Foo* %arg) +void take(Foo arg) {} + +int G; + +// NonTrivial is not trivially-copyable, because it has a non-trivial copy +// constructor. +struct NonTrivial { + int a; + int b; + int c; + int d; + int e; + int f; + + NonTrivial(const NonTrivial &Other) { + a = G + 10 + Other.a; + } +}; + +// Make sure noalias is not added to indirect arguments that are not trivially +// copyable even if -fpass-by-value-is-noalias is provided. + +// WITH_NOALIAS: define void @_Z4take10NonTrivial(%struct.NonTrivial* %arg) +// NO_NOALIAS: define void @_Z4take10NonTrivial(%struct.NonTrivial* %arg) +void take(NonTrivial arg) {} + +// Escape examples. Pointers to the objects passed to take() may escape, depending on whether a temporary copy is created or not (e.g. due to NRVO). +struct A { + A(A **where) : data{"hello world 1"} { + *where = this; //Escaped pointer 1 (proposed UB?) + } + + A() : data{"hello world 2"} {} + + char data[32]; +}; +A *p; + +// WITH_NOALIAS: define void @_Z4take1A(%struct.A* noalias %arg) +// NO_NOALIAS: define void @_Z4take1A(%struct.A* %arg) +void take(A arg) {} + +// WITH_NOALIAS: define void @_Z7CreateAPP1A(%struct.A* noalias sret align 1 %agg.result, %struct.A** %where) +// NO_NOALIAS: define void @_Z7CreateAPP1A(%struct.A* noalias sret align 1 %agg.result, %struct.A** %where) +A CreateA(A **where) { + A justlikethis; + *where = &justlikethis; //Escaped pointer 2 (should also be UB, then) + return justlikethis; +} + +// elsewhere, perhaps compiled by a smarter compiler that doesn't make a copy here +void test() { + take({&p}); // 1 + take(CreateA(&p)); // 2 +} diff --git a/clang/test/CodeGenCXX/ubsan-nullability-arg.cpp b/clang/test/CodeGenCXX/ubsan-nullability-arg.cpp new file mode 100644 index 0000000000000..fbebd153a9eae --- /dev/null +++ b/clang/test/CodeGenCXX/ubsan-nullability-arg.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=nullability-arg | FileCheck %s -check-prefixes=ITANIUM,ALL +// RUN: %clang_cc1 -x c++ -triple x86_64-pc-windows-msvc -emit-llvm -o - %s -fsanitize=nullability-arg | FileCheck %s -check-prefixes=MSVC,ALL + +namespace method_ptr { + +struct S0 { + void foo1(); +}; + +void foo1(void (S0::*_Nonnull f)()); + +// ITANIUM-LABEL: @_ZN10method_ptr5test1Ev(){{.*}} { +// ITANIUM: br i1 icmp ne (i64 ptrtoint (void (%"struct.method_ptr::S0"*)* @_ZN10method_ptr2S04foo1Ev to i64), i64 0), label %[[CONT:.*]], label %[[FAIL:[^,]*]] +// ITANIUM-EMPTY: +// ITANIUM-NEXT: [[FAIL]]: +// ITANIUM-NEXT: call void @__ubsan_handle_nullability_arg + +// MSVC-LABEL: @"?test1@method_ptr@@YAXXZ"(){{.*}} { +// MSVC: br i1 true, label %[[CONT:.*]], label %[[FAIL:[^,]*]] +// MSVC-EMPTY: +// MSVC-NEXT: [[FAIL]]: +// MSVC-NEXT: call void @__ubsan_handle_nullability_arg +void test1() { + foo1(&S0::foo1); +} + +} // namespace method_ptr + +namespace data_ptr { + +struct S0 { + int field1; +}; + +using member_ptr = int S0::*; + +void foo1(member_ptr _Nonnull); + +// ITANIUM-LABEL: @_ZN8data_ptr5test1ENS_2S0E( +// MSVC-LABEL: @"?test1@data_ptr@@YAXUS0@1@@Z"( +// ALL: [[DATA_PTR_CHECK:%.*]] = icmp ne {{.*}}, -1, !nosanitize +// ALL-NEXT: br i1 [[DATA_PTR_CHECK]], label %[[CONT:.*]], label %[[FAIL:[^,]+]] +// ALL-EMPTY: +// ALL-NEXT: [[FAIL]]: +// ALL-NEXT: call void @__ubsan_handle_nullability_arg +void test1(S0 s) { + int S0::*member = &S0::field1; + foo1(member); +} + +} // namespace data_ptr diff --git a/clang/test/CodeGenObjC/pass-by-value-noalias.m b/clang/test/CodeGenObjC/pass-by-value-noalias.m new file mode 100644 index 0000000000000..08252800dba2f --- /dev/null +++ b/clang/test/CodeGenObjC/pass-by-value-noalias.m @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fpass-by-value-is-noalias -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns -fobjc-runtime-has-weak -fobjc-arc -fobjc-dispatch-method=mixed %s -o - 2>&1 | FileCheck --check-prefix=WITH_NOALIAS %s +// RUN: %clang_cc1 -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns -fobjc-runtime-has-weak -fobjc-arc -fobjc-dispatch-method=mixed %s -o - 2>&1 | FileCheck --check-prefix=NO_NOALIAS %s + +@interface Bar +@property char value; +@end + +// A struct large enough so it is not passed in registers on ARM64, but with a +// weak reference, so noalias should not be added even with +// -fpass-by-value-is-noalias. +struct Foo { + int a; + int b; + int c; + int d; + int e; + Bar *__weak f; +}; + +// WITH_NOALIAS: define void @take(%struct.Foo* %arg) +// NO_NOALIAS: define void @take(%struct.Foo* %arg) +void take(struct Foo arg) {} diff --git a/clang/test/Driver/pch-instantiate-templates.c b/clang/test/Driver/pch-instantiate-templates.c new file mode 100644 index 0000000000000..b0f7f34739938 --- /dev/null +++ b/clang/test/Driver/pch-instantiate-templates.c @@ -0,0 +1,13 @@ +// CL driver test cases +// RUN: %clang_cl -### /Yc /Fpfoo.pch /Fofoo.obj -- %s 2>&1 | FileCheck --check-prefix=CLANG_CL_YC %s +// RUN: %clang_cl -### /Yc /Fpfoo.pch /Fofoo.obj -fno-pch-instantiate-templates -- %s 2>&1 | FileCheck --check-prefix=CLANG_CL_YC_DISABLE %s + +// CLANG_CL_YC: "-fpch-instantiate-templates" +// CLANG_CL_YC_DISABLE-NOT: "-fpch-instantiate-templates" + +// GCC driver test cases +// RUN: %clang -### -x c-header %s -o %t/foo.pch 2>&1 | FileCheck -check-prefix=GCC_DEFAULT %s +// RUN: %clang -### -x c-header %s -o %t/foo.pch -fpch-instantiate-templates 2>&1 | FileCheck -check-prefix=GCC_DEFAULT_ENABLE %s + +// GCC_DEFAULT-NOT: "-fpch-instantiate-templates" +// GCC_DEFAULT_ENABLE: "-fpch-instantiate-templates" diff --git a/clang/test/Index/Inputs/hidden-redecls-sub.h b/clang/test/Index/Inputs/hidden-redecls-sub.h new file mode 100644 index 0000000000000..f5a77977cfba9 --- /dev/null +++ b/clang/test/Index/Inputs/hidden-redecls-sub.h @@ -0,0 +1,7 @@ +@protocol P1 +- (void)p1_method; +- (void)p1_method; +@end + +@interface Foo (SubP1) +@end diff --git a/clang/test/Index/Inputs/hidden-redecls.h b/clang/test/Index/Inputs/hidden-redecls.h new file mode 100644 index 0000000000000..c5558cf0ab18e --- /dev/null +++ b/clang/test/Index/Inputs/hidden-redecls.h @@ -0,0 +1,3 @@ +@interface Foo +- (void)parent_method; +@end diff --git a/clang/test/Index/Inputs/module.map b/clang/test/Index/Inputs/module.map index 10712accb1c24..cd5bcb4670322 100644 --- a/clang/test/Index/Inputs/module.map +++ b/clang/test/Index/Inputs/module.map @@ -20,3 +20,11 @@ module PreambleWithImplicitImport { export * } } + +module hidden_redecls { + header "hidden-redecls.h" + + explicit module sub { + header "hidden-redecls-sub.h" + } +} diff --git a/clang/test/Index/hidden-redecls.m b/clang/test/Index/hidden-redecls.m new file mode 100644 index 0000000000000..1735c0b5e184e --- /dev/null +++ b/clang/test/Index/hidden-redecls.m @@ -0,0 +1,12 @@ +@import hidden_redecls; + +@interface Foo (Top) +- (void)top_method; +@end + +// p1_method in protocol P1 is hidden since module_redecls.sub hasn't been +// imported yet. Check it is still indexed. + +// RUN: c-index-test -index-file-full %s -isystem %S/Inputs -fmodules -target x86_64-apple-macosx10.7 | FileCheck %s +// CHECK: [indexDeclaration]: kind: objc-instance-method | name: p1_method | {{.*}} | loc: {{.*}}hidden-redecls-sub.h:2:9 | {{.*}} | isRedecl: 0 +// CHECK: [indexDeclaration]: kind: objc-instance-method | name: p1_method | {{.*}} | loc: {{.*}}hidden-redecls-sub.h:3:9 | {{.*}} | isRedecl: 1 diff --git a/clang/test/Misc/warning-wall.c b/clang/test/Misc/warning-wall.c index c63d4beecff04..ac2b124e3312f 100644 --- a/clang/test/Misc/warning-wall.c +++ b/clang/test/Misc/warning-wall.c @@ -15,6 +15,7 @@ CHECK-NEXT: -Wnonnull CHECK-NEXT: -Wformat-security CHECK-NEXT: -Wformat-y2k CHECK-NEXT: -Wformat-invalid-specifier +CHECK-NEXT: -Wformat-insufficient-args CHECK-NEXT: -Wfor-loop-analysis CHECK-NEXT: -Wframe-address CHECK-NEXT: -Wimplicit diff --git a/clang/test/Modules/incomplete-umbrella.m b/clang/test/Modules/incomplete-umbrella.m index 8760b815718b2..0574921203b2d 100644 --- a/clang/test/Modules/incomplete-umbrella.m +++ b/clang/test/Modules/incomplete-umbrella.m @@ -6,8 +6,12 @@ #import @import Foo.Private; -// CHECK: warning: umbrella header for module 'Foo' does not include header 'Bar.h' -// CHECK: warning: umbrella header for module 'Foo.Private' does not include header 'Baz.h' +// CHECK: While building module 'Foo' imported from {{.*[/\]}}incomplete-umbrella.m:4: +// CHECK-NEXT: In file included from :1: +// CHECK-NEXT: {{.*Foo[.]framework[/\]Headers[/\]}}FooPublic.h:2:1: warning: umbrella header for module 'Foo' does not include header 'Bar.h' +// CHECK: While building module 'Foo' imported from {{.*[/\]}}incomplete-umbrella.m:4: +// CHECK-NEXT: In file included from :2: +// CHECK-NEXT: {{.*Foo[.]framework[/\]PrivateHeaders[/\]}}Foo.h:2:1: warning: umbrella header for module 'Foo.Private' does not include header 'Baz.h' int foo() { int a = BAR_PUBLIC; int b = BAZ_PRIVATE; diff --git a/clang/test/Sema/warn-printf-insufficient-data-args.c b/clang/test/Sema/warn-printf-insufficient-data-args.c new file mode 100644 index 0000000000000..a8de7118e8b1f --- /dev/null +++ b/clang/test/Sema/warn-printf-insufficient-data-args.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=WARNING-ON %s +// RUN: %clang_cc1 -fsyntax-only -Wno-format-insufficient-args -verify=WARNING-OFF %s + + +int printf(const char * format, ...); + +int main(void) { + int patatino = 42; + printf("%i %i", patatino); // WARNING-ON-warning {{more '%' conversions than data arguments}} + // WARNING-OFF-no-diagnostics +} diff --git a/clang/test/SemaCXX/warn-overaligned-type-thrown.cpp b/clang/test/SemaCXX/warn-overaligned-type-thrown.cpp index d7468445f8b79..9f2386ddc3c61 100644 --- a/clang/test/SemaCXX/warn-overaligned-type-thrown.cpp +++ b/clang/test/SemaCXX/warn-overaligned-type-thrown.cpp @@ -3,6 +3,7 @@ // RUN: %clang_cc1 -triple arm64-apple-tvos10 -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions -DUNDERALIGNED %s // RUN: %clang_cc1 -triple arm64-apple-watchos4 -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions -DUNDERALIGNED %s // RUN: %clang_cc1 -triple arm-linux-gnueabi -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions -DUNDERALIGNED %s +// RUN: %clang_cc1 -triple thumbv7em-apple-unknown-macho -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions -DUNDERALIGNED %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.14 -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions %s // RUN: %clang_cc1 -triple arm64-apple-ios12 -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions %s // RUN: %clang_cc1 -triple arm64-apple-tvos12 -verify -fsyntax-only -std=c++11 -fcxx-exceptions -fexceptions %s diff --git a/clang/unittests/DirectoryWatcher/CMakeLists.txt b/clang/unittests/DirectoryWatcher/CMakeLists.txt index 0355525a86b0a..84a1a9d40c250 100644 --- a/clang/unittests/DirectoryWatcher/CMakeLists.txt +++ b/clang/unittests/DirectoryWatcher/CMakeLists.txt @@ -1,4 +1,4 @@ -if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Linux") +if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME STREQUAL Windows) set(LLVM_LINK_COMPONENTS Support diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 311eb877cdc49..13878f20e1014 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -74,6 +74,7 @@ typedef struct lprofFilename { unsigned OwnsFilenamePat; const char *ProfilePathPrefix; char PidChars[MAX_PID_SIZE]; + char *TmpDir; char Hostname[COMPILER_RT_MAX_HOSTLEN]; unsigned NumPids; unsigned NumHosts; @@ -90,8 +91,8 @@ typedef struct lprofFilename { ProfileNameSpecifier PNS; } lprofFilename; -static lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0}, 0, - 0, 0, {0}, 0, PNS_unknown}; +static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL, {0}, + 0, 0, 0, {0}, 0, PNS_unknown}; static int ProfileMergeRequested = 0; static int isProfileMergeRequested() { return ProfileMergeRequested; } @@ -773,6 +774,14 @@ static int parseFilenamePattern(const char *FilenamePat, FilenamePat); return -1; } + } else if (FilenamePat[I] == 't') { + lprofCurFilename.TmpDir = getenv("TMPDIR"); + if (!lprofCurFilename.TmpDir) { + PROF_WARN("Unable to get the TMPDIR environment variable, referenced " + "in %s. Using the default path.", + FilenamePat); + return -1; + } } else if (FilenamePat[I] == 'c') { if (__llvm_profile_is_continuous_mode_enabled()) { PROF_WARN("%%c specifier can only be specified once in %s.\n", @@ -874,12 +883,14 @@ static int getCurFilenameLength() { return 0; if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || - lprofCurFilename.MergePoolSize || lprofCurFilename.NumExitSignals)) + lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize || + lprofCurFilename.NumExitSignals)) return strlen(lprofCurFilename.FilenamePat); Len = strlen(lprofCurFilename.FilenamePat) + lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + - lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); + lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) + + (lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0); if (lprofCurFilename.MergePoolSize) Len += SIGLEN; for (I = 0; I < lprofCurFilename.NumExitSignals; ++I) { @@ -896,14 +907,14 @@ static int getCurFilenameLength() { * current filename pattern string is directly returned, unless ForceUseBuf * is enabled. */ static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { - int I, J, PidLength, HostNameLength, FilenamePatLength; + int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength; const char *FilenamePat = lprofCurFilename.FilenamePat; if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) return 0; if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || - lprofCurFilename.MergePoolSize || + lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize || __llvm_profile_is_continuous_mode_enabled() || lprofCurFilename.NumExitSignals)) { if (!ForceUseBuf) @@ -917,6 +928,7 @@ static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { PidLength = strlen(lprofCurFilename.PidChars); HostNameLength = strlen(lprofCurFilename.Hostname); + TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0; /* Construct the new filename. */ for (I = 0, J = 0; FilenamePat[I]; ++I) if (FilenamePat[I] == '%') { @@ -929,6 +941,10 @@ static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { } else if (containsExitOnSignalSpecifier(FilenamePat, I)) { while (FilenamePat[I] != 'x') ++I; + } else if (FilenamePat[I] == 't') { + memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength); + FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR; + J += TmpDirLength + 1; } else { if (!getMergePoolSize(FilenamePat, &I)) continue; diff --git a/compiler-rt/test/profile/instrprof-tmpdir.c b/compiler-rt/test/profile/instrprof-tmpdir.c new file mode 100644 index 0000000000000..036313850ed63 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-tmpdir.c @@ -0,0 +1,22 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: cd %t +// RUN: %clang_profgen -o %t/binary %s +// +// Check that a dir separator is appended after %t is subsituted. +// RUN: env TMPDIR="%t" LLVM_PROFILE_FILE="%%traw1.profraw" %run ./binary +// RUN: llvm-profdata show ./raw1.profraw | FileCheck %s -check-prefix TMPDIR +// +// Check that substitution works even if a redundant dir separator is added. +// RUN: env TMPDIR="%t" LLVM_PROFILE_FILE="%%t/raw2.profraw" %run ./binary +// RUN: llvm-profdata show ./raw2.profraw | FileCheck %s -check-prefix TMPDIR +// +// Check that we fall back to the default path if TMPDIR is missing. +// RUN: env -u TMPDIR LLVM_PROFILE_FILE="%%t/raw3.profraw" %run ./binary 2>&1 | FileCheck %s -check-prefix MISSING +// RUN: llvm-profdata show ./default.profraw | FileCheck %s -check-prefix TMPDIR + +// TMPDIR: Maximum function count: 1 + +// MISSING: Unable to get the TMPDIR environment variable, referenced in {{.*}}raw3.profraw. Using the default path. + +int main() { return 0; } diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index 13e675f1096e5..e8b81215356c4 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -62,7 +62,6 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) if(LLVM_ENABLE_ZLIB) find_package(ZLIB REQUIRED) endif() - option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON) option(LLVM_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) include(CMakeParseArguments) diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt index bd8176c67925f..34277e6bd00a9 100644 --- a/libunwind/CMakeLists.txt +++ b/libunwind/CMakeLists.txt @@ -73,8 +73,6 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_B endif() if (EXISTS ${LLVM_CMAKE_PATH}) - # Enable warnings, otherwise -w gets added to the cflags by HandleLLVMOptions. - set(LLVM_ENABLE_WARNINGS ON) list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") include("${LLVM_CMAKE_PATH}/AddLLVM.cmake") include("${LLVM_CMAKE_PATH}/HandleLLVMOptions.cmake") diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index db1a60063ece6..67ecb8f027463 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -61,7 +61,7 @@ endif() if (LLDB_ENABLE_PYTHON) execute_process( - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${Python3_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib(True, False, ''))" OUTPUT_VARIABLE LLDB_PYTHON_DEFAULT_RELATIVE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/lldb/bindings/interface/SBBreakpoint.i b/lldb/bindings/interface/SBBreakpoint.i index e386ace9dee8a..696795241b118 100644 --- a/lldb/bindings/interface/SBBreakpoint.i +++ b/lldb/bindings/interface/SBBreakpoint.i @@ -100,6 +100,9 @@ public: void ClearAllBreakpointSites (); + lldb::SBTarget + GetTarget() const; + lldb::SBBreakpointLocation FindLocationByAddress (lldb::addr_t vm_addr); diff --git a/lldb/bindings/interface/SBModule.i b/lldb/bindings/interface/SBModule.i index 83596c2f37c09..ed947b61f3e39 100644 --- a/lldb/bindings/interface/SBModule.i +++ b/lldb/bindings/interface/SBModule.i @@ -356,6 +356,17 @@ public: static uint32_t GetNumberAllocatedModules(); + %feature("docstring", " + Removes all modules which are no longer needed by any part of LLDB from + the module cache. + + This is an implementation detail exposed for testing and should not be + relied upon. Use SBDebugger::MemoryPressureDetected instead to reduce + LLDB's memory consumption during execution. + ") GarbageCollectAllocatedModules; + static void + GarbageCollectAllocatedModules(); + STRING_EXTENSION(SBModule) #ifdef SWIGPYTHON diff --git a/lldb/bindings/interface/SBThreadPlan.i b/lldb/bindings/interface/SBThreadPlan.i index 36131d529b7b7..2003c6fdee3a3 100644 --- a/lldb/bindings/interface/SBThreadPlan.i +++ b/lldb/bindings/interface/SBThreadPlan.i @@ -92,6 +92,14 @@ public: bool IsPlanStale(); + %feature("docstring", "Return whether this plan will ask to stop other threads when it runs.") GetStopOthers; + bool + GetStopOthers(); + + %feature("docstring", "Set whether this plan will ask to stop other threads when it runs.") GetStopOthers; + void + SetStopOthers(bool stop_others); + SBThreadPlan QueueThreadPlanForStepOverRange (SBAddress &start_address, lldb::addr_t range_size); diff --git a/lldb/bindings/interface/SBTypeEnumMember.i b/lldb/bindings/interface/SBTypeEnumMember.i index 006bdeaa8cee1..518e2bf90115a 100644 --- a/lldb/bindings/interface/SBTypeEnumMember.i +++ b/lldb/bindings/interface/SBTypeEnumMember.i @@ -71,10 +71,18 @@ protected: SBTypeEnumMember (const lldb::TypeEnumMemberImplSP &); }; -%feature( - "docstring", - "Represents a list of SBTypeEnumMembers." -) SBTypeEnumMemberList; +%feature("docstring", +"Represents a list of SBTypeEnumMembers. +SBTypeEnumMemberList supports SBTypeEnumMember iteration. +It also supports [] access either by index, or by enum +element name by doing: + + myType = target.FindFirstType('MyEnumWithElementA') + members = myType.GetEnumMembers() + first_elem = members[0] + elem_A = members['A'] + +") SBTypeEnumMemberList; class SBTypeEnumMemberList { @@ -99,6 +107,29 @@ public: uint32_t GetSize(); +#ifdef SWIGPYTHON + %pythoncode %{ + def __iter__(self): + '''Iterate over all members in a lldb.SBTypeEnumMemberList object.''' + return lldb_iter(self, 'GetSize', 'GetTypeEnumMemberAtIndex') + + def __len__(self): + '''Return the number of members in a lldb.SBTypeEnumMemberList object.''' + return self.GetSize() + + def __getitem__(self, key): + num_elements = self.GetSize() + if type(key) is int: + if key < num_elements: + return self.GetTypeEnumMemberAtIndex(key) + elif type(key) is str: + for idx in range(num_elements): + item = self.GetTypeEnumMemberAtIndex(idx) + if item.name == key: + return item + return None + %} +#endif private: std::unique_ptr m_opaque_ap; diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt index 02b1d08ead873..7e40d082970b6 100644 --- a/lldb/bindings/python/CMakeLists.txt +++ b/lldb/bindings/python/CMakeLists.txt @@ -26,7 +26,7 @@ function(create_python_package swig_target working_dir pkg_dir) set(copy_cmd COMMAND ${CMAKE_COMMAND} -E copy ${ARG_FILES} ${pkg_dir}) endif() if(NOT ARG_NOINIT) - set(init_cmd COMMAND ${PYTHON_EXECUTABLE} + set(init_cmd COMMAND ${Python3_EXECUTABLE} "${LLDB_SOURCE_DIR}/bindings/python/createPythonInit.py" "${pkg_dir}" ${ARG_FILES}) endif() diff --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig index 1bc8e1de967c9..4c19bda2e6aad 100644 --- a/lldb/bindings/python/python-swigsafecast.swig +++ b/lldb/bindings/python/python-swigsafecast.swig @@ -161,3 +161,10 @@ SBTypeToSWIGWrapper (lldb::SBSymbolContext* sym_ctx_sb) { return SWIG_NewPointerObj((void *) sym_ctx_sb, SWIGTYPE_p_lldb__SBSymbolContext, 0); } + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBStream* stream_sb) +{ + return SWIG_NewPointerObj((void *) stream_sb, SWIGTYPE_p_lldb__SBStream, 0); +} diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig index 516590ed57713..c00deba6073b4 100644 --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -468,6 +468,127 @@ LLDBSwigPythonCallBreakpointResolver return ret_val; } +SWIGEXPORT void * +LLDBSwigPythonCreateScriptedStopHook +( + lldb::TargetSP target_sp, + const char *python_class_name, + const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, + Status &error +) +{ + if (python_class_name == NULL || python_class_name[0] == '\0') { + error.SetErrorString("Empty class name."); + Py_RETURN_NONE; + } + if (!session_dictionary_name) { + error.SetErrorString("No session dictionary"); + Py_RETURN_NONE; + } + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = + PythonModule::MainModule().ResolveName( + session_dictionary_name); + auto pfunc = + PythonObject::ResolveNameWithDictionary( + python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error.SetErrorStringWithFormat("Could not find class: %s.", + python_class_name); + return nullptr; + } + + lldb::SBTarget *target_val + = new lldb::SBTarget(target_sp); + + PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(target_val)); + + lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl); + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value)); + + PythonObject result = pfunc(target_arg, args_arg, dict); + + if (result.IsAllocated()) + { + // Check that the handle_stop callback is defined: + auto callback_func = result.ResolveName("handle_stop"); + if (callback_func.IsAllocated()) { + if (auto args_info = callback_func.GetArgInfo()) { + size_t num_args = (*args_info).max_positional_args; + if (num_args != 2) { + error.SetErrorStringWithFormat("Wrong number of args for " + "handle_stop callback, should be 2 (excluding self), got: %d", + num_args); + Py_RETURN_NONE; + } else + return result.release(); + } else { + error.SetErrorString("Couldn't get num arguments for handle_stop " + "callback."); + Py_RETURN_NONE; + } + return result.release(); + } + else { + error.SetErrorStringWithFormat("Class \"%s\" is missing the required " + "handle_stop callback.", + python_class_name); + result.release(); + } + } + Py_RETURN_NONE; +} + +SWIGEXPORT bool +LLDBSwigPythonStopHookCallHandleStop +( + void *implementor, + lldb::ExecutionContextRefSP exc_ctx_sp, + lldb::StreamSP stream +) +{ + // handle_stop will return a bool with the meaning "should_stop"... + // If you return nothing we'll assume we are going to stop. + // Also any errors should return true, since we should stop on error. + + PyErr_Cleaner py_err_cleaner(false); + PythonObject self(PyRefType::Borrowed, static_cast(implementor)); + auto pfunc = self.ResolveName("handle_stop"); + + if (!pfunc.IsAllocated()) + return true; + + PythonObject result; + lldb::SBExecutionContext sb_exc_ctx(exc_ctx_sp); + PythonObject exc_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_exc_ctx)); + lldb::SBStream sb_stream; + PythonObject sb_stream_arg(PyRefType::Owned, + SBTypeToSWIGWrapper(sb_stream)); + result = pfunc(exc_ctx_arg, sb_stream_arg); + + if (PyErr_Occurred()) + { + stream->PutCString("Python error occurred handling stop-hook."); + PyErr_Print(); + PyErr_Clear(); + return true; + } + + // Now add the result to the output stream. SBStream only + // makes an internally help StreamString which I can't interpose, so I + // have to copy it over here. + stream->PutCString(sb_stream.GetData()); + + if (result.get() == Py_False) + return false; + else + return true; +} + // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember diff --git a/lldb/bindings/python/static-binding/LLDBWrapPython.cpp b/lldb/bindings/python/static-binding/LLDBWrapPython.cpp index 605e1fcb77cb9..bfc62f2f886e7 100644 --- a/lldb/bindings/python/static-binding/LLDBWrapPython.cpp +++ b/lldb/bindings/python/static-binding/LLDBWrapPython.cpp @@ -8071,6 +8071,33 @@ SWIGINTERN PyObject *_wrap_SBBreakpoint_ClearAllBreakpointSites(PyObject *SWIGUN } +SWIGINTERN PyObject *_wrap_SBBreakpoint_GetTarget(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + lldb::SBBreakpoint *arg1 = (lldb::SBBreakpoint *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + lldb::SBTarget result; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_lldb__SBBreakpoint, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SBBreakpoint_GetTarget" "', argument " "1"" of type '" "lldb::SBBreakpoint const *""'"); + } + arg1 = reinterpret_cast< lldb::SBBreakpoint * >(argp1); + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = ((lldb::SBBreakpoint const *)arg1)->GetTarget(); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_NewPointerObj((new lldb::SBTarget(static_cast< const lldb::SBTarget& >(result))), SWIGTYPE_p_lldb__SBTarget, SWIG_POINTER_OWN | 0 ); + return resultobj; +fail: + return NULL; +} + + SWIGINTERN PyObject *_wrap_SBBreakpoint_FindLocationByAddress(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; lldb::SBBreakpoint *arg1 = (lldb::SBBreakpoint *) 0 ; @@ -41805,6 +41832,22 @@ SWIGINTERN PyObject *_wrap_SBModule_GetNumberAllocatedModules(PyObject *SWIGUNUS } +SWIGINTERN PyObject *_wrap_SBModule_GarbageCollectAllocatedModules(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + + if (!SWIG_Python_UnpackTuple(args, "SBModule_GarbageCollectAllocatedModules", 0, 0, 0)) SWIG_fail; + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + lldb::SBModule::GarbageCollectAllocatedModules(); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + SWIGINTERN PyObject *_wrap_SBModule___str__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; lldb::SBModule *arg1 = (lldb::SBModule *) 0 ; @@ -65741,6 +65784,66 @@ SWIGINTERN PyObject *_wrap_SBThreadPlan_IsPlanStale(PyObject *SWIGUNUSEDPARM(sel } +SWIGINTERN PyObject *_wrap_SBThreadPlan_GetStopOthers(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + lldb::SBThreadPlan *arg1 = (lldb::SBThreadPlan *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + bool result; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_lldb__SBThreadPlan, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SBThreadPlan_GetStopOthers" "', argument " "1"" of type '" "lldb::SBThreadPlan *""'"); + } + arg1 = reinterpret_cast< lldb::SBThreadPlan * >(argp1); + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (bool)(arg1)->GetStopOthers(); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_From_bool(static_cast< bool >(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_SBThreadPlan_SetStopOthers(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + lldb::SBThreadPlan *arg1 = (lldb::SBThreadPlan *) 0 ; + bool arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + bool val2 ; + int ecode2 = 0 ; + PyObject *swig_obj[2] ; + + if (!SWIG_Python_UnpackTuple(args, "SBThreadPlan_SetStopOthers", 2, 2, swig_obj)) SWIG_fail; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_lldb__SBThreadPlan, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SBThreadPlan_SetStopOthers" "', argument " "1"" of type '" "lldb::SBThreadPlan *""'"); + } + arg1 = reinterpret_cast< lldb::SBThreadPlan * >(argp1); + ecode2 = SWIG_AsVal_bool(swig_obj[1], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "SBThreadPlan_SetStopOthers" "', argument " "2"" of type '" "bool""'"); + } + arg2 = static_cast< bool >(val2); + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + (arg1)->SetStopOthers(arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + SWIGINTERN PyObject *_wrap_SBThreadPlan_QueueThreadPlanForStepOverRange(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; lldb::SBThreadPlan *arg1 = (lldb::SBThreadPlan *) 0 ; @@ -81908,6 +82011,127 @@ LLDBSwigPythonCallBreakpointResolver return ret_val; } +SWIGEXPORT void * +LLDBSwigPythonCreateScriptedStopHook +( + lldb::TargetSP target_sp, + const char *python_class_name, + const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, + Status &error +) +{ + if (python_class_name == NULL || python_class_name[0] == '\0') { + error.SetErrorString("Empty class name."); + Py_RETURN_NONE; + } + if (!session_dictionary_name) { + error.SetErrorString("No session dictionary"); + Py_RETURN_NONE; + } + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = + PythonModule::MainModule().ResolveName( + session_dictionary_name); + auto pfunc = + PythonObject::ResolveNameWithDictionary( + python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error.SetErrorStringWithFormat("Could not find class: %s.", + python_class_name); + return nullptr; + } + + lldb::SBTarget *target_val + = new lldb::SBTarget(target_sp); + + PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(target_val)); + + lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl); + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value)); + + PythonObject result = pfunc(target_arg, args_arg, dict); + + if (result.IsAllocated()) + { + // Check that the handle_stop callback is defined: + auto callback_func = result.ResolveName("handle_stop"); + if (callback_func.IsAllocated()) { + if (auto args_info = callback_func.GetArgInfo()) { + size_t num_args = (*args_info).max_positional_args; + if (num_args != 2) { + error.SetErrorStringWithFormat("Wrong number of args for " + "handle_stop callback, should be 2 (excluding self), got: %d", + num_args); + Py_RETURN_NONE; + } else + return result.release(); + } else { + error.SetErrorString("Couldn't get num arguments for handle_stop " + "callback."); + Py_RETURN_NONE; + } + return result.release(); + } + else { + error.SetErrorStringWithFormat("Class \"%s\" is missing the required " + "handle_stop callback.", + python_class_name); + result.release(); + } + } + Py_RETURN_NONE; +} + +SWIGEXPORT bool +LLDBSwigPythonStopHookCallHandleStop +( + void *implementor, + lldb::ExecutionContextRefSP exc_ctx_sp, + lldb::StreamSP stream +) +{ + // handle_stop will return a bool with the meaning "should_stop"... + // If you return nothing we'll assume we are going to stop. + // Also any errors should return true, since we should stop on error. + + PyErr_Cleaner py_err_cleaner(false); + PythonObject self(PyRefType::Borrowed, static_cast(implementor)); + auto pfunc = self.ResolveName("handle_stop"); + + if (!pfunc.IsAllocated()) + return true; + + PythonObject result; + lldb::SBExecutionContext sb_exc_ctx(exc_ctx_sp); + PythonObject exc_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_exc_ctx)); + lldb::SBStream sb_stream; + PythonObject sb_stream_arg(PyRefType::Owned, + SBTypeToSWIGWrapper(sb_stream)); + result = pfunc(exc_ctx_arg, sb_stream_arg); + + if (PyErr_Occurred()) + { + stream->PutCString("Python error occurred handling stop-hook."); + PyErr_Print(); + PyErr_Clear(); + return true; + } + + // Now add the result to the output stream. SBStream only + // makes an internally help StreamString which I can't interpose, so I + // have to copy it over here. + stream->PutCString(sb_stream.GetData()); + + if (result.get() == Py_False) + return false; + else + return true; +} + // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember @@ -82656,7 +82880,8 @@ static PyMethodDef SwigMethods[] = { { (char *)"SBBreakpoint_IsValid", _wrap_SBBreakpoint_IsValid, METH_VARARGS, (char *)"SBBreakpoint_IsValid(SBBreakpoint self) -> bool"}, { (char *)"SBBreakpoint___nonzero__", _wrap_SBBreakpoint___nonzero__, METH_VARARGS, (char *)"SBBreakpoint___nonzero__(SBBreakpoint self) -> bool"}, { (char *)"SBBreakpoint_ClearAllBreakpointSites", _wrap_SBBreakpoint_ClearAllBreakpointSites, METH_VARARGS, (char *)"SBBreakpoint_ClearAllBreakpointSites(SBBreakpoint self)"}, - { (char *)"SBBreakpoint_FindLocationByAddress", _wrap_SBBreakpoint_FindLocationByAddress, METH_VARARGS, (char *)"SBBreakpoint_FindLocationByAddress(SBBreakpoint self, lldb::addr_t vm_addr) -> SBBreakpointLocation"}, + { (char *)"SBBreakpoint_GetTarget", _wrap_SBBreakpoint_GetTarget, METH_O, "SBBreakpoint_GetTarget(SBBreakpoint self) -> SBTarget"}, + { "SBBreakpoint_FindLocationByAddress", _wrap_SBBreakpoint_FindLocationByAddress, METH_VARARGS, (char *)"SBBreakpoint_FindLocationByAddress(SBBreakpoint self, lldb::addr_t vm_addr) -> SBBreakpointLocation"}, { (char *)"SBBreakpoint_FindLocationIDByAddress", _wrap_SBBreakpoint_FindLocationIDByAddress, METH_VARARGS, (char *)"SBBreakpoint_FindLocationIDByAddress(SBBreakpoint self, lldb::addr_t vm_addr) -> lldb::break_id_t"}, { (char *)"SBBreakpoint_FindLocationByID", _wrap_SBBreakpoint_FindLocationByID, METH_VARARGS, (char *)"SBBreakpoint_FindLocationByID(SBBreakpoint self, lldb::break_id_t bp_loc_id) -> SBBreakpointLocation"}, { (char *)"SBBreakpoint_GetLocationAtIndex", _wrap_SBBreakpoint_GetLocationAtIndex, METH_VARARGS, (char *)"SBBreakpoint_GetLocationAtIndex(SBBreakpoint self, uint32_t index) -> SBBreakpointLocation"}, @@ -84236,7 +84461,18 @@ static PyMethodDef SwigMethods[] = { "@return\n" " The number of modules in the module cache.\n" ""}, - { (char *)"SBModule___str__", _wrap_SBModule___str__, METH_VARARGS, (char *)"SBModule___str__(SBModule self) -> std::string"}, + { (char *)"SBModule_GarbageCollectAllocatedModules", _wrap_SBModule_GarbageCollectAllocatedModules, METH_NOARGS, "\n" + "SBModule_GarbageCollectAllocatedModules()\n" + "\n" + " Removes all modules which are no longer needed by any part of LLDB from\n" + " the module cache.\n" + "\n" + " This is an implementation detail exposed for testing and should not be\n" + " relied upon. Use SBDebugger::MemoryPressureDetected instead to reduce\n" + " LLDB's memory consumption during execution.\n" + "\n" + ""}, + { "SBModule___str__", _wrap_SBModule___str__, METH_VARARGS, (char *)"SBModule___str__(SBModule self) -> std::string"}, { (char *)"SBModule_swigregister", SBModule_swigregister, METH_VARARGS, NULL}, { (char *)"new_SBModuleSpec", _wrap_new_SBModuleSpec, METH_VARARGS, (char *)"\n" "SBModuleSpec()\n" @@ -85832,7 +86068,12 @@ static PyMethodDef SwigMethods[] = { { (char *)"SBThreadPlan_SetPlanComplete", _wrap_SBThreadPlan_SetPlanComplete, METH_VARARGS, (char *)"SBThreadPlan_SetPlanComplete(SBThreadPlan self, bool success)"}, { (char *)"SBThreadPlan_IsPlanComplete", _wrap_SBThreadPlan_IsPlanComplete, METH_VARARGS, (char *)"SBThreadPlan_IsPlanComplete(SBThreadPlan self) -> bool"}, { (char *)"SBThreadPlan_IsPlanStale", _wrap_SBThreadPlan_IsPlanStale, METH_VARARGS, (char *)"SBThreadPlan_IsPlanStale(SBThreadPlan self) -> bool"}, - { (char *)"SBThreadPlan_QueueThreadPlanForStepOverRange", _wrap_SBThreadPlan_QueueThreadPlanForStepOverRange, METH_VARARGS, (char *)"SBThreadPlan_QueueThreadPlanForStepOverRange(SBThreadPlan self, SBAddress start_address, lldb::addr_t range_size) -> SBThreadPlan"}, + { (char *)"SBThreadPlan_GetStopOthers", _wrap_SBThreadPlan_GetStopOthers, METH_O, "\n" + "SBThreadPlan_GetStopOthers(SBThreadPlan self) -> bool\n" + "Return whether this plan will ask to stop other threads when it runs.\n" + ""}, + { "SBThreadPlan_SetStopOthers", _wrap_SBThreadPlan_SetStopOthers, METH_VARARGS, "SBThreadPlan_SetStopOthers(SBThreadPlan self, bool stop_others)"}, + { "SBThreadPlan_QueueThreadPlanForStepOverRange", _wrap_SBThreadPlan_QueueThreadPlanForStepOverRange, METH_VARARGS, (char *)"SBThreadPlan_QueueThreadPlanForStepOverRange(SBThreadPlan self, SBAddress start_address, lldb::addr_t range_size) -> SBThreadPlan"}, { (char *)"SBThreadPlan_QueueThreadPlanForStepInRange", _wrap_SBThreadPlan_QueueThreadPlanForStepInRange, METH_VARARGS, (char *)"SBThreadPlan_QueueThreadPlanForStepInRange(SBThreadPlan self, SBAddress start_address, lldb::addr_t range_size) -> SBThreadPlan"}, { (char *)"SBThreadPlan_QueueThreadPlanForStepOut", _wrap_SBThreadPlan_QueueThreadPlanForStepOut, METH_VARARGS, (char *)"\n" "QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, bool first_insn=False) -> SBThreadPlan\n" @@ -88221,6 +88462,7 @@ SWIG_init(void) { SWIG_Python_SetConstant(d, "LLDB_INVALID_SIGNAL_NUMBER",SWIG_From_int(static_cast< int >(2147483647))); SWIG_Python_SetConstant(d, "LLDB_INVALID_OFFSET",SWIG_From_unsigned_SS_long_SS_long(static_cast< unsigned long long >(18446744073709551615ULL))); SWIG_Python_SetConstant(d, "LLDB_INVALID_LINE_NUMBER",SWIG_From_unsigned_SS_int(static_cast< unsigned int >(4294967295U))); + SWIG_Python_SetConstant(d, "LLDB_INVALID_COLUMN_NUMBER",SWIG_From_int(static_cast< int >(0))); SWIG_Python_SetConstant(d, "LLDB_INVALID_QUEUE_ID",SWIG_From_int(static_cast< int >(0))); SWIG_Python_SetConstant(d, "LLDB_ARCH_DEFAULT",SWIG_FromCharPtr("systemArch")); SWIG_Python_SetConstant(d, "LLDB_ARCH_DEFAULT_32BIT",SWIG_FromCharPtr("systemArch32")); @@ -88239,6 +88481,7 @@ SWIG_init(void) { SWIG_Python_SetConstant(d, "LLDB_OPT_SET_9",SWIG_From_unsigned_SS_int(static_cast< unsigned int >((1U << 8)))); SWIG_Python_SetConstant(d, "LLDB_OPT_SET_10",SWIG_From_unsigned_SS_int(static_cast< unsigned int >((1U << 9)))); SWIG_Python_SetConstant(d, "LLDB_OPT_SET_11",SWIG_From_unsigned_SS_int(static_cast< unsigned int >((1U << 10)))); + SWIG_Python_SetConstant(d, "LLDB_OPT_SET_12",SWIG_From_unsigned_SS_int(static_cast< unsigned int >((1U << 11)))); SWIG_Python_SetConstant(d, "eStateInvalid",SWIG_From_int(static_cast< int >(lldb::eStateInvalid))); SWIG_Python_SetConstant(d, "eStateUnloaded",SWIG_From_int(static_cast< int >(lldb::eStateUnloaded))); SWIG_Python_SetConstant(d, "eStateConnected",SWIG_From_int(static_cast< int >(lldb::eStateConnected))); @@ -88521,6 +88764,7 @@ SWIG_init(void) { SWIG_Python_SetConstant(d, "eArgTypeExpression",SWIG_From_int(static_cast< int >(lldb::eArgTypeExpression))); SWIG_Python_SetConstant(d, "eArgTypeExpressionPath",SWIG_From_int(static_cast< int >(lldb::eArgTypeExpressionPath))); SWIG_Python_SetConstant(d, "eArgTypeExprFormat",SWIG_From_int(static_cast< int >(lldb::eArgTypeExprFormat))); + SWIG_Python_SetConstant(d, "eArgTypeFileLineColumn",SWIG_From_int(static_cast< int >(lldb::eArgTypeFileLineColumn))); SWIG_Python_SetConstant(d, "eArgTypeFilename",SWIG_From_int(static_cast< int >(lldb::eArgTypeFilename))); SWIG_Python_SetConstant(d, "eArgTypeFormat",SWIG_From_int(static_cast< int >(lldb::eArgTypeFormat))); SWIG_Python_SetConstant(d, "eArgTypeFrameIndex",SWIG_From_int(static_cast< int >(lldb::eArgTypeFrameIndex))); diff --git a/lldb/bindings/python/static-binding/lldb.py b/lldb/bindings/python/static-binding/lldb.py index 9340c4d6ee87c..51dcd8d438832 100644 --- a/lldb/bindings/python/static-binding/lldb.py +++ b/lldb/bindings/python/static-binding/lldb.py @@ -180,6 +180,9 @@ def __init__(self): LLDB_INVALID_SIGNAL_NUMBER = _lldb.LLDB_INVALID_SIGNAL_NUMBER LLDB_INVALID_OFFSET = _lldb.LLDB_INVALID_OFFSET LLDB_INVALID_LINE_NUMBER = _lldb.LLDB_INVALID_LINE_NUMBER +LLDB_INVALID_COLUMN_NUMBER = _lldb.LLDB_INVALID_COLUMN_NUMBER + + LLDB_INVALID_QUEUE_ID = _lldb.LLDB_INVALID_QUEUE_ID LLDB_ARCH_DEFAULT = _lldb.LLDB_ARCH_DEFAULT LLDB_ARCH_DEFAULT_32BIT = _lldb.LLDB_ARCH_DEFAULT_32BIT @@ -198,6 +201,9 @@ def __init__(self): LLDB_OPT_SET_9 = _lldb.LLDB_OPT_SET_9 LLDB_OPT_SET_10 = _lldb.LLDB_OPT_SET_10 LLDB_OPT_SET_11 = _lldb.LLDB_OPT_SET_11 +LLDB_OPT_SET_12 = _lldb.LLDB_OPT_SET_12 + + eStateInvalid = _lldb.eStateInvalid eStateUnloaded = _lldb.eStateUnloaded eStateConnected = _lldb.eStateConnected @@ -480,6 +486,9 @@ def __init__(self): eArgTypeExpression = _lldb.eArgTypeExpression eArgTypeExpressionPath = _lldb.eArgTypeExpressionPath eArgTypeExprFormat = _lldb.eArgTypeExprFormat + +eArgTypeFileLineColumn = _lldb.eArgTypeFileLineColumn + eArgTypeFilename = _lldb.eArgTypeFilename eArgTypeFormat = _lldb.eArgTypeFormat eArgTypeFrameIndex = _lldb.eArgTypeFrameIndex @@ -1586,6 +1595,9 @@ def ClearAllBreakpointSites(self): """ClearAllBreakpointSites(SBBreakpoint self)""" return _lldb.SBBreakpoint_ClearAllBreakpointSites(self) + def GetTarget(self): + r"""GetTarget(SBBreakpoint self) -> SBTarget""" + return _lldb.SBBreakpoint_GetTarget(self) def FindLocationByAddress(self, vm_addr): """FindLocationByAddress(SBBreakpoint self, lldb::addr_t vm_addr) -> SBBreakpointLocation""" @@ -8026,6 +8038,22 @@ def GetNumberAllocatedModules(): GetNumberAllocatedModules = staticmethod(GetNumberAllocatedModules) + @staticmethod + def GarbageCollectAllocatedModules(): + r""" + GarbageCollectAllocatedModules() + + Removes all modules which are no longer needed by any part of LLDB from + the module cache. + + This is an implementation detail exposed for testing and should not be + relied upon. Use SBDebugger::MemoryPressureDetected instead to reduce + LLDB's memory consumption during execution. + + """ + return _lldb.SBModule_GarbageCollectAllocatedModules() + + def __str__(self): """__str__(SBModule self) -> std::string""" return _lldb.SBModule___str__(self) @@ -8259,6 +8287,20 @@ def SBModule_GetNumberAllocatedModules(): """ return _lldb.SBModule_GetNumberAllocatedModules() +def SBModule_GarbageCollectAllocatedModules(): + r""" + SBModule_GarbageCollectAllocatedModules() + + Removes all modules which are no longer needed by any part of LLDB from + the module cache. + + This is an implementation detail exposed for testing and should not be + relied upon. Use SBDebugger::MemoryPressureDetected instead to reduce + LLDB's memory consumption during execution. + + """ + return _lldb.SBModule_GarbageCollectAllocatedModules() + class SBModuleSpec(_object): """Proxy of C++ lldb::SBModuleSpec class.""" @@ -12860,6 +12902,16 @@ def IsPlanStale(self): """IsPlanStale(SBThreadPlan self) -> bool""" return _lldb.SBThreadPlan_IsPlanStale(self) + def GetStopOthers(self): + r""" + GetStopOthers(SBThreadPlan self) -> bool + Return whether this plan will ask to stop other threads when it runs. + """ + return _lldb.SBThreadPlan_GetStopOthers(self) + + def SetStopOthers(self, stop_others): + r"""SetStopOthers(SBThreadPlan self, bool stop_others)""" + return _lldb.SBThreadPlan_SetStopOthers(self, stop_others) def QueueThreadPlanForStepOverRange(self, start_address, range_size): """QueueThreadPlanForStepOverRange(SBThreadPlan self, SBAddress start_address, lldb::addr_t range_size) -> SBThreadPlan""" @@ -14055,7 +14107,19 @@ def __str__(self): SBTypeEnumMember_swigregister(SBTypeEnumMember) class SBTypeEnumMemberList(_object): - """Represents a list of SBTypeEnumMembers.""" + r""" + Represents a list of SBTypeEnumMembers. + SBTypeEnumMemberList supports SBTypeEnumMember iteration. + It also supports [] access either by index, or by enum + element name by doing: + + myType = target.FindFirstType('MyEnumWithElementA') + members = myType.GetEnumMembers() + first_elem = members[0] + elem_A = members['A'] + + + """ __swig_setmethods__ = {} __setattr__ = lambda self, name, value: _swig_setattr(self, SBTypeEnumMemberList, name, value) @@ -14101,6 +14165,26 @@ def GetSize(self): """GetSize(SBTypeEnumMemberList self) -> uint32_t""" return _lldb.SBTypeEnumMemberList_GetSize(self) + def __iter__(self): + '''Iterate over all members in a lldb.SBTypeEnumMemberList object.''' + return lldb_iter(self, 'GetSize', 'GetTypeEnumMemberAtIndex') + + def __len__(self): + '''Return the number of members in a lldb.SBTypeEnumMemberList object.''' + return self.GetSize() + + def __getitem__(self, key): + num_elements = self.GetSize() + if type(key) is int: + if key < num_elements: + return self.GetTypeEnumMemberAtIndex(key) + elif type(key) is str: + for idx in range(num_elements): + item = self.GetTypeEnumMemberAtIndex(idx) + if item.name == key: + return item + return None + SBTypeEnumMemberList_swigregister = _lldb.SBTypeEnumMemberList_swigregister SBTypeEnumMemberList_swigregister(SBTypeEnumMemberList) diff --git a/lldb/cmake/caches/Apple-lldb-macOS.cmake b/lldb/cmake/caches/Apple-lldb-macOS.cmake index 343290d704bf3..389cff45082df 100644 --- a/lldb/cmake/caches/Apple-lldb-macOS.cmake +++ b/lldb/cmake/caches/Apple-lldb-macOS.cmake @@ -2,6 +2,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/Apple-lldb-base.cmake) set(LLDB_BUILD_FRAMEWORK ON CACHE BOOL "") set(LLDB_NO_INSTALL_DEFAULT_RPATH ON CACHE BOOL "") +set(LLDB_SKIP_STRIP ON CACHE BOOL "") set(CMAKE_OSX_DEPLOYMENT_TARGET 10.11 CACHE STRING "") # Default install location on the enduser machine. On the build machine, use the diff --git a/lldb/cmake/modules/FindPythonAndSwig.cmake b/lldb/cmake/modules/FindPythonAndSwig.cmake new file mode 100644 index 0000000000000..4431707ab2d11 --- /dev/null +++ b/lldb/cmake/modules/FindPythonAndSwig.cmake @@ -0,0 +1,60 @@ +#.rst: +# FindPythonAndSwig +# ----------- +# +# Find the python interpreter and libraries as a whole. + +macro(FindPython3) + # Use PYTHON_HOME as a hint to find Python 3. + set(Python3_ROOT_DIR "${PYTHON_HOME}") + find_package(Python3 COMPONENTS Interpreter Development) + if(Python3_FOUND AND Python3_Interpreter_FOUND) + + # The install name for the Python 3 framework in Xcode is relative to + # the framework's location and not the dylib itself. + # + # @rpath/Python3.framework/Versions/3.x/Python3 + # + # This means that we need to compute the path to the Python3.framework + # and use that as the RPATH instead of the usual dylib's directory. + # + # The check below shouldn't match Homebrew's Python framework as it is + # called Python.framework instead of Python3.framework. + if (APPLE AND Python3_LIBRARIES MATCHES "Python3.framework") + string(FIND "${Python3_LIBRARIES}" "Python3.framework" python_framework_pos) + string(SUBSTRING "${Python3_LIBRARIES}" "0" ${python_framework_pos} Python3_RPATH) + endif() + + set(PYTHON3_FOUND TRUE) + mark_as_advanced( + Python3_LIBRARIES + Python3_INCLUDE_DIRS + Python3_EXECUTABLE + Python3_RPATH + SWIG_EXECUTABLE) + endif() +endmacro() + +if(Python3_LIBRARIES AND Python3_INCLUDE_DIRS AND Python3_EXECUTABLE AND SWIG_EXECUTABLE) + set(PYTHONANDSWIG_FOUND TRUE) +else() + find_package(SWIG 2.0) + if (SWIG_FOUND OR LLDB_USE_STATIC_BINDINGS) + if (LLDB_USE_STATIC_BINDINGS) + set(SWIG_EXECUTABLE "/not/found") + endif() + FindPython3() + else() + message(STATUS "SWIG 2 or later is required for Python support in LLDB but could not be found") + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(PythonAndSwig + FOUND_VAR + PYTHONANDSWIG_FOUND + REQUIRED_VARS + Python3_LIBRARIES + Python3_INCLUDE_DIRS + Python3_EXECUTABLE + SWIG_EXECUTABLE) +endif() diff --git a/lldb/cmake/modules/FindPythonInterpAndLibs.cmake b/lldb/cmake/modules/FindPythonInterpAndLibs.cmake deleted file mode 100644 index 49a29990c1bd3..0000000000000 --- a/lldb/cmake/modules/FindPythonInterpAndLibs.cmake +++ /dev/null @@ -1,120 +0,0 @@ -#.rst: -# FindPythonInterpAndLibs -# ----------- -# -# Find the python interpreter and libraries as a whole. - -macro(FindPython3) - # Use PYTHON_HOME as a hint to find Python 3. - set(Python3_ROOT_DIR "${PYTHON_HOME}") - find_package(Python3 COMPONENTS Interpreter Development) - if(Python3_FOUND AND Python3_Interpreter_FOUND) - set(PYTHON_LIBRARIES ${Python3_LIBRARIES}) - set(PYTHON_INCLUDE_DIRS ${Python3_INCLUDE_DIRS}) - set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) - - # The install name for the Python 3 framework in Xcode is relative to - # the framework's location and not the dylib itself. - # - # @rpath/Python3.framework/Versions/3.x/Python3 - # - # This means that we need to compute the path to the Python3.framework - # and use that as the RPATH instead of the usual dylib's directory. - # - # The check below shouldn't match Homebrew's Python framework as it is - # called Python.framework instead of Python3.framework. - if (APPLE AND Python3_LIBRARIES MATCHES "Python3.framework") - string(FIND "${Python3_LIBRARIES}" "Python3.framework" python_framework_pos) - string(SUBSTRING "${Python3_LIBRARIES}" "0" ${python_framework_pos} PYTHON_RPATH) - endif() - - set(PYTHON3_FOUND TRUE) - mark_as_advanced( - PYTHON_LIBRARIES - PYTHON_INCLUDE_DIRS - PYTHON_EXECUTABLE - PYTHON_RPATH - SWIG_EXECUTABLE) - endif() -endmacro() - -macro(FindPython2) - # Use PYTHON_HOME as a hint to find Python 2. - set(Python2_ROOT_DIR "${PYTHON_HOME}") - find_package(Python2 COMPONENTS Interpreter Development) - if(Python2_FOUND AND Python2_Interpreter_FOUND) - set(PYTHON_LIBRARIES ${Python2_LIBRARIES}) - set(PYTHON_INCLUDE_DIRS ${Python2_INCLUDE_DIRS}) - set(PYTHON_EXECUTABLE ${Python2_EXECUTABLE}) - - set(PYTHON2_FOUND TRUE) - mark_as_advanced( - PYTHON_LIBRARIES - PYTHON_INCLUDE_DIRS - PYTHON_EXECUTABLE - SWIG_EXECUTABLE) - endif() -endmacro() - -if(PYTHON_LIBRARIES AND PYTHON_INCLUDE_DIRS AND PYTHON_EXECUTABLE AND SWIG_EXECUTABLE) - set(PYTHONINTERPANDLIBS_FOUND TRUE) -else() - find_package(SWIG 2.0) - if (SWIG_FOUND OR LLDB_USE_STATIC_BINDINGS) - if (LLDB_USE_STATIC_BINDINGS) - set(SWIG_EXECUTABLE "/not/found") - endif() - if(NOT CMAKE_VERSION VERSION_LESS 3.12) - if (LLDB_PYTHON_VERSION) - if (LLDB_PYTHON_VERSION VERSION_EQUAL "2") - FindPython2() - elseif(LLDB_PYTHON_VERSION VERSION_EQUAL "3") - FindPython3() - endif() - else() - FindPython3() - if (NOT PYTHON3_FOUND AND NOT CMAKE_SYSTEM_NAME STREQUAL Windows) - FindPython2() - endif() - endif() - else() - # SWIFT_ENABLE_TENSORFLOW - # Make it so that LLDB can find Python 3.6+ - set(Python_ADDITIONAL_VERSIONS 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.7 2.6 2.5) - - find_package(PythonInterp) - find_package(PythonLibs) - if(PYTHONINTERP_FOUND AND PYTHONLIBS_FOUND AND SWIG_FOUND) - if (NOT CMAKE_CROSSCOMPILING) - string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING}) - list(GET pythonlibs_version_list 0 pythonlibs_major) - list(GET pythonlibs_version_list 1 pythonlibs_minor) - - # Ignore the patch version. Some versions of macOS report a different - # patch version for the system provided interpreter and libraries. - if (CMAKE_CROSSCOMPILING OR (PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major AND - PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor)) - mark_as_advanced( - PYTHON_LIBRARIES - PYTHON_INCLUDE_DIRS - PYTHON_EXECUTABLE - SWIG_EXECUTABLE) - endif() - endif() - endif() - endif() - else() - message(STATUS "SWIG 2 or later is required for Python support in LLDB but could not be found") - endif() - - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(PythonInterpAndLibs - FOUND_VAR - PYTHONINTERPANDLIBS_FOUND - REQUIRED_VARS - PYTHON_LIBRARIES - PYTHON_INCLUDE_DIRS - PYTHON_EXECUTABLE - SWIG_EXECUTABLE) -endif() diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 4db10e064efbe..2d1c49555bcdf 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -56,7 +56,7 @@ add_optional_dependency(LLDB_ENABLE_LIBEDIT "Enable editline support in LLDB" Li add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" CursesAndPanel CURSESANDPANEL_FOUND) add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND) add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND) -add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonInterpAndLibs PYTHONINTERPANDLIBS_FOUND) +add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND) add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8) option(LLDB_USE_SYSTEM_SIX "Use six.py shipped with system and do not install a copy of it" OFF) @@ -88,11 +88,6 @@ if(LLDB_BUILD_FRAMEWORK) if(NOT APPLE) message(FATAL_ERROR "LLDB.framework can only be generated when targeting Apple platforms") endif() - # CMake 3.6 did not correctly emit POST_BUILD commands for Apple Framework targets - # CMake < 3.8 did not have the BUILD_RPATH target property - if(CMAKE_VERSION VERSION_LESS 3.8) - message(FATAL_ERROR "LLDB_BUILD_FRAMEWORK is not supported on CMake < 3.8") - endif() set(LLDB_FRAMEWORK_VERSION A CACHE STRING "LLDB.framework version (default is A)") set(LLDB_FRAMEWORK_BUILD_DIR bin CACHE STRING "Output directory for LLDB.framework") @@ -158,9 +153,9 @@ if (LLDB_ENABLE_PYTHON) "Embed PYTHONHOME in the binary. If set to OFF, PYTHONHOME environment variable will be used to to locate Python." ${default_embed_python_home}) - include_directories(${PYTHON_INCLUDE_DIRS}) + include_directories(${Python3_INCLUDE_DIRS}) if (LLDB_EMBED_PYTHON_HOME) - get_filename_component(PYTHON_HOME "${PYTHON_EXECUTABLE}" DIRECTORY) + get_filename_component(PYTHON_HOME "${Python3_EXECUTABLE}" DIRECTORY) set(LLDB_PYTHON_HOME "${PYTHON_HOME}" CACHE STRING "Path to use as PYTHONHOME in lldb. If a relative path is specified, it will be resolved at runtime relative to liblldb directory.") endif() diff --git a/lldb/docs/use/python-reference.rst b/lldb/docs/use/python-reference.rst index 8c76ef1a08307..60474c94f1850 100644 --- a/lldb/docs/use/python-reference.rst +++ b/lldb/docs/use/python-reference.rst @@ -819,3 +819,49 @@ When the program is stopped at the beginning of the 'read' function in libc, we frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read (lldb) frame variable (int) fd = 3 + + Writing Target Stop-Hooks in Python: + ------------------------------------ + + Stop hooks fire whenever the process stops just before control is returned to the + user. Stop hooks can either be a set of lldb command-line commands, or can + be implemented by a suitably defined Python class. The Python based stop-hooks + can also be passed as set of -key -value pairs when they are added, and those + will get packaged up into a SBStructuredData Dictionary and passed to the + constructor of the Python object managing the stop hook. This allows for + parametrization of the stop hooks. + + To add a Python-based stop hook, first define a class with the following methods: + ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| Name | Arguments | Description | ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| **__init__** | **target: lldb.SBTarget** | This is the constructor for the new stop-hook. | +| | **extra_args: lldb.SBStructuredData** | | +| | | | +| | | **target** is the SBTarget to which the stop hook is added. | +| | | | +| | | **extra_args** is an SBStructuredData object that the user can pass in when creating instances of this | +| | | breakpoint. It is not required, but allows for reuse of stop-hook classes. | ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| **handle_stop** | **exe_ctx: lldb.SBExecutionContext** | This is the called when the target stops. | +| | **stream: lldb.SBStream** | | +| | | **exe_ctx** argument will be filled with the current stop point for which the stop hook is | +| | | being evaluated. | +| | | | +| | | **stream** an lldb.SBStream, anything written to this stream will be written to the debugger console. | +| | | | +| | | The return value is a "Should Stop" vote from this thread. If the method returns either True or no return | +| | | this thread votes to stop. If it returns False, then the thread votes to continue after all the stop-hooks | +| | | are evaluated. | +| | | Note, the --auto-continue flag to 'target stop-hook add' overrides a True return value from the method. | ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ + +To use this class in lldb, run the command: + +:: + + (lldb) command script import MyModule.py + (lldb) target stop-hook add -P MyModule.MyStopHook -k first -v 1 -k second -v 2 + +where MyModule.py is the file containing the class definition MyStopHook. diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index 39a021145fb7b..e13dbc5c35168 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -42,6 +42,8 @@ class LLDB_API SBBreakpoint { void ClearAllBreakpointSites(); + lldb::SBTarget GetTarget() const; + lldb::SBBreakpointLocation FindLocationByAddress(lldb::addr_t vm_addr); lldb::break_id_t FindLocationIDByAddress(lldb::addr_t vm_addr); diff --git a/lldb/include/lldb/API/SBModule.h b/lldb/include/lldb/API/SBModule.h index a38852f3ae819..df7954861b112 100644 --- a/lldb/include/lldb/API/SBModule.h +++ b/lldb/include/lldb/API/SBModule.h @@ -293,6 +293,9 @@ class LLDB_API SBModule { /// Get the number of global modules. static uint32_t GetNumberAllocatedModules(); + /// Remove any global modules which are no longer needed. + static void GarbageCollectAllocatedModules(); + private: friend class SBAddress; friend class SBFrame; diff --git a/lldb/include/lldb/API/SBThreadPlan.h b/lldb/include/lldb/API/SBThreadPlan.h index 6639c10e437b3..0dc48437a6681 100644 --- a/lldb/include/lldb/API/SBThreadPlan.h +++ b/lldb/include/lldb/API/SBThreadPlan.h @@ -77,6 +77,10 @@ class LLDB_API SBThreadPlan { bool IsValid(); + bool GetStopOthers(); + + void SetStopOthers(bool stop_others); + // This section allows an SBThreadPlan to push another of the common types of // plans... SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address, diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h index 926a74b933ef1..2aa19d068aec3 100644 --- a/lldb/include/lldb/Core/Disassembler.h +++ b/lldb/include/lldb/Core/Disassembler.h @@ -48,6 +48,7 @@ class DataExtractor; class Debugger; class Disassembler; class Module; +class StackFrame; class Stream; class SymbolContext; class SymbolContextList; @@ -408,11 +409,8 @@ class Disassembler : public std::enable_shared_from_this, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); - static bool - Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, - const char *flavor, const ExecutionContext &exe_ctx, - uint32_t num_instructions, bool mixed_source_and_assembly, - uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); + static bool Disassemble(Debugger &debugger, const ArchSpec &arch, + StackFrame &frame, Stream &strm); // Constructors and Destructors Disassembler(const ArchSpec &arch, const char *flavor); diff --git a/lldb/include/lldb/Interpreter/OptionValue.h b/lldb/include/lldb/Interpreter/OptionValue.h index 5b07427094bf2..a8176e39940a0 100644 --- a/lldb/include/lldb/Interpreter/OptionValue.h +++ b/lldb/include/lldb/Interpreter/OptionValue.h @@ -31,6 +31,7 @@ class OptionValue { eTypeChar, eTypeDictionary, eTypeEnum, + eTypeFileLineColumn, eTypeFileSpec, eTypeFileSpecList, eTypeFormat, @@ -84,7 +85,7 @@ class OptionValue { SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign); - virtual bool Clear() = 0; + virtual void Clear() = 0; virtual lldb::OptionValueSP DeepCopy() const = 0; @@ -135,6 +136,8 @@ class OptionValue { return eTypeDictionary; case 1u << eTypeEnum: return eTypeEnum; + case 1u << eTypeFileLineColumn: + return eTypeFileLineColumn; case 1u << eTypeFileSpec: return eTypeFileSpec; case 1u << eTypeFileSpecList: diff --git a/lldb/include/lldb/Interpreter/OptionValueArch.h b/lldb/include/lldb/Interpreter/OptionValueArch.h index 7b63c68fddbf0..809261ef22c36 100644 --- a/lldb/include/lldb/Interpreter/OptionValueArch.h +++ b/lldb/include/lldb/Interpreter/OptionValueArch.h @@ -47,10 +47,9 @@ class OptionValueArch : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueArray.h b/lldb/include/lldb/Interpreter/OptionValueArray.h index 000351c2f5867..4546bbb803941 100644 --- a/lldb/include/lldb/Interpreter/OptionValueArray.h +++ b/lldb/include/lldb/Interpreter/OptionValueArray.h @@ -36,10 +36,9 @@ class OptionValueArray : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_values.clear(); m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueBoolean.h b/lldb/include/lldb/Interpreter/OptionValueBoolean.h index d221f6d034c2d..1af14a4980ed9 100644 --- a/lldb/include/lldb/Interpreter/OptionValueBoolean.h +++ b/lldb/include/lldb/Interpreter/OptionValueBoolean.h @@ -37,10 +37,9 @@ class OptionValueBoolean : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } void AutoComplete(CommandInterpreter &interpreter, diff --git a/lldb/include/lldb/Interpreter/OptionValueChar.h b/lldb/include/lldb/Interpreter/OptionValueChar.h index 8d0aa91d7076a..a8ecf507a4cfc 100644 --- a/lldb/include/lldb/Interpreter/OptionValueChar.h +++ b/lldb/include/lldb/Interpreter/OptionValueChar.h @@ -38,10 +38,9 @@ class OptionValueChar : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } // Subclass specific functions diff --git a/lldb/include/lldb/Interpreter/OptionValueDictionary.h b/lldb/include/lldb/Interpreter/OptionValueDictionary.h index 1bc45252607c4..dab1c3ea0c1cf 100644 --- a/lldb/include/lldb/Interpreter/OptionValueDictionary.h +++ b/lldb/include/lldb/Interpreter/OptionValueDictionary.h @@ -35,10 +35,9 @@ class OptionValueDictionary : public OptionValue { SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - bool Clear() override { + void Clear() override { m_values.clear(); m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueEnumeration.h b/lldb/include/lldb/Interpreter/OptionValueEnumeration.h index 26ba7ad5f646a..12c6473c7f1c2 100644 --- a/lldb/include/lldb/Interpreter/OptionValueEnumeration.h +++ b/lldb/include/lldb/Interpreter/OptionValueEnumeration.h @@ -47,10 +47,9 @@ class OptionValueEnumeration : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueFileColonLine.h b/lldb/include/lldb/Interpreter/OptionValueFileColonLine.h new file mode 100644 index 0000000000000..bb504d4644f86 --- /dev/null +++ b/lldb/include/lldb/Interpreter/OptionValueFileColonLine.h @@ -0,0 +1,64 @@ +//===-- OptionValueFileColonLine.h -----------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_INTERPRETER_OPTIONVALUEFILECOLONLINE_H +#define LLDB_INTERPRETER_OPTIONVALUEFILECOLONLINE_H + +#include "lldb/Interpreter/OptionValue.h" + +#include "lldb/Utility/FileSpec.h" +#include "llvm/Support/Chrono.h" + +namespace lldb_private { + +class OptionValueFileColonLine : public OptionValue { +public: + OptionValueFileColonLine(); + OptionValueFileColonLine(const llvm::StringRef input); + + ~OptionValueFileColonLine() override {} + + OptionValue::Type GetType() const override { return eTypeFileLineColumn; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + void Clear() override { + m_file_spec.Clear(); + m_line_number = LLDB_INVALID_LINE_NUMBER; + m_column_number = LLDB_INVALID_COLUMN_NUMBER; + } + + lldb::OptionValueSP DeepCopy() const override; + + void AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) override; + + FileSpec &GetFileSpec() { return m_file_spec; } + uint32_t GetLineNumber() { return m_line_number; } + uint32_t GetColumnNumber() { return m_column_number; } + + void SetCompletionMask(uint32_t mask) { m_completion_mask = mask; } + +protected: + FileSpec m_file_spec; + uint32_t m_line_number; + uint32_t m_column_number; + uint32_t m_completion_mask; +}; + +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_OPTIONVALUEFILECOLONLINE_H diff --git a/lldb/include/lldb/Interpreter/OptionValueFileSpec.h b/lldb/include/lldb/Interpreter/OptionValueFileSpec.h index 2b18c9533f912..4fde3f6e3c8a2 100644 --- a/lldb/include/lldb/Interpreter/OptionValueFileSpec.h +++ b/lldb/include/lldb/Interpreter/OptionValueFileSpec.h @@ -41,12 +41,11 @@ class OptionValueFileSpec : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; m_data_sp.reset(); m_data_mod_time = llvm::sys::TimePoint<>(); - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h b/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h index 7b762bf6b3098..38773525c8db9 100644 --- a/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h +++ b/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h @@ -39,11 +39,10 @@ class OptionValueFileSpecList : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { std::lock_guard lock(m_mutex); m_current_value.Clear(); m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueFormat.h b/lldb/include/lldb/Interpreter/OptionValueFormat.h index 6904c93a2f338..5a83ff3b8983d 100644 --- a/lldb/include/lldb/Interpreter/OptionValueFormat.h +++ b/lldb/include/lldb/Interpreter/OptionValueFormat.h @@ -38,10 +38,9 @@ class OptionValueFormat : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h b/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h index beb5d6843a98b..7c2f9fba0242e 100644 --- a/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h +++ b/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h @@ -34,7 +34,7 @@ class OptionValueFormatEntity : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override; + void Clear() override; lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueLanguage.h b/lldb/include/lldb/Interpreter/OptionValueLanguage.h index f4ca2fd69ab59..1293652967596 100644 --- a/lldb/include/lldb/Interpreter/OptionValueLanguage.h +++ b/lldb/include/lldb/Interpreter/OptionValueLanguage.h @@ -41,10 +41,9 @@ class OptionValueLanguage : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValuePathMappings.h b/lldb/include/lldb/Interpreter/OptionValuePathMappings.h index 18f5cbaf43366..6d1a0816f45b8 100644 --- a/lldb/include/lldb/Interpreter/OptionValuePathMappings.h +++ b/lldb/include/lldb/Interpreter/OptionValuePathMappings.h @@ -35,10 +35,9 @@ class OptionValuePathMappings : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_path_mappings.Clear(m_notify_changes); m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueProperties.h b/lldb/include/lldb/Interpreter/OptionValueProperties.h index 76f09cc771235..bd944b6a5adff 100644 --- a/lldb/include/lldb/Interpreter/OptionValueProperties.h +++ b/lldb/include/lldb/Interpreter/OptionValueProperties.h @@ -34,7 +34,7 @@ class OptionValueProperties Type GetType() const override { return eTypeProperties; } - bool Clear() override; + void Clear() override; lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueRegex.h b/lldb/include/lldb/Interpreter/OptionValueRegex.h index b09b8414d5bf4..4751a1dc27ed0 100644 --- a/lldb/include/lldb/Interpreter/OptionValueRegex.h +++ b/lldb/include/lldb/Interpreter/OptionValueRegex.h @@ -36,10 +36,9 @@ class OptionValueRegex : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_regex = RegularExpression(m_default_regex_str); m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueSInt64.h b/lldb/include/lldb/Interpreter/OptionValueSInt64.h index fbabaaeb2ff4b..87917c1088651 100644 --- a/lldb/include/lldb/Interpreter/OptionValueSInt64.h +++ b/lldb/include/lldb/Interpreter/OptionValueSInt64.h @@ -50,10 +50,9 @@ class OptionValueSInt64 : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueString.h b/lldb/include/lldb/Interpreter/OptionValueString.h index cd371c5670204..ed44dae67d1dc 100644 --- a/lldb/include/lldb/Interpreter/OptionValueString.h +++ b/lldb/include/lldb/Interpreter/OptionValueString.h @@ -85,10 +85,9 @@ class OptionValueString : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueUInt64.h b/lldb/include/lldb/Interpreter/OptionValueUInt64.h index 0096e87de3677..1164fb802f682 100644 --- a/lldb/include/lldb/Interpreter/OptionValueUInt64.h +++ b/lldb/include/lldb/Interpreter/OptionValueUInt64.h @@ -47,10 +47,9 @@ class OptionValueUInt64 : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValueUUID.h b/lldb/include/lldb/Interpreter/OptionValueUUID.h index 2fb8caa3aa531..1f663e999b9d0 100644 --- a/lldb/include/lldb/Interpreter/OptionValueUUID.h +++ b/lldb/include/lldb/Interpreter/OptionValueUUID.h @@ -36,10 +36,9 @@ class OptionValueUUID : public OptionValue { SetValueFromString(const char *, VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_uuid.Clear(); m_value_was_set = false; - return true; } lldb::OptionValueSP DeepCopy() const override; diff --git a/lldb/include/lldb/Interpreter/OptionValues.h b/lldb/include/lldb/Interpreter/OptionValues.h index 36e7c192d60a3..6efc9e1ad064c 100644 --- a/lldb/include/lldb/Interpreter/OptionValues.h +++ b/lldb/include/lldb/Interpreter/OptionValues.h @@ -17,6 +17,7 @@ #include "lldb/Interpreter/OptionValueChar.h" #include "lldb/Interpreter/OptionValueDictionary.h" #include "lldb/Interpreter/OptionValueEnumeration.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/OptionValueFileSpec.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueFormat.h" diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 491923e6a6c4f..c38786fd50d42 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -298,6 +298,23 @@ class ScriptInterpreter : public PluginInterface { return lldb::eSearchDepthModule; } + virtual StructuredData::GenericSP + CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, + StructuredDataImpl *args_data, Status &error) { + error.SetErrorString("Creating scripted stop-hooks with the current " + "script interpreter is not supported."); + return StructuredData::GenericSP(); + } + + // This dispatches to the handle_stop method of the stop-hook class. It + // returns a "should_stop" bool. + virtual bool + ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, + ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) { + return true; + } + virtual StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { return StructuredData::ObjectSP(); diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index ea51dd6db6e87..b14962226f333 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -95,6 +95,17 @@ class ObjectFile : public std::enable_shared_from_this, eStrataJIT }; + /// If we have a corefile binary hint, this enum + /// specifies the binary type which we can use to + /// select the correct DynamicLoader plugin. + enum BinaryType { + eBinaryTypeInvalid = 0, + eBinaryTypeUnknown, + eBinaryTypeKernel, /// kernel binary + eBinaryTypeUser, /// user process binary + eBinaryTypeStandalone /// standalone binary / firmware + }; + struct LoadableData { lldb::addr_t Dest; llvm::ArrayRef Contents; @@ -504,12 +515,17 @@ class ObjectFile : public std::enable_shared_from_this, /// If the uuid of the binary is specified, this will be set. /// If no UUID is available, will be cleared. /// + /// \param[out] type + /// Return the type of the binary, which will dictate which + /// DynamicLoader plugin should be used. + /// /// \return /// Returns true if either address or uuid has been set. - virtual bool GetCorefileMainBinaryInfo (lldb::addr_t &address, UUID &uuid) { - address = LLDB_INVALID_ADDRESS; - uuid.Clear(); - return false; + virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &address, UUID &uuid, + ObjectFile::BinaryType &type) { + address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + return false; } virtual lldb::RegisterContextSP diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h index cc49ce51c7139..0f99364596c27 100644 --- a/lldb/include/lldb/Symbol/SymbolContext.h +++ b/lldb/include/lldb/Symbol/SymbolContext.h @@ -340,7 +340,7 @@ class SymbolContextSpecifier { void Clear(); - bool SymbolContextMatches(SymbolContext &sc); + bool SymbolContextMatches(const SymbolContext &sc); bool AddressMatches(lldb::addr_t addr); diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 284d91011be51..fbe77c28a1433 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -56,6 +56,7 @@ class SymbolFileType : public std::enable_shared_from_this, Type *operator->() { return GetType(); } Type *GetType(); + SymbolFile &GetSymbolFile() const { return m_symbol_file; } protected: SymbolFile &m_symbol_file; @@ -220,7 +221,6 @@ class Type : public std::enable_shared_from_this, public UserID { Declaration m_decl; CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state; - bool m_is_swift_fixed_value_buffer = false; /// Language-specific flags. Payload m_payload; diff --git a/lldb/include/lldb/Symbol/Variable.h b/lldb/include/lldb/Symbol/Variable.h index 204cb9e5297a7..f9d6e84cd8704 100644 --- a/lldb/include/lldb/Symbol/Variable.h +++ b/lldb/include/lldb/Symbol/Variable.h @@ -33,7 +33,8 @@ class Variable : public UserID, public std::enable_shared_from_this { const lldb::SymbolFileTypeSP &symfile_type_sp, lldb::ValueType scope, SymbolContextScope *owner_scope, const RangeList &scope_range, Declaration *decl, const DWARFExpression &location, bool external, - bool artificial, bool static_member, bool constant); + bool artificial, bool location_is_constant_data, bool static_member, + bool constant); virtual ~Variable(); @@ -64,6 +65,8 @@ class Variable : public UserID, public std::enable_shared_from_this { lldb::ValueType GetScope() const { return m_scope; } + const RangeList &GetScopeRange() const { return m_scope_range; } + bool IsExternal() const { return m_external; } bool IsArtificial() const { return m_artificial; } diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index ad25ead07265d..d69e79df33b3c 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -91,6 +91,7 @@ class ProcessProperties : public Properties { std::chrono::seconds GetUtilityExpressionTimeout() const; bool GetOSPluginReportsAllThreads() const; void SetOSPluginReportsAllThreads(bool does_report); + bool GetSteppingRunsAllThreads() const; protected: Process *m_process; // Can be nullptr for global ProcessProperties diff --git a/lldb/include/lldb/Target/SwiftLanguageRuntime.h b/lldb/include/lldb/Target/SwiftLanguageRuntime.h index e2743d5593483..b6637a40e0301 100644 --- a/lldb/include/lldb/Target/SwiftLanguageRuntime.h +++ b/lldb/include/lldb/Target/SwiftLanguageRuntime.h @@ -260,7 +260,8 @@ class SwiftLanguageRuntime : public LanguageRuntime { llvm::Optional GetByteStride(CompilerType type); /// Ask Remote mirrors for the alignment of a Swift type. - llvm::Optional GetBitAlignment(CompilerType type); + llvm::Optional GetBitAlignment(CompilerType type, + ExecutionContextScope *exe_scope); /// Release the RemoteASTContext associated with the given swift::ASTContext. /// Note that a RemoteASTContext must be destroyed before its associated diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index efd67bce6784a..d8cf9cf69a706 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -37,6 +37,7 @@ #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/PathMappingList.h" #include "lldb/Target/SectionLoadHistory.h" +#include "lldb/Target/ThreadSpec.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Broadcaster.h" @@ -552,6 +553,8 @@ class Target : public std::enable_shared_from_this, static void SetDefaultArchitecture(const ArchSpec &arch); + bool IsDummyTarget() const { return m_is_dummy_target; } + /// Find a binary on the system and return its Module, /// or return an existing Module that is already in the Target. /// @@ -1221,23 +1224,32 @@ class Target : public std::enable_shared_from_this, class StopHook : public UserID { public: StopHook(const StopHook &rhs); + virtual ~StopHook() = default; - ~StopHook(); - - StringList *GetCommandPointer() { return &m_commands; } - - const StringList &GetCommands() { return m_commands; } + enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased }; + enum class StopHookResult : uint32_t { + KeepStopped = 0, + RequestContinue, + AlreadyContinued + }; lldb::TargetSP &GetTarget() { return m_target_sp; } - void SetCommands(StringList &in_commands) { m_commands = in_commands; } - // Set the specifier. The stop hook will own the specifier, and is // responsible for deleting it when we're done. void SetSpecifier(SymbolContextSpecifier *specifier); SymbolContextSpecifier *GetSpecifier() { return m_specifier_sp.get(); } + bool ExecutionContextPasses(const ExecutionContext &exe_ctx); + + // Called on stop, this gets passed the ExecutionContext for each "stop + // with a reason" thread. It should add to the stream whatever text it + // wants to show the user, and return False to indicate it wants the target + // not to stop. + virtual StopHookResult HandleStop(ExecutionContext &exe_ctx, + lldb::StreamSP output) = 0; + // Set the Thread Specifier. The stop hook will own the thread specifier, // and is responsible for deleting it when we're done. void SetThreadSpecifier(ThreadSpec *specifier); @@ -1255,28 +1267,84 @@ class Target : public std::enable_shared_from_this, bool GetAutoContinue() const { return m_auto_continue; } void GetDescription(Stream *s, lldb::DescriptionLevel level) const; + virtual void GetSubclassDescription(Stream *s, + lldb::DescriptionLevel level) const = 0; - private: + protected: lldb::TargetSP m_target_sp; - StringList m_commands; lldb::SymbolContextSpecifierSP m_specifier_sp; std::unique_ptr m_thread_spec_up; bool m_active = true; bool m_auto_continue = false; + StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid); + }; + + class StopHookCommandLine : public StopHook { + public: + virtual ~StopHookCommandLine() = default; + + StringList &GetCommands() { return m_commands; } + void SetActionFromString(const std::string &strings); + void SetActionFromStrings(const std::vector &strings); + + StopHookResult HandleStop(ExecutionContext &exc_ctx, + lldb::StreamSP output_sp) override; + void GetSubclassDescription(Stream *s, + lldb::DescriptionLevel level) const override; + + private: + StringList m_commands; // Use CreateStopHook to make a new empty stop hook. The GetCommandPointer // and fill it with commands, and SetSpecifier to set the specifier shared // pointer (can be null, that will match anything.) - StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid); + StopHookCommandLine(lldb::TargetSP target_sp, lldb::user_id_t uid) + : StopHook(target_sp, uid) {} + friend class Target; + }; + + class StopHookScripted : public StopHook { + public: + virtual ~StopHookScripted() = default; + StopHookResult HandleStop(ExecutionContext &exc_ctx, + lldb::StreamSP output) override; + + Status SetScriptCallback(std::string class_name, + StructuredData::ObjectSP extra_args_sp); + + void GetSubclassDescription(Stream *s, + lldb::DescriptionLevel level) const override; + + private: + std::string m_class_name; + /// This holds the dictionary of keys & values that can be used to + /// parametrize any given callback's behavior. + StructuredDataImpl *m_extra_args; // We own this structured data, + // but the SD itself manages the UP. + /// This holds the python callback object. + StructuredData::GenericSP m_implementation_sp; + + /// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer + /// and fill it with commands, and SetSpecifier to set the specifier shared + /// pointer (can be null, that will match anything.) + StopHookScripted(lldb::TargetSP target_sp, lldb::user_id_t uid) + : StopHook(target_sp, uid) {} friend class Target; }; + typedef std::shared_ptr StopHookSP; - // Add an empty stop hook to the Target's stop hook list, and returns a - // shared pointer to it in new_hook. Returns the id of the new hook. - StopHookSP CreateStopHook(); + /// Add an empty stop hook to the Target's stop hook list, and returns a + /// shared pointer to it in new_hook. Returns the id of the new hook. + StopHookSP CreateStopHook(StopHook::StopHookKind kind); + + /// If you tried to create a stop hook, and that failed, call this to + /// remove the stop hook, as it will also reset the stop hook counter. + void UndoCreateStopHook(lldb::user_id_t uid); - void RunStopHooks(); + // Runs the stop hooks that have been registered for this target. + // Returns true if the stop hooks cause the target to resume. + bool RunStopHooks(); size_t GetStopHookSize(); diff --git a/lldb/include/lldb/Target/ThreadPlanPython.h b/lldb/include/lldb/Target/ThreadPlanPython.h index 27bf3a560b1ff..7b37b2b9ce5ab 100644 --- a/lldb/include/lldb/Target/ThreadPlanPython.h +++ b/lldb/include/lldb/Target/ThreadPlanPython.h @@ -45,7 +45,9 @@ class ThreadPlanPython : public ThreadPlan { bool WillStop() override; - bool StopOthers() override; + bool StopOthers() override { return m_stop_others; } + + void SetStopOthers(bool new_value) override { m_stop_others = new_value; } void DidPush() override; @@ -67,6 +69,7 @@ class ThreadPlanPython : public ThreadPlan { std::string m_error_str; StructuredData::ObjectSP m_implementation_sp; bool m_did_push; + bool m_stop_others; ThreadPlanPython(const ThreadPlanPython &) = delete; const ThreadPlanPython &operator=(const ThreadPlanPython &) = delete; diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h index fea8079779a13..487cd0b01d5c5 100644 --- a/lldb/include/lldb/lldb-defines.h +++ b/lldb/include/lldb/lldb-defines.h @@ -95,6 +95,7 @@ #define LLDB_INVALID_SIGNAL_NUMBER INT32_MAX #define LLDB_INVALID_OFFSET UINT64_MAX // Must match max of lldb::offset_t #define LLDB_INVALID_LINE_NUMBER UINT32_MAX +#define LLDB_INVALID_COLUMN_NUMBER 0 #define LLDB_INVALID_QUEUE_ID 0 /// CPU Type definitions @@ -119,6 +120,7 @@ #define LLDB_OPT_SET_9 (1U << 8) #define LLDB_OPT_SET_10 (1U << 9) #define LLDB_OPT_SET_11 (1U << 10) +#define LLDB_OPT_SET_12 (1U << 11) #define LLDB_OPT_SET_FROM_TO(A, B) \ (((1U << (B)) - 1) ^ (((1U << (A)) - 1) >> 1)) diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index b382956cd8b73..e2ad54cadd1a6 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -529,6 +529,7 @@ enum CommandArgumentType { eArgTypeExpression, eArgTypeExpressionPath, eArgTypeExprFormat, + eArgTypeFileLineColumn, eArgTypeFilename, eArgTypeFormat, eArgTypeFrameIndex, diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 4aaa444222a1c..35fd2b06d2c54 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -527,10 +527,9 @@ def are_sb_headers_missing(): if lldb.remote_platform: return "skip because SBHeaders tests make no sense remotely" - if lldbplatformutil.getHostPlatform() == 'darwin': + if lldbplatformutil.getHostPlatform() == 'darwin' and configuration.lldb_framework_path: header = os.path.join( - os.environ["LLDB_LIB_DIR"], - 'LLDB.framework', + configuration.lldb_framework_path, 'Versions', 'Current', 'Headers', @@ -627,6 +626,8 @@ def skipUnlessTargetAndroid(func): def swiftTest(func): """Decorate the item as a Swift test (Darwin/Linux only, no i386).""" def is_not_swift_compatible(self): + if not _get_bool_config("swift"): + return "Swift plugin not enabled" if self.getDebugInfo() == "gmodules": return "skipping (gmodules only makes sense for clang tests)" @@ -884,11 +885,14 @@ def skipIfAsan(func): """Skip this test if the environment is set up to run LLDB *itself* under ASAN.""" return skipTestIfFn(is_running_under_asan)(func) -def _get_bool_config_skip_if_decorator(key): +def _get_bool_config(key): config = lldb.SBDebugger.GetBuildConfiguration() value_node = config.GetValueForKey(key) fail_value = True # More likely to notice if something goes wrong - have = value_node.GetValueForKey("value").GetBooleanValue(fail_value) + return value_node.GetValueForKey("value").GetBooleanValue(fail_value) + +def _get_bool_config_skip_if_decorator(key): + have = _get_bool_config(key) return unittest2.skipIf(not have, "requires " + key) def skipIfCursesSupportMissing(func): diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index 8bc9da65d7fff..ff565d2eca83a 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -549,13 +549,6 @@ def setupSysPath(): print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") sys.exit(-1) - # confusingly, this is the "bin" directory - lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) - os.environ["LLDB_LIB_DIR"] = lldbLibDir - lldbImpLibDir = configuration.lldb_libs_dir - os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir - print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) - print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) os.system('%s -v' % lldbtest_config.lldbExec) lldbDir = os.path.dirname(lldbtest_config.lldbExec) @@ -570,70 +563,33 @@ def setupSysPath(): configuration.skip_categories.append("lldb-vscode") lldbPythonDir = None # The directory that contains 'lldb/__init__.py' - if not configuration.lldb_framework_path and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): - configuration.lldb_framework_path = os.path.join(lldbLibDir, "LLDB.framework") - if configuration.lldb_framework_path: - lldbtest_config.lldb_framework_path = configuration.lldb_framework_path - candidatePath = os.path.join( - configuration.lldb_framework_path, 'Resources', 'Python') - if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): - lldbPythonDir = candidatePath - if not lldbPythonDir: - print( - 'Resources/Python/lldb/__init__.py was not found in ' + - configuration.lldb_framework_path) - sys.exit(-1) - else: - # If our lldb supports the -P option, use it to find the python path: - init_in_python_dir = os.path.join('lldb', '__init__.py') - - lldb_dash_p_result = subprocess.check_output( - [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) - - if lldb_dash_p_result and not lldb_dash_p_result.startswith( - ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): - lines = lldb_dash_p_result.splitlines() - - # Workaround for readline vs libedit issue on FreeBSD. If stdout - # is not a terminal Python executes - # rl_variable_bind ("enable-meta-key", "off"); - # This produces a warning with FreeBSD's libedit because the - # enable-meta-key variable is unknown. Not an issue on Apple - # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ - # around the call. See http://bugs.python.org/issue19884 for more - # information. For now we just discard the warning output. - if len(lines) >= 1 and lines[0].startswith( - "bind: Invalid command"): - lines.pop(0) - - # Taking the last line because lldb outputs - # 'Cannot read termcap database;\nusing dumb terminal settings.\n' - # before the path - if len(lines) >= 1 and os.path.isfile( - os.path.join(lines[-1], init_in_python_dir)): - lldbPythonDir = lines[-1] - if "freebsd" in sys.platform or "linux" in sys.platform: - os.environ['LLDB_LIB_DIR'] = os.path.join( - lldbPythonDir, '..', '..') - - if not lldbPythonDir: - print( - "Unable to load lldb extension module. Possible reasons for this include:") - print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") - print( - " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") - print( - " the version of Python that LLDB built and linked against, and PYTHONPATH") - print( - " should contain the Lib directory for the same python distro, as well as the") - print(" location of LLDB\'s site-packages folder.") - print( - " 3) A different version of Python than that which was built against is exported in") - print(" the system\'s PATH environment variable, causing conflicts.") - print( - " 4) The executable '%s' could not be found. Please check " % - lldbtest_config.lldbExec) - print(" that it exists and is executable.") + + # If our lldb supports the -P option, use it to find the python path: + lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], universal_newlines=True) + if lldb_dash_p_result: + for line in lldb_dash_p_result.splitlines(): + if os.path.isdir(line) and os.path.exists(os.path.join(line, 'lldb', '__init__.py')): + lldbPythonDir = line + break + + if not lldbPythonDir: + print( + "Unable to load lldb extension module. Possible reasons for this include:") + print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") + print( + " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") + print( + " the version of Python that LLDB built and linked against, and PYTHONPATH") + print( + " should contain the Lib directory for the same python distro, as well as the") + print(" location of LLDB\'s site-packages folder.") + print( + " 3) A different version of Python than that which was built against is exported in") + print(" the system\'s PATH environment variable, causing conflicts.") + print( + " 4) The executable '%s' could not be found. Please check " % + lldbtest_config.lldbExec) + print(" that it exists and is executable.") if lldbPythonDir: lldbPythonDir = os.path.normpath(lldbPythonDir) @@ -647,6 +603,9 @@ def setupSysPath(): lldbPythonDir = os.path.abspath(lldbPythonDir) + if "freebsd" in sys.platform or "linux" in sys.platform: + os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') + # If tests need to find LLDB_FRAMEWORK, now they can do it os.environ["LLDB_FRAMEWORK"] = os.path.dirname( os.path.dirname(lldbPythonDir)) diff --git a/lldb/packages/Python/lldbsuite/test/lldbplaygroundrepl.py b/lldb/packages/Python/lldbsuite/test/lldbplaygroundrepl.py index b3238f5025a26..5f13d6352ef5d 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbplaygroundrepl.py +++ b/lldb/packages/Python/lldbsuite/test/lldbplaygroundrepl.py @@ -24,8 +24,6 @@ class PlaygroundREPLTest(TestBase): - mydir = TestBase.compute_mydir(__file__) - @decorators.skipUnlessDarwin @decorators.swiftTest @decorators.skipIf( @@ -129,6 +127,7 @@ def did_crash(self, result): error = self.get_stream_data(result) print("Crash Error: {}".format(error)) + @swiftTest def test_playgrounds(self): # Build self.build_all() diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 903410bd91118..e055336a4177c 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -846,28 +846,18 @@ def setUp(self): self.setPlatformWorkingDir() self.enableLogChannelsForCurrentTest() - lib_dir = os.environ["LLDB_LIB_DIR"] - self.dsym = None + self.lib_lldb = None self.framework_dir = None - self.darwinWithFramework = self.platformIsDarwin() - if sys.platform.startswith("darwin"): - # Handle the framework environment variable if it is set - if hasattr(lldbtest_config, 'lldb_framework_path'): - framework_path = lldbtest_config.lldb_framework_path - # Framework dir should be the directory containing the framework - self.framework_dir = framework_path[:framework_path.rfind('LLDB.framework')] - # If a framework dir was not specified assume the Xcode build - # directory layout where the framework is in LLDB_LIB_DIR. - else: - self.framework_dir = lib_dir - self.dsym = os.path.join(self.framework_dir, 'LLDB.framework', 'LLDB') - # If the framework binary doesn't exist, assume we didn't actually - # build a framework, and fallback to standard *nix behavior by - # setting framework_dir and dsym to None. - if not os.path.exists(self.dsym): - self.framework_dir = None - self.dsym = None - self.darwinWithFramework = False + self.darwinWithFramework = False + + if sys.platform.startswith("darwin") and configuration.lldb_framework_path: + framework = configuration.lldb_framework_path + lib = os.path.join(framework, 'LLDB') + if os.path.exists(lib): + self.framework_dir = os.path.dirname(framework) + self.lib_lldb = lib + self.darwinWithFramework = self.platformIsDarwin() + self.makeBuildDir() def setAsync(self, value): @@ -1039,6 +1029,18 @@ def tearDown(self): lldb.SBDebugger.Destroy(self.dbg) del self.dbg + # All modules should be orphaned now so that they can be cleared from + # the shared module cache. + lldb.SBModule.GarbageCollectAllocatedModules() + + # Modules are not orphaned during reproducer replay because they're + # leaked on purpose. + if not configuration.is_reproducer(): + # Assert that the global module cache is empty. + # (rdar://problem/64424164) self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0) + pass + + # ========================================================= # Various callbacks to allow introspection of test progress # ========================================================= @@ -1432,7 +1434,7 @@ def buildDriver(self, sources, exe_name): 'EXE': exe_name, 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, - 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), + 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir), } elif sys.platform.startswith('win'): d = { @@ -1443,7 +1445,7 @@ def buildDriver(self, sources, exe_name): os.path.join( os.environ["LLDB_SRC"], "include")), - 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} + 'LD_EXTRAS': "-L%s -lliblldb" % lib_dir} else: d = { 'CXX_SOURCES': sources, @@ -1472,7 +1474,7 @@ def buildLibrary(self, sources, lib_name): 'DYLIB_NAME': lib_name, 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, - 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), + 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.lib_lldb, self.framework_dir), } elif self.getPlatform() == 'windows': d = { @@ -1482,7 +1484,7 @@ def buildLibrary(self, sources, lib_name): os.path.join( os.environ["LLDB_SRC"], "include")), - 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} + 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % lib_dir} else: d = { 'DYLIB_CXX_SOURCES': sources, @@ -1697,13 +1699,11 @@ def getLLDBLibraryEnvVal(self): """ existing_library_path = os.environ[ self.dylibPath] if self.dylibPath in os.environ else None - lib_dir = os.environ["LLDB_LIB_DIR"] if existing_library_path: - return "%s:%s" % (existing_library_path, lib_dir) - elif sys.platform.startswith("darwin"): - return os.path.join(lib_dir, 'LLDB.framework') - else: - return lib_dir + return "%s:%s" % (existing_library_path, configuration.lldb_libs_dir) + if sys.platform.startswith("darwin") and configuration.lldb_framework_path: + return configuration.lldb_framework_path + return configuration.lldb_libs_dir def getLibcPlusPlusLibs(self): if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): @@ -2001,13 +2001,9 @@ def tearDown(self): for target in targets: self.dbg.DeleteTarget(target) - # Modules are not orphaned during reproducer replay because they're - # leaked on purpose. if not configuration.is_reproducer(): # Assert that all targets are deleted. - assert self.dbg.GetNumTargets() == 0 - # Assert that the global module cache is empty. - # (rdar://problem/64424164) assert lldb.SBModule.GetNumberAllocatedModules() == 0 + self.assertEqual(self.dbg.GetNumTargets(), 0) # Do this last, to make sure it's in reverse order from how we setup. Base.tearDown(self) diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py index 7a301d23575d0..6a0582c0c1288 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -540,6 +540,29 @@ def run_break_set_by_source_regexp( return get_bpno_from_match(break_results) +def run_break_set_by_file_colon_line( + test, + specifier, + path, + line_number, + column_number = 0, + extra_options=None, + num_expected_locations=-1): + command = 'breakpoint set -y "%s"'%(specifier) + if extra_options: + command += " " + extra_options + + print("About to run: '%s'", command) + break_results = run_break_set_command(test, command) + check_breakpoint_result( + test, + break_results, + num_locations = num_expected_locations, + file_name = path, + line_number = line_number, + column_number = column_number) + + return get_bpno_from_match(break_results) def run_break_set_command(test, command): """Run the command passed in - it must be some break set variant - and analyze the result. @@ -553,6 +576,7 @@ def run_break_set_command(test, command): If there is only one location, the dictionary MAY contain: file - source file name line_no - source line number + column - source column number symbol - symbol name inline_symbol - inlined symbol name offset - offset from the original symbol @@ -604,6 +628,7 @@ def check_breakpoint_result( break_results, file_name=None, line_number=-1, + column_number=0, symbol_name=None, symbol_match_exact=True, module_name=None, @@ -643,6 +668,17 @@ def check_breakpoint_result( (line_number, out_line_number)) + if column_number != 0: + out_column_number = 0 + if 'column' in break_results: + out_column_number = break_results['column'] + + test.assertTrue( + column_number == out_column_number, + "Breakpoint column number %s doesn't match resultant column %s." % + (column_number, + out_column_number)) + if symbol_name: out_symbol_name = "" # Look first for the inlined symbol name, otherwise use the symbol diff --git a/lldb/packages/Python/lldbsuite/test/test_categories.py b/lldb/packages/Python/lldbsuite/test/test_categories.py index d72da48f65173..d07f7c0777a4b 100644 --- a/lldb/packages/Python/lldbsuite/test/test_categories.py +++ b/lldb/packages/Python/lldbsuite/test/test_categories.py @@ -19,27 +19,29 @@ ] all_categories = { + 'basic_process': 'Basic process execution sniff tests.', + 'cmdline': 'Tests related to the LLDB command-line interface', + 'darwin-log': 'Darwin log tests', 'dataformatters': 'Tests related to the type command and the data formatters subsystem', + 'dsym': 'Tests that can be run with DSYM debug information', 'dwarf': 'Tests that can be run with DWARF debug information', 'dwo': 'Tests that can be run with DWO debug information', - 'dsym': 'Tests that can be run with DSYM debug information', - 'gmodules': 'Tests that can be run with -gmodules debug information', + 'dyntype': 'Tests related to dynamic type support', 'expression': 'Tests related to the expression parser', + 'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution', + 'gmodules': 'Tests that can be run with -gmodules debug information', + 'instrumentation-runtime': 'Tests for the instrumentation runtime plugins', 'libc++': 'Test for libc++ data formatters', 'libstdcxx': 'Test for libstdcxx data formatters', + 'lldb-server': 'Tests related to lldb-server', + 'lldb-vscode': 'Visual Studio Code debug adaptor tests', 'objc': 'Tests related to the Objective-C programming language support', 'pyapi': 'Tests related to the Python API', - 'basic_process': 'Basic process execution sniff tests.', - 'cmdline': 'Tests related to the LLDB command-line interface', - 'dyntype': 'Tests related to dynamic type support', - 'stresstest': 'Tests related to stressing lldb limits', - 'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution', - 'frame-diagnose': 'Frame diagnose tests', - 'darwin-log': 'Darwin log tests', 'std-module': 'Tests related to importing the std module', + 'stresstest': 'Tests related to stressing lldb limits', 'watchpoint': 'Watchpoint-related tests', - 'lldb-vscode': 'Visual Studio Code debug adaptor tests', - 'lldb-server': 'Tests related to lldb-server', + + 'frame-diagnose': 'Frame diagnose tests', } diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index bef7b46f07bba..dd5df0c0abeda 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -136,9 +136,9 @@ if(LLDB_ENABLE_PYTHON AND (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB) AND UNIX A set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "\$ORIGIN/../../../../lib${LLVM_LIBDIR_SUFFIX}") endif() -if(PYTHON_RPATH) - set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${PYTHON_RPATH}") - set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") +if(Python3_RPATH) + set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}") + set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") endif() if (MSVC) @@ -202,9 +202,9 @@ endif() if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) # Only MSVC has the ABI compatibility problem and avoids using FindPythonLibs, - # so only it needs to explicitly link against ${PYTHON_LIBRARIES} + # so only it needs to explicitly link against ${Python3_LIBRARIES} if (MSVC AND LLDB_ENABLE_PYTHON) - target_link_libraries(liblldb PRIVATE ${PYTHON_LIBRARIES}) + target_link_libraries(liblldb PRIVATE ${Python3_LIBRARIES}) endif() else() set_target_properties(liblldb diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 96b77bd8539e8..96ae305ffce5b 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -81,6 +81,16 @@ bool SBBreakpoint::operator!=(const lldb::SBBreakpoint &rhs) { return m_opaque_wp.lock() != rhs.m_opaque_wp.lock(); } +SBTarget SBBreakpoint::GetTarget() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBTarget, SBBreakpoint, GetTarget); + + BreakpointSP bkpt_sp = GetSP(); + if (bkpt_sp) + return LLDB_RECORD_RESULT(SBTarget(bkpt_sp->GetTargetSP())); + + return LLDB_RECORD_RESULT(SBTarget()); +} + break_id_t SBBreakpoint::GetID() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::break_id_t, SBBreakpoint, GetID); @@ -987,6 +997,7 @@ void RegisterMethods(Registry &R) { SBBreakpoint, operator==,(const lldb::SBBreakpoint &)); LLDB_REGISTER_METHOD(bool, SBBreakpoint, operator!=,(const lldb::SBBreakpoint &)); + LLDB_REGISTER_METHOD_CONST(lldb::SBTarget, SBBreakpoint, GetTarget, ()); LLDB_REGISTER_METHOD_CONST(lldb::break_id_t, SBBreakpoint, GetID, ()); LLDB_REGISTER_METHOD_CONST(bool, SBBreakpoint, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBBreakpoint, operator bool, ()); diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index e8851333770c8..e1f64be177a4f 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -702,6 +702,12 @@ SBStructuredData SBDebugger::GetBuildConfiguration() { "A boolean value that indicates if lua support is enabled in LLDB"); AddLLVMTargets(*config_up); +#ifdef LLDB_ENABLE_SWIFT + AddBoolConfigEntry( + *config_up, "swift", true, + "A boolean value that indicates if Swift support is enabled in LLDB"); +#endif // LLDB_ENABLE_SWIFT + SBStructuredData data; data.m_impl_up->SetObjectSP(std::move(config_up)); return LLDB_RECORD_RESULT(data); diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp index 3dfae905aec70..1b4e37565d4bc 100644 --- a/lldb/source/API/SBModule.cpp +++ b/lldb/source/API/SBModule.cpp @@ -714,6 +714,13 @@ uint32_t SBModule::GetNumberAllocatedModules() { return Module::GetNumberAllocatedModules(); } +void SBModule::GarbageCollectAllocatedModules() { + LLDB_RECORD_STATIC_METHOD_NO_ARGS(void, SBModule, + GarbageCollectAllocatedModules); + const bool mandatory = false; + ModuleList::RemoveOrphanSharedModules(mandatory); +} + namespace lldb_private { namespace repro { diff --git a/lldb/source/API/SBThreadPlan.cpp b/lldb/source/API/SBThreadPlan.cpp index c740c8b7492fc..9af673b0f3a99 100644 --- a/lldb/source/API/SBThreadPlan.cpp +++ b/lldb/source/API/SBThreadPlan.cpp @@ -196,6 +196,23 @@ bool SBThreadPlan::IsValid() { return false; } +bool SBThreadPlan::GetStopOthers() { + LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, GetStopOthers); + + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + return thread_plan_sp->StopOthers(); + return false; +} + +void SBThreadPlan::SetStopOthers(bool stop_others) { + LLDB_RECORD_METHOD(void, SBThreadPlan, SetStopOthers, (bool), stop_others); + + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + thread_plan_sp->SetStopOthers(stop_others); +} + // This section allows an SBThreadPlan to push another of the common types of // plans... // @@ -463,6 +480,8 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanComplete, ()); LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanStale, ()); LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsValid, ()); + LLDB_REGISTER_METHOD(void, SBThreadPlan, SetStopOthers, (bool)); + LLDB_REGISTER_METHOD(bool, SBThreadPlan, GetStopOthers, ()); LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, QueueThreadPlanForStepOverRange, (lldb::SBAddress &, lldb::addr_t)); diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp index 689fa076deca6..158989b0f23ce 100644 --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -17,13 +17,13 @@ #include "lldb/Utility/Timer.h" #include "llvm/Support/TargetSelect.h" -// BEGIN SWIFT +#ifdef LLDB_ENABLE_SWIFT #include "Plugins/ExpressionParser/Swift/SwiftREPL.h" #include "Plugins/InstrumentationRuntime/SwiftRuntimeReporting/SwiftRuntimeReporting.h" #include "Plugins/Language/Swift/SwiftLanguage.h" #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" #include "lldb/Target/SwiftLanguageRuntime.h" -// END SWIFT +#endif //LLDB_ENABLE_SWIFT #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 8557487fe9892..48a20e167199c 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -17,6 +17,7 @@ #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" @@ -448,7 +449,22 @@ class CommandObjectBreakpointSet : public CommandObjectParsed { case 'X': m_source_regex_func_names.insert(std::string(option_arg)); break; - + + case 'y': + { + OptionValueFileColonLine value; + Status fcl_err = value.SetValueFromString(option_arg); + if (!fcl_err.Success()) { + error.SetErrorStringWithFormat( + "Invalid value for file:line specifier: %s", + fcl_err.AsCString()); + } else { + m_filenames.AppendIfUnique(value.GetFileSpec()); + m_line_num = value.GetLineNumber(); + m_column = value.GetColumnNumber(); + } + } break; + default: llvm_unreachable("Unimplemented option"); } @@ -1412,7 +1428,8 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed { class CommandOptions : public Options { public: - CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} + CommandOptions() : Options(), m_use_dummy(false), m_force(false), + m_delete_disabled(false) {} ~CommandOptions() override = default; @@ -1429,6 +1446,10 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed { case 'D': m_use_dummy = true; break; + + case 'd': + m_delete_disabled = true; + break; default: llvm_unreachable("Unimplemented option"); @@ -1440,6 +1461,7 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed { void OptionParsingStarting(ExecutionContext *execution_context) override { m_use_dummy = false; m_force = false; + m_delete_disabled = false; } llvm::ArrayRef GetDefinitions() override { @@ -1449,16 +1471,18 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed { // Instance variables to hold the values for command options. bool m_use_dummy; bool m_force; + bool m_delete_disabled; }; protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy); - + result.Clear(); + std::unique_lock lock; target.GetBreakpointList().GetListMutex(lock); - const BreakpointList &breakpoints = target.GetBreakpointList(); + BreakpointList &breakpoints = target.GetBreakpointList(); size_t num_breakpoints = breakpoints.GetSize(); @@ -1468,7 +1492,7 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed { return false; } - if (command.empty()) { + if (command.empty() && !m_options.m_delete_disabled) { if (!m_options.m_force && !m_interpreter.Confirm( "About to delete all breakpoints, do you want to do that?", @@ -1484,10 +1508,34 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed { } else { // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, &target, result, &valid_bp_ids, - BreakpointName::Permissions::PermissionKinds::deletePerm); - + + if (m_options.m_delete_disabled) { + BreakpointIDList excluded_bp_ids; + + if (!command.empty()) { + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( + command, &target, result, &excluded_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); + } + for (auto breakpoint_sp : breakpoints.Breakpoints()) { + if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) { + BreakpointID bp_id(breakpoint_sp->GetID()); + size_t pos = 0; + if (!excluded_bp_ids.FindBreakpointID(bp_id, &pos)) + valid_bp_ids.AddBreakpointID(breakpoint_sp->GetID()); + } + } + if (valid_bp_ids.GetSize() == 0) { + result.AppendError("No disabled breakpoints."); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else { + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( + command, &target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); + } + if (result.Succeeded()) { int delete_count = 0; int disable_count = 0; diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp index 1ccfd3a5166f4..8fff22a06366c 100644 --- a/lldb/source/Commands/CommandObjectSource.cpp +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -16,6 +16,7 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/Options.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -667,6 +668,22 @@ class CommandObjectSourceList : public CommandObjectParsed { case 'r': reverse = true; break; + case 'y': + { + OptionValueFileColonLine value; + Status fcl_err = value.SetValueFromString(option_arg); + if (!fcl_err.Success()) { + error.SetErrorStringWithFormat( + "Invalid value for file:line specifier: %s", + fcl_err.AsCString()); + } else { + file_name = value.GetFileSpec().GetPath(); + start_line = value.GetLineNumber(); + // I don't see anything useful to do with a column number, but I don't + // want to complain since someone may well have cut and pasted a + // listing from somewhere that included a column. + } + } break; default: llvm_unreachable("Unimplemented option"); } diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 9c0620092fb52..cbfebbfee0fd7 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -24,6 +24,7 @@ #include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Interpreter/OptionGroupPlatform.h" +#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionGroupString.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionGroupUUID.h" @@ -922,6 +923,7 @@ class CommandObjectTargetVariable : public CommandObjectParsed { CompileUnit *comp_unit = nullptr; if (frame) { SymbolContext sc = frame->GetSymbolContext(eSymbolContextCompUnit); + comp_unit = sc.comp_unit; if (sc.comp_unit) { const bool can_create = true; VariableListSP comp_unit_varlist_sp( @@ -4413,10 +4415,10 @@ class CommandObjectTargetSymbols : public CommandObjectMultiword { class CommandObjectTargetStopHookAdd : public CommandObjectParsed, public IOHandlerDelegateMultiline { public: - class CommandOptions : public Options { + class CommandOptions : public OptionGroup { public: CommandOptions() - : Options(), m_line_start(0), m_line_end(UINT_MAX), + : OptionGroup(), m_line_start(0), m_line_end(UINT_MAX), m_func_name_type_mask(eFunctionNameTypeAuto), m_sym_ctx_specified(false), m_thread_specified(false), m_use_one_liner(false), m_one_liner() {} @@ -4430,7 +4432,8 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { Status error; - const int short_option = m_getopt_table[option_idx].val; + const int short_option = + g_target_stop_hook_add_options[option_idx].short_option; switch (short_option) { case 'c': @@ -4560,20 +4563,75 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, // Instance variables to hold the values for one_liner options. bool m_use_one_liner; std::vector m_one_liner; + bool m_auto_continue; }; CommandObjectTargetStopHookAdd(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "target stop-hook add", - "Add a hook to be executed when the target stops.", + "Add a hook to be executed when the target stops." + "The hook can either be a list of commands or an " + "appropriately defined Python class. You can also " + "add filters so the hook only runs a certain stop " + "points.", "target stop-hook add"), IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), - m_options() {} + m_options(), m_python_class_options("scripted stop-hook", true, 'P') { + SetHelpLong( + R"( +Command Based stop-hooks: +------------------------- + Stop hooks can run a list of lldb commands by providing one or more + --one-line-command options. The commands will get run in the order they are + added. Or you can provide no commands, in which case you will enter a + command editor where you can enter the commands to be run. + +Python Based Stop Hooks: +------------------------ + Stop hooks can be implemented with a suitably defined Python class, whose name + is passed in the --python-class option. + + When the stop hook is added, the class is initialized by calling: + + def __init__(self, target, extra_args, dict): + + target: The target that the stop hook is being added to. + extra_args: An SBStructuredData Dictionary filled with the -key -value + option pairs passed to the command. + dict: An implementation detail provided by lldb. + + Then when the stop-hook triggers, lldb will run the 'handle_stop' method. + The method has the signature: + + def handle_stop(self, exe_ctx, stream): + + exe_ctx: An SBExecutionContext for the thread that has stopped. + stream: An SBStream, anything written to this stream will be printed in the + the stop message when the process stops. + + Return Value: The method returns "should_stop". If should_stop is false + from all the stop hook executions on threads that stopped + with a reason, then the process will continue. Note that this + will happen only after all the stop hooks are run. + +Filter Options: +--------------- + Stop hooks can be set to always run, or to only run when the stopped thread + matches the filter options passed on the command line. The available filter + options include a shared library or a thread or queue specification, + a line range in a source file, a function name or a class name. + )"); + m_all_options.Append(&m_python_class_options, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_FROM_TO(4, 6)); + m_all_options.Append(&m_options); + m_all_options.Finalize(); + } ~CommandObjectTargetStopHookAdd() override = default; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { @@ -4597,10 +4655,15 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, error_sp->Flush(); } Target *target = GetDebugger().GetSelectedTarget().get(); - if (target) - target->RemoveStopHookByID(m_stop_hook_sp->GetID()); + if (target) { + target->UndoCreateStopHook(m_stop_hook_sp->GetID()); + } } else { - m_stop_hook_sp->GetCommandPointer()->SplitIntoLines(line); + // The IOHandler editor is only for command lines stop hooks: + Target::StopHookCommandLine *hook_ptr = + static_cast(m_stop_hook_sp.get()); + + hook_ptr->SetActionFromString(line); StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); if (output_sp) { output_sp->Printf("Stop hook #%" PRIu64 " added.\n", @@ -4617,7 +4680,10 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, m_stop_hook_sp.reset(); Target &target = GetSelectedOrDummyTarget(); - Target::StopHookSP new_hook_sp = target.CreateStopHook(); + Target::StopHookSP new_hook_sp = + target.CreateStopHook(m_python_class_options.GetName().empty() ? + Target::StopHook::StopHookKind::CommandBased + : Target::StopHook::StopHookKind::ScriptBased); // First step, make the specifier. std::unique_ptr specifier_up; @@ -4686,11 +4752,30 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, new_hook_sp->SetAutoContinue(m_options.m_auto_continue); if (m_options.m_use_one_liner) { - // Use one-liners. - for (auto cmd : m_options.m_one_liner) - new_hook_sp->GetCommandPointer()->AppendString(cmd.c_str()); + // This is a command line stop hook: + Target::StopHookCommandLine *hook_ptr = + static_cast(new_hook_sp.get()); + hook_ptr->SetActionFromStrings(m_options.m_one_liner); result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", new_hook_sp->GetID()); + } else if (!m_python_class_options.GetName().empty()) { + // This is a scripted stop hook: + Target::StopHookScripted *hook_ptr = + static_cast(new_hook_sp.get()); + Status error = hook_ptr->SetScriptCallback( + m_python_class_options.GetName(), + m_python_class_options.GetStructuredData()); + if (error.Success()) + result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", + new_hook_sp->GetID()); + else { + // FIXME: Set the stop hook ID counter back. + result.AppendErrorWithFormat("Couldn't add stop hook: %s", + error.AsCString()); + result.SetStatus(eReturnStatusFailed); + target.UndoCreateStopHook(new_hook_sp->GetID()); + return false; + } } else { m_stop_hook_sp = new_hook_sp; m_interpreter.GetLLDBCommandsFromIOHandler("> ", // Prompt @@ -4703,6 +4788,9 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, private: CommandOptions m_options; + OptionGroupPythonClassWithDict m_python_class_options; + OptionGroupOptions m_all_options; + Target::StopHookSP m_stop_hook_sp; }; diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index f0ad1798fec6a..666c208c32067 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -482,8 +482,16 @@ class ThreadStepScopeOptionGroup : public OptionGroup { // Check if we are in Non-Stop mode TargetSP target_sp = execution_context ? execution_context->GetTargetSP() : TargetSP(); - if (target_sp && target_sp->GetNonStopModeEnabled()) + if (target_sp && target_sp->GetNonStopModeEnabled()) { + // NonStopMode runs all threads by definition, so when it is on we don't + // need to check the process setting for runs all threads. m_run_mode = eOnlyThisThread; + } else { + ProcessSP process_sp = + execution_context ? execution_context->GetProcessSP() : ProcessSP(); + if (process_sp && process_sp->GetSteppingRunsAllThreads()) + m_run_mode = eAllThreads; + } m_avoid_regexp.clear(); m_step_in_target.clear(); @@ -612,8 +620,7 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed { if (m_options.m_run_mode == eAllThreads) bool_stop_other_threads = false; else if (m_options.m_run_mode == eOnlyDuringStepping) - bool_stop_other_threads = - (m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted); + bool_stop_other_threads = (m_step_type != eStepTypeOut); else bool_stop_other_threads = true; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index b18efdb1f708e..add98e2b2d61a 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -105,7 +105,7 @@ let Command = "breakpoint dummy" in { let Command = "breakpoint set" in { def breakpoint_set_shlib : Option<"shlib", "s">, Arg<"ShlibName">, - Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11]>, // *not* in group 10 + Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11,12]>, // *not* in group 10 Desc<"Set the breakpoint only in this shared library. Can repeat this " "option multiple times to specify multiple shared libraries.">; def breakpoint_set_hardware : Option<"hardware", "H">, @@ -198,21 +198,24 @@ let Command = "breakpoint set" in { "expression (note: currently only implemented for setting breakpoints on " "identifiers). If not set the target.language setting is used.">; def breakpoint_set_skip_prologue : Option<"skip-prologue", "K">, - Arg<"Boolean">, Groups<[1,3,4,5,6,7,8]>, + Arg<"Boolean">, Groups<[1,3,4,5,6,7,8,12]>, Desc<"sKip the prologue if the breakpoint is at the beginning of a " "function. If not set the target.skip-prologue setting is used.">; def breakpoint_set_breakpoint_name : Option<"breakpoint-name", "N">, Arg<"BreakpointName">, Desc<"Adds this to the list of names for this breakpoint.">; def breakpoint_set_address_slide : Option<"address-slide", "R">, - Arg<"Address">, Groups<[1,3,4,5,6,7,8]>, + Arg<"Address">, Groups<[1,3,4,5,6,7,8,12]>, Desc<"Add the specified offset to whatever address(es) the breakpoint " "resolves to. At present this applies the offset directly as given, and " "doesn't try to align it to instruction boundaries.">; def breakpoint_set_move_to_nearest_code : Option<"move-to-nearest-code", "m">, - Groups<[1, 9]>, Arg<"Boolean">, + Groups<[1,9,12]>, Arg<"Boolean">, Desc<"Move breakpoints to nearest code. If not set the " "target.move-to-nearest-codesetting is used.">; + def breakpoint_set_file_colon_line : Option<"joint-specifier", "y">, Group<12>, Arg<"FileLineColumn">, + Required, Completion<"SourceFile">, + Desc<"A specifier in the form filename:line[:column] for setting file & line breakpoints.">; /* Don't add this option till it actually does something useful... def breakpoint_set_exception_typename : Option<"exception-typename", "O">, Arg<"TypeName">, Desc<"The breakpoint will only stop if an " @@ -236,6 +239,9 @@ let Command = "breakpoint delete" in { def breakpoint_delete_dummy_breakpoints : Option<"dummy-breakpoints", "D">, Group<1>, Desc<"Delete Dummy breakpoints - i.e. breakpoints set before a " "file is provided, which prime new targets.">; + def breakpoint_delete_disabled : Option<"disabled", "d">, Group<1>, + Desc<"Delete all breakpoints which are currently disabled. When using the disabled option " + "any breakpoints listed on the command line are EXCLUDED from deletion.">; } let Command = "breakpoint name" in { @@ -333,7 +339,7 @@ let Command = "disassemble" in { def disassemble_options_pc : Option<"pc", "p">, Group<5>, Desc<"Disassemble around the current pc.">; def disassemble_options_line : Option<"line", "l">, Group<6>, - Desc<"Disassemble the current frame's current source line instructions if" + Desc<"Disassemble the current frame's current source line instructions if " "there is debug line table information, else disassemble around the pc.">; def disassemble_options_address : Option<"address", "a">, Group<7>, Arg<"AddressOrExpression">, @@ -749,7 +755,7 @@ let Command = "source info" in { let Command = "source list" in { def source_list_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of source lines to display.">; - def source_list_shlib : Option<"shlib", "s">, Groups<[1,2]>, Arg<"ShlibName">, + def source_list_shlib : Option<"shlib", "s">, Groups<[1,2,5]>, Arg<"ShlibName">, Completion<"Module">, Desc<"Look up the source file in the given shared library.">; def source_list_show_breakpoints : Option<"show-breakpoints", "b">, @@ -767,6 +773,10 @@ let Command = "source list" in { " information for the corresponding file and line.">; def source_list_reverse : Option<"reverse", "r">, Group<4>, Desc<"Reverse the" " listing to look backwards from the last displayed block of source.">; + def source_list_file_colon_line : Option<"joint-specifier", "y">, Group<5>, + Arg<"FileLineColumn">, Completion<"SourceFile">, + Desc<"A specifier in the form filename:line[:column] from which to display" + " source.">; } let Command = "target dependents" in { @@ -875,7 +885,7 @@ let Command = "target modules lookup" in { } let Command = "target stop hook add" in { - def target_stop_hook_add_one_liner : Option<"one-liner", "o">, + def target_stop_hook_add_one_liner : Option<"one-liner", "o">, GroupRange<1,3>, Arg<"OneLiner">, Desc<"Add a command for the stop hook. Can be specified " "more than once, and commands will be run in the order they appear.">; def target_stop_hook_add_shlib : Option<"shlib", "s">, Arg<"ShlibName">, @@ -893,19 +903,19 @@ let Command = "target stop hook add" in { def target_stop_hook_add_queue_name : Option<"queue-name", "q">, Arg<"QueueName">, Desc<"The stop hook is run only for threads in the queue " "whose name is given by this argument.">; - def target_stop_hook_add_file : Option<"file", "f">, Group<1>, + def target_stop_hook_add_file : Option<"file", "f">, Groups<[1,4]>, Arg<"Filename">, Desc<"Specify the source file within which the stop-hook " "is to be run.">, Completion<"SourceFile">; - def target_stop_hook_add_start_line : Option<"start-line", "l">, Group<1>, + def target_stop_hook_add_start_line : Option<"start-line", "l">, Groups<[1,4]>, Arg<"LineNum">, Desc<"Set the start of the line range for which the " "stop-hook is to be run.">; - def target_stop_hook_add_end_line : Option<"end-line", "e">, Group<1>, + def target_stop_hook_add_end_line : Option<"end-line", "e">, Groups<[1,4]>, Arg<"LineNum">, Desc<"Set the end of the line range for which the stop-hook" " is to be run.">; - def target_stop_hook_add_classname : Option<"classname", "c">, Group<2>, + def target_stop_hook_add_classname : Option<"classname", "c">, Groups<[2,5]>, Arg<"ClassName">, Desc<"Specify the class within which the stop-hook is to be run.">; - def target_stop_hook_add_name : Option<"name", "n">, Group<3>, + def target_stop_hook_add_name : Option<"name", "n">, Groups<[3,6]>, Arg<"FunctionName">, Desc<"Set the function name within which the stop hook" " will be run.">, Completion<"Symbol">; def target_stop_hook_add_auto_continue : Option<"auto-continue", "G">, diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index 4da823c7a2435..3902b17c09664 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -540,34 +540,29 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, } bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, - const char *plugin_name, const char *flavor, - const ExecutionContext &exe_ctx, - uint32_t num_instructions, - bool mixed_source_and_assembly, - uint32_t num_mixed_context_lines, - uint32_t options, Stream &strm) { + StackFrame &frame, Stream &strm) { AddressRange range; - StackFrame *frame = exe_ctx.GetFramePtr(); - if (frame) { - SymbolContext sc( - frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); - if (sc.function) { - range = sc.function->GetAddressRange(); - } else if (sc.symbol && sc.symbol->ValueIsAddress()) { - range.GetBaseAddress() = sc.symbol->GetAddressRef(); - range.SetByteSize(sc.symbol->GetByteSize()); - } else { - range.GetBaseAddress() = frame->GetFrameCodeAddress(); - } + SymbolContext sc( + frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); + if (sc.function) { + range = sc.function->GetAddressRange(); + } else if (sc.symbol && sc.symbol->ValueIsAddress()) { + range.GetBaseAddress() = sc.symbol->GetAddressRef(); + range.SetByteSize(sc.symbol->GetByteSize()); + } else { + range.GetBaseAddress() = frame.GetFrameCodeAddress(); + } if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0) range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); - } - return Disassemble( - debugger, arch, plugin_name, flavor, exe_ctx, range.GetBaseAddress(), - {Limit::Instructions, num_instructions}, mixed_source_and_assembly, - num_mixed_context_lines, options, strm); + Disassembler::Limit limit = {Disassembler::Limit::Bytes, + range.GetByteSize()}; + if (limit.value == 0) + limit.value = DEFAULT_DISASM_BYTE_SIZE; + + return Disassemble(debugger, arch, nullptr, nullptr, frame, + range.GetBaseAddress(), limit, false, 0, 0, strm); } Instruction::Instruction(const Address &address, AddressClass addr_class) diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index e6be40a212fe7..fc8ab253bf98b 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -681,13 +681,11 @@ Module::LookupInfo::LookupInfo(ConstString name, language == eLanguageTypeSwift) && swift_method.IsValid()) basename = swift_method.GetBasename(); - else if ((language == eLanguageTypeUnknown || - Language::LanguageIsCPlusPlus(language) || - Language::LanguageIsC(language) || - language == eLanguageTypeObjC_plus_plus) && - cpp_method.IsValid()) - basename = cpp_method.GetBasename(); #endif // LLDB_ENABLE_SWIFT + if ((language == eLanguageTypeUnknown || + Language::LanguageIsCFamily(language)) && + cpp_method.IsValid()) + basename = cpp_method.GetBasename(); if (basename.empty()) { if (CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index f6338351870da..dd6b12393b309 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -51,9 +51,9 @@ #include "lldb/Utility/StreamString.h" #include "lldb/lldb-private-types.h" -// BEGIN SWIFT +#ifdef LLDB_ENABLE_SWIFT #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" -// END SWIFT +#endif //LLDB_ENABLE_SWIFT #include "llvm/Support/Compiler.h" diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index 066108daae46a..6bd65f451bcc4 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -22,7 +22,9 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-types.h" +#ifdef LLDB_ENABLE_SWIFT #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" +#endif // LLDB_ENABLE_SWIFT #include namespace lldb_private { diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 87e2c82439392..b42c9cfafb4f2 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -2248,6 +2248,29 @@ bool DWARFExpression::Evaluate( } break; + // OPCODE: DW_OP_implicit_value + // OPERANDS: 2 + // ULEB128 size of the value block in bytes + // uint8_t* block bytes encoding value in target's memory + // representation + // DESCRIPTION: Value is immediately stored in block in the debug info with + // the memory representation of the target. + case DW_OP_implicit_value: { + const uint32_t len = opcodes.GetULEB128(&offset); + const void *data = opcodes.GetData(&offset, len); + + if (!data) { + LLDB_LOG(log, "Evaluate_DW_OP_implicit_value: could not be read data"); + LLDB_ERRORF(error_ptr, "Could not evaluate %s.", + DW_OP_value_to_name(op)); + return false; + } + + Value result(data, len); + stack.push_back(result); + break; + } + // OPCODE: DW_OP_push_object_address // OPERANDS: none // DESCRIPTION: Pushes the address of the object currently being diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index a142e547b7ed6..755e54308b3d4 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -25,7 +25,6 @@ #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/LanguageRuntime.h" -#include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" @@ -35,6 +34,10 @@ #include "lldb/../../source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "lldb/../../source/Plugins/ObjectFile/JIT/ObjectFileJIT.h" +#ifdef LLDB_ENABLE_SWIFT +#include "lldb/Target/SwiftLanguageRuntime.h" +#endif //LLDB_ENABLE_SWIFT + using namespace lldb_private; IRExecutionUnit::IRExecutionUnit(std::unique_ptr &context_up, diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 00ff4982be308..7f7f95f8f4677 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -23,7 +23,9 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" +#ifdef LLDB_ENABLE_SWIFT #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" +#endif //LLDB_ENABLE_SWIFT #include diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp index b011926ff8d13..47b07ac02f5c6 100644 --- a/lldb/source/Expression/REPL.cpp +++ b/lldb/source/Expression/REPL.cpp @@ -123,10 +123,11 @@ const char *REPL::IOHandlerGetHelpPrologue() { "Valid statements, expressions, and declarations are immediately " "compiled and executed.\n\n" "The complete set of LLDB debugging commands are also available as " - "described below. Commands " + "described below.\n\nCommands " "must be prefixed with a colon at the REPL prompt (:quit for " "example.) Typing just a colon " - "followed by return will switch to the LLDB prompt.\n\n"; + "followed by return will switch to the LLDB prompt.\n\n" + "Type “< path” to read in code from a text file “path”.\n\n"; } bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) { @@ -179,6 +180,36 @@ int REPL::IOHandlerFixIndentation(IOHandler &io_handler, return (int)desired_indent - actual_indent; } +static bool ReadCode(const std::string &path, std::string &code, + lldb::StreamFileSP &error_sp) { + auto &fs = FileSystem::Instance(); + llvm::Twine pathTwine(path); + if (!fs.Exists(pathTwine)) { + error_sp->Printf("no such file at path '%s'\n", path.c_str()); + return false; + } + if (!fs.Readable(pathTwine)) { + error_sp->Printf("could not read file at path '%s'\n", path.c_str()); + return false; + } + const size_t file_size = fs.GetByteSize(pathTwine); + const size_t max_size = code.max_size(); + if (file_size > max_size) { + error_sp->Printf("file at path '%s' too large: " + "file_size = %zu, max_size = %zu\n", + path.c_str(), file_size, max_size); + return false; + } + auto data_sp = fs.CreateDataBuffer(pathTwine); + if (data_sp == nullptr) { + error_sp->Printf("could not create buffer for file at path '%s'\n", + path.c_str()); + return false; + } + code.assign((const char *)data_sp->GetBytes(), data_sp->GetByteSize()); + return true; +} + void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) { lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); @@ -257,6 +288,15 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) { } } } else { + if (code[0] == '<') { + // User wants to read code from a file. + // Interpret rest of line as a literal path. + auto path = llvm::StringRef(code.substr(1)).trim().str(); + if (!ReadCode(path, code, error_sp)) { + return; + } + } + // Unwind any expression we might have been running in case our REPL // expression crashed and the user was looking around if (m_dedicated_repl_mode) { diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp index ab0fa5c476a58..0232aafcb04c0 100644 --- a/lldb/source/Expression/UserExpression.cpp +++ b/lldb/source/Expression/UserExpression.cpp @@ -44,7 +44,9 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#ifdef LLDB_ENABLE_SWIFT #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" +#endif //LLDB_ENABLE_SWIFT using namespace lldb_private; diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index b325bd2c5b745..5e06792e0fbf6 100644 --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -373,26 +373,19 @@ static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) { static std::string GetXcodeSDK(XcodeSDK sdk) { XcodeSDK::Info info = sdk.Parse(); std::string sdk_name = XcodeSDK::GetCanonicalName(info); - auto find_sdk = [](std::string sdk_name) -> std::string { - std::string xcrun_cmd; - std::string developer_dir = GetEnvDeveloperDir(); - if (developer_dir.empty()) - if (FileSpec fspec = HostInfo::GetShlibDir()) - if (FileSystem::Instance().Exists(fspec)) { - FileSpec path( - XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath())); - if (path.RemoveLastPathComponent()) - developer_dir = path.GetPath(); - } + + auto xcrun = [](const std::string &sdk, + llvm::StringRef developer_dir = "") -> std::string { + std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + sdk; if (!developer_dir.empty()) - xcrun_cmd = "/usr/bin/env DEVELOPER_DIR=\"" + developer_dir + "\" "; - xcrun_cmd += "xcrun --show-sdk-path --sdk " + sdk_name; + xcrun_cmd = "/usr/bin/env DEVELOPER_DIR=\"" + developer_dir.str() + + "\" " + xcrun_cmd; int status = 0; int signo = 0; std::string output_str; lldb_private::Status error = - Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + Host::RunShellCommand(xcrun_cmd, FileSpec(), &status, &signo, &output_str, std::chrono::seconds(15)); // Check that xcrun return something useful. @@ -414,6 +407,33 @@ FileSpec path( return output.str(); }; + auto find_sdk = [&xcrun](const std::string &sdk_name) -> std::string { + // Invoke xcrun with the developer dir specified in the environment. + std::string developer_dir = GetEnvDeveloperDir(); + if (!developer_dir.empty()) { + // Don't fallback if DEVELOPER_DIR was set. + return xcrun(sdk_name, developer_dir); + } + + // Invoke xcrun with the shlib dir. + if (FileSpec fspec = HostInfo::GetShlibDir()) { + if (FileSystem::Instance().Exists(fspec)) { + std::string contents_dir = + XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath()); + llvm::StringRef shlib_developer_dir = + llvm::sys::path::parent_path(contents_dir); + if (!shlib_developer_dir.empty()) { + std::string sdk = xcrun(sdk_name, std::move(shlib_developer_dir)); + if (!sdk.empty()) + return sdk; + } + } + } + + // Invoke xcrun without a developer dir as a last resort. + return xcrun(sdk_name); + }; + std::string path = find_sdk(sdk_name); while (path.empty()) { // Try an alternate spelling of the name ("macosx10.9internal"). diff --git a/lldb/source/Interpreter/CMakeLists.txt b/lldb/source/Interpreter/CMakeLists.txt index 0ed39869467ec..7a8c826d040cb 100644 --- a/lldb/source/Interpreter/CMakeLists.txt +++ b/lldb/source/Interpreter/CMakeLists.txt @@ -35,6 +35,7 @@ add_lldb_library(lldbInterpreter OptionValueChar.cpp OptionValueDictionary.cpp OptionValueEnumeration.cpp + OptionValueFileColonLine.cpp OptionValueFileSpec.cpp OptionValueFileSpecList.cpp OptionValueFormat.cpp diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 538f7a1ba6930..6f58b8ba0ea77 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -1064,6 +1064,7 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a list." }, { eArgTypeLanguage, "source-language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, nullptr }, { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { nullptr, false }, "Line number in a source file." }, + { eArgTypeFileLineColumn, "linespec", CommandCompletions::eNoCompletion, { nullptr, false }, "A source specifier in the form file:line[:column]" }, { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." }, { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." }, { eArgTypeMethod, "method", CommandCompletions::eNoCompletion, { nullptr, false }, "A C++ method name." }, diff --git a/lldb/source/Interpreter/OptionValue.cpp b/lldb/source/Interpreter/OptionValue.cpp index 2e3974b310198..0bd9a591af678 100644 --- a/lldb/source/Interpreter/OptionValue.cpp +++ b/lldb/source/Interpreter/OptionValue.cpp @@ -471,6 +471,8 @@ const char *OptionValue::GetBuiltinTypeAsCString(Type t) { return "dictionary"; case eTypeEnum: return "enum"; + case eTypeFileLineColumn: + return "file:line:column specifier"; case eTypeFileSpec: return "file"; case eTypeFileSpecList: diff --git a/lldb/source/Interpreter/OptionValueArray.cpp b/lldb/source/Interpreter/OptionValueArray.cpp index 9be11e32e2dbc..0b293ccfc248f 100644 --- a/lldb/source/Interpreter/OptionValueArray.cpp +++ b/lldb/source/Interpreter/OptionValueArray.cpp @@ -52,6 +52,7 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm, case eTypeChar: case eTypeEnum: case eTypeFileSpec: + case eTypeFileLineColumn: case eTypeFormat: case eTypeSInt64: case eTypeString: diff --git a/lldb/source/Interpreter/OptionValueDictionary.cpp b/lldb/source/Interpreter/OptionValueDictionary.cpp index caadccd042329..79323f502d179 100644 --- a/lldb/source/Interpreter/OptionValueDictionary.cpp +++ b/lldb/source/Interpreter/OptionValueDictionary.cpp @@ -62,6 +62,7 @@ void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx, case eTypeBoolean: case eTypeChar: case eTypeEnum: + case eTypeFileLineColumn: case eTypeFileSpec: case eTypeFormat: case eTypeSInt64: diff --git a/lldb/source/Interpreter/OptionValueFileColonLine.cpp b/lldb/source/Interpreter/OptionValueFileColonLine.cpp new file mode 100644 index 0000000000000..dac557c4248aa --- /dev/null +++ b/lldb/source/Interpreter/OptionValueFileColonLine.cpp @@ -0,0 +1,145 @@ +//===-- OptionValueFileColonLine.cpp---------------------------------------===// +// +// 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 "lldb/Interpreter/OptionValueFileColonLine.h" + +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Utility/Args.h" +#include "lldb/Utility/State.h" + +using namespace lldb; +using namespace lldb_private; + +// This is an OptionValue for parsing file:line:column specifications. +// I set the completer to "source file" which isn't quite right, but we can +// only usefully complete in the file name part of it so it should be good +// enough. +OptionValueFileColonLine::OptionValueFileColonLine() + : OptionValue(), m_file_spec(), m_line_number(LLDB_INVALID_LINE_NUMBER), + m_column_number(LLDB_INVALID_COLUMN_NUMBER), + m_completion_mask(CommandCompletions::eSourceFileCompletion) {} + +OptionValueFileColonLine::OptionValueFileColonLine(llvm::StringRef input) + : OptionValue(), m_file_spec(), m_line_number(LLDB_INVALID_LINE_NUMBER), + m_column_number(LLDB_INVALID_COLUMN_NUMBER), + m_completion_mask(CommandCompletions::eSourceFileCompletion) { + SetValueFromString(input, eVarSetOperationAssign); +} + +void OptionValueFileColonLine::DumpValue(const ExecutionContext *exe_ctx, + Stream &strm, uint32_t dump_mask) { + if (dump_mask & eDumpOptionType) + strm.Printf("(%s)", GetTypeAsCString()); + if (dump_mask & eDumpOptionValue) { + if (dump_mask & eDumpOptionType) + strm.PutCString(" = "); + + if (m_file_spec) + strm << '"' << m_file_spec.GetPath().c_str() << '"'; + if (m_line_number != LLDB_INVALID_LINE_NUMBER) + strm.Printf(":%d", m_line_number); + if (m_column_number != LLDB_INVALID_COLUMN_NUMBER) + strm.Printf(":%d", m_column_number); + } +} + +Status OptionValueFileColonLine::SetValueFromString(llvm::StringRef value, + VarSetOperationType op) { + Status error; + switch (op) { + case eVarSetOperationClear: + Clear(); + NotifyValueChanged(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (value.size() > 0) { + // This is in the form filename:linenumber:column. + // I wish we could use filename:linenumber.column, that would make the + // parsing unambiguous and so much easier... + // But clang & gcc both print the output with two : so we're stuck with + // the two colons. Practically, the only actual ambiguity this introduces + // is with files like "foo:10", which doesn't seem terribly likely. + + // Providing the column is optional, so the input value might have one or + // two colons. First pick off the last colon separated piece. + // It has to be there, since the line number is required: + llvm::StringRef last_piece; + llvm::StringRef left_of_last_piece; + + std::tie(left_of_last_piece, last_piece) = value.rsplit(':'); + if (last_piece.empty()) { + error.SetErrorStringWithFormat("Line specifier must include file and " + "line: '%s'", + value.str().c_str()); + return error; + } + + // Now see if there's another colon and if so pull out the middle piece: + // Then check whether the middle piece is an integer. If it is, then it + // was the line number, and if it isn't we're going to assume that there + // was a colon in the filename (see note at the beginning of the function) + // and ignore it. + llvm::StringRef file_name; + llvm::StringRef middle_piece; + + std::tie(file_name, middle_piece) = left_of_last_piece.rsplit(':'); + if (middle_piece.empty() || !llvm::to_integer(middle_piece, + m_line_number)) { + // The middle piece was empty or not an integer, so there were only two + // legit pieces; our original division was right. Reassign the file + // name and pull out the line number: + file_name = left_of_last_piece; + if (!llvm::to_integer(last_piece, m_line_number)) { + error.SetErrorStringWithFormat("Bad line number value '%s' in: '%s'", + last_piece.str().c_str(), + value.str().c_str()); + return error; + } + } else { + // There were three pieces, and we've got the line number. So now + // we just need to check the column number which was the last peice. + if (!llvm::to_integer(last_piece, m_column_number)) { + error.SetErrorStringWithFormat("Bad column value '%s' in: '%s'", + last_piece.str().c_str(), + value.str().c_str()); + return error; + } + } + + m_value_was_set = true; + m_file_spec.SetFile(file_name, FileSpec::Style::native); + NotifyValueChanged(); + } else { + error.SetErrorString("invalid value string"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromString(value, op); + break; + } + return error; +} + +lldb::OptionValueSP OptionValueFileColonLine::DeepCopy() const { + return OptionValueSP(new OptionValueFileColonLine(*this)); +} + +void OptionValueFileColonLine::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { + CommandCompletions::InvokeCommonCompletionCallbacks( + interpreter, m_completion_mask, request, nullptr); +} diff --git a/lldb/source/Interpreter/OptionValueFileSpec.cpp b/lldb/source/Interpreter/OptionValueFileSpec.cpp index 15acb7e5e5b08..a03fd55d0385a 100644 --- a/lldb/source/Interpreter/OptionValueFileSpec.cpp +++ b/lldb/source/Interpreter/OptionValueFileSpec.cpp @@ -64,13 +64,6 @@ Status OptionValueFileSpec::SetValueFromString(llvm::StringRef value, case eVarSetOperationReplace: case eVarSetOperationAssign: if (value.size() > 0) { - // The setting value may have whitespace, double-quotes, or single-quotes - // around the file path to indicate that internal spaces are not word - // breaks. Strip off any ws & quotes from the start and end of the file - // path - we aren't doing any word // breaking here so the quoting is - // unnecessary. NB this will cause a problem if someone tries to specify - // a file path that legitimately begins or ends with a " or ' character, - // or whitespace. value = value.trim("\"' \t"); m_value_was_set = true; m_current_value.SetFile(value.str(), FileSpec::Style::native); diff --git a/lldb/source/Interpreter/OptionValueFormatEntity.cpp b/lldb/source/Interpreter/OptionValueFormatEntity.cpp index 3a32a4721b68e..509a21752e480 100644 --- a/lldb/source/Interpreter/OptionValueFormatEntity.cpp +++ b/lldb/source/Interpreter/OptionValueFormatEntity.cpp @@ -29,11 +29,10 @@ OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) } } -bool OptionValueFormatEntity::Clear() { +void OptionValueFormatEntity::Clear() { m_current_entry = m_default_entry; m_current_format = m_default_format; m_value_was_set = false; - return true; } static void EscapeBackticks(llvm::StringRef str, std::string &dst) { diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp index 24cda056977ea..5b82008ca5717 100644 --- a/lldb/source/Interpreter/OptionValueProperties.cpp +++ b/lldb/source/Interpreter/OptionValueProperties.cpp @@ -517,11 +517,10 @@ bool OptionValueProperties::SetPropertyAtIndexAsUInt64( return false; } -bool OptionValueProperties::Clear() { +void OptionValueProperties::Clear() { const size_t num_properties = m_properties.size(); for (size_t i = 0; i < num_properties; ++i) m_properties[i].GetValue()->Clear(); - return true; } Status OptionValueProperties::SetValueFromString(llvm::StringRef value, diff --git a/lldb/source/Interpreter/Property.cpp b/lldb/source/Interpreter/Property.cpp index 9238112498533..a02497662ff5f 100644 --- a/lldb/source/Interpreter/Property.cpp +++ b/lldb/source/Interpreter/Property.cpp @@ -99,6 +99,12 @@ Property::Property(const PropertyDefinition &definition) } break; + case OptionValue::eTypeFileLineColumn: + // "definition.default_uint_value" is not used for a + // OptionValue::eTypeFileSpecList + m_value_sp = std::make_shared(); + break; + case OptionValue::eTypeFileSpec: { // "definition.default_uint_value" represents if the // "definition.default_cstr_value" should be resolved or not diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 68a0335682d3a..d0d5a99b28edc 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -517,12 +517,8 @@ DynamicLoaderDarwinKernel::DynamicLoaderDarwinKernel(Process *process, Status error; PlatformSP platform_sp( Platform::Create(PlatformDarwinKernel::GetPluginNameStatic(), error)); - // Only select the darwin-kernel Platform if we've been asked to load kexts. - // It can take some time to scan over all of the kext info.plists and that - // shouldn't be done if kext loading is explicitly disabled. - if (platform_sp.get() && GetGlobalProperties()->GetLoadKexts()) { + if (platform_sp.get()) process->GetTarget().SetPlatform(platform_sp); - } } // Destructor diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index c1bc0d53fa08a..bba770312127b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" @@ -125,6 +126,12 @@ void ClangExpressionDeclMap::InstallCodeGenerator( m_parser_vars->m_code_gen = code_gen; } +void ClangExpressionDeclMap::InstallDiagnosticManager( + DiagnosticManager &diag_manager) { + assert(m_parser_vars); + m_parser_vars->m_diagnostics = &diag_manager; +} + void ClangExpressionDeclMap::DidParse() { if (m_parser_vars && m_parser_vars->m_persistent_vars) { for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); @@ -196,6 +203,17 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (ast == nullptr) return false; + // Check if we already declared a persistent variable with the same name. + if (lldb::ExpressionVariableSP conflicting_var = + m_parser_vars->m_persistent_vars->GetVariable(name)) { + std::string msg = llvm::formatv("redefinition of persistent variable '{0}'", + name).str(); + m_parser_vars->m_diagnostics->AddDiagnostic( + msg, DiagnosticSeverity::eDiagnosticSeverityError, + DiagnosticOrigin::eDiagnosticOriginLLDB); + return false; + } + if (m_parser_vars->m_materializer && is_result) { Status err; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 6974535a89934..0c81d46c6c528 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -102,6 +102,8 @@ class ClangExpressionDeclMap : public ClangASTSource { void InstallCodeGenerator(clang::ASTConsumer *code_gen); + void InstallDiagnosticManager(DiagnosticManager &diag_manager); + /// Disable the state needed for parsing and IR transformation. void DidParse(); @@ -330,6 +332,8 @@ class ClangExpressionDeclMap : public ClangASTSource { clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator ///that receives new top-level ///functions. + DiagnosticManager *m_diagnostics = nullptr; + private: ParserVars(const ParserVars &) = delete; const ParserVars &operator=(const ParserVars &) = delete; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 202eb87cca3d0..68446a3d181c7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -1074,6 +1074,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer()); + decl_map->InstallDiagnosticManager(diagnostic_manager); clang::ExternalASTSource *ast_source = decl_map->CreateProxy(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 8abb7e4205757..b76fa6fbf690c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -137,14 +137,12 @@ bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSystem::Instance().Resolve(file_spec); return true; } - raw_path = lldb_shlib_spec.GetPath(); } - raw_path.resize(rev_it - r_end); - } else { - raw_path.resize(rev_it - r_end); } // Fall back to the Clang resource directory inside the framework. + raw_path = lldb_shlib_spec.GetPath(); + raw_path.resize(rev_it - r_end); raw_path.append("LLDB.framework/Resources/Clang"); file_spec.GetDirectory().SetString(raw_path.c_str()); FileSystem::Instance().Resolve(file_spec); diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp index 4008a62dce9e4..7b733d6cfec04 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp @@ -15,6 +15,7 @@ #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" #include "lldb/Expression/ExpressionParser.h" #include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Log.h" @@ -1021,11 +1022,6 @@ GetPatternBindingForVarDecl(swift::VarDecl *var_decl, return pattern_binding; } -static inline swift::Type GetSwiftType(CompilerType type) { - return swift::Type( - reinterpret_cast(type.GetOpaqueQualType())); -} - bool SwiftASTManipulator::AddExternalVariables( llvm::MutableArrayRef variables) { if (!IsValid()) @@ -1331,21 +1327,15 @@ swift::ValueDecl *SwiftASTManipulator::MakeGlobalTypealias( if (!IsValid()) return nullptr; - swift::SourceLoc source_loc; - - if (m_extension_decl) - source_loc = m_extension_decl->getEndLoc(); - else - source_loc = m_function_decl->getEndLoc(); - swift::ASTContext &ast_context = m_source_file.getASTContext(); swift::TypeAliasDecl *type_alias_decl = new (ast_context) - swift::TypeAliasDecl(source_loc, swift::SourceLoc(), name, source_loc, - nullptr, &m_source_file); + swift::TypeAliasDecl(swift::SourceLoc(), swift::SourceLoc(), name, + swift::SourceLoc(), nullptr, &m_source_file); swift::Type underlying_type = GetSwiftType(type); type_alias_decl->setUnderlyingType(underlying_type); type_alias_decl->markAsDebuggerAlias(true); + type_alias_decl->setImplicit(true); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (log) { diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index c2a5240d7d5ad..c503deb86b86e 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -55,17 +55,18 @@ #include "clang/Rewrite/Core/RewriteBuffer.h" #include "swift/AST/ASTContext.h" -#include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticConsumer.h" +#include "swift/AST/DiagnosticEngine.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/IRGenRequests.h" +#include "swift/AST/Import.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" -#include "swift/Demangling/Demangle.h" +#include "swift/Basic/OptimizationMode.h" #include "swift/Basic/PrimarySpecificPaths.h" #include "swift/Basic/SourceManager.h" -#include "swift/Basic/OptimizationMode.h" #include "swift/ClangImporter/ClangImporter.h" +#include "swift/Demangling/Demangle.h" #include "swift/Frontend/Frontend.h" #include "swift/Parse/LocalContext.h" #include "swift/Parse/PersistentParserState.h" @@ -447,10 +448,10 @@ class LLDBREPLNameLookup : public LLDBNameLookup { }; }; // END Anonymous namespace -static void -AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp, - SwiftASTContextForExpressions &swift_ast_context, - SwiftASTManipulator &manipulator) { +static void AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp, + SwiftASTContextForExpressions &swift_ast_context, + SwiftASTManipulator &manipulator, + lldb::DynamicValueType use_dynamic) { // First emit the typealias for "$__lldb_context". if (!block) return; @@ -480,7 +481,7 @@ AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp, if (stack_frame_sp) { lldb::ValueObjectSP valobj_sp = stack_frame_sp->GetValueObjectForFrameVariable(self_var_sp, - lldb::eNoDynamicValues); + use_dynamic); if (valobj_sp) self_type = valobj_sp->GetCompilerType(); @@ -576,19 +577,36 @@ AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp, } } +/// Returns the Swift type for a ValueObject representing a variable. +/// An invalid CompilerType is returned on error. +static CompilerType GetSwiftTypeForVariableValueObject( + lldb::ValueObjectSP valobj_sp, lldb::StackFrameSP &stack_frame_sp, + SwiftLanguageRuntime *runtime, bool use_dynamic_value) { + // Check that the passed ValueObject is valid. + if (!valobj_sp || valobj_sp->GetError().Fail()) + return CompilerType(); + CompilerType result = valobj_sp->GetCompilerType(); + if (use_dynamic_value) + result = runtime->BindGenericTypeParameters(*stack_frame_sp, result); + if (!result.GetTypeSystem()->SupportsLanguage(lldb::eLanguageTypeSwift)) + return CompilerType(); + return result; +} + /// Create a \c VariableInfo record for \c variable if there isn't /// already shadowing inner declaration in \c processed_variables. -static void AddVariableInfo( +static llvm::Optional AddVariableInfo( lldb::VariableSP variable_sp, lldb::StackFrameSP &stack_frame_sp, SwiftASTContextForExpressions &ast_context, - SwiftLanguageRuntime *language_runtime, + SwiftLanguageRuntime *runtime, llvm::SmallDenseSet &processed_variables, - llvm::SmallVectorImpl &local_variables) { + llvm::SmallVectorImpl &local_variables, + lldb::DynamicValueType use_dynamic) { StringRef name = variable_sp->GetUnqualifiedName().GetStringRef(); const char *name_cstr = name.data(); assert(StringRef(name_cstr) == name && "missing null terminator"); if (name.empty()) - return; + return {}; // To support "guard let self = self" the function argument "self" // is processed (as the special self argument) even if it is @@ -599,45 +617,39 @@ static void AddVariableInfo( overridden_name = "$__lldb_injected_self"; if (processed_variables.count(overridden_name)) - return; + return {}; - CompilerType var_type; - if (stack_frame_sp) { - lldb::ValueObjectSP valobj_sp = - stack_frame_sp->GetValueObjectForFrameVariable(variable_sp, - lldb::eNoDynamicValues); + if (!stack_frame_sp) + return llvm::None; - if (!valobj_sp || valobj_sp->GetError().Fail()) { - // Ignore the variable if we couldn't find its corresponding - // value object. TODO if the expression tries to use an - // ignored variable, produce a sensible error. - return; - } - var_type = valobj_sp->GetCompilerType(); - } + lldb::ValueObjectSP valobj_sp = + stack_frame_sp->GetValueObjectForFrameVariable(variable_sp, + lldb::eNoDynamicValues); - if (!var_type.IsValid()) - if (Type *var_lldb_type = variable_sp->GetType()) - var_type = var_lldb_type->GetFullCompilerType(); + const bool use_dynamic_value = use_dynamic > lldb::eNoDynamicValues; - if (!var_type.IsValid()) - return; + CompilerType var_type = GetSwiftTypeForVariableValueObject( + valobj_sp, stack_frame_sp, runtime, use_dynamic_value); - if (!var_type.GetTypeSystem()->SupportsLanguage(lldb::eLanguageTypeSwift)) - return; + if (!var_type.IsValid()) + return {}; + + // If the type can't be realized and dynamic types are allowed, fall back to + // the dynamic type. + if (!SwiftASTContext::IsFullyRealized(var_type) && use_dynamic_value) { + var_type = GetSwiftTypeForVariableValueObject( + valobj_sp->GetDynamicValue(use_dynamic), stack_frame_sp, runtime, + use_dynamic_value); + if (!var_type.IsValid()) + return {}; + } Status error; CompilerType target_type = ast_context.ImportType(var_type, error); // If the import failed, give up. if (!target_type.IsValid()) - return; - - // Resolve all archetypes in the variable type. - if (stack_frame_sp) - if (language_runtime) - target_type = language_runtime->BindGenericTypeParameters(*stack_frame_sp, - target_type); + return {}; // If we couldn't fully realize the type, then we aren't going // to get very far making a local out of it, so discard it here. @@ -647,8 +659,17 @@ static void AddVariableInfo( if (log) log->Printf("Discarding local %s because we couldn't fully realize it, " "our best attempt was: %s.", - name_cstr, target_type.GetTypeName().AsCString("")); - return; + name_cstr, target_type.GetDisplayTypeName().AsCString("")); + // Not realizing self is a fatal error for an expression and the + // Swift compiler error alone is not particularly useful. + if (is_self) + return make_error( + inconvertibleErrorCode(), + llvm::Twine("Couldn't realize type of self.") + + (use_dynamic + ? "" + : " Try evaluating the expression with -d run-target")); + return {}; } if (log && is_self) @@ -661,8 +682,27 @@ static void AddVariableInfo( static_cast(swift_type.getPointer()), static_cast(ast_context.GetASTContext()), s.c_str()); } + // A one-off clone of variable_sp with the type replaced by target_type. + auto patched_variable_sp = std::make_shared( + 0, variable_sp->GetName().GetCString(), "", + std::make_shared( + *variable_sp->GetType()->GetSymbolFile(), + std::make_shared( + 0, variable_sp->GetType()->GetSymbolFile(), + variable_sp->GetType()->GetName(), llvm::None, + variable_sp->GetType()->GetSymbolContextScope(), LLDB_INVALID_UID, + Type::eEncodingIsUID, variable_sp->GetType()->GetDeclaration(), + target_type, lldb_private::Type::ResolveState::Full, + variable_sp->GetType()->GetPayload())), + variable_sp->GetScope(), variable_sp->GetSymbolContextScope(), + variable_sp->GetScopeRange(), + const_cast(&variable_sp->GetDeclaration()), + variable_sp->LocationExpression(), variable_sp->IsExternal(), + variable_sp->IsArtificial(), + variable_sp->GetLocationIsConstantValueData(), + variable_sp->IsStaticMember(), variable_sp->IsConstant()); SwiftASTManipulatorBase::VariableMetadataSP metadata_sp( - new VariableMetadataVariable(variable_sp)); + new VariableMetadataVariable(patched_variable_sp)); SwiftASTManipulator::VariableInfo variable_info( target_type, ast_context.GetASTContext()->getIdentifier(overridden_name), metadata_sp, @@ -671,15 +711,17 @@ static void AddVariableInfo( local_variables.push_back(variable_info); processed_variables.insert(overridden_name); + return {}; } /// Create a \c VariableInfo record for each visible variable. -static void RegisterAllVariables( +static llvm::Optional RegisterAllVariables( SymbolContext &sc, lldb::StackFrameSP &stack_frame_sp, SwiftASTContextForExpressions &ast_context, - llvm::SmallVectorImpl &local_variables) { + llvm::SmallVectorImpl &local_variables, + lldb::DynamicValueType use_dynamic) { if (!sc.block && !sc.function) - return; + return {}; Block *block = sc.block; Block *top_block = block->GetContainingInlinedBlock(); @@ -734,9 +776,11 @@ static void RegisterAllVariables( } for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi) - AddVariableInfo({variables.GetVariableAtIndex(vi)}, stack_frame_sp, - ast_context, language_runtime, processed_names, - local_variables); + if (auto error = AddVariableInfo( + {variables.GetVariableAtIndex(vi)}, stack_frame_sp, ast_context, + language_runtime, processed_names, local_variables, use_dynamic)) + return error; + return {}; } static void ResolveSpecialNames( @@ -927,6 +971,23 @@ CreateMainFile(SwiftASTContextForExpressions &swift_ast_context, return {buffer_id, filename.str()}; } +/// Determine whether this type was defined inside an LLDB expression. +template bool FromLLDBModuleImpl(TypeType *type) { + if (auto *decl = type->getDecl()) + if (auto *module = decl->getModuleContext()) + return module->getName().str().startswith("__lldb_expr_"); + return false; +}; + +/// Determine whether this type was defined inside an LLDB expression. +static bool FromLLDBModule(swift::TypeBase *type) { + if (auto *type_alias = llvm::dyn_cast(type)) + return FromLLDBModuleImpl(type_alias); + if (auto *nominal = llvm::dyn_cast(type)) + return FromLLDBModuleImpl(nominal); + return false; +} + /// Attempt to materialize one variable. static llvm::Optional MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable, @@ -964,23 +1025,7 @@ MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable, } } } else { - CompilerType actual_type(variable.GetType()); - auto orig_swift_type = GetSwiftType(actual_type); - auto *swift_type = orig_swift_type->mapTypeOutOfContext().getPointer(); - actual_type = ToCompilerType(swift_type); - lldb::StackFrameSP stack_frame_sp = stack_frame_wp.lock(); - if (swift_type->hasTypeParameter()) { - if (stack_frame_sp && stack_frame_sp->GetThread() && - stack_frame_sp->GetThread()->GetProcess()) { - auto *swift_runtime = SwiftLanguageRuntime::Get( - stack_frame_sp->GetThread()->GetProcess()); - if (swift_runtime) { - actual_type = swift_runtime->BindGenericTypeParameters( - *stack_frame_sp, actual_type); - } - } - } - + CompilerType actual_type = variable.GetType(); // Desugar '$lldb_context', etc. auto transformed_type = GetSwiftType(actual_type).transform( [](swift::Type t) -> swift::Type { @@ -991,7 +1036,19 @@ MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable, } return t; }); - actual_type = ToCompilerType(transformed_type.getPointer()); + actual_type = + ToCompilerType(transformed_type->mapTypeOutOfContext().getPointer()); + auto *swift_ast_ctx = + llvm::cast(actual_type.GetTypeSystem()); + + // Currently the Swift runtime cannot resolve types that were + // defined in the expression evaluator. That's because we don't + // tell it about type metadata sections that were JIT-compiled + // by the expression evaluator. Until that is implemented, fall + // back to SwiftASTContext. + if (!FromLLDBModule(transformed_type.getPointer())) + actual_type = + swift_ast_ctx->GetTypeRefType(actual_type.GetOpaqueQualType()); if (is_result) offset = materializer.AddResultVariable( @@ -1019,9 +1076,6 @@ MaterializeVariable(SwiftASTManipulatorBase::VariableInfo &variable, VariableMetadataVariable *variable_metadata = static_cast(variable.m_metadata.get()); - // FIXME: It would be nice if we could do something like - // variable_metadata->m_variable_sp->SetType(variable.GetType()) - // here. offset = materializer.AddVariable(variable_metadata->m_variable_sp, error); if (!error.Success()) { @@ -1147,6 +1201,7 @@ static llvm::Expected ParseAndImport( lldb::StackFrameWP &stack_frame_wp, SymbolContext &sc, ExecutionContextScope &exe_scope, const EvaluateExpressionOptions &options, bool repl, bool playground) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); auto should_disable_objc_runtime = [&]() { lldb::StackFrameSP this_frame_sp(stack_frame_wp.lock()); @@ -1172,7 +1227,20 @@ static llvm::Expected ParseAndImport( if (playground) { auto *persistent_state = sc.target_sp->GetSwiftPersistentExpressionState(exe_scope); - persistent_state->AddHandLoadedModule(ConstString("Swift")); + + Status error; + SourceModule module_info; + module_info.path.emplace_back("Swift"); + swift::ModuleDecl *module = + swift_ast_context->GetModule(module_info, error); + + if (error.Fail() || !module) { + LLDB_LOG(log, "couldn't load Swift Standard Library\n"); + return error.ToError(); + } + + persistent_state->AddHandLoadedModule(ConstString("Swift"), + swift::ImportedModule(module)); } std::string main_filename; @@ -1188,7 +1256,8 @@ static llvm::Expected ParseAndImport( // The Swift stdlib needs to be imported before the SwiftLanguageRuntime can // be used. Status implicit_import_error; - llvm::SmallVector additional_imports; + llvm::SmallVector, 16> + additional_imports; if (!SwiftASTContext::GetImplicitImports(*swift_ast_context, sc, exe_scope, stack_frame_wp, additional_imports, implicit_import_error)) { @@ -1198,8 +1267,8 @@ static llvm::Expected ParseAndImport( swift::ImplicitImportInfo importInfo; importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib; - for (auto *module : additional_imports) - importInfo.AdditionalModules.emplace_back(module, /*exported*/ false); + for (auto &attributed_import : additional_imports) + importInfo.AdditionalImports.emplace_back(attributed_import); auto module_id = ast_context->getIdentifier(expr_name_buf); auto &module = *swift::ModuleDecl::create(module_id, *ast_context, @@ -1302,11 +1371,12 @@ static llvm::Expected ParseAndImport( if (local_context_is_swift) { AddRequiredAliases(sc.block, stack_frame_sp, *swift_ast_context, - *code_manipulator); + *code_manipulator, options.GetUseDynamic()); // Register all local variables so that lookups to them resolve. - RegisterAllVariables(sc, stack_frame_sp, *swift_ast_context, - local_variables); + if (auto error = RegisterAllVariables(sc, stack_frame_sp, *swift_ast_context, + local_variables, options.GetUseDynamic())) + return std::move(*error); } // Register all magic variables. diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.h b/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.h index ad8b54eb0967b..176155098e62a 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.h +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.h @@ -15,10 +15,13 @@ #include "SwiftExpressionVariable.h" +#include "swift/AST/Import.h" +#include "swift/AST/Module.h" + #include "lldb/Core/SwiftForward.h" #include "lldb/Expression/ExpressionVariable.h" -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include @@ -38,7 +41,9 @@ namespace lldb_private { /// 0-based counter for naming result variables. //---------------------------------------------------------------------- class SwiftPersistentExpressionState : public PersistentExpressionState { - typedef std::set HandLoadedModuleSet; + + typedef llvm::StringMap> + HandLoadedModuleSet; public: class SwiftDeclMap { @@ -118,8 +123,11 @@ class SwiftPersistentExpressionState : public PersistentExpressionState { // This just adds this module to the list of hand-loaded modules, it doesn't // actually load it. - void AddHandLoadedModule(ConstString module_name) { - m_hand_loaded_modules.insert(module_name); + void AddHandLoadedModule( + ConstString module_name, + swift::AttributedImport attributed_import) { + m_hand_loaded_modules.insert_or_assign(module_name.GetStringRef(), + attributed_import); } /// This returns the list of hand-loaded modules. diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp index 78ad560531bdd..aa97390f3a4b0 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp @@ -285,8 +285,38 @@ bool SwiftUserExpression::Parse(DiagnosticManager &diagnostic_manager, "couldn't start parsing (no target)"); return false; } + + StackFrame *frame = exe_ctx.GetFramePtr(); + if (!frame) { + LLDB_LOG(log, "no stack frame"); + return false; + } + + // Make sure the target's SwiftASTContext has been setup before doing any + // Swift name lookups. + llvm::Optional maybe_swift_ast_ctx = + target->GetScratchSwiftASTContext(err, *frame); + if (!maybe_swift_ast_ctx) { + LLDB_LOG(log, "no Swift AST Context"); + return false; + } + + SwiftASTContext *swift_ast_ctx = maybe_swift_ast_ctx->get(); + if (auto *persistent_state = GetPersistentState(target, exe_ctx)) { - persistent_state->AddHandLoadedModule(ConstString("Swift")); + + Status error; + SourceModule module_info; + module_info.path.emplace_back("Swift"); + swift::ModuleDecl *module = swift_ast_ctx->GetModule(module_info, error); + + if (error.Fail() || !module) { + LLDB_LOG(log, "couldn't load Swift Standard Library\n"); + return false; + } + + persistent_state->AddHandLoadedModule(ConstString("Swift"), + swift::ImportedModule(module)); m_result_delegate.RegisterPersistentState(persistent_state); m_error_delegate.RegisterPersistentState(persistent_state); } else { diff --git a/lldb/source/Plugins/Language/Swift/SwiftCodeCompletion.cpp b/lldb/source/Plugins/Language/Swift/SwiftCodeCompletion.cpp index c257624ff25ed..44be479e12723 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftCodeCompletion.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftCodeCompletion.cpp @@ -207,14 +207,15 @@ SwiftCompleteCode(SwiftASTContext &SwiftCtx, // in previous REPL executions. swift::ImplicitImportInfo importInfo; importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib; - for (const ConstString moduleName : + for (const auto& entry: PersistentExpressionState.GetHandLoadedModules()) { SourceModule moduleInfo; - moduleInfo.path.push_back(moduleName); + moduleInfo.path.push_back(ConstString(entry.getKey())); ModuleDecl *module = SwiftCtx.GetModule(moduleInfo, error); if (!module) continue; - importInfo.AdditionalModules.emplace_back(module, /*exported*/ false); + importInfo.AdditionalImports.emplace_back(swift::ImportedModule(module), + swift::ImportOptions()); } // Set up the following AST: diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 8aa803a8553e9..d3a25f37985f1 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -154,6 +154,9 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( member__f_ = sub_member__f_; } + if (!member__f_) + return optional_info; + lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); optional_info.member__f_pointer_value = member__f_pointer_value; diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 76f6d7ad0d78a..77ca511bd7cf1 100644 --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -3,4 +3,4 @@ add_subdirectory(ELF) add_subdirectory(Mach-O) add_subdirectory(PECOFF) add_subdirectory(JIT) -add_subdirectory(wasm) \ No newline at end of file +add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index e038a66b910ea..3a08a6eeb6de9 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -40,7 +40,10 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MipsABIFlags.h" + +#ifdef LLDB_ENABLE_SWIFT #include "swift/ABI/ObjectFile.h" +#endif //LLDB_ENABLE_SWIFT #define CASE_AND_STREAM(s, def, width) \ case def: \ @@ -3409,6 +3412,10 @@ ObjectFileELF::GetLoadableData(Target &target) { llvm::StringRef ObjectFileELF::GetReflectionSectionIdentifier( swift::ReflectionSectionKind section) { +#ifdef LLDB_ENABLE_SWIFT swift::SwiftObjectFileFormatELF file_format_elf; return file_format_elf.getSectionName(section); +#else + llvm_unreachable("Swift support disabled"); +#endif //LLDB_ENABLE_SWIFT } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 4b87cebe786c4..0ebcd9c8b4958 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -27,7 +27,6 @@ #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" -#include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadList.h" @@ -47,7 +46,10 @@ #include "llvm/Support/MemoryBuffer.h" #include "ObjectFileMachO.h" +#ifdef LLDB_ENABLE_SWIFT #include "swift/ABI/ObjectFile.h" +#include "lldb/Target/SwiftLanguageRuntime.h" +#endif //LLDB_ENABLE_SWIFT #if defined(__APPLE__) #include @@ -5548,7 +5550,8 @@ std::string ObjectFileMachO::GetIdentifierString() { return result; } -bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) { +bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid, + ObjectFile::BinaryType &type) { address = LLDB_INVALID_ADDRESS; uuid.Clear(); ModuleSP module_sp(GetModule()); @@ -5571,24 +5574,43 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) { // "main bin spec" (main binary specification) data payload is // formatted: // uint32_t version [currently 1] - // uint32_t type [0 == unspecified, 1 == kernel, 2 == user - // process] uint64_t address [ UINT64_MAX if address not - // specified ] uuid_t uuid [ all zero's if uuid not - // specified ] uint32_t log2_pagesize [ process page size in log base - // 2, e.g. 4k pages are 12. 0 for unspecified ] + // uint32_t type [0 == unspecified, 1 == kernel, + // 2 == user process, 3 == firmware ] + // uint64_t address [ UINT64_MAX if address not specified ] + // uuid_t uuid [ all zero's if uuid not specified ] + // uint32_t log2_pagesize [ process page size in log base + // 2, e.g. 4k pages are 12. + // 0 for unspecified ] + // uint32_t unused [ for alignment ] if (strcmp("main bin spec", data_owner) == 0 && size >= 32) { offset = fileoff; uint32_t version; if (m_data.GetU32(&offset, &version, 1) != nullptr && version == 1) { - uint32_t type = 0; + uint32_t binspec_type = 0; uuid_t raw_uuid; memset(raw_uuid, 0, sizeof(uuid_t)); - if (m_data.GetU32(&offset, &type, 1) && + if (m_data.GetU32(&offset, &binspec_type, 1) && m_data.GetU64(&offset, &address, 1) && m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) { uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t)); + // convert the "main bin spec" type into our + // ObjectFile::BinaryType enum + switch (binspec_type) { + case 0: + type = eBinaryTypeUnknown; + break; + case 1: + type = eBinaryTypeKernel; + break; + case 2: + type = eBinaryTypeUser; + break; + case 3: + type = eBinaryTypeStandalone; + break; + } return true; } } @@ -6454,6 +6476,10 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, llvm::StringRef ObjectFileMachO::GetReflectionSectionIdentifier( swift::ReflectionSectionKind section) { +#ifdef LLDB_ENABLE_SWIFT swift::SwiftObjectFileFormatMachO file_format_mach_o; return file_format_mach_o.getSectionName(section); +#else + llvm_unreachable("Swift support disabled"); +#endif //LLDB_ENABLE_SWIFT } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 8f316879b555f..14adbaf952ebe 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -112,7 +112,9 @@ class ObjectFileMachO : public lldb_private::ObjectFile { std::string GetIdentifierString() override; - bool GetCorefileMainBinaryInfo (lldb::addr_t &address, lldb_private::UUID &uuid) override; + bool GetCorefileMainBinaryInfo(lldb::addr_t &address, + lldb_private::UUID &uuid, + ObjectFile::BinaryType &type) override; lldb::RegisterContextSP GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 095426985f0eb..c966190c536bf 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -33,7 +33,9 @@ #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" +#ifdef LLDB_ENABLE_SWIFT #include "swift/ABI/ObjectFile.h" +#endif //LLDB_ENABLE_SWIFT #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 @@ -1257,6 +1259,10 @@ uint32_t ObjectFilePECOFF::GetPluginVersion() { return 1; } llvm::StringRef ObjectFilePECOFF::GetReflectionSectionIdentifier( swift::ReflectionSectionKind section) { +#ifdef LLDB_ENABLE_SWIFT swift::SwiftObjectFileFormatCOFF file_format_coff; return file_format_coff.getSectionName(section); +#else + llvm_unreachable("Swift support disabled"); +#endif //LLDB_ENABLE_SWIFT } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index d31559bc90183..d1064a0c8f3e6 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1477,25 +1477,20 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( StreamString minimum_version_option; bool use_current_os_version = false; + // If the SDK type is for the host OS, use its version number. + auto get_host_os = []() { return HostInfo::GetTargetTriple().getOS(); }; switch (sdk_type) { + case XcodeSDK::Type::MacOSX: + use_current_os_version = get_host_os() == llvm::Triple::MacOSX; + break; case XcodeSDK::Type::iPhoneOS: -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - use_current_os_version = true; -#else - use_current_os_version = false; -#endif + use_current_os_version = get_host_os() == llvm::Triple::IOS; break; - - case XcodeSDK::Type::iPhoneSimulator: - use_current_os_version = false; + case XcodeSDK::Type::AppleTVOS: + use_current_os_version = get_host_os() == llvm::Triple::TvOS; break; - - case XcodeSDK::Type::MacOSX: -#if defined(__i386__) || defined(__x86_64__) - use_current_os_version = true; -#else - use_current_os_version = false; -#endif + case XcodeSDK::Type::watchOS: + use_current_os_version = get_host_os() == llvm::Triple::WatchOS; break; default: break; @@ -1515,24 +1510,49 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( } } // Only add the version-min options if we got a version from somewhere - if (!version.empty()) { + if (!version.empty() && sdk_type != XcodeSDK::Type::Linux) { +#define OPTION(PREFIX, NAME, VAR, ...) \ + const char *opt_##VAR = NAME; \ + (void)opt_##VAR; +#include "clang/Driver/Options.inc" +#undef OPTION + minimum_version_option << '-'; switch (sdk_type) { - case XcodeSDK::Type::iPhoneOS: - minimum_version_option.PutCString("-mios-version-min="); - minimum_version_option.PutCString(version.getAsString()); + case XcodeSDK::Type::MacOSX: + minimum_version_option << opt_mmacosx_version_min_EQ; break; case XcodeSDK::Type::iPhoneSimulator: - minimum_version_option.PutCString("-mios-simulator-version-min="); - minimum_version_option.PutCString(version.getAsString()); + minimum_version_option << opt_mios_simulator_version_min_EQ; break; - case XcodeSDK::Type::MacOSX: - minimum_version_option.PutCString("-mmacosx-version-min="); - minimum_version_option.PutCString(version.getAsString()); + case XcodeSDK::Type::iPhoneOS: + minimum_version_option << opt_mios_version_min_EQ; break; - default: - llvm_unreachable("unsupported sdk"); + case XcodeSDK::Type::AppleTVSimulator: + minimum_version_option << opt_mtvos_simulator_version_min_EQ; + break; + case XcodeSDK::Type::AppleTVOS: + minimum_version_option << opt_mtvos_version_min_EQ; + break; + case XcodeSDK::Type::WatchSimulator: + minimum_version_option << opt_mwatchos_simulator_version_min_EQ; + break; + case XcodeSDK::Type::watchOS: + minimum_version_option << opt_mwatchos_version_min_EQ; + break; + case XcodeSDK::Type::bridgeOS: + case XcodeSDK::Type::Linux: + case XcodeSDK::Type::unknown: + if (lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)) { + XcodeSDK::Info info; + info.type = sdk_type; + LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + "Clang modules on %s are not supported", + XcodeSDK::GetCanonicalName(info).c_str()); + } + return; } - options.push_back(std::string(minimum_version_option.GetString())); + minimum_version_option << version.getAsString(); + options.emplace_back(std::string(minimum_version_option.GetString())); } FileSpec sysroot_spec; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index f6c0f262a3798..54f49601e8112 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -199,13 +199,6 @@ class PlatformDarwinKernelProperties : public Properties { virtual ~PlatformDarwinKernelProperties() {} - bool GetSearchForKexts() const { - const uint32_t idx = ePropertySearchForKexts; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - NULL, idx, - g_platformdarwinkernel_properties[idx].default_uint_value != 0); - } - FileSpecList GetKextDirectories() const { const uint32_t idx = ePropertyKextDirectories; const OptionValueFileSpecList *option_value = @@ -245,14 +238,12 @@ PlatformDarwinKernel::PlatformDarwinKernel( m_name_to_kext_path_map_with_dsyms(), m_name_to_kext_path_map_without_dsyms(), m_search_directories(), m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(), - m_kernel_binaries_without_dsyms(), - m_ios_debug_session(is_ios_debug_session) + m_kernel_binaries_without_dsyms(), m_kernel_dsyms_no_binaries(), + m_kernel_dsyms_yaas(), m_ios_debug_session(is_ios_debug_session) { - if (GetGlobalProperties()->GetSearchForKexts()) { - CollectKextAndKernelDirectories(); - SearchForKextsAndKernelsRecursively(); - } + CollectKextAndKernelDirectories(); + SearchForKextsAndKernelsRecursively(); } /// Destructor. @@ -293,6 +284,10 @@ void PlatformDarwinKernel::GetStatus(Stream &strm) { (int)m_kernel_binaries_with_dsyms.size()); strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n", (int)m_kernel_binaries_without_dsyms.size()); + strm.Printf(" Number of Kernel dSYMs with no binaries indexed: %d\n", + (int)m_kernel_dsyms_no_binaries.size()); + strm.Printf(" Number of Kernel dSYM.yaa's indexed: %d\n", + (int)m_kernel_dsyms_yaas.size()); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) { @@ -305,14 +300,22 @@ void PlatformDarwinKernel::GetStatus(Stream &strm) { for (auto pos : m_name_to_kext_path_map_without_dsyms) { LLDB_LOGF(log, "%s", pos.second.GetPath().c_str()); } - LLDB_LOGF(log, "\nkernels with dSYMS"); + LLDB_LOGF(log, "\nkernel binaries with dSYMS"); for (auto fs : m_kernel_binaries_with_dsyms) { LLDB_LOGF(log, "%s", fs.GetPath().c_str()); } - LLDB_LOGF(log, "\nkernels without dSYMS"); + LLDB_LOGF(log, "\nkernel binaries without dSYMS"); for (auto fs : m_kernel_binaries_without_dsyms) { LLDB_LOGF(log, "%s", fs.GetPath().c_str()); } + LLDB_LOGF(log, "\nkernel dSYMS with no binaries"); + for (auto fs : m_kernel_dsyms_no_binaries) { + LLDB_LOGF(log, "%s", fs.GetPath().c_str()); + } + LLDB_LOGF(log, "\nkernels .dSYM.yaa's"); + for (auto fs : m_kernel_dsyms_yaas) { + LLDB_LOGF(log, "%s", fs.GetPath().c_str()); + } LLDB_LOGF(log, "\n"); } } @@ -497,56 +500,79 @@ PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( file_spec.GetPath().c_str()); PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; + + llvm::StringRef filename = file_spec.GetFilename().GetStringRef(); + bool is_kernel_filename = + filename.startswith("kernel") || filename.startswith("mach"); + bool is_dsym_yaa = filename.endswith(".dSYM.yaa"); + if (ft == llvm::sys::fs::file_type::regular_file || ft == llvm::sys::fs::file_type::symlink_file) { - ConstString filename = file_spec.GetFilename(); - if ((strncmp(filename.GetCString(), "kernel", 6) == 0 || - strncmp(filename.GetCString(), "mach", 4) == 0) && - file_spec_extension != g_dsym_suffix) { - if (KernelHasdSYMSibling(file_spec)) - { - LLDB_LOGF(log, - "PlatformDarwinKernel registering kernel binary '%s' with " - "dSYM sibling", - file_spec.GetPath().c_str()); - thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); + if (is_kernel_filename) { + if (file_spec_extension != g_dsym_suffix && !is_dsym_yaa) { + if (KernelHasdSYMSibling(file_spec)) { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kernel binary '%s' with " + "dSYM sibling", + file_spec.GetPath().c_str()); + thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); + } else { + LLDB_LOGF( + log, + "PlatformDarwinKernel registering kernel binary '%s', no dSYM", + file_spec.GetPath().c_str()); + thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); + } } - else - { - LLDB_LOGF( - log, "PlatformDarwinKernel registering kernel binary '%s', no dSYM", - file_spec.GetPath().c_str()); - thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); + if (is_dsym_yaa) { + LLDB_LOGF(log, "PlatformDarwinKernel registering kernel .dSYM.yaa '%s'", + file_spec.GetPath().c_str()); + thisp->m_kernel_dsyms_yaas.push_back(file_spec); } return FileSystem::eEnumerateDirectoryResultNext; } - } else if (ft == llvm::sys::fs::file_type::directory_file && - file_spec_extension == g_kext_suffix) { - AddKextToMap(thisp, file_spec); - // Look to see if there is a PlugIns subdir with more kexts - FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns"); - std::string search_here_too; - if (FileSystem::Instance().IsDirectory(contents_plugins)) { - search_here_too = contents_plugins.GetPath(); - } else { - FileSpec plugins(file_spec.GetPath() + "/PlugIns"); - if (FileSystem::Instance().IsDirectory(plugins)) { - search_here_too = plugins.GetPath(); - } - } + } else { + if (ft == llvm::sys::fs::file_type::directory_file) { + if (file_spec_extension == g_kext_suffix) { + AddKextToMap(thisp, file_spec); + // Look to see if there is a PlugIns subdir with more kexts + FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns"); + std::string search_here_too; + if (FileSystem::Instance().IsDirectory(contents_plugins)) { + search_here_too = contents_plugins.GetPath(); + } else { + FileSpec plugins(file_spec.GetPath() + "/PlugIns"); + if (FileSystem::Instance().IsDirectory(plugins)) { + search_here_too = plugins.GetPath(); + } + } - if (!search_here_too.empty()) { - const bool find_directories = true; - const bool find_files = false; - const bool find_other = false; - FileSystem::Instance().EnumerateDirectory( - search_here_too.c_str(), find_directories, find_files, find_other, - recurse ? GetKernelsAndKextsInDirectoryWithRecursion - : GetKernelsAndKextsInDirectoryNoRecursion, - baton); + if (!search_here_too.empty()) { + const bool find_directories = true; + const bool find_files = false; + const bool find_other = false; + FileSystem::Instance().EnumerateDirectory( + search_here_too.c_str(), find_directories, find_files, find_other, + recurse ? GetKernelsAndKextsInDirectoryWithRecursion + : GetKernelsAndKextsInDirectoryNoRecursion, + baton); + } + return FileSystem::eEnumerateDirectoryResultNext; + } + // Do we have a kernel dSYM with no kernel binary? + if (is_kernel_filename && file_spec_extension == g_dsym_suffix) { + if (KerneldSYMHasNoSiblingBinary(file_spec)) { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kernel dSYM '%s' with " + "no binary sibling", + file_spec.GetPath().c_str()); + thisp->m_kernel_dsyms_no_binaries.push_back(file_spec); + return FileSystem::eEnumerateDirectoryResultNext; + } + } } - return FileSystem::eEnumerateDirectoryResultNext; } + // Don't recurse into dSYM/kext/bundle directories if (recurse && file_spec_extension != g_dsym_suffix && file_spec_extension != g_kext_suffix && @@ -642,6 +668,63 @@ bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { return FileSystem::Instance().IsDirectory(kernel_dsym); } +// Given a FileSpec of /dir/dir/mach.development.t7004.dSYM +// Return true if only the dSYM exists, no binary next to it. +// /dir/dir/mach.development.t7004.dSYM +// but no +// /dir/dir/mach.development.t7004 +bool PlatformDarwinKernel::KerneldSYMHasNoSiblingBinary( + const FileSpec &kernel_dsym) { + static ConstString g_dsym_suffix = ConstString(".dSYM"); + std::string possible_path = kernel_dsym.GetPath(); + if (kernel_dsym.GetFileNameExtension() != g_dsym_suffix) + return false; + + FileSpec binary_filespec = kernel_dsym; + // Chop off the '.dSYM' extension on the filename + binary_filespec.GetFilename() = + binary_filespec.GetFileNameStrippingExtension(); + + // Is there a binary next to this this? Then return false. + if (FileSystem::Instance().Exists(binary_filespec)) + return false; + + // If we have at least one binary in the DWARF subdir, then + // this is a properly formed dSYM and it has no binary next + // to it. + if (GetDWARFBinaryInDSYMBundle(kernel_dsym).size() > 0) + return true; + + return false; +} + +// TODO: This method returns a vector of FileSpec's because a +// dSYM bundle may contain multiple DWARF binaries, but it +// only implements returning the base name binary for now; +// it should iterate over every binary in the DWARF subdir +// and return them all. +std::vector +PlatformDarwinKernel::GetDWARFBinaryInDSYMBundle(FileSpec dsym_bundle) { + std::vector results; + static ConstString g_dsym_suffix = ConstString(".dSYM"); + if (dsym_bundle.GetFileNameExtension() != g_dsym_suffix) { + return results; + } + // Drop the '.dSYM' from the filename + std::string filename = + dsym_bundle.GetFileNameStrippingExtension().GetCString(); + std::string dirname = dsym_bundle.GetDirectory().GetCString(); + + std::string binary_filepath = dsym_bundle.GetPath(); + binary_filepath += "/Contents/Resources/DWARF/"; + binary_filepath += filename; + + FileSpec binary_fspec(binary_filepath); + if (FileSystem::Instance().Exists(binary_fspec)) + results.push_back(binary_fspec); + return results; +} + Status PlatformDarwinKernel::GetSharedModule( const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, @@ -653,111 +736,176 @@ Status PlatformDarwinKernel::GetSharedModule( // Treat the file's path as a kext bundle ID (e.g. // "com.apple.driver.AppleIRController") and search our kext index. std::string kext_bundle_id = platform_file.GetPath(); - if (!kext_bundle_id.empty()) { - ConstString kext_bundle_cs(kext_bundle_id.c_str()); - - // First look through the kext bundles that had a dsym next to them - if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) { - for (BundleIDToKextIterator it = - m_name_to_kext_path_map_with_dsyms.begin(); - it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { - if (it->first == kext_bundle_cs) { - error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), - module_spec.GetArchitecture(), - module_sp); - if (module_sp.get()) { - return error; - } - } - } - } + if (!kext_bundle_id.empty() && module_spec.GetUUID().IsValid()) { + if (kext_bundle_id == "mach_kernel") { + return GetSharedModuleKernel(module_spec, process, module_sp, + module_search_paths_ptr, old_module_sp_ptr, + did_create_ptr); + } else { + return GetSharedModuleKext(module_spec, process, module_sp, + module_search_paths_ptr, old_module_sp_ptr, + did_create_ptr); + } + } else { // Give the generic methods, including possibly calling into DebugSymbols // framework on macOS systems, a chance. - error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + return PlatformDarwin::GetSharedModule(module_spec, process, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr); - if (error.Success() && module_sp.get()) { - return error; + } +} + +Status PlatformDarwinKernel::GetSharedModuleKext( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) { + Status error; + module_sp.reset(); + const FileSpec &platform_file = module_spec.GetFileSpec(); + + // Treat the file's path as a kext bundle ID (e.g. + // "com.apple.driver.AppleIRController") and search our kext index. + ConstString kext_bundle(platform_file.GetPath().c_str()); + // First look through the kext bundles that had a dsym next to them + if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle) > 0) { + for (BundleIDToKextIterator it = m_name_to_kext_path_map_with_dsyms.begin(); + it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { + if (it->first == kext_bundle) { + error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), + module_spec.GetArchitecture(), + module_sp); + if (module_sp.get()) { + return error; + } + } + } + } + + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. + error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, + old_module_sp_ptr, did_create_ptr); + if (error.Success() && module_sp.get()) { + return error; + } + + // Lastly, look through the kext binarys without dSYMs + if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle) > 0) { + for (BundleIDToKextIterator it = + m_name_to_kext_path_map_without_dsyms.begin(); + it != m_name_to_kext_path_map_without_dsyms.end(); ++it) { + if (it->first == kext_bundle) { + error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), + module_spec.GetArchitecture(), + module_sp); + if (module_sp.get()) { + return error; + } + } } + } + return error; +} - // Lastly, look through the kext binarys without dSYMs - if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) { - for (BundleIDToKextIterator it = - m_name_to_kext_path_map_without_dsyms.begin(); - it != m_name_to_kext_path_map_without_dsyms.end(); ++it) { - if (it->first == kext_bundle_cs) { - error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), - module_spec.GetArchitecture(), - module_sp); - if (module_sp.get()) { +Status PlatformDarwinKernel::GetSharedModuleKernel( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) { + Status error; + module_sp.reset(); + + // First try all kernel binaries that have a dSYM next to them + for (auto possible_kernel : m_kernel_binaries_with_dsyms) { + if (FileSystem::Instance().Exists(possible_kernel)) { + ModuleSpec kern_spec(possible_kernel); + kern_spec.GetUUID() = module_spec.GetUUID(); + module_sp.reset(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr, + nullptr, nullptr); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { return error; } + module_sp.reset(); } } } } - if (kext_bundle_id == "mach_kernel" && module_spec.GetUUID().IsValid()) { - // First try all kernel binaries that have a dSYM next to them - for (auto possible_kernel : m_kernel_binaries_with_dsyms) { - if (FileSystem::Instance().Exists(possible_kernel)) { - ModuleSpec kern_spec(possible_kernel); - kern_spec.GetUUID() = module_spec.GetUUID(); - ModuleSP module_sp(new Module(kern_spec)); - if (module_sp && module_sp->GetObjectFile() && - module_sp->MatchesModuleSpec(kern_spec)) { - // module_sp is an actual kernel binary we want to add. - if (process) { - process->GetTarget().GetImages().AppendIfNeeded(module_sp); - error.Clear(); + // Next try all dSYMs that have no kernel binary next to them (load + // the kernel DWARF stub as the main binary) + for (auto possible_kernel_dsym : m_kernel_dsyms_no_binaries) { + std::vector objfile_names = + GetDWARFBinaryInDSYMBundle(possible_kernel_dsym); + for (FileSpec objfile : objfile_names) { + ModuleSpec kern_spec(objfile); + kern_spec.GetUUID() = module_spec.GetUUID(); + kern_spec.GetSymbolFileSpec() = possible_kernel_dsym; + + module_sp.reset(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr, + nullptr, nullptr); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { return error; - } else { - error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, - NULL, NULL); - if (module_sp && module_sp->GetObjectFile() && - module_sp->GetObjectFile()->GetType() != - ObjectFile::Type::eTypeCoreFile) { - return error; - } - module_sp.reset(); } + module_sp.reset(); } } } + } - // Give the generic methods, including possibly calling into DebugSymbols - // framework on macOS systems, a chance. - error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, - module_search_paths_ptr, - old_module_sp_ptr, did_create_ptr); - if (error.Success() && module_sp.get()) { - return error; - } + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. + error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, + old_module_sp_ptr, did_create_ptr); + if (error.Success() && module_sp.get()) { + return error; + } - // Next try all kernel binaries that don't have a dSYM - for (auto possible_kernel : m_kernel_binaries_without_dsyms) { - if (FileSystem::Instance().Exists(possible_kernel)) { - ModuleSpec kern_spec(possible_kernel); - kern_spec.GetUUID() = module_spec.GetUUID(); - ModuleSP module_sp(new Module(kern_spec)); - if (module_sp && module_sp->GetObjectFile() && - module_sp->MatchesModuleSpec(kern_spec)) { - // module_sp is an actual kernel binary we want to add. - if (process) { - process->GetTarget().GetImages().AppendIfNeeded(module_sp); - error.Clear(); + // Lastly, try all kernel binaries that don't have a dSYM + for (auto possible_kernel : m_kernel_binaries_without_dsyms) { + if (FileSystem::Instance().Exists(possible_kernel)) { + ModuleSpec kern_spec(possible_kernel); + kern_spec.GetUUID() = module_spec.GetUUID(); + module_sp.reset(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr, + nullptr, nullptr); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { return error; - } else { - error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, - NULL, NULL); - if (module_sp && module_sp->GetObjectFile() && - module_sp->GetObjectFile()->GetType() != - ObjectFile::Type::eTypeCoreFile) { - return error; - } - module_sp.reset(); } + module_sp.reset(); } } } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h index 9cf9e41208eb8..cd9e9d70f8ed8 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h @@ -126,7 +126,30 @@ class PlatformDarwinKernel : public PlatformDarwin { // Returns true if there is a .dSYM bundle next to the kernel static bool - KernelHasdSYMSibling(const lldb_private::FileSpec &kext_bundle_filepath); + KernelHasdSYMSibling(const lldb_private::FileSpec &kernel_filepath); + + // Returns true if there is a .dSYM bundle with NO kernel binary next to it + static bool KerneldSYMHasNoSiblingBinary( + const lldb_private::FileSpec &kernel_dsym_filepath); + + // Given a dsym_bundle argument ('.../foo.dSYM'), return a FileSpec + // with the binary inside it ('.../foo.dSYM/Contents/Resources/DWARF/foo'). + // A dSYM bundle may have multiple DWARF binaries in them, so a vector + // of matches is returned. + static std::vector + GetDWARFBinaryInDSYMBundle(lldb_private::FileSpec dsym_bundle); + + lldb_private::Status + GetSharedModuleKext(const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); + + lldb_private::Status GetSharedModuleKernel( + const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); lldb_private::Status ExamineKextForMatchingUUID(const lldb_private::FileSpec &kext_bundle_path, @@ -170,6 +193,13 @@ class PlatformDarwinKernel : public PlatformDarwin { // on local // filesystem, with // dSYMs next to them + KernelBinaryCollection m_kernel_dsyms_no_binaries; // list of kernel + // dsyms with no + // binaries next to + // them + KernelBinaryCollection m_kernel_dsyms_yaas; // list of kernel + // .dSYM.yaa files + lldb_private::LazyBool m_ios_debug_session; PlatformDarwinKernel(const PlatformDarwinKernel &) = delete; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td index 07e4e3e81d8c5..39e9641daae04 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td @@ -1,10 +1,6 @@ include "../../../../include/lldb/Core/PropertiesBase.td" let Definition = "platformdarwinkernel" in { - def SearchForKexts: Property<"search-locally-for-kexts", "Boolean">, - Global, - DefaultTrue, - Desc<"Automatically search for kexts on the local system when doing kernel debugging.">; def KextDirectories: Property<"kext-directories", "FileSpecList">, DefaultStringValue<"">, Desc<"Directories/KDKs to search for kexts in when starting a kernel debug session.">; diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 4dd619e3bade8..d4b0f4039da95 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -14,79 +14,72 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS - // ===== =========== ======== ===== ====== - // ====================================== ====== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, - "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", - "SIGCLD"); - AddSignal(18, "SIGCONT", false, true, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", - "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, - "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, - "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, - "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill - // -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + AddSignal(7, "SIGBUS", false, true, true, "bus error"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); + AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + AddSignal(14, "SIGALRM", false, false, false, "alarm"); + AddSignal(15, "SIGTERM", false, true, true, "termination requested"); + AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); + AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + AddSignal(18, "SIGCONT", false, false, true, "process continue"); + AddSignal(19, "SIGSTOP", true, true, true, "process stop"); + AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); + AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); + AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); + AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); + AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); + AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + AddSignal(30, "SIGPWR", false, true, true, "power failure"); + AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); + AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); + AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); + AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); + AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format on } diff --git a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp index 8f75844277c0e..fb51c56953f85 100644 --- a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -14,79 +14,72 @@ MipsLinuxSignals::MipsLinuxSignals() : UnixSignals() { Reset(); } void MipsLinuxSignals::Reset() { m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS - // ===== =========== ======== ===== ====== - // ====================================== ======== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGBUS", false, true, true, "bus error"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(13, "SIGPIPE", false, true, true, - "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", - "SIGCLD"); - AddSignal(19, "SIGPWR", false, true, true, "power failure"); - AddSignal(20, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(21, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", - "SIGPOLL"); - AddSignal(23, "SIGSTOP", true, true, true, "process stop"); - AddSignal(24, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(25, "SIGCONT", false, true, true, "process continue"); - AddSignal(26, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(27, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(32, "SIG32", false, false, false, - "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, - "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, - "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill - // -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGBUS", false, true, true, "bus error"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGSYS", false, true, true, "invalid system call"); + AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + AddSignal(14, "SIGALRM", false, false, false, "alarm"); + AddSignal(15, "SIGTERM", false, true, true, "termination requested"); + AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2"); + AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + AddSignal(19, "SIGPWR", false, true, true, "power failure"); + AddSignal(20, "SIGWINCH", false, true, true, "window size changes"); + AddSignal(21, "SIGURG", false, true, true, "urgent data on socket"); + AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + AddSignal(23, "SIGSTOP", true, true, true, "process stop"); + AddSignal(24, "SIGTSTP", false, true, true, "tty stop"); + AddSignal(25, "SIGCONT", false, false, true, "process continue"); + AddSignal(26, "SIGTTIN", false, true, true, "background tty read"); + AddSignal(27, "SIGTTOU", false, true, true, "background tty write"); + AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm"); + AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded"); + AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded"); + AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); + AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); + AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); + AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format on } diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index b78276d345e1f..744942115016e 100644 --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -281,8 +281,9 @@ Status ProcessMachCore::DoLoadCore() { addr_t objfile_binary_addr; UUID objfile_binary_uuid; - if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid)) - { + ObjectFile::BinaryType type; + if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_addr, + objfile_binary_uuid, type)) { if (objfile_binary_addr != LLDB_INVALID_ADDRESS) { m_mach_kernel_addr = objfile_binary_addr; @@ -293,7 +294,7 @@ Status ProcessMachCore::DoLoadCore() { m_mach_kernel_addr); } } - + // This checks for the presence of an LC_IDENT string in a core file; // LC_IDENT is very obsolete and should not be used in new code, but if the // load command is present, let's use the contents. @@ -326,58 +327,81 @@ Status ProcessMachCore::DoLoadCore() { addr, corefile_identifier.c_str()); } } - if (found_main_binary_definitively == false - && corefile_identifier.find("EFI ") != std::string::npos) { - UUID uuid; + + // In the case where we have an LC_NOTE specifying a standalone + // binary with only a UUID (and no load address) (iBoot, EFI, etc), + // then let's try to force a load of the binary and set its + // load address to 0-offset. + // + // The two forms this can come in is either a + // 'kern ver str' LC_NOTE with "EFI UUID=...." + // 'main bin spec' LC_NOTE with UUID and no load address. + + if (found_main_binary_definitively == false && + (corefile_identifier.find("EFI ") != std::string::npos || + (objfile_binary_uuid.IsValid() && + objfile_binary_addr == LLDB_INVALID_ADDRESS))) { + UUID uuid; + if (objfile_binary_uuid.IsValid()) { + uuid = objfile_binary_uuid; + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using the main bin spec " + "LC_NOTE with UUID %s and no load address", + uuid.GetAsString().c_str()); + } else { if (corefile_identifier.find("UUID=") != std::string::npos) { - size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); - std::string uuid_str = corefile_identifier.substr(p, 36); - uuid.SetFromStringRef(uuid_str); + size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); + std::string uuid_str = corefile_identifier.substr(p, 36); + uuid.SetFromStringRef(uuid_str); + if (uuid.IsValid()) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using the EFI " + "from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", + corefile_identifier.c_str()); + } } - if (uuid.IsValid()) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using the EFI " - "from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", - corefile_identifier.c_str()); - - // We're only given a UUID here, not a load address. - // But there are python scripts in the EFI binary's dSYM which - // know how to relocate the binary to the correct load address. - // lldb only needs to locate & load the binary + dSYM. - ModuleSpec module_spec; - module_spec.GetUUID() = uuid; - module_spec.GetArchitecture() = GetTarget().GetArchitecture(); - - // Lookup UUID locally, before attempting dsymForUUID like action - FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); - module_spec.GetSymbolFileSpec() = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); - if (module_spec.GetSymbolFileSpec()) { - ModuleSpec executable_module_spec = - Symbols::LocateExecutableObjectFile(module_spec); - if (FileSystem::Instance().Exists( - executable_module_spec.GetFileSpec())) { - module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); - } + } + + if (uuid.IsValid()) { + ModuleSpec module_spec; + module_spec.GetUUID() = uuid; + module_spec.GetArchitecture() = GetTarget().GetArchitecture(); + + // Lookup UUID locally, before attempting dsymForUUID-like action + FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); + module_spec.GetSymbolFileSpec() = + Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + if (module_spec.GetSymbolFileSpec()) { + ModuleSpec executable_module_spec = + Symbols::LocateExecutableObjectFile(module_spec); + if (FileSystem::Instance().Exists( + executable_module_spec.GetFileSpec())) { + module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); } + } - // Force a a dsymForUUID lookup, if that tool is available. - if (!module_spec.GetSymbolFileSpec()) - Symbols::DownloadObjectAndSymbolFile(module_spec, true); - - if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { - ModuleSP module_sp(new Module(module_spec)); - if (module_sp.get() && module_sp->GetObjectFile()) { - // Get the current target executable - ModuleSP exe_module_sp(GetTarget().GetExecutableModule()); - - // Make sure you don't already have the right module loaded - // and they will be uniqued - if (exe_module_sp.get() != module_sp.get()) - GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo); - } + // Force a a dsymForUUID lookup, if that tool is available. + if (!module_spec.GetSymbolFileSpec()) + Symbols::DownloadObjectAndSymbolFile(module_spec, true); + + // If we found a binary, load it at offset 0 and set our + // dyld_plugin to be the static plugin. + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { + ModuleSP module_sp(new Module(module_spec)); + if (module_sp.get() && module_sp->GetObjectFile()) { + GetTarget().GetImages().AppendIfNeeded(module_sp, true); + GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo); + found_main_binary_definitively = true; + bool changed = true; + module_sp->SetLoadAddress(GetTarget(), 0, true, changed); + ModuleList added_module; + added_module.Append(module_sp, false); + GetTarget().ModulesDidLoad(added_module); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + found_main_binary_definitively = true; } } + } } if (!found_main_binary_definitively && @@ -440,35 +464,37 @@ Status ProcessMachCore::DoLoadCore() { } } - // If we found both a user-process dyld and a kernel binary, we need to - // decide which to prefer. - if (GetCorefilePreference() == eKernelCorefile) { - if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); - } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } - } else { - if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + if (m_dyld_plugin_name.IsEmpty()) { + // If we found both a user-process dyld and a kernel binary, we need to + // decide which to prefer. + if (GetCorefilePreference() == eKernelCorefile) { + if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using kernel corefile image " + "at 0x%" PRIx64, + m_mach_kernel_addr); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using user process dyld " + "image at 0x%" PRIx64, + m_dyld_addr); + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + } + } else { + if (m_dyld_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using user process dyld " + "image at 0x%" PRIx64, + m_dyld_addr); + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using kernel corefile image " + "at 0x%" PRIx64, + m_mach_kernel_addr); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + } } } diff --git a/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt index 7e7dd5896f7c8..ce4fb4f9c0a03 100644 --- a/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt @@ -4,4 +4,4 @@ add_lldb_library(lldbPluginScriptInterpreterNone PLUGIN LINK_LIBS lldbCore lldbInterpreter - ) \ No newline at end of file + ) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 761772f3a3718..2cbf8bcbb229d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -19,7 +19,7 @@ add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN lldbHost lldbInterpreter lldbTarget - ${PYTHON_LIBRARIES} + ${Python3_LIBRARIES} ${LLDB_LIBEDIT_LIBS} LINK_COMPONENTS diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 9f56b4fa60a50..f67572c1f0299 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -127,6 +127,16 @@ extern "C" unsigned int LLDBSwigPythonCallBreakpointResolver(void *implementor, const char *method_name, lldb_private::SymbolContext *sym_ctx); +extern "C" void *LLDBSwigPythonCreateScriptedStopHook( + TargetSP target_sp, const char *python_class_name, + const char *session_dictionary_name, lldb_private::StructuredDataImpl *args, + lldb_private::Status &error); + +extern "C" bool +LLDBSwigPythonStopHookCallHandleStop(void *implementor, + lldb::ExecutionContextRefSP exc_ctx, + lldb::StreamSP stream); + extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor, uint32_t max); @@ -1979,6 +1989,60 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( return lldb::eSearchDepthModule; } +StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedStopHook( + TargetSP target_sp, const char *class_name, StructuredDataImpl *args_data, + Status &error) { + + if (!target_sp) { + error.SetErrorString("No target for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + if (class_name == nullptr || class_name[0] == '\0') { + error.SetErrorString("No class name for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + ScriptInterpreter *script_interpreter = m_debugger.GetScriptInterpreter(); + ScriptInterpreterPythonImpl *python_interpreter = + static_cast(script_interpreter); + + if (!script_interpreter) { + error.SetErrorString("No script interpreter for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + void *ret_val; + + { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + ret_val = LLDBSwigPythonCreateScriptedStopHook( + target_sp, class_name, python_interpreter->m_dictionary_name.c_str(), + args_data, error); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +bool ScriptInterpreterPythonImpl::ScriptedStopHookHandleStop( + StructuredData::GenericSP implementor_sp, ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) { + assert(implementor_sp && + "can't call a stop hook with an invalid implementor"); + assert(stream_sp && "can't call a stop hook with an invalid stream"); + + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + lldb::ExecutionContextRefSP exc_ctx_ref_sp(new ExecutionContextRef(exc_ctx)); + + bool ret_val = LLDBSwigPythonStopHookCallHandleStop( + implementor_sp->GetValue(), exc_ctx_ref_sp, stream_sp); + return ret_val; +} + StructuredData::ObjectSP ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 22b2c8152eac0..f89c3d461f7fd 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -105,6 +105,14 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython { lldb::SearchDepth ScriptedBreakpointResolverSearchDepth( StructuredData::GenericSP implementor_sp) override; + StructuredData::GenericSP + CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, + StructuredDataImpl *args_data, Status &error) override; + + bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, + ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) override; + StructuredData::GenericSP CreateFrameRecognizer(const char *class_name) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index 7dc52c1e2df06..7062c9bfae235 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -39,7 +39,7 @@ DWARFDebugAranges::extract(const DWARFDataExtractor &debug_aranges_data) { Range range; while (debug_aranges_data.ValidOffset(offset)) { llvm::Error error = set.extract(debug_aranges_data, &offset); - if (!error) + if (error) return error; const uint32_t num_descriptors = set.NumDescriptors(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index b401352c693dd..fe6a55520978f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -42,6 +42,7 @@ class DWARFFormValue { DWARFFormValue(const DWARFUnit *unit) : m_unit(unit) {} DWARFFormValue(const DWARFUnit *unit, dw_form_t form) : m_unit(unit), m_form(form) {} + const DWARFUnit *GetUnit() const { return m_unit; } void SetUnit(const DWARFUnit *unit) { m_unit = unit; } dw_form_t Form() const { return m_form; } dw_form_t& FormRef() { return m_form; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 9e6d9730e5d59..9d0d0e3403449 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -249,11 +249,6 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, return support_files; } -static inline bool IsSwiftLanguage(LanguageType language) { - return language == eLanguageTypePLI || language == eLanguageTypeSwift || - ((uint32_t)language == (uint32_t)llvm::dwarf::DW_LANG_Swift); -} - void SymbolFileDWARF::Initialize() { LogChannelDWARF::Initialize(); PluginManager::RegisterPlugin(GetPluginNameStatic(), @@ -974,7 +969,7 @@ bool SymbolFileDWARF::ParseImportedModules( return false; auto lang = sc.comp_unit->GetLanguage(); if (!ClangModulesDeclVendor::LanguageSupportsClangModules(lang) && - !IsSwiftLanguage(lang)) + lang != eLanguageTypeSwift) return false; UpdateExternalModuleListIfNeeded(); @@ -3185,18 +3180,15 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, const char *name = nullptr; const char *mangled = nullptr; Declaration decl; - uint32_t i; DWARFFormValue type_die_form; DWARFExpression location; bool is_external = false; bool is_artificial = false; - bool location_is_const_value_data = false; - bool has_explicit_location = false; - DWARFFormValue const_value; + DWARFFormValue const_value_form, location_form; Variable::RangeList scope_ranges; // AccessType accessibility = eAccessNone; - for (i = 0; i < num_attributes; ++i) { + for (size_t i = 0; i < num_attributes; ++i) { dw_attr_t attr = attributes.AttributeAtIndex(i); DWARFFormValue form_value; @@ -3226,65 +3218,11 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, is_external = form_value.Boolean(); break; case DW_AT_const_value: - // If we have already found a DW_AT_location attribute, ignore this - // attribute. - if (!has_explicit_location) { - location_is_const_value_data = true; - // The constant value will be either a block, a data value or a - // string. - auto debug_info_data = die.GetData(); - if (DWARFFormValue::IsBlockForm(form_value.Form())) { - // Retrieve the value as a block expression. - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); - location = DWARFExpression( - module, - DataExtractor(debug_info_data, block_offset, block_length), - die.GetCU()); - } else if (DWARFFormValue::IsDataForm(form_value.Form())) { - // Constant value size does not have to match the size of the - // variable. We will fetch the size of the type after we create - // it. - const_value = form_value; - } else if (const char *str = form_value.AsCString()) { - uint32_t string_length = strlen(str) + 1; - location = DWARFExpression( - module, - DataExtractor(str, string_length, - die.GetCU()->GetByteOrder(), - die.GetCU()->GetAddressByteSize()), - die.GetCU()); - } - } + const_value_form = form_value; + break; + case DW_AT_location: + location_form = form_value; break; - case DW_AT_location: { - location_is_const_value_data = false; - has_explicit_location = true; - if (DWARFFormValue::IsBlockForm(form_value.Form())) { - auto data = die.GetData(); - - uint32_t block_offset = - form_value.BlockData() - data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); - location = DWARFExpression( - module, DataExtractor(data, block_offset, block_length), - die.GetCU()); - } else { - DataExtractor data = die.GetCU()->GetLocationData(); - dw_offset_t offset = form_value.Unsigned(); - if (form_value.Form() == DW_FORM_loclistx) - offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); - if (data.ValidOffset(offset)) { - data = DataExtractor(data, offset, data.GetByteSize() - offset); - location = DWARFExpression(module, data, die.GetCU()); - assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListAddresses( - attributes.CompileUnitAtIndex(i)->GetBaseAddress(), - func_low_pc); - } - } - } break; case DW_AT_specification: spec_die = form_value.Reference(); break; @@ -3311,8 +3249,68 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } if (tag == DW_TAG_variable && mangled && - IsSwiftLanguage(sc.comp_unit->GetLanguage())) - mangled = NULL; + sc.comp_unit->GetLanguage() == eLanguageTypeSwift) + mangled = nullptr; + + // Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g. + // for static constexpr member variables -- DW_AT_const_value will be + // present in the class declaration and DW_AT_location in the DIE defining + // the member. + bool location_is_const_value_data = false; + bool has_explicit_location = false; + bool use_type_size_for_value = false; + if (location_form.IsValid()) { + has_explicit_location = true; + if (DWARFFormValue::IsBlockForm(location_form.Form())) { + const DWARFDataExtractor &data = die.GetData(); + + uint32_t block_offset = + location_form.BlockData() - data.GetDataStart(); + uint32_t block_length = location_form.Unsigned(); + location = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), + die.GetCU()); + } else { + DataExtractor data = die.GetCU()->GetLocationData(); + dw_offset_t offset = location_form.Unsigned(); + if (location_form.Form() == DW_FORM_loclistx) + offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); + if (data.ValidOffset(offset)) { + data = DataExtractor(data, offset, data.GetByteSize() - offset); + location = DWARFExpression(module, data, die.GetCU()); + assert(func_low_pc != LLDB_INVALID_ADDRESS); + location.SetLocationListAddresses( + location_form.GetUnit()->GetBaseAddress(), func_low_pc); + } + } + } else if (const_value_form.IsValid()) { + location_is_const_value_data = true; + // The constant value will be either a block, a data value or a + // string. + const DWARFDataExtractor &debug_info_data = die.GetData(); + if (DWARFFormValue::IsBlockForm(const_value_form.Form())) { + // Retrieve the value as a block expression. + uint32_t block_offset = + const_value_form.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = const_value_form.Unsigned(); + location = DWARFExpression( + module, + DataExtractor(debug_info_data, block_offset, block_length), + die.GetCU()); + } else if (DWARFFormValue::IsDataForm(const_value_form.Form())) { + // Constant value size does not have to match the size of the + // variable. We will fetch the size of the type after we create + // it. + use_type_size_for_value = true; + } else if (const char *str = const_value_form.AsCString()) { + uint32_t string_length = strlen(str) + 1; + location = DWARFExpression( + module, + DataExtractor(str, string_length, die.GetCU()->GetByteOrder(), + die.GetCU()->GetAddressByteSize()), + die.GetCU()); + } + } const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); const dw_tag_t parent_tag = die.GetParent().Tag(); @@ -3493,18 +3491,18 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } if (symbol_context_scope) { - SymbolFileTypeSP type_sp( - new SymbolFileType(*this, GetUID(type_die_form.Reference()))); + auto type_sp = std::make_shared( + *this, GetUID(type_die_form.Reference())); - if (const_value.Form() && type_sp && type_sp->GetType()) + if (use_type_size_for_value && type_sp->GetType()) location.UpdateValue( - const_value.Unsigned(), + const_value_form.Unsigned(), type_sp->GetType()->GetByteSize(nullptr).getValueOr(0), die.GetCU()->GetAddressByteSize()); // Swift let-bindings are marked by a DW_TAG_const_type. bool is_constant = false; - if (IsSwiftLanguage(sc.comp_unit->GetLanguage())) { + if (sc.comp_unit->GetLanguage() == eLanguageTypeSwift) { DWARFDIE type_die = die.GetReferencedDIE(llvm::dwarf::DW_AT_type); if (type_die && type_die.Tag() == llvm::dwarf::DW_TAG_const_type) is_constant = true; @@ -3513,9 +3511,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, var_sp = std::make_shared( die.GetID(), name, mangled, type_sp, scope, symbol_context_scope, scope_ranges, &decl, location, is_external, is_artificial, - is_static_member, is_constant); - - var_sp->SetLocationIsConstantValueData(location_is_const_value_data); + location_is_const_value_data, is_static_member, is_constant); } else { // Not ready to parse this variable yet. It might be a global or static // variable that is in a function scope and the function in the symbol diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index d4451b3adcdc4..7bf310807400e 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -812,8 +812,7 @@ VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) { VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp, scope, comp_unit.get(), ranges, &decl, location, is_external, false, - false, false); - var_sp->SetLocationIsConstantValueData(false); + false, false, false); return var_sp; } @@ -840,8 +839,7 @@ SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id, VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(), type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location, - false, false, false, true); - var_sp->SetLocationIsConstantValueData(true); + false, false, true, false, true); return var_sp; } @@ -1346,7 +1344,7 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false, - false, false, false); + false, false, false, false); if (!is_param) m_ast->GetOrCreateVariableDecl(scope_id, var_id); diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 8e6a4cc455152..8a11502094467 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -1020,9 +1020,8 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData( var_sp = std::make_shared( var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope, - ranges, &decl, location, is_external, is_artificial, is_static_member, - is_constant); - var_sp->SetLocationIsConstantValueData(is_constant); + ranges, &decl, location, is_external, is_artificial, is_constant, + is_static_member, is_constant); m_variables.insert(std::make_pair(var_uid, var_sp)); return var_sp; diff --git a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp index b53b014ac25a1..77019492f43f8 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp @@ -23,9 +23,11 @@ #include "swift/AST/ASTMangler.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/Decl.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/GenericParamList.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/ImportCache.h" @@ -1264,6 +1266,7 @@ static const char *getImportFailureString(swift::serialization::Status status) { return "The module file was built for a target newer than the current " "target."; } + llvm_unreachable("covered switch"); } /// Initialize the compiler invocation with it the search paths from a @@ -2996,6 +2999,7 @@ class SwiftDWARFImporterDelegate : public swift::DWARFImporterDelegate { // described in DWARF. return true; } + llvm_unreachable("covered switch"); } clang::Decl *GetDeclForTypeAndKind(clang::QualType qual_type, @@ -3368,6 +3372,12 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { m_ast_context_ap->addModuleLoader(std::move(memory_buffer_loader_ap)); } + // Add a module interface checker. + m_ast_context_ap->addModuleInterfaceChecker( + std::make_unique(*m_ast_context_ap, + moduleCachePath, prebuiltModuleCachePath, + swift::ModuleInterfaceLoaderOptions())); + // 2. Create and install the module interface loader. // // The ordering of 2-4 is the same as the Swift compiler's 1-3, @@ -3382,8 +3392,9 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { if (loading_mode != swift::ModuleLoadingMode::OnlySerialized) { std::unique_ptr module_interface_loader_ap( swift::ModuleInterfaceLoader::create( - *m_ast_context_ap, moduleCachePath, prebuiltModuleCachePath, - m_dependency_tracker.get(), loading_mode)); + *m_ast_context_ap, *static_cast( + m_ast_context_ap->getModuleInterfaceChecker()), m_dependency_tracker.get(), + loading_mode)); if (module_interface_loader_ap) m_ast_context_ap->addModuleLoader(std::move(module_interface_loader_ap)); } @@ -4423,6 +4434,9 @@ static SwiftASTContext::TypeOrDecl DeclToTypeOrDecl(swift::ASTContext *ast, case swift::DeclKind::Accessor: case swift::DeclKind::PoundDiagnostic: break; + + default: + break; } } return CompilerType(); @@ -5559,6 +5573,9 @@ SwiftASTContext::GetTypeInfo(opaque_compiler_type_t type, case swift::TypeKind::SILToken: break; + + default: + break; } return swift_flags; } @@ -5572,18 +5589,11 @@ lldb::TypeClass SwiftASTContext::GetTypeClass(opaque_compiler_type_t type) { swift::CanType swift_can_type(GetCanonicalSwiftType(type)); const swift::TypeKind type_kind = swift_can_type->getKind(); switch (type_kind) { - case swift::TypeKind::Error: - return lldb::eTypeClassOther; case swift::TypeKind::BuiltinInteger: - return lldb::eTypeClassBuiltin; case swift::TypeKind::BuiltinFloat: - return lldb::eTypeClassBuiltin; case swift::TypeKind::BuiltinRawPointer: - return lldb::eTypeClassBuiltin; case swift::TypeKind::BuiltinNativeObject: - return lldb::eTypeClassBuiltin; case swift::TypeKind::BuiltinUnsafeValueBuffer: - return lldb::eTypeClassBuiltin; case swift::TypeKind::BuiltinBridgeObject: return lldb::eTypeClassBuiltin; case swift::TypeKind::BuiltinVector: @@ -5595,56 +5605,39 @@ lldb::TypeClass SwiftASTContext::GetTypeClass(opaque_compiler_type_t type) { case swift::TypeKind::WeakStorage: return ToCompilerType(swift_can_type->getReferenceStorageReferent()) .GetTypeClass(); - case swift::TypeKind::GenericTypeParam: - return lldb::eTypeClassOther; - case swift::TypeKind::DependentMember: - return lldb::eTypeClassOther; case swift::TypeKind::Enum: + case swift::TypeKind::BoundGenericEnum: return lldb::eTypeClassUnion; case swift::TypeKind::Struct: + case swift::TypeKind::BoundGenericStruct: return lldb::eTypeClassStruct; case swift::TypeKind::Class: + case swift::TypeKind::BoundGenericClass: return lldb::eTypeClassClass; + case swift::TypeKind::GenericTypeParam: + case swift::TypeKind::DependentMember: case swift::TypeKind::Protocol: - return lldb::eTypeClassOther; + case swift::TypeKind::ProtocolComposition: case swift::TypeKind::Metatype: - return lldb::eTypeClassOther; case swift::TypeKind::Module: - return lldb::eTypeClassOther; case swift::TypeKind::PrimaryArchetype: case swift::TypeKind::OpenedArchetype: case swift::TypeKind::NestedArchetype: - return lldb::eTypeClassOther; - case swift::TypeKind::Function: - return lldb::eTypeClassFunction; - case swift::TypeKind::GenericFunction: - return lldb::eTypeClassFunction; - case swift::TypeKind::ProtocolComposition: - return lldb::eTypeClassOther; - case swift::TypeKind::LValue: - return lldb::eTypeClassReference; case swift::TypeKind::UnboundGeneric: - return lldb::eTypeClassOther; - case swift::TypeKind::BoundGenericClass: - return lldb::eTypeClassClass; - case swift::TypeKind::BoundGenericEnum: - return lldb::eTypeClassUnion; - case swift::TypeKind::BoundGenericStruct: - return lldb::eTypeClassStruct; case swift::TypeKind::TypeVariable: - return lldb::eTypeClassOther; case swift::TypeKind::ExistentialMetatype: - return lldb::eTypeClassOther; - case swift::TypeKind::DynamicSelf: - return lldb::eTypeClassOther; case swift::TypeKind::SILBox: - return lldb::eTypeClassOther; - case swift::TypeKind::SILFunction: - return lldb::eTypeClassFunction; + case swift::TypeKind::DynamicSelf: case swift::TypeKind::SILBlockStorage: - return lldb::eTypeClassOther; case swift::TypeKind::Unresolved: + case swift::TypeKind::Error: return lldb::eTypeClassOther; + case swift::TypeKind::Function: + case swift::TypeKind::GenericFunction: + case swift::TypeKind::SILFunction: + return lldb::eTypeClassFunction; + case swift::TypeKind::LValue: + return lldb::eTypeClassReference; case swift::TypeKind::Optional: case swift::TypeKind::TypeAlias: @@ -5656,6 +5649,9 @@ lldb::TypeClass SwiftASTContext::GetTypeClass(opaque_compiler_type_t type) { case swift::TypeKind::SILToken: break; + + default: + break; } return lldb::eTypeClassOther; @@ -5884,10 +5880,11 @@ CompilerType SwiftASTContext::GetPointerType(opaque_compiler_type_t type) { VALID_OR_RETURN(CompilerType()); if (type) { - swift::Type swift_type(GetSwiftType({this, type})); - const swift::TypeKind type_kind = swift_type->getKind(); - if (type_kind == swift::TypeKind::BuiltinRawPointer) - return ToCompilerType({swift_type}); + auto swift_type = GetSwiftType({this, type}); + auto pointer_type = + swift_type->wrapInPointer(swift::PointerTypeKind::PTK_UnsafePointer); + if (pointer_type) + return ToCompilerType(pointer_type); } return {}; } @@ -6060,6 +6057,8 @@ SwiftASTContext::GetTypeBitAlign(opaque_compiler_type_t type, exe_scope->CalculateExecutionContext(exe_ctx); auto swift_scratch_ctx_lock = SwiftASTContextLock(&exe_ctx); CompilerType bound_type = BindGenericTypeParameters({this, type}, exe_scope); + if (bound_type.GetOpaqueQualType() == type) + return {}; // Note thay the bound type may be in a different AST context. return bound_type.GetTypeBitAlign(exe_scope); } @@ -6067,13 +6066,13 @@ SwiftASTContext::GetTypeBitAlign(opaque_compiler_type_t type, const swift::irgen::FixedTypeInfo *fixed_type_info = GetSwiftFixedTypeInfo(type); if (fixed_type_info) - return fixed_type_info->getFixedAlignment().getValue(); + return fixed_type_info->getFixedAlignment().getValue() * 8; // Ask the dynamic type system. if (!exe_scope) return {}; if (auto *runtime = SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) - return runtime->GetBitAlignment({this, type}); + return runtime->GetBitAlignment({this, type}, exe_scope); return {}; } @@ -6159,6 +6158,9 @@ lldb::Encoding SwiftASTContext::GetEncoding(opaque_compiler_type_t type, case swift::TypeKind::SILToken: break; + + default: + break; } count = 0; return lldb::eEncodingInvalid; @@ -6245,6 +6247,9 @@ lldb::Format SwiftASTContext::GetFormat(opaque_compiler_type_t type) { case swift::TypeKind::SILToken: break; + + default: + break; } // We don't know hot to display this type. return lldb::eFormatBytes; @@ -6357,6 +6362,9 @@ uint32_t SwiftASTContext::GetNumChildren(opaque_compiler_type_t type, case swift::TypeKind::SILToken: break; + + default: + break; } return num_children; @@ -6472,6 +6480,9 @@ uint32_t SwiftASTContext::GetNumFields(opaque_compiler_type_t type) { case swift::TypeKind::SILToken: break; + + default: + break; } return count; @@ -6757,6 +6768,9 @@ CompilerType SwiftASTContext::GetFieldAtIndex(opaque_compiler_type_t type, case swift::TypeKind::SILToken: break; + + default: + break; } return CompilerType(); @@ -6833,6 +6847,9 @@ uint32_t SwiftASTContext::GetNumPointeeChildren(opaque_compiler_type_t type) { case swift::TypeKind::SILToken: break; + + default: + break; } return 0; @@ -7196,6 +7213,9 @@ CompilerType SwiftASTContext::GetChildCompilerTypeAtIndex( case swift::TypeKind::SILToken: break; + + default: + break; } return CompilerType(); } @@ -7412,6 +7432,9 @@ size_t SwiftASTContext::GetIndexOfChildMemberWithName( case swift::TypeKind::SILToken: break; + + default: + break; } } return 0; @@ -7796,6 +7819,9 @@ bool SwiftASTContext::DumpTypeValue( case swift::TypeKind::SILToken: break; + + default: + break; } return 0; @@ -7921,8 +7947,7 @@ void SwiftASTContext::DumpTypeDescription(opaque_compiler_type_t type, bool print_help_if_available, bool print_extensions_if_available, lldb::DescriptionLevel level) { - llvm::SmallVector buf; - llvm::raw_svector_ostream llvm_ostrm(buf); + const auto initial_written_bytes = s->GetWrittenBytes(); if (type) { swift::CanType swift_can_type(GetCanonicalSwiftType(type)); @@ -8086,12 +8111,10 @@ void SwiftASTContext::DumpTypeDescription(opaque_compiler_type_t type, } } break; } - - if (buf.size() > 0) { - s->Write(buf.data(), buf.size()); - } } - s->Printf(""); + + if (s->GetWrittenBytes() == initial_written_bytes) + s->Printf(""); } TypeSP SwiftASTContext::GetCachedType(ConstString mangled) { @@ -8282,7 +8305,9 @@ static swift::ModuleDecl *LoadOneModule(const SourceModule &module, bool SwiftASTContext::GetImplicitImports( SwiftASTContext &swift_ast_context, SymbolContext &sc, ExecutionContextScope &exe_scope, lldb::StackFrameWP &stack_frame_wp, - llvm::SmallVectorImpl &modules, Status &error) { + llvm::SmallVectorImpl> + &modules, + Status &error) { if (!GetCompileUnitImports(swift_ast_context, sc, stack_frame_wp, modules, error)) { return false; @@ -8292,15 +8317,28 @@ bool SwiftASTContext::GetImplicitImports( sc.target_sp->GetSwiftPersistentExpressionState(exe_scope); // Get the hand-loaded modules from the SwiftPersistentExpressionState. - for (ConstString name : persistent_expression_state->GetHandLoadedModules()) { + for (auto &module_pair : + persistent_expression_state->GetHandLoadedModules()) { + + auto &attributed_import = module_pair.second; + + // If the ImportedModule in the SwiftPersistentExpressionState has a + // non-null ModuleDecl, add it to the ImplicitImports list. + if (attributed_import.module.importedModule) { + modules.emplace_back(attributed_import); + continue; + } + + // Otherwise, try reloading the ModuleDecl using the module name. SourceModule module_info; - module_info.path.push_back(name); - auto *module = LoadOneModule(module_info, swift_ast_context, stack_frame_wp, - error); + module_info.path.emplace_back(module_pair.first()); + auto *module = + LoadOneModule(module_info, swift_ast_context, stack_frame_wp, error); if (!module) return false; - modules.push_back(module); + attributed_import.module = swift::ImportedModule(module); + modules.emplace_back(attributed_import); } return true; } @@ -8312,23 +8350,13 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context, swift::SourceFile &source_file, Status &error) { llvm::SmallString<1> m_description; - llvm::SmallVector parsed_imports; - - swift::ModuleDecl::ImportFilter import_filter { - swift::ModuleDecl::ImportFilterKind::Exported, - swift::ModuleDecl::ImportFilterKind::Default, - swift::ModuleDecl::ImportFilterKind::ImplementationOnly, - swift::ModuleDecl::ImportFilterKind::SPIAccessControl, - swift::ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay - }; - - source_file.getImportedModules(parsed_imports, import_filter); auto *persistent_expression_state = sc.target_sp->GetSwiftPersistentExpressionState(exe_scope); - for (auto module_pair : parsed_imports) { - swift::ModuleDecl *module = module_pair.importedModule; + for (const auto &attributed_import : source_file.getImports()) { + swift::ModuleDecl *module = attributed_import.module.importedModule; + if (module) { std::string module_name; GetNameFromModule(module, module_name); @@ -8344,7 +8372,8 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context, return false; // How do we tell we are in REPL or playground mode? - persistent_expression_state->AddHandLoadedModule(module_const_str); + persistent_expression_state->AddHandLoadedModule(module_const_str, + attributed_import); } } } @@ -8354,16 +8383,18 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context, bool SwiftASTContext::GetCompileUnitImports( SwiftASTContext &swift_ast_context, SymbolContext &sc, lldb::StackFrameWP &stack_frame_wp, - llvm::SmallVectorImpl &modules, Status &error) { + llvm::SmallVectorImpl> + &modules, + Status &error) { // Import the Swift standard library and its dependencies. SourceModule swift_module; - swift_module.path.push_back(ConstString("Swift")); + swift_module.path.emplace_back("Swift"); auto *stdlib = LoadOneModule(swift_module, swift_ast_context, stack_frame_wp, error); if (!stdlib) return false; - modules.push_back(stdlib); + modules.emplace_back(swift::ImportedModule(stdlib)); CompileUnit *compile_unit = sc.comp_unit; if (!compile_unit || compile_unit->GetLanguage() != lldb::eLanguageTypeSwift) @@ -8384,7 +8415,7 @@ bool SwiftASTContext::GetCompileUnitImports( if (!loaded_module) return false; - modules.push_back(loaded_module); + modules.emplace_back(swift::ImportedModule(loaded_module)); } return true; } diff --git a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h index 223e0d2b7cd17..5a84782787839 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h +++ b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h @@ -175,6 +175,8 @@ class SwiftASTContext : public TypeSystemSwift { bool SupportsLanguage(lldb::LanguageType language) override; + SwiftASTContext *GetSwiftASTContext() override { return this; } + Status IsCompatible() override; swift::SourceManager &GetSourceManager(); @@ -763,7 +765,9 @@ class SwiftASTContext : public TypeSystemSwift { static bool GetImplicitImports( SwiftASTContext &swift_ast_context, SymbolContext &sc, ExecutionContextScope &exe_scope, lldb::StackFrameWP &stack_frame_wp, - llvm::SmallVectorImpl &modules, Status &error); + llvm::SmallVectorImpl> + &modules, + Status &error); /// Cache the user's imports from a SourceFile in a given execution scope such /// that they are carried over into future expression evaluations. @@ -774,11 +778,12 @@ class SwiftASTContext : public TypeSystemSwift { swift::SourceFile &source_file, Status &error); /// Retrieve the modules imported by the compilation unit. - static bool - GetCompileUnitImports(SwiftASTContext &swift_ast_context, SymbolContext &sc, - lldb::StackFrameWP &stack_frame_wp, - llvm::SmallVectorImpl &modules, - Status &error); + static bool GetCompileUnitImports( + SwiftASTContext &swift_ast_context, SymbolContext &sc, + lldb::StackFrameWP &stack_frame_wp, + llvm::SmallVectorImpl> + &modules, + Status &error); protected: /// This map uses the string value of ConstStrings as the key, and the diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h index 04b8235859c1c..adcba7e4984c7 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h @@ -27,6 +27,7 @@ class Decl; namespace lldb_private { class TypeSystemClang; +class SwiftASTContext; /// The implementation of lldb::Type's m_payload field for TypeSystemSwift. class TypePayloadSwift { @@ -97,6 +98,7 @@ class TypeSystemSwift : public TypeSystem { /// \} static LanguageSet GetSupportedLanguagesForTypes(); + virtual SwiftASTContext *GetSwiftASTContext() = 0; virtual Module *GetModule() const = 0; virtual lldb::TypeSP GetCachedType(ConstString mangled) = 0; virtual void SetCachedType(ConstString mangled, diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp index dde158b52ab98..a1c446c9e0a9f 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h" +#include "Plugins/TypeSystem/Swift/SwiftASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/TypeList.h" @@ -52,23 +53,39 @@ static ConstString GetTypeAlias(swift::Demangle::Demangler &dem, return ConstString(mangleNode(global)); } -/// Find a Clang type by name in module \p M. -static TypeSP LookupClangType(Module &M, StringRef name) { - llvm::SmallVector decl_context; - decl_context.push_back({CompilerContextKind::AnyModule, ConstString()}); - decl_context.push_back({CompilerContextKind::AnyType, ConstString(name)}); - llvm::DenseSet searched_symbol_files; - TypeMap clang_types; - M.FindTypes(decl_context, TypeSystemClang::GetSupportedLanguagesForTypes(), - searched_symbol_files, clang_types); - if (clang_types.Empty()) +/// Find a Clang type by name in the modules in \p module_holder. +static TypeSP LookupClangType(SwiftASTContext *module_holder, StringRef name) { + auto lookup = [](Module &M, StringRef name) -> TypeSP { + llvm::SmallVector decl_context; + decl_context.push_back({CompilerContextKind::AnyModule, ConstString()}); + decl_context.push_back({CompilerContextKind::AnyType, ConstString(name)}); + llvm::DenseSet searched_symbol_files; + TypeMap clang_types; + M.FindTypes(decl_context, TypeSystemClang::GetSupportedLanguagesForTypes(), + searched_symbol_files, clang_types); + if (clang_types.Empty()) + return {}; + return clang_types.GetTypeAtIndex(0); + }; + if (!module_holder) + return {}; + if (auto *M = module_holder->GetModule()) + return lookup(*M, name); + TargetSP target_sp = module_holder->GetTarget().lock(); + if (!target_sp) return {}; - return clang_types.GetTypeAtIndex(0); + TypeSP result; + target_sp->GetImages().ForEach([&](const ModuleSP &module) -> bool { + result = lookup(const_cast(*module), name); + return !result; + }); + return result; } /// Find a Clang type by name in module \p M. -CompilerType LookupClangForwardType(Module &M, StringRef name) { - if (TypeSP type = LookupClangType(M, name)) +static CompilerType LookupClangForwardType(SwiftASTContext *module_holder, + StringRef name) { + if (TypeSP type = LookupClangType(module_holder, name)) return type->GetForwardCompilerType(); return {}; } @@ -90,8 +107,7 @@ GetClangTypeNode(CompilerType clang_type, swift::Demangle::Demangler &dem) { } /// \return the child of the \p Type node. -static swift::Demangle::NodePointer GetType(swift::Demangle::Demangler &dem, - swift::Demangle::NodePointer n) { +static NodePointer GetType(swift::Demangle::NodePointer n) { using namespace swift::Demangle; if (!n || n->getKind() != Node::Kind::Global || !n->hasChildren()) return nullptr; @@ -109,7 +125,7 @@ static swift::Demangle::NodePointer GetType(swift::Demangle::Demangler &dem, static swift::Demangle::NodePointer GetDemangledType(swift::Demangle::Demangler &dem, StringRef name) { NodePointer n = dem.demangleSymbol(name); - return GetType(dem, n); + return GetType(n); } /// Resolve a type alias node and return a demangle tree for the @@ -120,22 +136,28 @@ GetDemangledType(swift::Demangle::Demangler &dem, StringRef name) { /// __C module are resolved as Clang types. /// static std::pair -ResolveTypeAlias(lldb_private::Module *M, swift::Demangle::Demangler &dem, +ResolveTypeAlias(SwiftASTContext *module_holder, + swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node, bool prefer_clang_types = false) { // Try to look this up as a Swift type alias. For each *Swift* // type alias there is a debug info entry that has the mangled // name as name and the aliased type as a type. ConstString mangled = GetTypeAlias(dem, node); - if (!M) { - LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), - "No module. Couldn't resolve type alias %s", mangled.AsCString()); - return {{}, {}}; - } TypeList types; if (!prefer_clang_types) { - llvm::DenseSet searched_symbol_files; - M->FindTypes({mangled}, false, 1, searched_symbol_files, types); + llvm::DenseSet searched_symbol_files; + if (auto *M = module_holder->GetModule()) + M->FindTypes({mangled}, false, 1, searched_symbol_files, types); + else if (TargetSP target_sp = module_holder->GetTarget().lock()) + target_sp->GetImages().FindTypes(nullptr, {mangled}, + false, 1, searched_symbol_files, types); + else { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "No module. Couldn't resolve type alias %s", + mangled.AsCString()); + return {{}, {}}; + } } if (prefer_clang_types || types.Empty()) { // No Swift type found -- this could be a Clang typedef. This @@ -147,7 +169,7 @@ ResolveTypeAlias(lldb_private::Module *M, swift::Demangle::Demangler &dem, node->getChild(1)->hasText()) { // Resolve the typedef within the Clang debug info. auto clang_type = - LookupClangForwardType(*M, node->getChild(1)->getText()); + LookupClangForwardType(module_holder, node->getChild(1)->getText()); if (!clang_type) return {{}, {}}; return {{}, clang_type.GetCanonicalType()}; @@ -181,158 +203,189 @@ ResolveTypeAlias(lldb_private::Module *M, swift::Demangle::Demangler &dem, return {n, {}}; } +std::string +TypeSystemSwiftTypeRef::GetTupleElementName(lldb::opaque_compiler_type_t type, + size_t idx) { + using namespace swift::Demangle; + Demangler dem; + NodePointer node = TypeSystemSwiftTypeRef::DemangleCanonicalType(dem, type); + if (!node || node->getKind() != Node::Kind::Tuple) + return ""; + if (node->getNumChildren() < idx) + return ""; + NodePointer child = node->getChild(idx); + if (child->getNumChildren() != 1 && + child->getKind() != Node::Kind::TupleElement) + return ""; + for (NodePointer name : *child) { + if (name->getKind() != Node::Kind::TupleElementName) + continue; + return name->getText().str(); + } + std::string name; + llvm::raw_string_ostream(name) << idx; + return name; +} + +swift::Demangle::NodePointer TypeSystemSwiftTypeRef::Transform( + swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node, + std::function + fn) { + if (!node) + return node; + using namespace swift::Demangle; + llvm::SmallVector children; + bool changed = false; + for (NodePointer child : *node) { + NodePointer transformed = Transform(dem, child, fn); + changed |= (child != transformed); + assert(transformed && "callback returned a nullptr"); + if (transformed) + children.push_back(transformed); + } + if (changed) { + // Create a new node with the transformed children. + auto kind = node->getKind(); + if (node->hasText()) + node = dem.createNodeWithAllocatedText(kind, node->getText()); + else if (node->hasIndex()) + node = dem.createNode(kind, node->getIndex()); + else + node = dem.createNode(kind); + for (NodePointer transformed_child : children) + node->addChild(transformed_child, dem); + } + return fn(node); +} + /// Iteratively resolve all type aliases in \p node by looking up their /// desugared types in the debug info of module \p M. static swift::Demangle::NodePointer -GetCanonicalNode(lldb_private::Module *M, swift::Demangle::Demangler &dem, +GetCanonicalNode(SwiftASTContext *module_holder, + swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node) { - if (!node) - return node; using namespace swift::Demangle; - auto getCanonicalNode = [&](NodePointer node) -> NodePointer { - return GetCanonicalNode(M, dem, node); - }; - - NodePointer canonical = nullptr; - auto kind = node->getKind(); - switch (kind) { - case Node::Kind::SugaredOptional: - // FIXME: Factor these three cases out. - assert(node->getNumChildren() == 1); - if (node->getNumChildren() != 1) - return node; - - canonical = dem.createNode(Node::Kind::BoundGenericEnum); - { - NodePointer type = dem.createNode(Node::Kind::Type); - NodePointer e = dem.createNode(Node::Kind::Enum); - NodePointer module = dem.createNodeWithAllocatedText(Node::Kind::Module, - swift::STDLIB_NAME); - e->addChild(module, dem); - NodePointer optional = - dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Optional"); - e->addChild(optional, dem); - type->addChild(e, dem); - canonical->addChild(type, dem); - } - { - NodePointer typelist = dem.createNode(Node::Kind::TypeList); - NodePointer type = dem.createNode(Node::Kind::Type); - type->addChild(getCanonicalNode(node->getFirstChild()), dem); - typelist->addChild(type, dem); - canonical->addChild(typelist, dem); - } - return canonical; - case Node::Kind::SugaredArray: { - assert(node->getNumChildren() == 1); - if (node->getNumChildren() != 1) - return node; - - canonical = dem.createNode(Node::Kind::BoundGenericStructure); - { - NodePointer type = dem.createNode(Node::Kind::Type); - NodePointer structure = dem.createNode(Node::Kind::Structure); - NodePointer module = dem.createNodeWithAllocatedText(Node::Kind::Module, - swift::STDLIB_NAME); - structure->addChild(module, dem); - NodePointer array = - dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Array"); - structure->addChild(array, dem); - type->addChild(structure, dem); - canonical->addChild(type, dem); - } - { - NodePointer typelist = dem.createNode(Node::Kind::TypeList); - NodePointer type = dem.createNode(Node::Kind::Type); - type->addChild(getCanonicalNode(node->getFirstChild()), dem); - typelist->addChild(type, dem); - canonical->addChild(typelist, dem); - } - return canonical; - } - case Node::Kind::SugaredDictionary: - // FIXME: This isnt covered by any test. - assert(node->getNumChildren() == 2); - if (node->getNumChildren() != 2) - return node; + return TypeSystemSwiftTypeRef::Transform(dem, node, [&](NodePointer node) { + NodePointer canonical = nullptr; + auto kind = node->getKind(); + switch (kind) { + case Node::Kind::SugaredOptional: + // FIXME: Factor these three cases out. + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; - canonical = dem.createNode(Node::Kind::BoundGenericStructure); - { - NodePointer type = dem.createNode(Node::Kind::Type); - NodePointer structure = dem.createNode(Node::Kind::Structure); - NodePointer module = dem.createNodeWithAllocatedText(Node::Kind::Module, - swift::STDLIB_NAME); - structure->addChild(module, dem); - NodePointer dict = - dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Dictionary"); - structure->addChild(dict, dem); - type->addChild(structure, dem); - canonical->addChild(type, dem); - } - { - NodePointer typelist = dem.createNode(Node::Kind::TypeList); + canonical = dem.createNode(Node::Kind::BoundGenericEnum); { NodePointer type = dem.createNode(Node::Kind::Type); - type->addChild(getCanonicalNode(node->getChild(0)), dem); + NodePointer e = dem.createNode(Node::Kind::Enum); + NodePointer module = dem.createNodeWithAllocatedText( + Node::Kind::Module, swift::STDLIB_NAME); + e->addChild(module, dem); + NodePointer optional = + dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Optional"); + e->addChild(optional, dem); + type->addChild(e, dem); + canonical->addChild(type, dem); + } + { + NodePointer typelist = dem.createNode(Node::Kind::TypeList); + NodePointer type = dem.createNode(Node::Kind::Type); + type->addChild(node->getFirstChild(), dem); typelist->addChild(type, dem); + canonical->addChild(typelist, dem); } + return canonical; + case Node::Kind::SugaredArray: { + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + + canonical = dem.createNode(Node::Kind::BoundGenericStructure); { NodePointer type = dem.createNode(Node::Kind::Type); - type->addChild(getCanonicalNode(node->getChild(1)), dem); + NodePointer structure = dem.createNode(Node::Kind::Structure); + NodePointer module = dem.createNodeWithAllocatedText( + Node::Kind::Module, swift::STDLIB_NAME); + structure->addChild(module, dem); + NodePointer array = + dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Array"); + structure->addChild(array, dem); + type->addChild(structure, dem); + canonical->addChild(type, dem); + } + { + NodePointer typelist = dem.createNode(Node::Kind::TypeList); + NodePointer type = dem.createNode(Node::Kind::Type); + type->addChild(node->getFirstChild(), dem); typelist->addChild(type, dem); + canonical->addChild(typelist, dem); } - canonical->addChild(typelist, dem); + return canonical; } - return canonical; - case Node::Kind::SugaredParen: - assert(node->getNumChildren() == 1); - if (node->getNumChildren() != 1) + case Node::Kind::SugaredDictionary: + // FIXME: This isnt covered by any test. + assert(node->getNumChildren() == 2); + if (node->getNumChildren() != 2) + return node; + + canonical = dem.createNode(Node::Kind::BoundGenericStructure); + { + NodePointer type = dem.createNode(Node::Kind::Type); + NodePointer structure = dem.createNode(Node::Kind::Structure); + NodePointer module = dem.createNodeWithAllocatedText( + Node::Kind::Module, swift::STDLIB_NAME); + structure->addChild(module, dem); + NodePointer dict = dem.createNodeWithAllocatedText( + Node::Kind::Identifier, "Dictionary"); + structure->addChild(dict, dem); + type->addChild(structure, dem); + canonical->addChild(type, dem); + } + { + NodePointer typelist = dem.createNode(Node::Kind::TypeList); + { + NodePointer type = dem.createNode(Node::Kind::Type); + type->addChild(node->getChild(0), dem); + typelist->addChild(type, dem); + } + { + NodePointer type = dem.createNode(Node::Kind::Type); + type->addChild(node->getChild(1), dem); + typelist->addChild(type, dem); + } + canonical->addChild(typelist, dem); + } + return canonical; + case Node::Kind::SugaredParen: + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + return node->getFirstChild(); + + case Node::Kind::BoundGenericTypeAlias: + case Node::Kind::TypeAlias: { + auto node_clangtype = ResolveTypeAlias(module_holder, dem, node); + if (CompilerType clang_type = node_clangtype.second) + return GetClangTypeNode(clang_type, dem); + if (node_clangtype.first) + return node_clangtype.first; return node; - return getCanonicalNode(node->getFirstChild()); - - case Node::Kind::BoundGenericTypeAlias: - case Node::Kind::TypeAlias: { - auto node_clangtype = ResolveTypeAlias(M, dem, node); - if (CompilerType clang_type = node_clangtype.second) - return getCanonicalNode(GetClangTypeNode(clang_type, dem)); - if (node_clangtype.first) - return getCanonicalNode(node_clangtype.first); + } + default: + break; + } return node; - } - case Node::Kind::DynamicSelf: { - // Substitute the static type for dynamic self. - assert(node->getNumChildren() == 1); - if (node->getNumChildren() != 1) - return node; - NodePointer type = node->getChild(0); - if (type->getKind() != Node::Kind::Type || type->getNumChildren() != 1) - return node; - return getCanonicalNode(type->getChild(0)); - } - default: - break; - } - - // Recurse through all children. - // FIXME: don't create new nodes if children don't change! - if (node->hasText()) - canonical = dem.createNodeWithAllocatedText(kind, node->getText()); - else if (node->hasIndex()) - canonical = dem.createNode(kind, node->getIndex()); - else - canonical = dem.createNode(kind); - for (unsigned i = 0; i < node->getNumChildren(); ++i) - canonical->addChild(getCanonicalNode(node->getChild(i)), dem); - return canonical; + }); } /// Return the demangle tree representation of this type's canonical /// (type aliases resolved) type. swift::Demangle::NodePointer TypeSystemSwiftTypeRef::GetCanonicalDemangleTree( - lldb_private::Module *Module, swift::Demangle::Demangler &dem, + SwiftASTContext *module_holder, swift::Demangle::Demangler &dem, StringRef mangled_name) { NodePointer node = dem.demangleSymbol(mangled_name); - NodePointer canonical = GetCanonicalNode(Module, dem, node); + NodePointer canonical = GetCanonicalNode(module_holder, dem, node); return canonical; } @@ -493,13 +546,10 @@ TypeSystemSwiftTypeRef::GetSwiftified(swift::Demangle::Demangler &dem, StringRef ident = GetObjCTypeName(node); if (ident.empty()) return node; - auto *Module = GetModule(); - if (!Module) - return node; // This is an imported Objective-C type; look it up in the // debug info. - TypeSP clang_type = LookupClangType(*Module, ident); + TypeSP clang_type = LookupClangType(m_swift_ast_context, ident); if (!clang_type) return node; @@ -553,128 +603,110 @@ TypeSystemSwiftTypeRef::GetSwiftified(swift::Demangle::Demangler &dem, swift::Demangle::NodePointer TypeSystemSwiftTypeRef::GetNodeForPrintingImpl( swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node, bool resolve_objc_module, bool desugar) { - if (!node) - return node; using namespace swift::Demangle; - auto getNodeForPrinting = [&](NodePointer node) -> NodePointer { - return GetNodeForPrintingImpl(dem, node, resolve_objc_module, desugar); - }; + return Transform(dem, node, [&](NodePointer node) { + NodePointer canonical = node; + auto kind = node->getKind(); + switch (kind) { + case Node::Kind::Class: + case Node::Kind::Structure: + case Node::Kind::TypeAlias: + return GetSwiftified(dem, node, resolve_objc_module); - NodePointer canonical = nullptr; - auto kind = node->getKind(); - switch (kind) { - case Node::Kind::Class: - case Node::Kind::Structure: - case Node::Kind::TypeAlias: - return GetSwiftified(dem, node, resolve_objc_module); + // + // The remaining cases are all about bug-for-bug compatibility + // with the type dumper and we don't need to carry them forward + // necessarily. + // - // - // The remaining cases are all about bug-for-bug compatibility - // with the type dumper and we don't need to carry them forward - // necessarily. - // - - // The type dumper doesn't print these. + // The type dumper doesn't print these. #define REF_STORAGE(Name, ...) \ case Node::Kind::Name: \ - return (node->getNumChildren() == 1) \ - ? getNodeForPrinting(node->getChild(0)) \ - : node; + return (node->getNumChildren() == 1) ? node->getChild(0) : node; #include "swift/AST/ReferenceStorage.def" - case Node::Kind::ImplFunctionType: { - // Rewrite ImplFunctionType nodes as FunctionType nodes. - NodePointer fnty = dem.createNode(Node::Kind::FunctionType); - NodePointer args = dem.createNode(Node::Kind::ArgumentTuple); - NodePointer rett = dem.createNode(Node::Kind::ReturnType); - NodePointer args_ty = dem.createNode(Node::Kind::Type); - NodePointer args_tuple = dem.createNode(Node::Kind::Tuple); - for (NodePointer child : *node) { - if (child->getKind() == Node::Kind::ImplParameter) { - for (NodePointer type : *node) - if (type->getKind() == Node::Kind::Type && - type->getNumChildren() == 1) - rett->addChild(type->getChild(0), dem); - } else if (child->getKind() == Node::Kind::ImplResult) { - for (NodePointer type : *node) - if (type->getKind() == Node::Kind::Type) - rett->addChild(type, dem); + case Node::Kind::ImplFunctionType: { + // Rewrite ImplFunctionType nodes as FunctionType nodes. + NodePointer fnty = dem.createNode(Node::Kind::FunctionType); + NodePointer args = dem.createNode(Node::Kind::ArgumentTuple); + NodePointer rett = dem.createNode(Node::Kind::ReturnType); + NodePointer args_ty = dem.createNode(Node::Kind::Type); + NodePointer args_tuple = dem.createNode(Node::Kind::Tuple); + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplParameter) { + for (NodePointer type : *node) + if (type->getKind() == Node::Kind::Type && + type->getNumChildren() == 1) + rett->addChild(type->getChild(0), dem); + } else if (child->getKind() == Node::Kind::ImplResult) { + for (NodePointer type : *node) + if (type->getKind() == Node::Kind::Type) + rett->addChild(type, dem); + } } + args_ty->addChild(args_tuple, dem); + args->addChild(args_ty, dem); + fnty->addChild(args, dem); + if (rett->getNumChildren() != 1) + rett->addChild(dem.createNode(Node::Kind::Tuple), dem); + fnty->addChild(rett, dem); + return fnty; } - args_ty->addChild(args_tuple, dem); - args->addChild(args_ty, dem); - fnty->addChild(args, dem); - if (rett->getNumChildren() != 1) - rett->addChild(dem.createNode(Node::Kind::Tuple), dem); - fnty->addChild(rett, dem); - return fnty; - } - case Node::Kind::SugaredOptional: - // This is particularly silly. The outermost sugared Optional is desugared. - // See SwiftASTContext::GetTypeName() and remove it there, too! - if (desugar && node->getNumChildren() == 1) { - desugar = false; - return Desugar(dem, node, Node::Kind::BoundGenericEnum, Node::Kind::Enum, - "Optional"); - } - return node; - case Node::Kind::SugaredArray: - // See comment on SugaredOptional. - if (desugar && node->getNumChildren() == 1) { - desugar = false; - return Desugar(dem, node, Node::Kind::BoundGenericStructure, - Node::Kind::Structure, "Array"); - } - return node; - case Node::Kind::SugaredDictionary: - // See comment on SugaredOptional. - if (desugar && node->getNumChildren() == 1) { - desugar = false; - return Desugar(dem, node, Node::Kind::BoundGenericStructure, - Node::Kind::Structure, "Dictionary"); + case Node::Kind::SugaredOptional: + // This is particularly silly. The outermost sugared Optional is + // desugared. See SwiftASTContext::GetTypeName() and remove it there, too! + if (desugar && node->getNumChildren() == 1) { + desugar = false; + return Desugar(dem, node, Node::Kind::BoundGenericEnum, + Node::Kind::Enum, "Optional"); + } + return node; + case Node::Kind::SugaredArray: + // See comment on SugaredOptional. + if (desugar && node->getNumChildren() == 1) { + desugar = false; + return Desugar(dem, node, Node::Kind::BoundGenericStructure, + Node::Kind::Structure, "Array"); + } + return node; + case Node::Kind::SugaredDictionary: + // See comment on SugaredOptional. + if (desugar && node->getNumChildren() == 1) { + desugar = false; + return Desugar(dem, node, Node::Kind::BoundGenericStructure, + Node::Kind::Structure, "Dictionary"); + } + return node; + case Node::Kind::DependentAssociatedTypeRef: + if (node->getNumChildren() == 2 && + node->getChild(0)->getKind() == Node::Kind::Identifier) + return node->getChild(0); + break; + default: + break; } - return node; - case Node::Kind::DependentAssociatedTypeRef: - if (node->getNumChildren() == 2 && - node->getChild(0)->getKind() == Node::Kind::Identifier) - return node->getChild(0); - break; - default: - break; - } - - // Recurse through all children. - // FIXME: don't create new nodes if children don't change! - if (node->hasText()) - canonical = dem.createNodeWithAllocatedText(kind, node->getText()); - else if (node->hasIndex()) - canonical = dem.createNode(kind, node->getIndex()); - else - canonical = dem.createNode(kind); - - // Bug-for-bug compatibility. Remove this loop! - // Strip out LocalDeclNames. - for (unsigned i = 0; i < node->getNumChildren(); ++i) { - NodePointer child = node->getChild(i); - if (child->getKind() == Node::Kind::LocalDeclName) - for (NodePointer identifier : *child) - if (identifier->getKind() == Node::Kind::Identifier) { - NodePointer module = nullptr; - if (node->getChild(0)->getNumChildren() > 1) - module = node->getChild(0)->getChild(0); - if (module->getKind() != Node::Kind::Module) - break; - - canonical->addChild(module, dem); - canonical->addChild(identifier, dem); - return canonical; - } - } - for (unsigned i = 0; i < node->getNumChildren(); ++i) - canonical->addChild(getNodeForPrinting(node->getChild(i)), dem); - return canonical; + // Bug-for-bug compatibility. Remove this loop! + // Strip out LocalDeclNames. + for (unsigned i = 0; i < node->getNumChildren(); ++i) { + NodePointer child = node->getChild(i); + if (child->getKind() == Node::Kind::LocalDeclName) + for (NodePointer identifier : *child) + if (identifier->getKind() == Node::Kind::Identifier) { + NodePointer module = nullptr; + if (node->getChild(0)->getNumChildren() > 1) + module = node->getChild(0)->getChild(0); + if (module->getKind() != Node::Kind::Module) + break; + + canonical->addChild(module, dem); + canonical->addChild(identifier, dem); + return canonical; + } + } + return canonical; + }); } /// Return the demangle tree representation with all "__C" module @@ -693,7 +725,8 @@ swift::Demangle::NodePointer TypeSystemSwiftTypeRef::GetDemangleTreeForPrinting( /// determine whether a node is generic or not, it needs to visit all /// nodes. The \p generic_walk argument specifies that the primary /// attributes have been collected and that we only look for generics. -static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, +static uint32_t collectTypeInfo(SwiftASTContext *module_holder, + swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node, bool generic_walk = false) { if (!node) @@ -737,6 +770,7 @@ static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, } else switch (node->getKind()) { + case Node::Kind::SugaredOptional: swift_flags |= eTypeIsGeneric | eTypeIsBound | eTypeHasChildren | eTypeHasValue | eTypeIsEnumeration; @@ -780,11 +814,18 @@ static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, swift_flags |= eTypeIsPointer | eTypeIsScalar; else if (node->getText() == swift::BUILTIN_TYPE_NAME_NATIVEOBJECT) swift_flags |= eTypeHasChildren | eTypeIsPointer | eTypeIsScalar; - else if (node->getText() == swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT) + else if (node->getText() == swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT || + node->getText() == swift::BUILTIN_TYPE_NAME_UNKNOWNOBJECT) swift_flags |= eTypeHasChildren | eTypeIsPointer | eTypeIsScalar | eTypeIsObjC; + else if (node->getText() == swift::BUILTIN_TYPE_NAME_FLOAT || + node->getText() == swift::BUILTIN_TYPE_NAME_FLOAT_PPC) + swift_flags |= eTypeIsFloat | eTypeIsScalar; else if (node->getText().startswith(swift::BUILTIN_TYPE_NAME_VEC)) swift_flags |= eTypeHasChildren | eTypeIsVector; + else if (node->getText().startswith(swift::BUILTIN_TYPE_NAME_INT) || + node->getText().startswith(swift::BUILTIN_TYPE_NAME_WORD)) + swift_flags |= eTypeIsInteger | eTypeIsScalar; } break; case Node::Kind::Tuple: @@ -800,7 +841,8 @@ static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, if (node->getNumChildren() != 2) break; // Bug-for-bug compatibility. - if (!(collectTypeInfo(M, dem, node->getChild(1)) & eTypeIsGenericTypeParam)) + if (!(collectTypeInfo(module_holder, dem, node->getChild(1)) & + eTypeIsGenericTypeParam)) swift_flags |= eTypeHasValue | eTypeHasChildren; auto module = node->getChild(0); if (module->hasText() && @@ -834,10 +876,9 @@ static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, if (ident->getKind() != Node::Kind::Identifier || !ident->hasText()) break; - if (!M) - break; // Look up the Clang type in DWARF. - CompilerType clang_type = LookupClangForwardType(*M, ident->getText()); + CompilerType clang_type = + LookupClangForwardType(module_holder, ident->getText()); collect_clang_type(clang_type.GetCanonicalType()); return swift_flags; } @@ -886,12 +927,14 @@ static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, case Node::Kind::TypeAlias: { // Bug-for-bug compatibility. // swift_flags |= eTypeIsTypedef; - auto node_clangtype = ResolveTypeAlias(M, dem, node); + auto node_clangtype = + ResolveTypeAlias(module_holder, dem, node); if (CompilerType clang_type = node_clangtype.second) { collect_clang_type(clang_type); return swift_flags; } - swift_flags |= collectTypeInfo(M, dem, node_clangtype.first, generic_walk); + swift_flags |= collectTypeInfo(module_holder, dem, node_clangtype.first, + generic_walk); return swift_flags; } default: @@ -904,7 +947,7 @@ static uint32_t collectTypeInfo(Module *M, swift::Demangle::Demangler &dem, // Visit the child nodes. for (unsigned i = 0; i < node->getNumChildren(); ++i) - swift_flags |= collectTypeInfo(M, dem, node->getChild(i), generic_walk); + swift_flags |= collectTypeInfo(module_holder, dem, node->getChild(i), generic_walk); return swift_flags; } @@ -1027,6 +1070,30 @@ DWARFASTParser *TypeSystemSwiftTypeRef::GetDWARFParser() { return m_swift_ast_context->GetDWARFParser(); } +TypeSP TypeSystemSwiftTypeRef::LookupTypeInModule( + lldb::opaque_compiler_type_t opaque_type) { + auto *M = GetModule(); + if (!M) + return {}; + swift::Demangle::Demangler dem; + auto *node = GetDemangledType(dem, AsMangledName(opaque_type)); + auto module_type = GetNominal(dem, node); + if (!module_type) + return {}; + // DW_AT_linkage_name is not part of the accelerator table, so + // we need to search by module+name. + ConstString module(module_type->first); + ConstString type(module_type->second); + llvm::SmallVector decl_context; + decl_context.push_back({CompilerContextKind::Module, module}); + decl_context.push_back({CompilerContextKind::AnyType, type}); + llvm::DenseSet searched_symbol_files; + TypeMap types; + M->FindTypes(decl_context, TypeSystemSwift::GetSupportedLanguagesForTypes(), + searched_symbol_files, types); + return types.Empty() ? TypeSP() : types.GetTypeAtIndex(0); +} + // Tests #ifndef NDEBUG @@ -1144,10 +1211,6 @@ template <> bool Equivalent(CompilerType l, CompilerType r) { /// matching that name. template <> bool Equivalent(ConstString l, ConstString r) { if (l != r) { - // Failure. Dump it for easier debugging. - llvm::dbgs() << "TypeSystemSwiftTypeRef diverges from SwiftASTContext: " - << l.GetStringRef() << " != " << r.GetStringRef() << "\n"; - // For some reason the Swift type dumper doesn't attach a module // name to the AnyObject protocol, and only that one. std::string l_prime = std::regex_replace( @@ -1180,7 +1243,11 @@ template <> bool Equivalent(ConstString l, ConstString r) { if (llvm::StringRef(l_prime) == r.GetStringRef()) return true; -#ifndef STRICT_VALIDATION +#ifdef STRICT_VALIDATION + // Failure. Dump it for easier debugging. + llvm::dbgs() << "TypeSystemSwiftTypeRef diverges from SwiftASTContext: " + << l.GetStringRef() << " != " << r.GetStringRef() << "\n"; +#else return true; #endif } @@ -1198,6 +1265,9 @@ bool Equivalent>(llvm::Optional l, // thus assume that a larger number is "better". if (l.hasValue() && r.hasValue() && *l > *r) return true; + // Assume that any value is "better" than none. + if (l.hasValue() && !r.hasValue()) + return true; llvm::dbgs() << l << " != " << r << "\n"; return false; } @@ -1256,9 +1326,9 @@ TypeSystemSwiftTypeRef::RemangleAsType(swift::Demangle::Demangler &dem, swift::Demangle::NodePointer TypeSystemSwiftTypeRef::DemangleCanonicalType( swift::Demangle::Demangler &dem, opaque_compiler_type_t opaque_type) { using namespace swift::Demangle; - NodePointer node = - GetCanonicalDemangleTree(GetModule(), dem, AsMangledName(opaque_type)); - return GetType(dem, node); + NodePointer node = GetCanonicalDemangleTree(m_swift_ast_context, dem, + AsMangledName(opaque_type)); + return GetType(node); } bool TypeSystemSwiftTypeRef::IsArrayType(opaque_compiler_type_t type, @@ -1518,7 +1588,7 @@ uint32_t TypeSystemSwiftTypeRef::GetTypeInfo( using namespace swift::Demangle; Demangler dem; NodePointer node = dem.demangleSymbol(AsMangledName(type)); - return collectTypeInfo(GetModule(), dem, node); + return collectTypeInfo(m_swift_ast_context, dem, node); }; VALIDATE_AND_RETURN(impl, GetTypeInfo, type, (ReconstructType(type), nullptr)); @@ -1567,13 +1637,35 @@ TypeSystemSwiftTypeRef::GetArrayElementType(opaque_compiler_type_t type, VALIDATE_AND_RETURN(impl, GetArrayElementType, type, (ReconstructType(type), nullptr, exe_scope)); } + +/// Determine wether this demangle tree contains an unresolved type alias. +static bool ContainsUnresolvedTypeAlias(swift::Demangle::NodePointer node) { + if (!node) + return false; + + if (node->getKind() == swift::Demangle::Node::Kind::TypeAlias) + return true; + + for (swift::Demangle::NodePointer child : *node) + if (ContainsUnresolvedTypeAlias(child)) + return true; + + return false; +} + CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(opaque_compiler_type_t type) { auto impl = [&]() { using namespace swift::Demangle; Demangler dem; NodePointer canonical = - GetCanonicalDemangleTree(GetModule(), dem, AsMangledName(type)); + GetCanonicalDemangleTree(m_swift_ast_context, dem, AsMangledName(type)); + if (ContainsUnresolvedTypeAlias(canonical)) { + // If this is a typealias defined in the expression evaluator, + // then we don't have debug info to resolve it from. + CompilerType ast_type = ReconstructType({this, type}).GetCanonicalType(); + return GetTypeFromMangledTypename(ast_type.GetMangledTypeName()); + } ConstString mangled(mangleNode(canonical)); return GetTypeFromMangledTypename(mangled); }; @@ -1636,9 +1728,46 @@ CompilerType TypeSystemSwiftTypeRef::GetPointeeType(opaque_compiler_type_t type) { return m_swift_ast_context->GetPointeeType(ReconstructType(type)); } + CompilerType TypeSystemSwiftTypeRef::GetPointerType(opaque_compiler_type_t type) { - return m_swift_ast_context->GetPointerType(ReconstructType(type)); + auto impl = [&]() -> CompilerType { + using namespace swift::Demangle; + Demangler dem; + + // The type that will be wrapped in UnsafePointer. + auto *pointee_type = GetDemangledType(dem, AsMangledName(type)); + // The UnsafePointer type. + auto *pointer_type = dem.createNode(Node::Kind::Type); + + auto *bgs = dem.createNode(Node::Kind::BoundGenericStructure); + pointer_type->addChild(bgs, dem); + + // Construct the first branch of BoundGenericStructure. + { + auto *type = dem.createNode(Node::Kind::Type); + bgs->addChild(type, dem); + auto *structure = dem.createNode(Node::Kind::Structure); + type->addChild(structure, dem); + structure->addChild(dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME), + dem); + structure->addChild( + dem.createNode(Node::Kind::Identifier, "UnsafePointer"), dem); + } + + // Construct the second branch of BoundGenericStructure. + { + auto *typelist = dem.createNode(Node::Kind::TypeList); + bgs->addChild(typelist, dem); + auto *type = dem.createNode(Node::Kind::Type); + typelist->addChild(type, dem); + type->addChild(pointee_type, dem); + } + + return RemangleAsType(dem, pointer_type); + }; + VALIDATE_AND_RETURN(impl, GetPointerType, type, (ReconstructType(type))); } // Exploring the type @@ -1665,34 +1794,23 @@ TypeSystemSwiftTypeRef::GetBitSize(opaque_compiler_type_t type, AsMangledName(type)); return {}; } + // The hot code path is to ask the Swift runtime for the size. if (auto *runtime = - SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) - return runtime->GetBitSize({this, type}, exe_scope); + SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) { + if (auto result = runtime->GetBitSize({this, type}, exe_scope)) + return result; + // If this is an expression context, perhaps the type was + // defined in the expression. In that case we don't have debug + // info for it, so defer to SwiftASTContext. + if (llvm::isa(m_swift_ast_context)) + return ReconstructType({this, type}).GetBitSize(exe_scope); + } // If there is no process, we can still try to get the static size // information out of DWARF. Because it is stored in the Type // object we need to look that up by name again. - if (auto *M = GetModule()) { - swift::Demangle::Demangler dem; - auto node = GetDemangledType(dem, AsMangledName(type)); - if (auto module_type = GetNominal(dem, node)) { - // DW_AT_linkage_name is not part of the accelerator table, so - // we need to search by module+name. - ConstString module(module_type->first); - ConstString type(module_type->second); - llvm::SmallVector decl_context; - decl_context.push_back({CompilerContextKind::Module, module}); - decl_context.push_back({CompilerContextKind::AnyType, type}); - llvm::DenseSet searched_symbol_files; - TypeMap types; - M->FindTypes(decl_context, - TypeSystemSwift::GetSupportedLanguagesForTypes(), - searched_symbol_files, types); - if (!types.Empty()) - if (auto type = types.GetTypeAtIndex(0)) - return type->GetByteSize(nullptr); - } - } + if (TypeSP type_sp = LookupTypeInModule(type)) + return type_sp->GetByteSize(exe_scope); LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), "Couldn't compute size of type %s without a process.", AsMangledName(type)); @@ -1793,7 +1911,7 @@ CompilerType TypeSystemSwiftTypeRef::GetAsClangTypeOrNull( node->getNumChildren() == 2 && node->getChild(0)->hasText() && node->getChild(0)->getText() == swift::MANGLING_MODULE_OBJC && node->getChild(1)->hasText()) { - auto node_clangtype = ResolveTypeAlias(GetModule(), dem, node, + auto node_clangtype = ResolveTypeAlias(m_swift_ast_context, dem, node, /*prefer_clang_types*/ true); if (node_clangtype.second) return node_clangtype.second; @@ -1814,8 +1932,8 @@ bool TypeSystemSwiftTypeRef::IsImportedType(opaque_compiler_type_t type, StringRef ident = GetObjCTypeName(node); if (ident.empty()) return {}; - if (original_type && GetModule()) - if (TypeSP clang_type = LookupClangType(*GetModule(), ident)) + if (original_type) + if (TypeSP clang_type = LookupClangType(m_swift_ast_context, ident)) *original_type = clang_type->GetForwardCompilerType(); return true; }; @@ -1866,10 +1984,58 @@ TypeSystemSwift::TypeAllocationStrategy TypeSystemSwiftTypeRef::GetAllocationStrategy(opaque_compiler_type_t type) { return m_swift_ast_context->GetAllocationStrategy(ReconstructType(type)); } + CompilerType TypeSystemSwiftTypeRef::CreateTupleType( const std::vector &elements) { - return m_swift_ast_context->CreateTupleType(elements); + auto impl = [&]() -> CompilerType { + using namespace swift::Demangle; + Demangler dem; + auto *tuple_type = dem.createNode(Node::Kind::Type); + auto *tuple = dem.createNode(Node::Kind::Tuple); + tuple_type->addChild(tuple, dem); + + for (const auto &element : elements) { + auto *tuple_element = dem.createNode(Node::Kind::TupleElement); + tuple->addChild(tuple_element, dem); + + // Add the element's name, if it has one. + // Ex: `(Int, Int)` vs `(x: Int, y: Int)` + if (!element.element_name.IsEmpty()) { + auto *name = dem.createNode(Node::Kind::TupleElementName, + element.element_name.GetStringRef()); + tuple_element->addChild(name, dem); + } + + auto *type = dem.createNode(Node::Kind::Type); + tuple_element->addChild(type, dem); + auto *element_type = GetDemangledType( + dem, element.element_type.GetMangledTypeName().GetStringRef()); + type->addChild(element_type, dem); + } + + return RemangleAsType(dem, tuple_type); + }; + + // The signature of VALIDATE_AND_RETURN doesn't support this function, below + // is an inlined function-specific variation. +#ifndef NDEBUG + { + auto result = impl(); + if (!m_swift_ast_context) + return result; + bool equivalent = + Equivalent(result, m_swift_ast_context->CreateTupleType(elements)); + if (!equivalent) + llvm::dbgs() << "failing tuple type\n"; + assert(equivalent && + "TypeSystemSwiftTypeRef diverges from SwiftASTContext"); + return result; + } +#else + return impl(); +#endif } + void TypeSystemSwiftTypeRef::DumpTypeDescription( opaque_compiler_type_t type, bool print_help_if_available, bool print_extensions_if_available, lldb::DescriptionLevel level) { @@ -1947,7 +2113,46 @@ bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType( llvm::Optional TypeSystemSwiftTypeRef::GetTypeBitAlign(opaque_compiler_type_t type, ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetTypeBitAlign(ReconstructType(type), exe_scope); + // This method doesn't use VALIDATE_AND_RETURN because except for + // fixed-size types the SwiftASTContext implementation forwards to + // SwiftLanguageRuntime anyway and for many fixed-size types the + // fixed layout still returns an incorrect default alignment of 0. + // + // Clang types can be resolved even without a process. + if (CompilerType clang_type = GetAsClangTypeOrNull(type)) { + // Swift doesn't know pointers: return the size alignment of the + // object pointer instead of the underlying object. + if (Flags(clang_type.GetTypeInfo()).AllSet(eTypeIsObjC | eTypeIsClass)) + return GetPointerByteSize() * 8; + return clang_type.GetTypeBitAlign(exe_scope); + } + if (!exe_scope) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Couldn't compute alignment of type %s without an execution " + "context.", + AsMangledName(type)); + return {}; + } + if (auto *runtime = + SwiftLanguageRuntime::Get(exe_scope->CalculateProcess())) { + if (auto result = runtime->GetBitAlignment({this, type}, exe_scope)) + return result; + // If this is an expression context, perhaps the type was + // defined in the expression. In that case we don't have debug + // info for it, so defer to SwiftASTContext. + if (llvm::isa(m_swift_ast_context)) + return ReconstructType({this, type}).GetTypeBitAlign(exe_scope); + } + + // If there is no process, we can still try to get the static + // alignment information out of DWARF. Because it is stored in the + // Type object we need to look that up by name again. + if (TypeSP type_sp = LookupTypeInModule(type)) + return type_sp->GetLayoutCompilerType().GetTypeBitAlign(exe_scope); + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Couldn't compute alignment of type %s without a process.", + AsMangledName(type)); + return {}; } bool TypeSystemSwiftTypeRef::IsTypedefType(opaque_compiler_type_t type) { return m_swift_ast_context->IsTypedefType(ReconstructType(type)); diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h index 443ff60000d05..b43ff7ab4236a 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h @@ -49,6 +49,7 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { /// \} TypeSystemSwiftTypeRef(SwiftASTContext *swift_ast_context); + SwiftASTContext *GetSwiftASTContext() override { return m_swift_ast_context; } Module *GetModule() const override; swift::CanType GetCanonicalSwiftType(CompilerType compiler_type); @@ -257,9 +258,22 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool print_help_if_available, bool print_extensions_if_available, lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override; + /// Return the nth tuple element's name, if it has one. + std::string GetTupleElementName(lldb::opaque_compiler_type_t type, + size_t idx); + + /// Recursively transform the demangle tree starting a \p node by + /// doing a post-order traversal and replacing each node with + /// fn(node). + /// The NodePointer passed to \p fn is guaranteed to be non-null. + static swift::Demangle::NodePointer Transform( + swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node, + std::function + fn); + /// Return the canonicalized Demangle tree for a Swift mangled type name. static swift::Demangle::NodePointer - GetCanonicalDemangleTree(lldb_private::Module *Module, + GetCanonicalDemangleTree(SwiftASTContext *module_holder, swift::Demangle::Demangler &dem, llvm::StringRef mangled_name); @@ -278,6 +292,9 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { /// Cast \p opaque_type as a mangled name. const char *AsMangledName(lldb::opaque_compiler_type_t type); + /// Lookup a type in the debug info. + lldb::TypeSP LookupTypeInModule(lldb::opaque_compiler_type_t type); + /// Demangle the mangled name of the canonical type of \p type and /// drill into the Global(TypeMangling(Type())). /// diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index 8f1dd0c79a470..a1caa05f27904 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -1012,11 +1012,15 @@ void SymbolContextSpecifier::Clear() { m_type = eNothingSpecified; } -bool SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) { +bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext &sc) { if (m_type == eNothingSpecified) return true; - if (m_target_sp.get() != sc.target_sp.get()) + // Only compare targets if this specifier has one and it's not the Dummy + // target. Otherwise if a specifier gets made in the dummy target and + // copied over we'll artificially fail the comparision. + if (m_target_sp && !m_target_sp->IsDummyTarget() && + m_target_sp != sc.target_sp) return false; if (m_type & eModuleSpecified) { diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp index a83b8b258b239..bd1d3204a0ee3 100644 --- a/lldb/source/Symbol/Variable.cpp +++ b/lldb/source/Symbol/Variable.cpp @@ -40,12 +40,13 @@ Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled, ValueType scope, SymbolContextScope *context, const RangeList &scope_range, Declaration *decl_ptr, const DWARFExpression &location, bool external, - bool artificial, bool static_member, bool constant) + bool artificial, bool location_is_constant_data, + bool static_member, bool constant) : UserID(uid), m_name(name), m_mangled(ConstString(mangled)), m_symfile_type_sp(symfile_type_sp), m_scope(scope), m_owner_scope(context), m_scope_range(scope_range), m_declaration(decl_ptr), m_location(location), m_external(external), - m_artificial(artificial), m_loc_is_const_data(false), + m_artificial(artificial), m_loc_is_const_data(location_is_constant_data), m_static_member(static_member), m_constant(constant) {} Variable::~Variable() {} diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index a7a33aca685e1..e9424cd602a06 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -19,7 +19,9 @@ #include "llvm/Support/TargetRegistry.h" #include +#ifdef LLDB_ENABLE_SWIFT #include "Plugins/TypeSystem/Swift/SwiftASTContext.h" +#endif //LLDB_ENABLE_SWIFT using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index bf0bd58de74a7..858adbe49117a 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -278,6 +278,12 @@ std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const { return std::chrono::seconds(value); } +bool ProcessProperties::GetSteppingRunsAllThreads() const { + const uint32_t idx = ePropertySteppingRunsAllThreads; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_process_properties[idx].default_uint_value != 0); +} + bool ProcessProperties::GetOSPluginReportsAllThreads() const { const bool fail_value = true; const Property *exp_property = @@ -4273,8 +4279,7 @@ void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) { // public (or SyncResume) broadcasters. StopHooks are just for // real public stops. They might also restart the target, // so watch for that. - process_sp->GetTarget().RunStopHooks(); - if (process_sp->GetPrivateState() == eStateRunning) + if (process_sp->GetTarget().RunStopHooks()) SetRestarted(true); } } diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 0fe36ef7f36b6..1261ca118b422 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -229,21 +229,16 @@ bool StackFrame::ChangePC(addr_t pc) { const char *StackFrame::Disassemble() { std::lock_guard guard(m_mutex); - if (m_disassembly.Empty()) { - ExecutionContext exe_ctx(shared_from_this()); - Target *target = exe_ctx.GetTargetPtr(); - if (target) { - const char *plugin_name = nullptr; - const char *flavor = nullptr; - Disassembler::Disassemble(target->GetDebugger(), - target->GetArchitecture(), plugin_name, flavor, - exe_ctx, 0, false, 0, 0, m_disassembly); - } - if (m_disassembly.Empty()) - return nullptr; + if (!m_disassembly.Empty()) + return m_disassembly.GetData(); + + ExecutionContext exe_ctx(shared_from_this()); + if (Target *target = exe_ctx.GetTargetPtr()) { + Disassembler::Disassemble(target->GetDebugger(), target->GetArchitecture(), + *this, m_disassembly); } - return m_disassembly.GetData(); + return m_disassembly.Empty() ? nullptr : m_disassembly.GetData(); } Block *StackFrame::GetFrameBlock() { diff --git a/lldb/source/Target/SwiftLanguageRuntime.cpp b/lldb/source/Target/SwiftLanguageRuntime.cpp index e33f2a100d622..eae0cda89c8f7 100644 --- a/lldb/source/Target/SwiftLanguageRuntime.cpp +++ b/lldb/source/Target/SwiftLanguageRuntime.cpp @@ -270,7 +270,8 @@ class SwiftLanguageRuntimeStub { return {}; } - llvm::Optional GetBitAlignment(CompilerType type) { + llvm::Optional GetBitAlignment(CompilerType type, + ExecutionContextScope *exe_scope) { STUB_LOG(); return {}; } @@ -2131,8 +2132,9 @@ SwiftLanguageRuntime::GetByteStride(CompilerType type) { } llvm::Optional -SwiftLanguageRuntime::GetBitAlignment(CompilerType type) { - FORWARD(GetBitAlignment, type); +SwiftLanguageRuntime::GetBitAlignment(CompilerType type, + ExecutionContextScope *exe_scope) { + FORWARD(GetBitAlignment, type, exe_scope); } bool SwiftLanguageRuntime::IsValidErrorValue(ValueObject &in_value) { diff --git a/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp b/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp index 3a39fb6566741..5900ae2e323dd 100644 --- a/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp +++ b/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp @@ -280,6 +280,20 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, void *outBuffer) override { switch (type) { + // FIXME: add support for case DLQ_GetPtrAuthMask: + case DLQ_GetObjCReservedLowBits: { + auto *result = static_cast(outBuffer); + auto &triple = m_process.GetTarget().GetArchitecture().GetTriple(); + if (triple.isMacOSX() && triple.getArch() == llvm::Triple::x86_64) { + // Obj-C reserves low bit on 64-bit Intel macOS only. + // Other Apple platforms don't reserve this bit (even when + // running on x86_64-based simulators). + *result = 1; + } else { + *result = 0; + } + break; + } case DLQ_GetPointerSize: { auto result = static_cast(outBuffer); *result = m_process.GetAddressByteSize(); @@ -965,7 +979,7 @@ llvm::Optional SwiftLanguageRuntimeImpl::GetMemberVariableOffset( } if (offset) { LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), - "[GetMemberVariableOffset] offset of %s is %d", + "[GetMemberVariableOffset] offset of %s is %lld", member_name.str().c_str(), *offset); } else { LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), @@ -1325,9 +1339,20 @@ SwiftLanguageRuntimeImpl::BindGenericTypeParameters(StackFrame &stack_frame, } swift::Demangle::Demangler dem; - swift::Demangle::NodePointer canonical = - TypeSystemSwiftTypeRef::GetCanonicalDemangleTree( - ts.GetModule(), dem, mangled_name.GetStringRef()); + swift::Demangle::NodePointer canonical = TypeSystemSwiftTypeRef::Transform( + dem, dem.demangleSymbol(mangled_name.GetStringRef()), + [](swift::Demangle::NodePointer node) { + if (node->getKind() != Node::Kind::DynamicSelf) + return node; + // Substitute the static type for dynamic self. + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + NodePointer type = node->getChild(0); + if (type->getKind() != Node::Kind::Type || type->getNumChildren() != 1) + return node; + return type->getChild(0); + }); // Build the list of type substitutions. swift::reflection::GenericArgumentMap substitutions; @@ -1434,6 +1459,21 @@ SwiftLanguageRuntimeImpl::BindGenericTypeParameters(StackFrame &stack_frame, return type; }); + // Thicken generic metatypes. Once substituted, they should always + // be thick. TypeRef::subst() does the same transformation. + target_swift_type = + target_swift_type.transform([](swift::Type type) -> swift::Type { + using namespace swift; + const auto thin = MetatypeRepresentation::Thin; + const auto thick = MetatypeRepresentation::Thick; + if (auto *metatype = dyn_cast(type.getPointer())) + if (metatype->hasRepresentation() && + metatype->getRepresentation() == thin && + metatype->getInstanceType()->hasTypeParameter()) + return MetatypeType::get(metatype->getInstanceType(), thick); + return type; + }); + while (target_swift_type->hasOpaqueArchetype()) { auto old_type = target_swift_type; target_swift_type = target_swift_type.subst( @@ -2007,7 +2047,7 @@ bool SwiftLanguageRuntime::IsTaggedPointer(lldb::addr_t addr, // Check whether this is a reference to an Objective-C object. if ((addr & 1) == 1) return true; - } + } break; default: break; } @@ -2072,7 +2112,7 @@ lldb::addr_t SwiftLanguageRuntime::FixupAddress(lldb::addr_t addr, if (extra_deref) return refd_addr; } - } + } break; default: break; } @@ -2080,7 +2120,8 @@ lldb::addr_t SwiftLanguageRuntime::FixupAddress(lldb::addr_t addr, } const swift::reflection::TypeRef * -SwiftLanguageRuntimeImpl::GetTypeRef(CompilerType type, Module *module) { +SwiftLanguageRuntimeImpl::GetTypeRef(CompilerType type, + SwiftASTContext *module_holder) { // Demangle the mangled name. swift::Demangle::Demangler dem; ConstString mangled_name = type.GetMangledTypeName(); @@ -2089,7 +2130,8 @@ SwiftLanguageRuntimeImpl::GetTypeRef(CompilerType type, Module *module) { return nullptr; swift::Demangle::NodePointer node = TypeSystemSwiftTypeRef::GetCanonicalDemangleTree( - module ? module : ts->GetModule(), dem, mangled_name.GetStringRef()); + module_holder ? module_holder : ts->GetSwiftASTContext(), dem, + mangled_name.GetStringRef()); if (!node) return nullptr; @@ -2113,6 +2155,9 @@ SwiftLanguageRuntimeImpl::GetTypeInfo(CompilerType type, if (!ts) return nullptr; + // Resolve all type aliases. + type = type.GetCanonicalType(); + // Resolve all generic type parameters in the type for the current // frame. Archetype binding has to happen in the scratch context, // so we lock it while we are in this function. @@ -2132,7 +2177,7 @@ SwiftLanguageRuntimeImpl::GetTypeInfo(CompilerType type, // context, but we need to resolve (any DWARF links in) the typeref // in the original module. const swift::reflection::TypeRef *type_ref = - GetTypeRef(type, ts->GetModule()); + GetTypeRef(type, ts->GetSwiftASTContext()); if (!type_ref) return nullptr; @@ -2166,9 +2211,10 @@ SwiftLanguageRuntimeImpl::GetByteStride(CompilerType type) { } llvm::Optional -SwiftLanguageRuntimeImpl::GetBitAlignment(CompilerType type) { - if (auto *type_info = GetTypeInfo(type, nullptr)) - return type_info->getAlignment(); +SwiftLanguageRuntimeImpl::GetBitAlignment(CompilerType type, + ExecutionContextScope *exe_scope) { + if (auto *type_info = GetTypeInfo(type, exe_scope)) + return type_info->getAlignment() * 8; return {}; } diff --git a/lldb/source/Target/SwiftLanguageRuntimeImpl.h b/lldb/source/Target/SwiftLanguageRuntimeImpl.h index 834eb6f634925..bb8f894bbcd6c 100644 --- a/lldb/source/Target/SwiftLanguageRuntimeImpl.h +++ b/lldb/source/Target/SwiftLanguageRuntimeImpl.h @@ -92,7 +92,8 @@ class SwiftLanguageRuntimeImpl { llvm::Optional GetByteStride(CompilerType type); /// Ask Remote mirrors for the alignment of a Swift type. - llvm::Optional GetBitAlignment(CompilerType type); + llvm::Optional GetBitAlignment(CompilerType type, + ExecutionContextScope *exe_scope); SwiftLanguageRuntime::MetadataPromiseSP GetMetadataPromise(lldb::addr_t addr, ValueObject &for_object); @@ -147,19 +148,8 @@ class SwiftLanguageRuntimeImpl { protected: /// Use the reflection context to build a TypeRef object. - /// - /// \param module can be used to specify a module to look up DWARF - /// type references (such as type aliases and Clang types) - /// in. Module only needs to be specified when it is different from - /// \c type.GetTypeSystem().GetModule(). The only situation where it - /// is necessary to specify the module explicitly is if a type has - /// been imported into the scratch context. This is always the - /// module of the outermost type. Even for bound generic types, - /// we're only interested in the module the bound generic type came - /// from, the bound generic parameters can be resolved from their - /// type metadata alone. const swift::reflection::TypeRef *GetTypeRef(CompilerType type, - Module *module = nullptr); + SwiftASTContext *module_holder); /// If \p instance points to a Swift object, retrieve its /// RecordTypeInfo pass it to the callback \p fn. Repeat the process diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index a224d5098960b..182e262e6a242 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2504,7 +2504,8 @@ llvm::Optional Target::GetScratchSwiftASTContext( !swift_ast_ctx->HasFatalErrors()) { StackFrameWP frame_wp(frame_sp); SymbolContext sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything); - llvm::SmallVector modules; + llvm::SmallVector, 16> + modules; swift_ast_ctx->GetCompileUnitImports(*swift_ast_ctx, sc, frame_wp, modules, error); } @@ -2787,13 +2788,28 @@ ClangModulesDeclVendor *Target::GetClangModulesDeclVendor() { return m_clang_modules_decl_vendor_up.get(); } -Target::StopHookSP Target::CreateStopHook() { +Target::StopHookSP Target::CreateStopHook(StopHook::StopHookKind kind) { lldb::user_id_t new_uid = ++m_stop_hook_next_id; - Target::StopHookSP stop_hook_sp(new StopHook(shared_from_this(), new_uid)); + Target::StopHookSP stop_hook_sp; + switch (kind) { + case StopHook::StopHookKind::CommandBased: + stop_hook_sp.reset(new StopHookCommandLine(shared_from_this(), new_uid)); + break; + case StopHook::StopHookKind::ScriptBased: + stop_hook_sp.reset(new StopHookScripted(shared_from_this(), new_uid)); + break; + } m_stop_hooks[new_uid] = stop_hook_sp; return stop_hook_sp; } +void Target::UndoCreateStopHook(lldb::user_id_t user_id) { + if (!RemoveStopHookByID(user_id)) + return; + if (user_id == m_stop_hook_next_id) + m_stop_hook_next_id--; +} + bool Target::RemoveStopHookByID(lldb::user_id_t user_id) { size_t num_removed = m_stop_hooks.erase(user_id); return (num_removed != 0); @@ -2829,45 +2845,39 @@ void Target::SetAllStopHooksActiveState(bool active_state) { } } -void Target::RunStopHooks() { +bool Target::RunStopHooks() { if (m_suppress_stop_hooks) - return; + return false; if (!m_process_sp) - return; + return false; // Somebody might have restarted the process: + // Still return false, the return value is about US restarting the target. if (m_process_sp->GetState() != eStateStopped) - return; + return false; // make sure we check that we are not stopped // because of us running a user expression since in that case we do not want // to run the stop-hooks if (m_process_sp->GetModIDRef().IsLastResumeForUserExpression()) - return; + return false; if (m_stop_hooks.empty()) - return; - - StopHookCollection::iterator pos, end = m_stop_hooks.end(); + return false; // If there aren't any active stop hooks, don't bother either. - // Also see if any of the active hooks want to auto-continue. bool any_active_hooks = false; - bool auto_continue = false; for (auto hook : m_stop_hooks) { if (hook.second->IsActive()) { any_active_hooks = true; - auto_continue |= hook.second->GetAutoContinue(); + break; } } if (!any_active_hooks) - return; - - CommandReturnObject result(m_debugger.GetUseColor()); + return false; std::vector exc_ctx_with_reasons; - std::vector sym_ctx_with_reasons; ThreadList &cur_threadlist = m_process_sp->GetThreadList(); size_t num_threads = cur_threadlist.GetSize(); @@ -2875,103 +2885,127 @@ void Target::RunStopHooks() { lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex(i); if (cur_thread_sp->ThreadStoppedForAReason()) { lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0); - exc_ctx_with_reasons.push_back(ExecutionContext( - m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get())); - sym_ctx_with_reasons.push_back( - cur_frame_sp->GetSymbolContext(eSymbolContextEverything)); + exc_ctx_with_reasons.emplace_back(m_process_sp.get(), cur_thread_sp.get(), + cur_frame_sp.get()); } } // If no threads stopped for a reason, don't run the stop-hooks. size_t num_exe_ctx = exc_ctx_with_reasons.size(); if (num_exe_ctx == 0) - return; + return false; - result.SetImmediateOutputStream(m_debugger.GetAsyncOutputStream()); - result.SetImmediateErrorStream(m_debugger.GetAsyncErrorStream()); + StreamSP output_sp = m_debugger.GetAsyncOutputStream(); - bool keep_going = true; + bool auto_continue = false; bool hooks_ran = false; bool print_hook_header = (m_stop_hooks.size() != 1); bool print_thread_header = (num_exe_ctx != 1); - bool did_restart = false; + bool should_stop = false; + bool somebody_restarted = false; - for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++) { - // result.Clear(); - StopHookSP cur_hook_sp = (*pos).second; + for (auto stop_entry : m_stop_hooks) { + StopHookSP cur_hook_sp = stop_entry.second; if (!cur_hook_sp->IsActive()) continue; bool any_thread_matched = false; - for (size_t i = 0; keep_going && i < num_exe_ctx; i++) { - if ((cur_hook_sp->GetSpecifier() == nullptr || - cur_hook_sp->GetSpecifier()->SymbolContextMatches( - sym_ctx_with_reasons[i])) && - (cur_hook_sp->GetThreadSpecifier() == nullptr || - cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests( - exc_ctx_with_reasons[i].GetThreadRef()))) { - if (!hooks_ran) { - hooks_ran = true; - } - if (print_hook_header && !any_thread_matched) { - const char *cmd = - (cur_hook_sp->GetCommands().GetSize() == 1 - ? cur_hook_sp->GetCommands().GetStringAtIndex(0) - : nullptr); - if (cmd) - result.AppendMessageWithFormat("\n- Hook %" PRIu64 " (%s)\n", - cur_hook_sp->GetID(), cmd); - else - result.AppendMessageWithFormat("\n- Hook %" PRIu64 "\n", - cur_hook_sp->GetID()); - any_thread_matched = true; - } + for (auto exc_ctx : exc_ctx_with_reasons) { + // We detect somebody restarted in the stop-hook loop, and broke out of + // that loop back to here. So break out of here too. + if (somebody_restarted) + break; - if (print_thread_header) - result.AppendMessageWithFormat( - "-- Thread %d\n", - exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID()); - - CommandInterpreterRunOptions options; - options.SetStopOnContinue(true); - options.SetStopOnError(true); - options.SetEchoCommands(false); - options.SetPrintResults(true); - options.SetPrintErrors(true); - options.SetAddToHistory(false); - - // Force Async: - bool old_async = GetDebugger().GetAsyncExecution(); - GetDebugger().SetAsyncExecution(true); - GetDebugger().GetCommandInterpreter().HandleCommands( - cur_hook_sp->GetCommands(), &exc_ctx_with_reasons[i], options, - result); - GetDebugger().SetAsyncExecution(old_async); - // If the command started the target going again, we should bag out of - // running the stop hooks. - if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult) || - (result.GetStatus() == eReturnStatusSuccessContinuingResult)) { - // But only complain if there were more stop hooks to do: - StopHookCollection::iterator tmp = pos; - if (++tmp != end) - result.AppendMessageWithFormat( - "\nAborting stop hooks, hook %" PRIu64 - " set the program running.\n" - " Consider using '-G true' to make " - "stop hooks auto-continue.\n", - cur_hook_sp->GetID()); - keep_going = false; - did_restart = true; - } + if (!cur_hook_sp->ExecutionContextPasses(exc_ctx)) + continue; + + // We only consult the auto-continue for a stop hook if it matched the + // specifier. + auto_continue |= cur_hook_sp->GetAutoContinue(); + + if (!hooks_ran) + hooks_ran = true; + + if (print_hook_header && !any_thread_matched) { + StreamString s; + cur_hook_sp->GetDescription(&s, eDescriptionLevelBrief); + if (s.GetSize() != 0) + output_sp->Printf("\n- Hook %" PRIu64 " (%s)\n", cur_hook_sp->GetID(), + s.GetData()); + else + output_sp->Printf("\n- Hook %" PRIu64 "\n", cur_hook_sp->GetID()); + any_thread_matched = true; + } + + if (print_thread_header) + output_sp->Printf("-- Thread %d\n", + exc_ctx.GetThreadPtr()->GetIndexID()); + + StopHook::StopHookResult this_result = + cur_hook_sp->HandleStop(exc_ctx, output_sp); + bool this_should_stop = true; + + switch (this_result) { + case StopHook::StopHookResult::KeepStopped: + // If this hook is set to auto-continue that should override the + // HandleStop result... + if (cur_hook_sp->GetAutoContinue()) + this_should_stop = false; + else + this_should_stop = true; + + break; + case StopHook::StopHookResult::RequestContinue: + this_should_stop = false; + break; + case StopHook::StopHookResult::AlreadyContinued: + // We don't have a good way to prohibit people from restarting the + // target willy nilly in a stop hook. If the hook did so, give a + // gentle suggestion here and bag out if the hook processing. + output_sp->Printf("\nAborting stop hooks, hook %" PRIu64 + " set the program running.\n" + " Consider using '-G true' to make " + "stop hooks auto-continue.\n", + cur_hook_sp->GetID()); + somebody_restarted = true; + break; } + // If we're already restarted, stop processing stop hooks. + // FIXME: if we are doing non-stop mode for real, we would have to + // check that OUR thread was restarted, otherwise we should keep + // processing stop hooks. + if (somebody_restarted) + break; + + // If anybody wanted to stop, we should all stop. + if (!should_stop) + should_stop = this_should_stop; } } + + output_sp->Flush(); + + // If one of the commands in the stop hook already restarted the target, + // report that fact. + if (somebody_restarted) + return true; + // Finally, if auto-continue was requested, do it now: - if (!did_restart && auto_continue) - m_process_sp->PrivateResume(); + // We only compute should_stop against the hook results if a hook got to run + // which is why we have to do this conjoint test. + if ((hooks_ran && !should_stop) || auto_continue) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Status error = m_process_sp->PrivateResume(); + if (error.Success()) { + LLDB_LOG(log, "Resuming from RunStopHooks"); + return true; + } else { + LLDB_LOG(log, "Resuming from RunStopHooks failed: {0}", error); + return false; + } + } - result.GetImmediateOutputStream()->Flush(); - result.GetImmediateErrorStream()->Flush(); + return false; } const TargetPropertiesSP &Target::GetGlobalProperties() { @@ -3482,20 +3516,17 @@ void Target::FinalizeFileActions(ProcessLaunchInfo &info) { // Target::StopHook Target::StopHook::StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid) - : UserID(uid), m_target_sp(target_sp), m_commands(), m_specifier_sp(), + : UserID(uid), m_target_sp(target_sp), m_specifier_sp(), m_thread_spec_up() {} Target::StopHook::StopHook(const StopHook &rhs) : UserID(rhs.GetID()), m_target_sp(rhs.m_target_sp), - m_commands(rhs.m_commands), m_specifier_sp(rhs.m_specifier_sp), - m_thread_spec_up(), m_active(rhs.m_active), - m_auto_continue(rhs.m_auto_continue) { + m_specifier_sp(rhs.m_specifier_sp), m_thread_spec_up(), + m_active(rhs.m_active), m_auto_continue(rhs.m_auto_continue) { if (rhs.m_thread_spec_up) m_thread_spec_up = std::make_unique(*rhs.m_thread_spec_up); } -Target::StopHook::~StopHook() = default; - void Target::StopHook::SetSpecifier(SymbolContextSpecifier *specifier) { m_specifier_sp.reset(specifier); } @@ -3504,8 +3535,31 @@ void Target::StopHook::SetThreadSpecifier(ThreadSpec *specifier) { m_thread_spec_up.reset(specifier); } +bool Target::StopHook::ExecutionContextPasses(const ExecutionContext &exc_ctx) { + SymbolContextSpecifier *specifier = GetSpecifier(); + if (!specifier) + return true; + + bool will_run = true; + if (exc_ctx.GetFramePtr()) + will_run = GetSpecifier()->SymbolContextMatches( + exc_ctx.GetFramePtr()->GetSymbolContext(eSymbolContextEverything)); + if (will_run && GetThreadSpecifier() != nullptr) + will_run = + GetThreadSpecifier()->ThreadPassesBasicTests(exc_ctx.GetThreadRef()); + + return will_run; +} + void Target::StopHook::GetDescription(Stream *s, lldb::DescriptionLevel level) const { + + // For brief descriptions, only print the subclass description: + if (level == eDescriptionLevelBrief) { + GetSubclassDescription(s, level); + return; + } + unsigned indent_level = s->GetIndentLevel(); s->SetIndentLevel(indent_level + 2); @@ -3536,15 +3590,154 @@ void Target::StopHook::GetDescription(Stream *s, s->PutCString("\n"); s->SetIndentLevel(indent_level + 2); } + GetSubclassDescription(s, level); +} +void Target::StopHookCommandLine::GetSubclassDescription( + Stream *s, lldb::DescriptionLevel level) const { + // The brief description just prints the first command. + if (level == eDescriptionLevelBrief) { + if (m_commands.GetSize() == 1) + s->PutCString(m_commands.GetStringAtIndex(0)); + return; + } s->Indent("Commands: \n"); - s->SetIndentLevel(indent_level + 4); + s->SetIndentLevel(s->GetIndentLevel() + 4); uint32_t num_commands = m_commands.GetSize(); for (uint32_t i = 0; i < num_commands; i++) { s->Indent(m_commands.GetStringAtIndex(i)); s->PutCString("\n"); } - s->SetIndentLevel(indent_level); + s->SetIndentLevel(s->GetIndentLevel() - 4); +} + +// Target::StopHookCommandLine +void Target::StopHookCommandLine::SetActionFromString(const std::string &string) { + GetCommands().SplitIntoLines(string); +} + +void Target::StopHookCommandLine::SetActionFromStrings( + const std::vector &strings) { + for (auto string : strings) + GetCommands().AppendString(string.c_str()); +} + +Target::StopHook::StopHookResult +Target::StopHookCommandLine::HandleStop(ExecutionContext &exc_ctx, + StreamSP output_sp) { + assert(exc_ctx.GetTargetPtr() && "Can't call PerformAction on a context " + "with no target"); + + if (!m_commands.GetSize()) + return StopHookResult::KeepStopped; + + CommandReturnObject result(false); + result.SetImmediateOutputStream(output_sp); + Debugger &debugger = exc_ctx.GetTargetPtr()->GetDebugger(); + CommandInterpreterRunOptions options; + options.SetStopOnContinue(true); + options.SetStopOnError(true); + options.SetEchoCommands(false); + options.SetPrintResults(true); + options.SetPrintErrors(true); + options.SetAddToHistory(false); + + // Force Async: + bool old_async = debugger.GetAsyncExecution(); + debugger.SetAsyncExecution(true); + debugger.GetCommandInterpreter().HandleCommands(GetCommands(), &exc_ctx, + options, result); + debugger.SetAsyncExecution(old_async); + lldb::ReturnStatus status = result.GetStatus(); + if (status == eReturnStatusSuccessContinuingNoResult || + status == eReturnStatusSuccessContinuingResult) + return StopHookResult::AlreadyContinued; + return StopHookResult::KeepStopped; +} + +// Target::StopHookScripted +Status Target::StopHookScripted::SetScriptCallback( + std::string class_name, StructuredData::ObjectSP extra_args_sp) { + Status error; + + ScriptInterpreter *script_interp = + GetTarget()->GetDebugger().GetScriptInterpreter(); + if (!script_interp) { + error.SetErrorString("No script interpreter installed."); + return error; + } + + m_class_name = class_name; + + m_extra_args = new StructuredDataImpl(); + + if (extra_args_sp) + m_extra_args->SetObjectSP(extra_args_sp); + + m_implementation_sp = script_interp->CreateScriptedStopHook( + GetTarget(), m_class_name.c_str(), m_extra_args, error); + + return error; +} + +Target::StopHook::StopHookResult +Target::StopHookScripted::HandleStop(ExecutionContext &exc_ctx, + StreamSP output_sp) { + assert(exc_ctx.GetTargetPtr() && "Can't call HandleStop on a context " + "with no target"); + + ScriptInterpreter *script_interp = + GetTarget()->GetDebugger().GetScriptInterpreter(); + if (!script_interp) + return StopHookResult::KeepStopped; + + bool should_stop = script_interp->ScriptedStopHookHandleStop( + m_implementation_sp, exc_ctx, output_sp); + + return should_stop ? StopHookResult::KeepStopped + : StopHookResult::RequestContinue; +} + +void Target::StopHookScripted::GetSubclassDescription( + Stream *s, lldb::DescriptionLevel level) const { + if (level == eDescriptionLevelBrief) { + s->PutCString(m_class_name); + return; + } + s->Indent("Class:"); + s->Printf("%s\n", m_class_name.c_str()); + + // Now print the extra args: + // FIXME: We should use StructuredData.GetDescription on the m_extra_args + // but that seems to rely on some printing plugin that doesn't exist. + if (!m_extra_args->IsValid()) + return; + StructuredData::ObjectSP object_sp = m_extra_args->GetObjectSP(); + if (!object_sp || !object_sp->IsValid()) + return; + + StructuredData::Dictionary *as_dict = object_sp->GetAsDictionary(); + if (!as_dict || !as_dict->IsValid()) + return; + + uint32_t num_keys = as_dict->GetSize(); + if (num_keys == 0) + return; + + s->Indent("Args:\n"); + s->SetIndentLevel(s->GetIndentLevel() + 4); + + auto print_one_element = [&s](ConstString key, + StructuredData::Object *object) { + s->Indent(); + s->Printf("%s : %s\n", key.GetCString(), + object->GetStringValue().str().c_str()); + return true; + }; + + as_dict->ForEach(print_one_element); + + s->SetIndentLevel(s->GetIndentLevel() - 4); } static constexpr OptionEnumValueElement g_dynamic_value_types[] = { diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index d4d3740286b7c..e02a638492f94 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -254,7 +254,8 @@ Status TargetList::CreateTargetInternal( // If we have a valid architecture, make sure the current platform is // compatible with that architecture. if (!prefer_platform_arch && arch.IsValid()) { - if (!platform_sp->IsCompatibleArchitecture(arch, false, nullptr)) { + ArchSpec compatible_arch; + if (!platform_sp->IsCompatibleArchitecture(arch, false, &compatible_arch)) { platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); if (!is_dummy_target && platform_sp) debugger.GetPlatformList().SetSelectedPlatform(platform_sp); diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 3e86f5f0ae91b..e1ff447446159 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -235,6 +235,9 @@ let Definition = "process" in { def UtilityExpressionTimeout: Property<"utility-expression-timeout", "UInt64">, DefaultUnsignedValue<15>, Desc<"The time in seconds to wait for LLDB-internal utility expressions.">; + def SteppingRunsAllThreads: Property<"run-all-threads", "Boolean">, + DefaultFalse, + Desc<"If true, stepping operations will run all threads. This is equivalent to setting the run-mode option to 'all-threads'.">; } let Definition = "platform" in { diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index c72d33cdcba3c..0d5c02dfb98ca 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1423,7 +1423,7 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name, extra_args_impl)); - + thread_plan_sp->SetStopOthers(stop_other_threads); status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index f30ca6d158981..0bb56f351a157 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -18,7 +18,6 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" -#include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" @@ -27,6 +26,10 @@ #include +#ifdef LLDB_ENABLE_SWIFT +#include "lldb/Target/SwiftLanguageRuntime.h" +#endif //LLDB_ENABLE_SWIFT + using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp index 8171186319f5c..e83f0e9e715e4 100644 --- a/lldb/source/Target/ThreadPlanPython.cpp +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -25,11 +25,12 @@ using namespace lldb_private; // ThreadPlanPython -ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, +ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, StructuredDataImpl *args_data) : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_class_name(class_name), m_args_data(args_data), m_did_push(false) { + m_class_name(class_name), m_args_data(args_data), m_did_push(false), + m_stop_others(false) { SetIsMasterPlan(true); SetOkayToDiscard(true); SetPrivate(false); @@ -162,13 +163,6 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() { } // The ones below are not currently exported to Python. - -bool ThreadPlanPython::StopOthers() { - // For now Python plans run all threads, but we should add some controls for - // this. - return false; -} - void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { s->Printf("Python thread plan implemented by class %s.", m_class_name.c_str()); diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index a553fc9799a73..b6fb9bf6e030d 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -20,7 +20,6 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" -#include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanStepOverRange.h" #include "lldb/Target/ThreadPlanStepThrough.h" @@ -28,6 +27,10 @@ #include +#ifdef LLDB_ENABLE_SWIFT +#include "lldb/Target/SwiftLanguageRuntime.h" +#endif // LLDB_ENABLE_SWIFT + using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index dce32adbf0a36..4ec2e25c7e3b0 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -65,55 +65,49 @@ UnixSignals::UnixSignals(const UnixSignals &rhs) : m_signals(rhs.m_signals) {} UnixSignals::~UnixSignals() = default; void UnixSignals::Reset() { - // This builds one standard set of Unix Signals. If yours aren't quite in + // This builds one standard set of Unix Signals. If yours aren't quite in // this order, you can either subclass this class, and use Add & Remove to - // change them - // or you can subclass and build them afresh in your constructor; + // change them or you can subclass and build them afresh in your constructor. // - // Note: the signals below are the Darwin signals. Do not change these! + // Note: the signals below are the Darwin signals. Do not change these! + m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============ ======== ====== ====== - // =================================================== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()"); - AddSignal(7, "SIGEMT", false, true, true, "pollable event"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGBUS", false, true, true, "bus error"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call"); - AddSignal(13, "SIGPIPE", false, false, false, - "write on a pipe with no one to read it"); - AddSignal(14, "SIGALRM", false, false, false, "alarm clock"); - AddSignal(15, "SIGTERM", false, true, true, - "software termination signal from kill"); - AddSignal(16, "SIGURG", false, false, false, - "urgent condition on IO channel"); - AddSignal(17, "SIGSTOP", true, true, true, - "sendable stop signal not from tty"); - AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty"); - AddSignal(19, "SIGCONT", false, true, true, "continue a stopped process"); - AddSignal(20, "SIGCHLD", false, false, false, - "to parent on child stop or exit"); - AddSignal(21, "SIGTTIN", false, true, true, - "to readers process group upon background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, - "to readers process group upon background tty write"); - AddSignal(23, "SIGIO", false, false, false, "input/output possible signal"); - AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit"); - AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit"); - AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, false, false, "window size changes"); - AddSignal(29, "SIGINFO", false, true, true, "information request"); - AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2"); + + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()"); + AddSignal(7, "SIGEMT", false, true, true, "pollable event"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGBUS", false, true, true, "bus error"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call"); + AddSignal(13, "SIGPIPE", false, false, false, "write on a pipe with no one to read it"); + AddSignal(14, "SIGALRM", false, false, false, "alarm clock"); + AddSignal(15, "SIGTERM", false, true, true, "software termination signal from kill"); + AddSignal(16, "SIGURG", false, false, false, "urgent condition on IO channel"); + AddSignal(17, "SIGSTOP", true, true, true, "sendable stop signal not from tty"); + AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty"); + AddSignal(19, "SIGCONT", false, false, true, "continue a stopped process"); + AddSignal(20, "SIGCHLD", false, false, false, "to parent on child stop or exit"); + AddSignal(21, "SIGTTIN", false, true, true, "to readers process group upon background tty read"); + AddSignal(22, "SIGTTOU", false, true, true, "to readers process group upon background tty write"); + AddSignal(23, "SIGIO", false, false, false, "input/output possible signal"); + AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit"); + AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit"); + AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm"); + AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(28, "SIGWINCH", false, false, false, "window size changes"); + AddSignal(29, "SIGINFO", false, true, true, "information request"); + AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2"); + // clang-format on } void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress, diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index 942fec2350474..cbb2dc1fc4e9f 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -36,16 +36,6 @@ static const char *GetLLDBRepository() { #endif } -#if LLDB_IS_BUILDBOT_BUILD -static std::string GetBuildDate() { -#if defined(LLDB_BUILD_DATE) - return std::string(LLDB_BUILD_DATE); -#else - return std::string(); -#endif -} -#endif - #define QUOTE(str) #str #define EXPAND_AND_QUOTE(str) QUOTE(str) @@ -71,23 +61,14 @@ const char *lldb_private::GetVersion() { } g_version_str += ")"; } - -#if LLDB_IS_BUILDBOT_BUILD - std::string build_date = GetBuildDate(); - if(!build_date.empty()) - g_version_str += " (buildbot " + build_date + ")"; -#endif #ifdef LLDB_ENABLE_SWIFT auto const swift_version = swift::version::getSwiftFullVersion(); g_version_str += "\n" + swift_version; -#endif // LLDB_ENABLE_SWIFT - +#else // getSwiftFullVersion() also prints clang and llvm versions, no // need to print them again. We keep this code here to not diverge // too much from upstream. -#undef LLDB_UPSTREAM -#ifdef LLDB_UPSTREAM std::string clang_rev(clang::getClangRevision()); if (clang_rev.length() > 0) { g_version_str += "\n clang revision "; @@ -98,7 +79,7 @@ const char *lldb_private::GetVersion() { g_version_str += "\n llvm revision "; g_version_str += llvm_rev; } -#endif // LLDB_UPSTREAM +#endif // LLDB_ENABLE_SWIFT } return g_version_str.c_str(); } diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt index 986197f170b83..724196258a02f 100644 --- a/lldb/test/API/CMakeLists.txt +++ b/lldb/test/API/CMakeLists.txt @@ -1,6 +1,6 @@ function(add_python_test_target name test_script args comment) set(PYTHON_TEST_COMMAND - ${PYTHON_EXECUTABLE} + ${Python3_EXECUTABLE} ${test_script} ${args} ) @@ -32,13 +32,11 @@ option(LLDB_TEST_SWIFT "Use in-tree swift when testing lldb" On) if(LLDB_TEST_SWIFT) set(LLDB_SWIFTC ${SWIFT_BINARY_DIR}/bin/swiftc CACHE STRING "Path to swift compiler") set(LLDB_SWIFT_LIBS ${SWIFT_LIBRARY_DIR}/swift CACHE STRING "Path to swift libraries") + # Prefer the just-built stdlib over the system one. set(SWIFT_TEST_ARGS - --swift-compiler ${LLDB_SWIFTC} - # Prefer the just-built stdlib over the system one. --inferior-env "DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"" --inferior-env "LD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/${CMAKE_SYSTEM_PROCESSOR}\\\"" - --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"" - ) + --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"") endif() # END - Swift Mods @@ -53,14 +51,15 @@ set(LLDB_TEST_USER_ARGS # hash of filename and .text section, there *will* be conflicts inside # the build directory. set(LLDB_TEST_COMMON_ARGS - -s - ${CMAKE_BINARY_DIR}/lldb-test-traces -S nm -u CXXFLAGS -u CFLAGS ${SWIFT_TEST_ARGS} ) +# Configure the traces directory. +set(LLDB_TEST_TRACE_DIRECTORY "${PROJECT_BINARY_DIR}/lldb-test-traces" CACHE PATH "The test traces directory.") + # Set the path to the default lldb test executable. set(LLDB_DEFAULT_TEST_EXECUTABLE "${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb${CMAKE_EXECUTABLE_SUFFIX}") @@ -119,7 +118,7 @@ endif() if(CMAKE_HOST_APPLE) if(LLDB_BUILD_FRAMEWORK) - list(APPEND LLDB_TEST_COMMON_ARGS --framework ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework) + set(LLDB_FRAMEWORK_DIR ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework) endif() # Use the same identity for testing @@ -140,12 +139,12 @@ if(CMAKE_HOST_APPLE) elseif(TARGET debugserver) set(debugserver_path ${LLVM_RUNTIME_OUTPUT_INTDIR}/debugserver) message(STATUS "LLDB Tests use just-built debugserver: ${debugserver_path}") - list(APPEND LLDB_TEST_COMMON_ARGS --server ${debugserver_path}) + set(LLDB_TEST_SERVER ${debugserver_path}) add_lldb_test_dependency(debugserver) elseif(TARGET lldb-server) set(lldb_server_path ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-server) message(STATUS "LLDB Tests use just-built lldb-server: ${lldb_server_path}") - list(APPEND LLDB_TEST_COMMON_ARGS --server ${lldb_server_path}) + set(LLDB_TEST_SERVER ${lldb_server_path}) add_lldb_test_dependency(lldb-server) else() message(WARNING "LLDB Tests enabled, but no server available") @@ -160,12 +159,15 @@ if(LLDB_BUILT_STANDALONE) string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} config_runtime_output_dir ${LLVM_RUNTIME_OUTPUT_INTDIR}) string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_DOTEST_ARGS "${LLDB_DOTEST_ARGS}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_SOURCE_DIR "${LLDB_SOURCE_DIR}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_FRAMEWORK_DIR "${LLDB_FRAMEWORK_DIR}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_BUILD_DIRECTORY "${LLDB_TEST_BUILD_DIRECTORY}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_TRACE_DIRECTORY "${LLDB_TEST_TRACE_DIRECTORY}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_EXECUTABLE "${LLDB_TEST_EXECUTABLE}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_COMPILER "${LLDB_TEST_COMPILER}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_DSYMUTIL "${LLDB_TEST_DSYMUTIL}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_FILECHECK "${LLDB_TEST_FILECHECK}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_YAML2OBJ "${LLDB_TEST_YAML2OBJ}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_SERVER "${LLDB_TEST_SERVER}") # Remaining ones must be paths to the provided LLVM build-tree. if(LLVM_CONFIGURATION_TYPES) @@ -189,11 +191,13 @@ endif() string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_DOTEST_ARGS "${LLDB_DOTEST_ARGS}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_SOURCE_DIR "${LLDB_SOURCE_DIR}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_BUILD_DIRECTORY "${LLDB_TEST_BUILD_DIRECTORY}") +string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_TRACE_DIRECTORY "${LLDB_TEST_TRACE_DIRECTORY}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_EXECUTABLE "${LLDB_TEST_EXECUTABLE}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_COMPILER "${LLDB_TEST_COMPILER}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_DSYMUTIL "${LLDB_TEST_DSYMUTIL}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_FILECHECK "${LLDB_TEST_FILECHECK}") string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_YAML2OBJ "${LLDB_TEST_YAML2OBJ}") +string(REPLACE ${CMAKE_CFG_INTDIR} ${dotest_args_replacement} LLDB_TEST_SERVER "${LLDB_TEST_SERVER}") # Configure the API test suite. configure_lit_site_cfg( diff --git a/lldb/test/API/commands/disassemble/basic/TestFrameDisassemble.py b/lldb/test/API/commands/disassemble/basic/TestFrameDisassemble.py index 156458234a16f..5c573f064e1e3 100644 --- a/lldb/test/API/commands/disassemble/basic/TestFrameDisassemble.py +++ b/lldb/test/API/commands/disassemble/basic/TestFrameDisassemble.py @@ -57,4 +57,6 @@ def frame_disassemble_test(self): frame = threads[0].GetFrameAtIndex(0) disassembly = frame.Disassemble() - self.assertNotEqual(len(disassembly), 0, "Disassembly was empty.") + self.assertNotEqual(disassembly, "") + self.assertNotIn("error", disassembly) + self.assertIn(": nop", disassembly) diff --git a/lldb/test/API/commands/disassemble/basic/main.cpp b/lldb/test/API/commands/disassemble/basic/main.cpp index cfa2498fc0208..4a2d9c106e219 100644 --- a/lldb/test/API/commands/disassemble/basic/main.cpp +++ b/lldb/test/API/commands/disassemble/basic/main.cpp @@ -2,6 +2,7 @@ int sum (int a, int b) { int result = a + b; // Set a breakpoint here + asm("nop"); return result; } diff --git a/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/Makefile b/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/TestImportDefinitionArrayType.py b/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/TestImportDefinitionArrayType.py new file mode 100644 index 0000000000000..a485b94a680dc --- /dev/null +++ b/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/TestImportDefinitionArrayType.py @@ -0,0 +1,14 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestImportDefinitionArrayType(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp")) + + self.expect_expr("__private->o", result_type="char", result_value="'A'") diff --git a/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/main.cpp b/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/main.cpp new file mode 100644 index 0000000000000..99fc7b727cc80 --- /dev/null +++ b/lldb/test/API/commands/expression/codegen-crash-import-def-arraytype-element/main.cpp @@ -0,0 +1,52 @@ +// This is a reproducer for a crash during codegen. The base issue is when we +// Import the DeclContext we force FieldDecl that are RecordType to be defined +// since we need these to be defined in order to layout the class. +// This case involves an array member whose ElementType are records. In this +// case we need to check the ElementType of an ArrayType and if it is a record +// we need to import the definition. +struct A { + int x; +}; + +struct B { + // When we import the all the FieldDecl we need to check if we have an + // ArrayType and then check if the ElementType is a RecordDecl and if so + // import the defintion. Otherwise during codegen we will attempt to layout A + // but won't be able to. + A s1[2]; + A s2[2][2][3]; + char o; +}; + +class FB { +public: + union { + struct { + unsigned char *_s; + } t; + char *tt[1]; + } U; + + FB(B *p) : __private(p) {} + + // We import A but we don't import the definition. + void f(A **bounds) {} + + void init(); + +private: + B *__private; +}; + +void FB::init() { + return; // break here +} + +int main() { + B b; + FB fb(&b); + + b.o = 'A'; + + fb.init(); +} diff --git a/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py b/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py index ebe180998c634..bdd1ccc596964 100644 --- a/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py +++ b/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py @@ -41,3 +41,19 @@ def test_persistent_variables(self): # Test that $200 wasn't created by the previous expression. self.expect("expr $200", error=True, substrs=["use of undeclared identifier '$200'"]) + + # Try redeclaring the persistent variable with the same type. + # This should be rejected as we treat them as if they are globals. + self.expect("expr int $i = 123", error=True, + substrs=["error: redefinition of persistent variable '$i'"]) + self.expect_expr("$i", result_type="int", result_value="5") + + # Try redeclaring the persistent variable with another type. Should + # also be rejected. + self.expect("expr long $i = 123", error=True, + substrs=["error: redefinition of persistent variable '$i'"]) + self.expect_expr("$i", result_type="int", result_value="5") + + # Try assigning the persistent variable a new value. + self.expect("expr $i = 55") + self.expect_expr("$i", result_type="int", result_value="55") diff --git a/lldb/test/API/commands/help/TestHelp.py b/lldb/test/API/commands/help/TestHelp.py index c9dc39650d881..3147a2a47520b 100644 --- a/lldb/test/API/commands/help/TestHelp.py +++ b/lldb/test/API/commands/help/TestHelp.py @@ -81,6 +81,7 @@ def test_help_arch(self): substrs=['arm', 'i386', 'x86_64']) @no_debug_info_test + @swiftTest # Checks for the Swift version number in the output def test_help_version(self): """Test 'help version' and 'version' commands.""" self.expect("help version", diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py b/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py new file mode 100644 index 0000000000000..e650778fe8e3b --- /dev/null +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py @@ -0,0 +1,146 @@ +""" +Test stop hook functionality +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class TestStopHooks(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # If your test case doesn't stress debug info, the + # set this to true. That way it won't be run once for + # each debug info format. + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + full_path = os.path.join(self.getSourceDir(), "main.c") + self.main_start_line = line_number(full_path, "main()") + + def test_bad_handler(self): + """Test that we give a good error message when the handler is bad""" + self.script_setup() + result = lldb.SBCommandReturnObject() + + # First try the wrong number of args handler: + command = "target stop-hook add -P stop_hook.bad_handle_stop" + self.interp.HandleCommand(command, result) + self.assertFalse(result.Succeeded(), "Set the target stop hook") + self.assertIn("Wrong number of args", result.GetError(), "Got the wrong number of args error") + + # Next the no handler at all handler: + command = "target stop-hook add -P stop_hook.no_handle_stop" + + self.interp.HandleCommand(command, result) + self.assertFalse(result.Succeeded(), "Set the target stop hook") + self.assertIn('Class "stop_hook.no_handle_stop" is missing the required handle_stop callback', result.GetError(), "Got the right error") + + def test_stop_hooks_scripted(self): + """Test that a scripted stop hook works with no specifiers""" + self.stop_hooks_scripted(5) + + def test_stop_hooks_scripted_right_func(self): + """Test that a scripted stop hook fires when there is a function match""" + self.stop_hooks_scripted(5, "-n step_out_of_me") + + def test_stop_hooks_scripted_wrong_func(self): + """Test that a scripted stop hook doesn't fire when the function does not match""" + self.stop_hooks_scripted(0, "-n main") + + def test_stop_hooks_scripted_right_lines(self): + """Test that a scripted stop hook fires when there is a function match""" + self.stop_hooks_scripted(5, "-f main.c -l 1 -e %d"%(self.main_start_line)) + + def test_stop_hooks_scripted_wrong_lines(self): + """Test that a scripted stop hook doesn't fire when the function does not match""" + self.stop_hooks_scripted(0, "-f main.c -l %d -e 100"%(self.main_start_line)) + + def test_stop_hooks_scripted_auto_continue(self): + """Test that the --auto-continue flag works""" + self.do_test_auto_continue(False) + + def test_stop_hooks_scripted_return_false(self): + """Test that the returning False from a stop hook works""" + self.do_test_auto_continue(True) + + def do_test_auto_continue(self, return_true): + """Test that auto-continue works.""" + # We set auto-continue to 1 but the stop hook only applies to step_out_of_me, + # so we should end up stopped in main, having run the expression only once. + self.script_setup() + + result = lldb.SBCommandReturnObject() + + if return_true: + command = "target stop-hook add -P stop_hook.stop_handler -k increment -v 5 -k return_false -v 1 -n step_out_of_me" + else: + command = "target stop-hook add -G 1 -P stop_hook.stop_handler -k increment -v 5 -n step_out_of_me" + + self.interp.HandleCommand(command, result) + self.assertTrue(result.Succeeded, "Set the target stop hook") + + # First run to main. If we go straight to the first stop hook hit, + # run_to_source_breakpoint will fail because we aren't at original breakpoint + + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Stop here first", self.main_source_file) + + # Now set the breakpoint on step_out_of_me, and make sure we run the + # expression, then continue back to main. + bkpt = target.BreakpointCreateBySourceRegex("Set a breakpoint here and step out", self.main_source_file) + self.assertTrue(bkpt.GetNumLocations() > 0, "Got breakpoints in step_out_of_me") + process.Continue() + + var = target.FindFirstGlobalVariable("g_var") + self.assertTrue(var.IsValid()) + self.assertEqual(var.GetValueAsUnsigned(), 5, "Updated g_var") + + func_name = process.GetSelectedThread().frames[0].GetFunctionName() + self.assertEqual("main", func_name, "Didn't stop at the expected function.") + + def script_setup(self): + self.interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + + # Bring in our script file: + script_name = os.path.join(self.getSourceDir(), "stop_hook.py") + command = "command script import " + script_name + self.interp.HandleCommand(command, result) + self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError())) + + # set a breakpoint at the end of main to catch our auto-continue tests. + # Do it in the dummy target so it will get copied to our target even when + # we don't have a chance to stop. + dummy_target = self.dbg.GetDummyTarget() + dummy_target.BreakpointCreateBySourceRegex("return result", self.main_source_file) + + + def stop_hooks_scripted(self, g_var_value, specifier = None): + self.script_setup() + + result = lldb.SBCommandReturnObject() + + command = "target stop-hook add -P stop_hook.stop_handler -k increment -v 5 " + if specifier: + command += specifier + + self.interp.HandleCommand(command, result) + self.assertTrue(result.Succeeded, "Set the target stop hook") + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", self.main_source_file) + # At this point we've hit our stop hook so we should have run our expression, + # which increments g_var by the amount specified by the increment key's value. + while process.GetState() == lldb.eStateRunning: + continue + + var = target.FindFirstGlobalVariable("g_var") + self.assertTrue(var.IsValid()) + self.assertEqual(var.GetValueAsUnsigned(), g_var_value, "Updated g_var") diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index 64686afe627da..43447a845156d 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -1,5 +1,5 @@ """ -Test that stop hooks trigger on "step-out" +Test stop hook functionality """ @@ -18,10 +18,15 @@ class TestStopHooks(TestBase): # each debug info format. NO_DEBUG_INFO_TESTCASE = True - def test_stop_hooks_step_out(self): - """Test that stop hooks fire on step-out.""" + def setUp(self): + TestBase.setUp(self) self.build() self.main_source_file = lldb.SBFileSpec("main.c") + full_path = os.path.join(self.getSourceDir(), "main.c") + self.main_start_line = line_number(full_path, "main()") + + def test_stop_hooks_step_out(self): + """Test that stop hooks fire on step-out.""" self.step_out_test() def step_out_test(self): @@ -37,4 +42,3 @@ def step_out_test(self): self.assertTrue(var.IsValid()) self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var") - diff --git a/lldb/test/API/commands/target/stop-hooks/main.c b/lldb/test/API/commands/target/stop-hooks/main.c index d08ad14776b5a..16bfc0ce5db6b 100644 --- a/lldb/test/API/commands/target/stop-hooks/main.c +++ b/lldb/test/API/commands/target/stop-hooks/main.c @@ -10,5 +10,6 @@ int step_out_of_me() int main() { - return step_out_of_me(); + int result = step_out_of_me(); // Stop here first + return result; } diff --git a/lldb/test/API/commands/target/stop-hooks/stop_hook.py b/lldb/test/API/commands/target/stop-hooks/stop_hook.py new file mode 100644 index 0000000000000..1abc2bdeeb31b --- /dev/null +++ b/lldb/test/API/commands/target/stop-hooks/stop_hook.py @@ -0,0 +1,49 @@ +import lldb + +class stop_handler: + def __init__(self, target, extra_args, dict): + self.extra_args = extra_args + self.target = target + self.counter = 0 + ret_val = self.extra_args.GetValueForKey("return_false") + if ret_val: + self.ret_val = False + else: + self.ret_val = True + + def handle_stop(self, exe_ctx, stream): + self.counter += 1 + stream.Print("I have stopped %d times.\n"%(self.counter)) + increment = 1 + value = self.extra_args.GetValueForKey("increment") + if value: + incr_as_str = value.GetStringValue(100) + increment = int(incr_as_str) + else: + stream.Print("Could not find increment in extra_args\n") + frame = exe_ctx.GetFrame() + expression = "g_var += %d"%(increment) + expr_result = frame.EvaluateExpression(expression) + if not expr_result.GetError().Success(): + stream.Print("Error running expression: %s"%(expr_result.GetError().GetCString())) + value = exe_ctx.target.FindFirstGlobalVariable("g_var") + if not value.IsValid(): + stream.Print("Didn't get a valid value for g_var.") + else: + int_val = value.GetValueAsUnsigned() + stream.Print("Returning value: %d from handle_stop.\n"%(self.ret_val)) + return self.ret_val + +class bad_handle_stop: + def __init__(self, target, extra_args, dict): + print("I am okay") + + def handle_stop(self): + print("I am bad") + +class no_handle_stop: + def __init__(self, target, extra_args, dict): + print("I am okay") + + + diff --git a/lldb/test/API/functionalities/asan/.categories b/lldb/test/API/functionalities/asan/.categories new file mode 100644 index 0000000000000..c756cb1241945 --- /dev/null +++ b/lldb/test/API/functionalities/asan/.categories @@ -0,0 +1 @@ +instrumentation-runtime diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/Makefile b/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/Makefile new file mode 100644 index 0000000000000..ad42b20df4ed5 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 -gcolumn-info + +include Makefile.rules diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/TestBreakpointByFileColonLine.py b/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/TestBreakpointByFileColonLine.py new file mode 100644 index 0000000000000..011fcdce8da46 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/TestBreakpointByFileColonLine.py @@ -0,0 +1,42 @@ +""" +Test setting a breakpoint by line and column. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class BreakpointByLineAndColumnTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def testBreakpointSpecWithLine(self): + self.build() + exe = self.getBuildArtifact("a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # This one should work: + lldbutil.run_break_set_by_file_colon_line(self, "main.c:11", "main.c", 11, num_expected_locations = 1) + # Let's try an illegal specifier to make sure the command fails. I'm not being exhaustive + # since the UnitTest has more bad patterns. I'm just testing that if the SetFromString + # fails, we propagate the error. + self.expect("break set -y 'foo.c'", error=True) + + ## Skip gcc version less 7.1 since it doesn't support -gcolumn-info + @skipIf(compiler="gcc", compiler_version=['<', '7.1']) + def testBreakpointByLine(self): + self.build() + exe = self.getBuildArtifact("a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + main_c = lldb.SBFileSpec("main.c") + lldbutil.run_break_set_by_file_colon_line(self, "main.c:11:50", "main.c", 11, num_expected_locations = 1) + diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/main.c b/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/main.c new file mode 100644 index 0000000000000..6e3f7e2ddbf93 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_by_file_colon_line/main.c @@ -0,0 +1,14 @@ +int square(int x) +{ + return x * x; +} + +int main (int argc, char const *argv[]) +{ + int did_call = 0; + + // Line 11. v Column 50. + if(square(argc+1) != 0) { did_call = 1; return square(argc); } + // ^ + return square(0); +} diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py index 9a66df9a798b7..69e8862808394 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py @@ -287,3 +287,33 @@ def breakpoint_commands_on_creation(self): self.assertEqual(com_list.GetStringAtIndex(0), "bt", "First bt") self.assertEqual(com_list.GetStringAtIndex(1), "thread list", "Next thread list") self.assertEqual(com_list.GetStringAtIndex(2), "continue", "Last continue") + + def test_breakpoint_delete_disabled(self): + """Test 'break delete --disabled' works""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + self.assertTrue(target.IsValid(), "Created an invalid target.") + + bp_1 = target.BreakpointCreateByName("main") + bp_2 = target.BreakpointCreateByName("not_here") + bp_3 = target.BreakpointCreateByName("main") + bp_3.AddName("DeleteMeNot") + + bp_1.SetEnabled(False) + bp_3.SetEnabled(False) + + bp_id_1 = bp_1.GetID() + bp_id_2 = bp_2.GetID() + bp_id_3 = bp_3.GetID() + + self.runCmd("breakpoint delete --disabled DeleteMeNot") + + bp_1 = target.FindBreakpointByID(bp_id_1) + self.assertFalse(bp_1.IsValid(), "Didn't delete disabled breakpoint 1") + + bp_2 = target.FindBreakpointByID(bp_id_2) + self.assertTrue(bp_2.IsValid(), "Deleted enabled breakpoint 2") + + bp_3 = target.FindBreakpointByID(bp_id_3) + self.assertTrue(bp_3.IsValid(), "DeleteMeNot didn't protect disabled breakpoint 3") diff --git a/lldb/test/API/functionalities/mtc/.categories b/lldb/test/API/functionalities/mtc/.categories new file mode 100644 index 0000000000000..c756cb1241945 --- /dev/null +++ b/lldb/test/API/functionalities/mtc/.categories @@ -0,0 +1 @@ +instrumentation-runtime diff --git a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py index de5ed00f4d28a..b27f8530be4fb 100644 --- a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py +++ b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py @@ -19,6 +19,7 @@ class MTCSwiftPropertyTestCase(TestBase): @expectedFailureAll(bugnumber="rdar://60396797", setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin + @swiftTest def test(self): self.mtc_dylib_path = findMainThreadCheckerDylib() self.assertTrue(self.mtc_dylib_path != "") diff --git a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py index fbfaeea46e09b..9fc68a2e8feb9 100644 --- a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py +++ b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py @@ -19,6 +19,7 @@ class MTCSwiftTestCase(TestBase): @expectedFailureAll(bugnumber="rdar://60396797", setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin + @swiftTest def test(self): self.mtc_dylib_path = findMainThreadCheckerDylib() self.assertTrue(self.mtc_dylib_path != "") diff --git a/lldb/test/API/functionalities/step_scripted/Steps.py b/lldb/test/API/functionalities/step_scripted/Steps.py index 4133cbbe6086a..d41d01d43095e 100644 --- a/lldb/test/API/functionalities/step_scripted/Steps.py +++ b/lldb/test/API/functionalities/step_scripted/Steps.py @@ -75,9 +75,29 @@ def should_stop(self, event): if not self.value.IsValid(): return True - print("Got next value: %d"%(self.value.GetValueAsUnsigned())) if not self.value.GetValueDidChange(): self.child_thread_plan = self.queue_child_thread_plan() return False else: return True + +# This plan does nothing, but sets stop_mode to the +# value of GetStopOthers for this plan. +class StepReportsStopOthers(): + stop_mode_dict = {} + + def __init__(self, thread_plan, args_data, dict): + self.thread_plan = thread_plan + self.key = args_data.GetValueForKey("token").GetStringValue(1000) + + def should_stop(self, event): + self.thread_plan.SetPlanComplete(True) + print("Called in should_stop") + StepReportsStopOthers.stop_mode_dict[self.key] = self.thread_plan.GetStopOthers() + return True + + def should_step(self): + return True + + def explains_stop(self, event): + return True diff --git a/lldb/test/API/functionalities/step_scripted/TestStepScripted.py b/lldb/test/API/functionalities/step_scripted/TestStepScripted.py index 3a7665a34a3c4..cee0885da9c31 100644 --- a/lldb/test/API/functionalities/step_scripted/TestStepScripted.py +++ b/lldb/test/API/functionalities/step_scripted/TestStepScripted.py @@ -1,7 +1,7 @@ """ Tests stepping with scripted thread plans. """ - +import threading import lldb import lldbsuite.test.lldbutil as lldbutil from lldbsuite.test.decorators import * @@ -108,3 +108,58 @@ def do_test_checking_variable(self, use_cli): # And foo should have changed: self.assertTrue(foo_val.GetValueDidChange(), "Foo changed") + + def test_stop_others_from_command(self): + """Test that the stop-others flag is set correctly by the command line. + Also test that the run-all-threads property overrides this.""" + self.do_test_stop_others() + + def run_step(self, stop_others_value, run_mode, token): + import Steps + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + + cmd = "thread step-scripted -C Steps.StepReportsStopOthers -k token -v %s"%(token) + if run_mode != None: + cmd = cmd + " --run-mode %s"%(run_mode) + print(cmd) + interp.HandleCommand(cmd, result) + self.assertTrue(result.Succeeded(), "Step scripted failed: %s."%(result.GetError())) + print(Steps.StepReportsStopOthers.stop_mode_dict) + value = Steps.StepReportsStopOthers.stop_mode_dict[token] + self.assertEqual(value, stop_others_value, "Stop others has the correct value.") + + def do_test_stop_others(self): + self.build() + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", + self.main_source_file) + # First run with stop others false and see that we got that. + thread_id = "" + if sys.version_info.major == 2: + thread_id = str(threading._get_ident()) + else: + thread_id = str(threading.get_ident()) + + # all-threads should set stop others to False. + self.run_step(False, "all-threads", thread_id) + + # this-thread should set stop others to True + self.run_step(True, "this-thread", thread_id) + + # The default value should be stop others: + self.run_step(True, None, thread_id) + + # The target.process.run-all-threads should override this: + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + + interp.HandleCommand("settings set target.process.run-all-threads true", result) + self.assertTrue(result.Succeeded, "setting run-all-threads works.") + + self.run_step(False, None, thread_id) + + + + + diff --git a/lldb/test/API/functionalities/target_var/no_vars/Makefile b/lldb/test/API/functionalities/target_var/no_vars/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/functionalities/target_var/no_vars/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/functionalities/target_var/no_vars/TestTargetVarNoVars.py b/lldb/test/API/functionalities/target_var/no_vars/TestTargetVarNoVars.py new file mode 100644 index 0000000000000..60ca8b1252b35 --- /dev/null +++ b/lldb/test/API/functionalities/target_var/no_vars/TestTargetVarNoVars.py @@ -0,0 +1,21 @@ +""" +Test that target var with no variables returns a correct error +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestTargetVarNoVars(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def test_target_var_no_vars(self): + self.build() + lldbutil.run_to_name_breakpoint(self, 'main') + self.expect("target variable", substrs=['no global variables in current compile unit', 'main.c'], error=True) + diff --git a/lldb/test/API/functionalities/target_var/no_vars/main.c b/lldb/test/API/functionalities/target_var/no_vars/main.c new file mode 100644 index 0000000000000..d7877b0a519bb --- /dev/null +++ b/lldb/test/API/functionalities/target_var/no_vars/main.c @@ -0,0 +1,5 @@ +int +main(int argc, char **argv) +{ + return argc; +} diff --git a/lldb/test/API/functionalities/tsan/.categories b/lldb/test/API/functionalities/tsan/.categories new file mode 100644 index 0000000000000..c756cb1241945 --- /dev/null +++ b/lldb/test/API/functionalities/tsan/.categories @@ -0,0 +1 @@ +instrumentation-runtime diff --git a/lldb/test/API/functionalities/ubsan/.categories b/lldb/test/API/functionalities/ubsan/.categories new file mode 100644 index 0000000000000..c756cb1241945 --- /dev/null +++ b/lldb/test/API/functionalities/ubsan/.categories @@ -0,0 +1 @@ +instrumentation-runtime diff --git a/lldb/test/API/lang/c/enum_types/TestEnumTypes.py b/lldb/test/API/lang/c/enum_types/TestEnumTypes.py index cb5bb8eccaa29..0442dd34196a2 100644 --- a/lldb/test/API/lang/c/enum_types/TestEnumTypes.py +++ b/lldb/test/API/lang/c/enum_types/TestEnumTypes.py @@ -18,11 +18,9 @@ def setUp(self): # Find the line number to break inside main(). self.line = line_number('main.c', '// Set break point at this line.') - def test(self): - """Test 'image lookup -t days' and check for correct display and enum value printing.""" + def test_command_line(self): + """Test 'image lookup -t enum_test_days' and check for correct display and enum value printing.""" self.build() - exe = self.getBuildArtifact("a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) lldbutil.run_to_source_breakpoint( self, '// Breakpoint for bitfield', lldb.SBFileSpec("main.c")) @@ -63,10 +61,10 @@ def test(self): self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE, substrs=[' resolved, hit count = 1']) - # Look up information about the 'days' enum type. + # Look up information about the 'enum_test_days' enum type. # Check for correct display. - self.expect("image lookup -t days", DATA_TYPES_DISPLAYED_CORRECTLY, - substrs=['enum days {', + self.expect("image lookup -t enum_test_days", DATA_TYPES_DISPLAYED_CORRECTLY, + substrs=['enum enum_test_days {', 'Monday', 'Tuesday', 'Wednesday', @@ -124,3 +122,41 @@ def test(self): 'check for valid enumeration value', substrs=[enum_value]) lldbutil.continue_to_breakpoint(self.process(), bkpt) + + def check_enum_members(self, members): + name_matches = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "kNumDays"] + value_matches = [-3, -2, -1, 0, 1, 2, 3, 4] + + # First test that the list of members from the type works + num_matches = len(name_matches) + self.assertEqual(len(members), num_matches, "enum_members returns the right number of elements") + for idx in range(0, num_matches): + member = members[idx] + self.assertTrue(member.IsValid(), "Got a valid member for idx: %d"%(idx)) + self.assertEqual(member.name, name_matches[idx], "Name matches for %d"%(idx)) + self.assertEqual(member.signed, value_matches[idx], "Value matches for %d"%(idx)) + + def test_api(self): + """Test the the SBTypeEnumMember API's work correctly for enum_test_days""" + self.build() + target = lldbutil.run_to_breakpoint_make_target(self) + + types = target.FindTypes("enum_test_days") + self.assertEqual(len(types), 1, "Found more than one enum_test_days type...") + type = types.GetTypeAtIndex(0) + + # First check using the Python list returned by the type: + self.check_enum_members(type.enum_members) + + # Now use the SBTypeEnumMemberList. + member_list = type.GetEnumMembers() + self.check_enum_members(member_list) + + # Now check that the by name accessor works: + for member in member_list: + name = member.name + check_member = member_list[name] + self.assertTrue(check_member.IsValid(), "Got a valid member for %s."%(name)) + self.assertEqual(name, check_member.name, "Got back the right name") + self.assertEqual(member.unsigned, check_member.unsigned) + diff --git a/lldb/test/API/lang/c/enum_types/main.c b/lldb/test/API/lang/c/enum_types/main.c index b866044e5e125..0aa73c970ec6f 100644 --- a/lldb/test/API/lang/c/enum_types/main.c +++ b/lldb/test/API/lang/c/enum_types/main.c @@ -25,7 +25,7 @@ int main (int argc, char const *argv[]) Beta = 4 }; - enum days { + enum enum_test_days { Monday = -3, Tuesday, Wednesday, @@ -40,7 +40,7 @@ int main (int argc, char const *argv[]) int nonsense = a + b + c + ab + ac + all; enum non_bitfield omega = Alpha | Beta; - enum days day; + enum enum_test_days day; struct foo f; f.op = NULL; // Breakpoint for bitfield for (day = Monday - 1; day <= kNumDays + 1; day++) diff --git a/lldb/test/API/lang/swift/availability/TestAvailability.py b/lldb/test/API/lang/swift/availability/TestAvailability.py index 9d9f89da06a7b..e8083e056075a 100644 --- a/lldb/test/API/lang/swift/availability/TestAvailability.py +++ b/lldb/test/API/lang/swift/availability/TestAvailability.py @@ -41,6 +41,7 @@ def setUp(self): # Call super's setUp(). TestBase.setUp(self) + @swiftTest @skipIf(oslist=['linux', 'windows']) def testAvailability(self): platform_name = lldbplatformutil.getPlatform() @@ -139,5 +140,5 @@ class C4 { for breakpoint in breakpoints: threads = lldbutil.continue_to_breakpoint(process, breakpoint) - self.expect("p f()", "can call") + self.expect("expr -d no-run-target -- f()", "can call") diff --git a/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py b/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py index e54408916884e..6e665e17e0228 100644 --- a/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py +++ b/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py @@ -12,6 +12,7 @@ class SwiftCompletionTest(PExpectTest): # under ASAN on a loaded machine.. @skipIfAsan @skipUnlessDarwin + @swiftTest def test_basic_completion(self): self.launch(extra_args=["--repl"], executable=None, dimensions=(100,500)) @@ -41,6 +42,7 @@ def test_basic_completion(self): # under ASAN on a loaded machine.. @skipIfAsan @skipIf(oslist=['windows']) + @swiftTest def test_lldb_command_completion(self): self.launch(extra_args=["--repl"], executable=None, dimensions=(100,500)) diff --git a/lldb/test/API/lang/swift/delayed_parsing_crash/TestDelayedParsingCrash.py b/lldb/test/API/lang/swift/delayed_parsing_crash/TestDelayedParsingCrash.py index 3c0912ac0181f..e0768afb05784 100644 --- a/lldb/test/API/lang/swift/delayed_parsing_crash/TestDelayedParsingCrash.py +++ b/lldb/test/API/lang/swift/delayed_parsing_crash/TestDelayedParsingCrash.py @@ -1,4 +1,4 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals()) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest]) diff --git a/lldb/test/API/lang/swift/deserialization_failure/TestSwiftDeserializationFailure.py b/lldb/test/API/lang/swift/deserialization_failure/TestSwiftDeserializationFailure.py index 5499d5d21dae4..56fe6b2af2186 100644 --- a/lldb/test/API/lang/swift/deserialization_failure/TestSwiftDeserializationFailure.py +++ b/lldb/test/API/lang/swift/deserialization_failure/TestSwiftDeserializationFailure.py @@ -37,6 +37,7 @@ def run_tests(self, target, process): # FIXME: this is formatted incorrectly. self.expect("fr var t", substrs=["(T)"]) #, "world"]) + @swiftTest @skipIf(oslist=['windows']) @skipIf(debug_info=no_match(["dwarf"])) @expectedFailureAll(archs=["arm64", "arm64e", 'arm64_32'], bugnumber="") @@ -47,6 +48,7 @@ def test_missing_module(self): target, process, _, _ = lldbutil.run_to_name_breakpoint(self, 'main') self.run_tests(target, process) + @swiftTest @skipIf(oslist=['windows']) @skipIf(debug_info=no_match(["dwarf"])) @expectedFailureAll(archs=["arm64", "arm64e", 'arm64_32'], bugnumber="") diff --git a/lldb/test/API/lang/swift/dwarfimporter/from_dylib/TestSwiftDWARFImporterFromDylib.py b/lldb/test/API/lang/swift/dwarfimporter/from_dylib/TestSwiftDWARFImporterFromDylib.py index 7369fcd926fb5..876290917fb90 100644 --- a/lldb/test/API/lang/swift/dwarfimporter/from_dylib/TestSwiftDWARFImporterFromDylib.py +++ b/lldb/test/API/lang/swift/dwarfimporter/from_dylib/TestSwiftDWARFImporterFromDylib.py @@ -4,7 +4,7 @@ import lldbsuite.test.lldbutil as lldbutil import os -class TestSwiftDWARFImporterC(lldbtest.TestBase): +class TestSwiftDWARFImporterFromDylib(lldbtest.TestBase): mydir = lldbtest.TestBase.compute_mydir(__file__) diff --git a/lldb/test/API/lang/swift/enum_associated/TestEnumAssociated.py b/lldb/test/API/lang/swift/enum_associated/TestEnumAssociated.py index 3c0912ac0181f..e0768afb05784 100644 --- a/lldb/test/API/lang/swift/enum_associated/TestEnumAssociated.py +++ b/lldb/test/API/lang/swift/enum_associated/TestEnumAssociated.py @@ -1,4 +1,4 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals()) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest]) diff --git a/lldb/test/API/lang/swift/expression/class_constrained_protocol/TestClassConstrainedProtocol.py b/lldb/test/API/lang/swift/expression/class_constrained_protocol/TestClassConstrainedProtocol.py index 6d6eb5cbbec87..e28df4b566eca 100644 --- a/lldb/test/API/lang/swift/expression/class_constrained_protocol/TestClassConstrainedProtocol.py +++ b/lldb/test/API/lang/swift/expression/class_constrained_protocol/TestClassConstrainedProtocol.py @@ -18,35 +18,42 @@ class TestClassConstrainedProtocol(TestBase): mydir = TestBase.compute_mydir(__file__) @swiftTest - def test_extension_weak_self (self): + def test_extension_weak_self(self): """Test that we can reconstruct weak self captured in a class constrained protocol.""" self.build() - self.do_self_test("Break here for weak self") + self.do_self_test("Break here for weak self", needs_dynamic=True) @swiftTest def test_extension_self (self): """Test that we can reconstruct self in method of a class constrained protocol.""" self.build() - self.do_self_test("Break here in class protocol") + self.do_self_test("Break here in class protocol", needs_dynamic=True) @swiftTest - def test_method_weak_self (self): + def test_method_weak_self(self): """Test that we can reconstruct weak self capture in method of a class conforming to a class constrained protocol.""" self.build() - self.do_self_test("Break here for method weak self") + self.do_self_test("Break here for method weak self", needs_dynamic=False) @swiftTest - def test_method_self (self): + def test_method_self(self): """Test that we can reconstruct self in method of a class conforming to a class constrained protocol.""" self.build() - self.do_self_test("Break here in method") + self.do_self_test("Break here in method", needs_dynamic=False) def setUp(self): # Call super's setUp(). TestBase.setUp(self) - def check_self(self, bkpt_pattern): + def check_self(self, bkpt_pattern, needs_dynamic): opts = lldb.SBExpressionOptions() + if needs_dynamic: + opts.SetFetchDynamicValue(lldb.eNoDynamicValues) + result = self.frame().EvaluateExpression("self", opts) + error = result.GetError() + self.assertTrue("self" in error.GetCString()) + self.assertTrue("run-target" in error.GetCString()) + opts.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) result = self.frame().EvaluateExpression("self", opts) error = result.GetError() self.assertTrue(error.Success(), @@ -58,7 +65,7 @@ def check_self(self, bkpt_pattern): self.assertTrue(f_ivar.GetValueAsSigned() == 12345, "Wrong value for f: %d"%(f_ivar.GetValueAsSigned())) - def do_self_test(self, bkpt_pattern): + def do_self_test(self, bkpt_pattern, needs_dynamic): lldbutil.run_to_source_breakpoint( self, bkpt_pattern, lldb.SBFileSpec('main.swift')) - self.check_self(bkpt_pattern) + self.check_self(bkpt_pattern, needs_dynamic) diff --git a/lldb/test/API/lang/swift/expression/errors/TestExpressionErrors.py b/lldb/test/API/lang/swift/expression/errors/TestExpressionErrors.py index e52aa32956af8..74927b5bc0869 100644 --- a/lldb/test/API/lang/swift/expression/errors/TestExpressionErrors.py +++ b/lldb/test/API/lang/swift/expression/errors/TestExpressionErrors.py @@ -24,6 +24,7 @@ class TestExpressionErrors(TestBase): mydir = TestBase.compute_mydir(__file__) + @swiftTest def test_CanThrowError(self): """Tests that swift expressions resolve scoped variables correctly""" self.build() diff --git a/lldb/test/API/lang/swift/expression/generic/TestSwiftGenericExpressions.py b/lldb/test/API/lang/swift/expression/generic/TestSwiftGenericExpressions.py index a6c7b07df3d6e..7134214d32254 100644 --- a/lldb/test/API/lang/swift/expression/generic/TestSwiftGenericExpressions.py +++ b/lldb/test/API/lang/swift/expression/generic/TestSwiftGenericExpressions.py @@ -42,7 +42,9 @@ def test_ivars_in_generic_expressions(self): self.do_ivar_test() def check_expression(self, expression, expected_result, use_summary=True): - value = self.frame().EvaluateExpression(expression) + opts = lldb.SBExpressionOptions() + opts.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) + value = self.frame().EvaluateExpression(expression, opts) self.assertTrue(value.IsValid(), expression + "returned a valid value") self.assertTrue(value.GetError().Success(), "expression failed") diff --git a/lldb/test/API/lang/swift/expression/generic_protocol_extension/main.swift b/lldb/test/API/lang/swift/expression/generic_protocol_extension/main.swift index 04e824f1f2a21..a59e982a356ee 100644 --- a/lldb/test/API/lang/swift/expression/generic_protocol_extension/main.swift +++ b/lldb/test/API/lang/swift/expression/generic_protocol_extension/main.swift @@ -20,7 +20,7 @@ class C : P { extension P { func f() -> Int { - return v //% self.expect("p self", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["a.C"]) + return v //% self.expect("expr -d run-target -- self", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["a.C"]) } } diff --git a/lldb/test/API/lang/swift/expression/mutating_struct_extension/main.swift b/lldb/test/API/lang/swift/expression/mutating_struct_extension/main.swift index df2120a303186..f42e9d7002677 100644 --- a/lldb/test/API/lang/swift/expression/mutating_struct_extension/main.swift +++ b/lldb/test/API/lang/swift/expression/mutating_struct_extension/main.swift @@ -14,7 +14,7 @@ extension Array { mutating func doGenericStuff() { - print("generic stuff") //% self.expect("expr 2+3", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["5"]) + print("generic stuff") //% self.expect("expr -d run-target -- 2+3", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["5"]) } } diff --git a/lldb/test/API/lang/swift/expression/static/TestSwiftExpressionsInClassFunctions.py b/lldb/test/API/lang/swift/expression/static/TestSwiftExpressionsInClassFunctions.py index 2af5dfae8d16c..5eee6d4b79ba5 100644 --- a/lldb/test/API/lang/swift/expression/static/TestSwiftExpressionsInClassFunctions.py +++ b/lldb/test/API/lang/swift/expression/static/TestSwiftExpressionsInClassFunctions.py @@ -28,31 +28,27 @@ def setUp(self): TestBase.setUp(self) def check_expression(self, expression, expected_result, use_summary=True): - value = self.frame().EvaluateExpression(expression) + opts = lldb.SBExpressionOptions() + opts.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) + value = self.frame().EvaluateExpression(expression, opts) self.assertTrue(value.IsValid(), expression + "returned a valid value") if use_summary: answer = value.GetSummary() else: answer = value.GetValue() - report_str = "%s expected: %s got: %s" % ( - expression, expected_result, answer) - self.assertTrue(answer == expected_result, report_str) + report_str = value.GetError() + self.assertEquals(answer, expected_result, report_str) @swiftTest def test_expressions_in_class_functions(self): """Test expressions in class func contexts""" self.build() - exe_name = "a.out" - exe = self.getBuildArtifact(exe_name) - - # Create the target - target = self.dbg.CreateTarget(exe) + target = self.dbg.CreateTarget(self.getBuildArtifact()) self.assertTrue(target, VALID_TARGET) - breakpoints = [None] - # Set the breakpoints + breakpoints = [None] for i in range(1, 8): breakpoints.append( target.BreakpointCreateBySourceRegex( @@ -63,7 +59,6 @@ def test_expressions_in_class_functions(self): # Launch the process, and do not stop at the entry point. process = target.LaunchSimple(None, None, os.getcwd()) - self.assertTrue(process, PROCESS_IS_VALID) # Check each context @@ -76,5 +71,14 @@ def test_expressions_in_class_functions(self): self.check_expression("i", str(i), False) if i == 6: self.check_expression("self", "a.H") + frame = threads[0].GetFrameAtIndex(0) + lldbutil.check_variable(self, frame.FindVariable("self"), + use_dynamic=True, + # FIXME: This should be '@thick a.H.Type' + # but valobj.GetDynamicValue(lldb.eDynamicCanRunTarget) + # doesn't seem to do its job. + # rdar://problem/69889462 + typename='@thin a.H<τ_0_0>.Type') + self.runCmd("continue") diff --git a/lldb/test/API/lang/swift/generic_class/Makefile b/lldb/test/API/lang/swift/generic_class/Makefile new file mode 100644 index 0000000000000..6bae433ab956a --- /dev/null +++ b/lldb/test/API/lang/swift/generic_class/Makefile @@ -0,0 +1,4 @@ +SWIFT_SOURCES := main.swift +SWIFTFLAGS_EXTRAS := -O + +include Makefile.rules diff --git a/lldb/test/API/lang/swift/generic_class/TestSwiftGenericClass.py b/lldb/test/API/lang/swift/generic_class/TestSwiftGenericClass.py new file mode 100644 index 0000000000000..ba46da2c49cf3 --- /dev/null +++ b/lldb/test/API/lang/swift/generic_class/TestSwiftGenericClass.py @@ -0,0 +1,22 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil +import unittest2 + + +class SwiftGenericClassTest(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @swiftTest + def test(self): + """Tests that a generic class type can be resolved from the instance metadata alone""" + self.build() + (target, process, thread, breakpoint) = lldbutil.run_to_source_breakpoint(self, + "break here", lldb.SBFileSpec("main.swift")) + + self.expect("frame variable -d run self", + substrs=["a.F", "23", "42", "128", "256"]) + self.expect("expr -d run -- self", + substrs=["a.F", "23", "42", "128", "256"]) diff --git a/lldb/test/API/lang/swift/generic_class/main.swift b/lldb/test/API/lang/swift/generic_class/main.swift new file mode 100644 index 0000000000000..a50d00f1123a1 --- /dev/null +++ b/lldb/test/API/lang/swift/generic_class/main.swift @@ -0,0 +1,25 @@ +public class F { + let a : A + var b = 42 + var c = 128 + var d = 256 + public init(_ val : A) { a = val } +} + +protocol P { + func method() +} +extension F : P { + @inline(never) func method() { + print("break here \(b)") + } +} + +// Defeat type specialization. +@inline(never) func getF() -> P { + return F(23) +} + +let obj = getF() +obj.method() + diff --git a/lldb/test/API/lang/swift/generic_extension/main.swift b/lldb/test/API/lang/swift/generic_extension/main.swift index 34c55b84a5ca3..9aca20c7e6f82 100644 --- a/lldb/test/API/lang/swift/generic_extension/main.swift +++ b/lldb/test/API/lang/swift/generic_extension/main.swift @@ -11,7 +11,7 @@ // ----------------------------------------------------------------------------- extension Array { func test() { - print("PATPAT") //% self.expect("p self", substrs=['[0] = 1', '[1] = 2', '[2] = 3']) + print("PATPAT") //% self.expect("expr -d run-target -- self", substrs=['[0] = 1', '[1] = 2', '[2] = 3']) return //% self.expect("frame variable -d run -- self", substrs=['[0] = 1', '[1] = 2', '[2] = 3']) } } diff --git a/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py b/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py index ca01eaf57eca5..f6bb817f70661 100644 --- a/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py +++ b/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py @@ -19,6 +19,7 @@ def setUp(self): # Call super's setUp(). TestBase.setUp(self) + @swiftTest @skipIf(oslist=['windows']) @skipIfDarwinEmbedded # swift crash inspecting swift stdlib with little other swift loaded def testMissingSDK(self): diff --git a/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py b/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py index b9d7ea746ad57..7a5870fd28c9b 100644 --- a/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py +++ b/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py @@ -28,6 +28,7 @@ class TestObjCIVarDiscovery(TestBase): @skipUnlessDarwin @skipIf(debug_info=no_match("dsym")) + @swiftTest def test_nodbg(self): self.build() shutil.rmtree(self.getBuildArtifact("aTestFramework.framework/Versions/A/aTestFramework.dSYM")) @@ -35,6 +36,7 @@ def test_nodbg(self): @skipUnlessDarwin @skipIf(debug_info=no_match("dsym")) + @swiftTest def test_dbg(self): self.build() self.do_test(True) diff --git a/lldb/test/API/lang/swift/printdecl/TestSwiftTypeLookup.py b/lldb/test/API/lang/swift/printdecl/TestSwiftTypeLookup.py index 20fc2139c5f05..b6c33ecfc9d0f 100644 --- a/lldb/test/API/lang/swift/printdecl/TestSwiftTypeLookup.py +++ b/lldb/test/API/lang/swift/printdecl/TestSwiftTypeLookup.py @@ -56,6 +56,12 @@ def test_swift_type_lookup(self): 'func bar()', 'var b']) + # Regression test. Ensure "" is not output. + self.expect( + "type lookup String", + matching=False, + substrs=[""]) + # check that specifiers are honored # self.expect('type lookup class Cla1', substrs=['class Cla1 {']) # self.expect('type lookup struct Cla1', substrs=['class Cla1 {'], matching=False, error=True) diff --git a/lldb/test/API/lang/swift/private_import/TestSwiftPrivateImport.py b/lldb/test/API/lang/swift/private_import/TestSwiftPrivateImport.py index 698b4bc0511fd..da77c07c8dbef 100644 --- a/lldb/test/API/lang/swift/private_import/TestSwiftPrivateImport.py +++ b/lldb/test/API/lang/swift/private_import/TestSwiftPrivateImport.py @@ -11,6 +11,7 @@ def setUp(self): TestBase.setUp(self) @skipUnlessDarwin + @swiftTest def test_private_import(self): """Test a library with a private import for which there is no debug info""" invisible_swift = self.getBuildArtifact("Invisible.swift") diff --git a/lldb/test/API/lang/swift/protocol_extension_computed_property/main.swift b/lldb/test/API/lang/swift/protocol_extension_computed_property/main.swift index 4a3a6591e9aa2..73d9ed537c92d 100644 --- a/lldb/test/API/lang/swift/protocol_extension_computed_property/main.swift +++ b/lldb/test/API/lang/swift/protocol_extension_computed_property/main.swift @@ -13,7 +13,7 @@ extension Measurement where UnitType == UnitAngle { } func f() { - return //%self.expect('p self.radians', substrs=["(CGFloat) $R0 = 1.745"]) + return //%self.expect('p self.radians', substrs=["CGFloat) $R0 = 1.745"]) //%self.expect('p self', substrs=["Measurement"]) } } diff --git a/lldb/test/API/lang/swift/protocol_extension_two/TestProtocolExtensionTwo.py b/lldb/test/API/lang/swift/protocol_extension_two/TestProtocolExtensionTwo.py index 3c0912ac0181f..e0768afb05784 100644 --- a/lldb/test/API/lang/swift/protocol_extension_two/TestProtocolExtensionTwo.py +++ b/lldb/test/API/lang/swift/protocol_extension_two/TestProtocolExtensionTwo.py @@ -1,4 +1,4 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals()) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest]) diff --git a/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_apply/main.swift b/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_apply/main.swift index b3066e587a625..8b8627edae8ae 100644 --- a/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_apply/main.swift +++ b/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_apply/main.swift @@ -14,7 +14,7 @@ func apply(_ T : Type, fn: (Type) -> Type) -> Type { return fn(T) } public func f(_ value : Type) { apply(value) { arg in - return arg //% self.expect('po arg', substrs=['3735928559']) + return arg //% self.expect('expr -o -d run -- arg', substrs=['3735928559']) //% self.expect('expr -d run -- arg', substrs=['Int', '3735928559']) //% self.expect('fr var -d run -- arg', substrs=['Int', '3735928559']) } diff --git a/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_array/main.swift b/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_array/main.swift index 0cbc60b32b7bd..be4b4bc29f7cd 100644 --- a/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_array/main.swift +++ b/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_array/main.swift @@ -13,7 +13,7 @@ public struct Q { let x: T } public func foo(_ arg: [Q]) { - print(arg) //% self.expect('po arg', substrs=['x : 3735928559']) + print(arg) //% self.expect('expr -o -d run -- arg', substrs=['x : 3735928559']) //% self.expect('expr -d run -- arg', substrs=['x = 3735928559']) //% self.expect('frame var -d run -- arg', substrs=['x = 3735928559']) } diff --git a/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_flatmap/main.swift b/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_flatmap/main.swift index e8ac3fd16fc38..b2fcf0bcc2405 100644 --- a/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_flatmap/main.swift +++ b/lldb/test/API/lang/swift/variables/generic_struct_debug_info/generic_flatmap/main.swift @@ -34,13 +34,13 @@ struct FlatMapper ] let _ = tuples.flatMap { tuple in - return tuple //% self.expect('po tuple', substrs=['originalIndex : 0', 'filteredIndex : 0', 'name : "Coffee"', 'ID : "1"']) + return tuple //% self.expect('expr -o -d run -- tuple', substrs=['originalIndex : 0', 'filteredIndex : 0', 'name : "Coffee"', 'ID : "1"']) //% self.expect('expr -d run -- tuple', substrs=['originalIndex = 0', 'filteredIndex = 0', 'name = "Coffee"', 'ID = "1"']) //% self.expect('frame var -d run -- tuple', substrs=['originalIndex = 0', 'filteredIndex = 0', 'name = "Coffee"', 'ID = "1"']) } let _ = values.flatMap { value in - return value //% self.expect('po value', substrs=['name : "Coffee"', 'ID : "1"']) + return value //% self.expect('expr -o -d run -- value', substrs=['name : "Coffee"', 'ID : "1"']) //% self.expect('expr -d run -- value', substrs=['name = "Coffee"', 'ID = "1"']) //% self.expect('frame var -d run -- value', substrs=['name = "Coffee"', 'ID = "1"']) } diff --git a/lldb/test/API/lang/swift/variables/protocol/TestSwiftProtocolTypes.py b/lldb/test/API/lang/swift/variables/protocol/TestSwiftProtocolTypes.py index ef86ebea19371..d04f1f9f12f43 100644 --- a/lldb/test/API/lang/swift/variables/protocol/TestSwiftProtocolTypes.py +++ b/lldb/test/API/lang/swift/variables/protocol/TestSwiftProtocolTypes.py @@ -101,7 +101,7 @@ def do_test(self): 'x = 1.25', 'y = 2.5']) self.expect("expression --raw-output --show-types -- loc3dCB", - substrs=['PointUtils & AnyObject) $R', + substrs=['PointUtils & Swift.AnyObject) $R', '(Builtin.RawPointer) instance = 0x', '(Builtin.RawPointer) witness_table_PointUtils = 0x']) diff --git a/lldb/test/API/lang/swift/variables/uninitialized/main.swift b/lldb/test/API/lang/swift/variables/uninitialized/main.swift index 8774c1c50c582..7fa335f7a352f 100644 --- a/lldb/test/API/lang/swift/variables/uninitialized/main.swift +++ b/lldb/test/API/lang/swift/variables/uninitialized/main.swift @@ -23,7 +23,7 @@ struct A { let c = cs[0] let k1 = b(t:c) - let k2 = b(t:c) //% self.expect("expression -- c", "Unreadable variable is ignored", substrs = ["= 3"]) + let k2 = b(t:c) //% self.expect("expr -d run -- c", "Unreadable variable is ignored", substrs = ["= 3"]) let k3 = b(t:c) if let maybeT = process(i : adict.count, k1:k1, k2:k2, k3:k3) { diff --git a/lldb/test/API/lit.cfg.py b/lldb/test/API/lit.cfg.py index 6ccc97b1375ca..45e3396f07d03 100644 --- a/lldb/test/API/lit.cfg.py +++ b/lldb/test/API/lit.cfg.py @@ -23,14 +23,14 @@ def mkdir_p(path): - import errno - try: - os.makedirs(path) - except OSError as e: - if e.errno != errno.EEXIST: - raise - if not os.path.isdir(path): - raise OSError(errno.ENOTDIR, "%s is not a directory"%path) + import errno + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + if not os.path.isdir(path): + raise OSError(errno.ENOTDIR, "%s is not a directory"%path) def find_sanitizer_runtime(name): @@ -85,25 +85,39 @@ def find_python_interpreter(): return copied_python -if 'Address' in config.llvm_use_sanitizer: - config.environment['ASAN_OPTIONS'] = 'detect_stack_use_after_return=1' - # Swift's libReflection builds without ASAN, which causes a known - # false positive in std::vector. - config.environment['ASAN_OPTIONS'] += ':detect_container_overflow=0' - if 'Darwin' in config.host_os and 'x86' in config.host_triple: - config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime( - 'libclang_rt.asan_osx_dynamic.dylib') +def is_configured(attr): + """Return the configuration attribute if it exists and None otherwise. + + This allows us to check if the attribute exists before trying to access it.""" + return getattr(config, attr, None) + + +def delete_module_cache(path): + """Clean the module caches in the test build directory. -if 'Thread' in config.llvm_use_sanitizer: - if 'Darwin' in config.host_os and 'x86' in config.host_triple: - config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime( - 'libclang_rt.tsan_osx_dynamic.dylib') + This is necessary in an incremental build whenever clang changes underneath, + so doing it once per lit.py invocation is close enough. """ + if os.path.isdir(path): + print("Deleting module cache at %s." % path) + shutil.rmtree(path) + +if is_configured('llvm_use_sanitizer'): + if 'Address' in config.llvm_use_sanitizer: + config.environment['ASAN_OPTIONS'] = 'detect_stack_use_after_return=1' + if 'Darwin' in config.host_os and 'x86' in config.host_triple: + config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime( + 'libclang_rt.asan_osx_dynamic.dylib') + + if 'Thread' in config.llvm_use_sanitizer: + if 'Darwin' in config.host_os and 'x86' in config.host_triple: + config.environment['DYLD_INSERT_LIBRARIES'] = find_sanitizer_runtime( + 'libclang_rt.tsan_osx_dynamic.dylib') if 'DYLD_INSERT_LIBRARIES' in config.environment and platform.system() == 'Darwin': config.python_executable = find_python_interpreter() # Shared library build of LLVM may require LD_LIBRARY_PATH or equivalent. -if config.shared_libs: +if is_configured('shared_libs'): for shlibpath_var in find_shlibpath_var(): # In stand-alone build llvm_shlib_dir specifies LLDB's lib directory while # llvm_libs_dir specifies LLVM's lib directory. @@ -132,14 +146,6 @@ def find_python_interpreter(): elif lldb_repro_mode == 'replay': config.available_features.add('lldb-repro-replay') -# Clean the module caches in the test build directory. This is necessary in an -# incremental build whenever clang changes underneath, so doing it once per -# lit.py invocation is close enough. -for cachedir in [config.clang_module_cache, config.lldb_module_cache]: - if os.path.isdir(cachedir): - print("Deleting module cache at %s." % cachedir) - shutil.rmtree(cachedir) - # Set a default per-test timeout of 10 minutes. Setting a timeout per test # requires that killProcessAndChildren() is supported on the platform and # lit complains if the value is set but it is not supported. @@ -150,12 +156,13 @@ def find_python_interpreter(): lit_config.warning("Could not set a default per-test timeout. " + errormsg) # Build dotest command. -dotest_cmd = [config.dotest_path] -dotest_cmd += ['--arch', config.test_arch] -dotest_cmd.extend(config.dotest_args_str.split(';')) +dotest_cmd = [os.path.join(config.lldb_src_root, 'test', 'API', 'dotest.py')] + +if is_configured('dotest_args_str'): + dotest_cmd.extend(config.dotest_args_str.split(';')) # Library path may be needed to locate just-built clang. -if config.llvm_libs_dir: +if is_configured('llvm_libs_dir'): dotest_cmd += ['--env', 'LLVM_LIBS_DIR=' + config.llvm_libs_dir] # Forward ASan-specific environment variables to tests, as a test may load an @@ -164,49 +171,65 @@ def find_python_interpreter(): if env_var in config.environment: dotest_cmd += ['--inferior-env', env_var + '=' + config.environment[env_var]] -if config.lldb_build_directory: +if is_configured('test_arch'): + dotest_cmd += ['--arch', config.test_arch] + +if is_configured('lldb_build_directory'): dotest_cmd += ['--build-dir', config.lldb_build_directory] -if config.lldb_module_cache: +if is_configured('lldb_trace_directory'): + dotest_cmd += ['-s', config.lldb_trace_directory] + +if is_configured('lldb_module_cache'): + delete_module_cache(config.lldb_module_cache) dotest_cmd += ['--lldb-module-cache-dir', config.lldb_module_cache] -if config.clang_module_cache: +if is_configured('clang_module_cache'): + delete_module_cache(config.clang_module_cache) dotest_cmd += ['--clang-module-cache-dir', config.clang_module_cache] -if config.lldb_executable: +if is_configured('lldb_executable'): dotest_cmd += ['--executable', config.lldb_executable] -if config.test_compiler: +if is_configured('test_compiler'): dotest_cmd += ['--compiler', config.test_compiler] -if config.dsymutil: +if is_configured('test_swift_compiler'): + dotest_cmd += ['--swift-compiler', config.test_swift_compiler] + +if is_configured('dsymutil'): dotest_cmd += ['--dsymutil', config.dsymutil] -if config.filecheck: +if is_configured('filecheck'): dotest_cmd += ['--filecheck', config.filecheck] -if config.yaml2obj: +if is_configured('yaml2obj'): dotest_cmd += ['--yaml2obj', config.yaml2obj] -if config.lldb_libs_dir: +if is_configured('server'): + dotest_cmd += ['--server', config.server] + +if is_configured('lldb_libs_dir'): dotest_cmd += ['--lldb-libs-dir', config.lldb_libs_dir] +if is_configured('lldb_framework_dir'): + dotest_cmd += ['--framework', config.lldb_framework_dir] + if 'lldb-repro-capture' in config.available_features or \ 'lldb-repro-replay' in config.available_features: dotest_cmd += ['--skip-category=lldb-vscode', '--skip-category=std-module'] -if config.enabled_plugins: +if is_configured('enabled_plugins'): for plugin in config.enabled_plugins: dotest_cmd += ['--enable-plugin', plugin] -# We don't want to force users passing arguments to lit to use `;` as a -# separator. We use Python's simple lexical analyzer to turn the args into a -# list. Pass there arguments last so they can override anything that was -# already configured. -if config.dotest_lit_args_str: +if is_configured('dotest_lit_args_str'): + # We don't want to force users passing arguments to lit to use `;` as a + # separator. We use Python's simple lexical analyzer to turn the args into a + # list. Pass there arguments last so they can override anything that was + # already configured. dotest_cmd.extend(shlex.split(config.dotest_lit_args_str)) - # Load LLDB test format. sys.path.append(os.path.join(config.lldb_src_root, "test", "API")) import lldbtest diff --git a/lldb/test/API/lit.site.cfg.py.in b/lldb/test/API/lit.site.cfg.py.in index 866dc1675e7cf..e4a5bdfb17434 100644 --- a/lldb/test/API/lit.site.cfg.py.in +++ b/lldb/test/API/lit.site.cfg.py.in @@ -11,6 +11,7 @@ config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" config.lldb_obj_root = "@LLDB_BINARY_DIR@" config.lldb_src_root = "@LLDB_SOURCE_DIR@" config.lldb_libs_dir = "@LLDB_LIBS_DIR@" +config.lldb_framework_dir = "@LLDB_FRAMEWORK_DIR@" config.cmake_cxx_compiler = "@CMAKE_CXX_COMPILER@" config.host_os = "@HOST_OS@" config.host_triple = "@LLVM_HOST_TRIPLE@" @@ -18,9 +19,9 @@ config.shared_libs = @LLVM_ENABLE_SHARED_LIBS@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.target_triple = "@TARGET_TRIPLE@" config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@" +config.lldb_trace_directory = "@LLDB_TEST_TRACE_DIRECTORY@" config.lldb_reproducer_directory = os.path.join("@LLDB_TEST_BUILD_DIRECTORY@", "reproducers") -config.python_executable = "@PYTHON_EXECUTABLE@" -config.dotest_path = "@LLDB_SOURCE_DIR@/test/API/dotest.py" +config.python_executable = "@Python3_EXECUTABLE@" config.dotest_args_str = "@LLDB_DOTEST_ARGS@" config.lldb_enable_python = @LLDB_ENABLE_PYTHON@ config.dotest_lit_args_str = None @@ -28,9 +29,11 @@ config.enabled_plugins = [] config.lldb_executable = '@LLDB_TEST_EXECUTABLE@' config.test_arch = '@LLDB_TEST_ARCH@' config.test_compiler = '@LLDB_TEST_COMPILER@' +config.test_swift_compiler = '@LLDB_SWIFTC@' config.dsymutil = '@LLDB_TEST_DSYMUTIL@' config.filecheck = '@LLDB_TEST_FILECHECK@' config.yaml2obj = '@LLDB_TEST_YAML2OBJ@' +config.server = '@LLDB_TEST_SERVER@' # The API tests use their own module caches. config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-api") config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-api") @@ -58,10 +61,13 @@ try: config.test_compiler = config.test_compiler % lit_config.params config.dsymutil = config.dsymutil % lit_config.params config.filecheck = config.filecheck % lit_config.params + config.yaml2obj = config.yaml2obj % lit_config.params + config.server = config.server % lit_config.params + config.lldb_framework_dir = config.lldb_framework_dir % lit_config.params config.dotest_args_str = config.dotest_args_str % lit_config.params except KeyError as e: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) # Let the main config do the real work. -lit_config.load_config(config, "@LLDB_SOURCE_DIR@/test/API/lit.cfg.py") +lit_config.load_config(config, os.path.join(config.lldb_src_root, "test", "API", "lit.cfg.py")) diff --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py index 94eb8ebd054aa..a03390ee38787 100644 --- a/lldb/test/API/lldbtest.py +++ b/lldb/test/API/lldbtest.py @@ -38,7 +38,7 @@ def execute(self, test, litConfig): if litConfig.noExecute: return lit.Test.PASS, '' - if not test.config.lldb_enable_python: + if not getattr(test.config, 'lldb_enable_python', False): return (lit.Test.UNSUPPORTED, 'Python module disabled') if test.config.unsupported: diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/Makefile b/lldb/test/API/macosx/lc-note/firmware-corefile/Makefile new file mode 100644 index 0000000000000..faa5ef2f29f43 --- /dev/null +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/Makefile @@ -0,0 +1,14 @@ +MAKE_DSYM := NO +C_SOURCES := main.c +CFLAGS_EXTRAS := -Wl,-random_uuid + +all: a.out b.out create-empty-corefile + +create-empty-corefile: + $(MAKE) -f $(MAKEFILE_RULES) EXE=create-empty-corefile \ + C_SOURCES=create-empty-corefile.c + +b.out: + $(MAKE) VPATH=$(SRCDIR)/$* -I $(SRCDIR) -f $(SRCDIR)/bout.mk + +include Makefile.rules diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py new file mode 100644 index 0000000000000..79a79056476b7 --- /dev/null +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py @@ -0,0 +1,133 @@ +"""Test that corefiles with LC_NOTE "kern ver str" and "main bin spec" load commands works.""" + + + +import os +import re +import subprocess + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestFirmwareCorefiles(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM") + @skipIf(archs=no_match(['x86_64'])) + @skipUnlessDarwin + def test_lc_note(self): + self.build() + self.aout_exe = self.getBuildArtifact("a.out") + self.bout_exe = self.getBuildArtifact("b.out") + self.create_corefile = self.getBuildArtifact("create-empty-corefile") + self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") + self.aout_corefile = self.getBuildArtifact("aout.core") + self.bout_corefile = self.getBuildArtifact("bout.core") + + ## We can hook in our dsym-for-uuid shell script to lldb with this env + ## var instead of requiring a defaults write. + os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = self.dsym_for_uuid + self.addTearDownHook(lambda: os.environ.pop('LLDB_APPLE_DSYMFORUUID_EXECUTABLE', None)) + + dwarfdump_uuid_regex = re.compile( + 'UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') + dwarfdump_cmd_output = subprocess.check_output( + ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True).decode("utf-8") + aout_uuid = None + for line in dwarfdump_cmd_output.splitlines(): + match = dwarfdump_uuid_regex.search(line) + if match: + aout_uuid = match.group(1) + self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out") + + dwarfdump_cmd_output = subprocess.check_output( + ('/usr/bin/dwarfdump --uuid "%s"' % self.bout_exe), shell=True).decode("utf-8") + bout_uuid = None + for line in dwarfdump_cmd_output.splitlines(): + match = dwarfdump_uuid_regex.search(line) + if match: + bout_uuid = match.group(1) + self.assertNotEqual(bout_uuid, None, "Could not get uuid of built b.out") + + ### Create our dsym-for-uuid shell script which returns self.aout_exe + ### or self.bout_exe, depending on the UUID on the command line. + shell_cmds = [ + '#! /bin/sh', + '# the last argument is the uuid', + 'while [ $# -gt 1 ]', + 'do', + ' shift', + 'done', + 'ret=0', + 'echo ""', + 'echo ""', + 'echo ""', + '', + 'if [ "$1" != "%s" -a "$1" != "%s" ]' % (aout_uuid, bout_uuid), + 'then', + ' echo "DBGErrornot found"', + ' echo ""', + ' exit 1', + 'fi', + 'if [ "$1" = "%s" ]' % aout_uuid, + 'then', + ' uuid=%s' % aout_uuid, + ' bin=%s' % self.aout_exe, + ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.aout_exe, os.path.basename(self.aout_exe)), + 'else', + ' uuid=%s' % bout_uuid, + ' bin=%s' % self.bout_exe, + ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.bout_exe, os.path.basename(self.bout_exe)), + 'fi', + 'echo "$uuid"', + '', + 'echo "DBGArchitecturex86_64"', + 'echo "DBGDSYMPath$dsym"', + 'echo "DBGSymbolRichExecutable$bin"', + 'echo ""', + 'exit $ret' + ] + + with open(self.dsym_for_uuid, "w") as writer: + for l in shell_cmds: + writer.write(l + '\n') + + os.chmod(self.dsym_for_uuid, 0o755) + + ### Create our corefile + retcode = call(self.create_corefile + " version-string " + self.aout_corefile + " " + self.aout_exe, shell=True) + retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile + " " + self.bout_exe, shell=True) + + ### Now run lldb on the corefile + ### which will give us a UUID + ### which we call dsym-for-uuid.sh with + ### which gives us a binary and dSYM + ### which lldb should load! + + # First, try the "kern ver str" corefile + self.target = self.dbg.CreateTarget('') + err = lldb.SBError() + self.process = self.target.LoadCore(self.aout_corefile) + self.assertEqual(self.process.IsValid(), True) + if self.TraceOn(): + self.runCmd("image list") + self.assertEqual(self.target.GetNumModules(), 1) + fspec = self.target.GetModuleAtIndex(0).GetFileSpec() + filepath = fspec.GetDirectory() + "/" + fspec.GetFilename() + self.assertEqual(filepath, self.aout_exe) + + + # Second, try the "main bin spec" corefile + self.target = self.dbg.CreateTarget('') + self.process = self.target.LoadCore(self.bout_corefile) + self.assertEqual(self.process.IsValid(), True) + if self.TraceOn(): + self.runCmd("image list") + self.assertEqual(self.target.GetNumModules(), 1) + fspec = self.target.GetModuleAtIndex(0).GetFileSpec() + filepath = fspec.GetDirectory() + "/" + fspec.GetFilename() + self.assertEqual(filepath, self.bout_exe) diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/bout.mk b/lldb/test/API/macosx/lc-note/firmware-corefile/bout.mk new file mode 100644 index 0000000000000..049b7b49aa461 --- /dev/null +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/bout.mk @@ -0,0 +1,10 @@ +MAKE_DSYM := NO + +C_SOURCES := main.c +CFLAGS_EXTRAS := -Wl,-random_uuid + +EXE := b.out + +all: b.out + +include Makefile.rules diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp b/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp new file mode 100644 index 0000000000000..5e02bad51d765 --- /dev/null +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp @@ -0,0 +1,347 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// Create an empty corefile with a "kern ver str" LC_NOTE +// or a "main bin spec" LC_NOTE.. +// If an existing binary is given as a 3rd argument on the cmd line, +// the UUID from that binary will be encoded in the corefile. +// Otherwise a pre-set UUID will be put in the corefile that +// is created. + +struct main_bin_spec_payload { + uint32_t version; + uint32_t type; + uint64_t address; + uuid_t uuid; + uint32_t log2_pagesize; + uint32_t unused; +}; + +union uint32_buf { + uint8_t bytebuf[4]; + uint32_t val; +}; + +union uint64_buf { + uint8_t bytebuf[8]; + uint64_t val; +}; + +void add_uint64(std::vector &buf, uint64_t val) { + uint64_buf conv; + conv.val = val; + for (int i = 0; i < 8; i++) + buf.push_back(conv.bytebuf[i]); +} + +void add_uint32(std::vector &buf, uint32_t val) { + uint32_buf conv; + conv.val = val; + for (int i = 0; i < 4; i++) + buf.push_back(conv.bytebuf[i]); +} + +std::vector x86_lc_thread_load_command() { + std::vector data; + add_uint32(data, LC_THREAD); // thread_command.cmd + add_uint32(data, 184); // thread_command.cmdsize + add_uint32(data, x86_THREAD_STATE64); // thread_command.flavor + add_uint32(data, x86_THREAD_STATE64_COUNT); // thread_command.count + add_uint64(data, 0x0000000000000000); // rax + add_uint64(data, 0x0000000000000400); // rbx + add_uint64(data, 0x0000000000000000); // rcx + add_uint64(data, 0x0000000000000000); // rdx + add_uint64(data, 0x0000000000000000); // rdi + add_uint64(data, 0x0000000000000000); // rsi + add_uint64(data, 0xffffff9246e2ba20); // rbp + add_uint64(data, 0xffffff9246e2ba10); // rsp + add_uint64(data, 0x0000000000000000); // r8 + add_uint64(data, 0x0000000000000000); // r9 + add_uint64(data, 0x0000000000000000); // r10 + add_uint64(data, 0x0000000000000000); // r11 + add_uint64(data, 0xffffff7f96ce5fe1); // r12 + add_uint64(data, 0x0000000000000000); // r13 + add_uint64(data, 0x0000000000000000); // r14 + add_uint64(data, 0xffffff9246e2bac0); // r15 + add_uint64(data, 0xffffff8015a8f6d0); // rip + add_uint64(data, 0x0000000000011111); // rflags + add_uint64(data, 0x0000000000022222); // cs + add_uint64(data, 0x0000000000033333); // fs + add_uint64(data, 0x0000000000044444); // gs + return data; +} + +void add_lc_note_kern_ver_str_load_command( + std::vector> &loadcmds, std::vector &payload, + int payload_file_offset, std::string uuid) { + std::string ident = "EFI UUID="; + ident += uuid; + std::vector loadcmd_data; + + add_uint32(loadcmd_data, LC_NOTE); // note_command.cmd + add_uint32(loadcmd_data, 40); // note_command.cmdsize + char lc_note_name[16]; + memset(lc_note_name, 0, 16); + strcpy(lc_note_name, "kern ver str"); + + // lc_note.data_owner + for (int i = 0; i < 16; i++) + loadcmd_data.push_back(lc_note_name[i]); + + // we start writing the payload at payload_file_offset to leave + // room at the start for the header & the load commands. + uint64_t current_payload_offset = payload.size() + payload_file_offset; + + add_uint64(loadcmd_data, current_payload_offset); // note_command.offset + add_uint64(loadcmd_data, 4 + ident.size() + 1); // note_command.size + + loadcmds.push_back(loadcmd_data); + + add_uint32(payload, 1); // kerneL_version_string.version + for (int i = 0; i < ident.size() + 1; i++) { + payload.push_back(ident[i]); + } +} + +void add_lc_note_main_bin_spec_load_command( + std::vector> &loadcmds, std::vector &payload, + int payload_file_offset, std::string uuidstr) { + std::vector loadcmd_data; + + add_uint32(loadcmd_data, LC_NOTE); // note_command.cmd + add_uint32(loadcmd_data, 40); // note_command.cmdsize + char lc_note_name[16]; + memset(lc_note_name, 0, 16); + strcpy(lc_note_name, "main bin spec"); + + // lc_note.data_owner + for (int i = 0; i < 16; i++) + loadcmd_data.push_back(lc_note_name[i]); + + // we start writing the payload at payload_file_offset to leave + // room at the start for the header & the load commands. + uint64_t current_payload_offset = payload.size() + payload_file_offset; + + add_uint64(loadcmd_data, current_payload_offset); // note_command.offset + add_uint64(loadcmd_data, + sizeof(struct main_bin_spec_payload)); // note_command.size + + loadcmds.push_back(loadcmd_data); + + // Now write the "main bin spec" payload. + add_uint32(payload, 1); // version + add_uint32(payload, 3); // type == 3 [ firmware, standalone,e tc ] + add_uint64(payload, UINT64_MAX); // load address unknown/unspecified + uuid_t uuid; + uuid_parse(uuidstr.c_str(), uuid); + for (int i = 0; i < sizeof(uuid_t); i++) + payload.push_back(uuid[i]); + add_uint32(payload, 0); // log2_pagesize unspecified + add_uint32(payload, 0); // unused +} + +void add_lc_segment(std::vector> &loadcmds, + std::vector &payload, int payload_file_offset) { + std::vector loadcmd_data; + struct segment_command_64 seg; + seg.cmd = LC_SEGMENT_64; + seg.cmdsize = sizeof(struct segment_command_64); // no sections + memset(seg.segname, 0, 16); + seg.vmaddr = 0xffffff7f96400000; + seg.vmsize = 4096; + seg.fileoff = payload.size() + payload_file_offset; + seg.filesize = 0; + seg.maxprot = 1; + seg.initprot = 1; + seg.nsects = 0; + seg.flags = 0; + + uint8_t *p = (uint8_t *)&seg; + for (int i = 0; i < sizeof(struct segment_command_64); i++) { + loadcmd_data.push_back(*(p + i)); + } + loadcmds.push_back(loadcmd_data); +} + +std::string get_uuid_from_binary(const char *fn) { + FILE *f = fopen(fn, "r"); + if (f == nullptr) { + fprintf(stderr, "Unable to open binary '%s' to get uuid\n", fn); + exit(1); + } + uint32_t num_of_load_cmds = 0; + uint32_t size_of_load_cmds = 0; + std::string uuid; + off_t file_offset = 0; + + uint8_t magic[4]; + if (::fread(magic, 1, 4, f) != 4) { + fprintf(stderr, "Failed to read magic number from input file %s\n", fn); + exit(1); + } + uint8_t magic_32_be[] = {0xfe, 0xed, 0xfa, 0xce}; + uint8_t magic_32_le[] = {0xce, 0xfa, 0xed, 0xfe}; + uint8_t magic_64_be[] = {0xfe, 0xed, 0xfa, 0xcf}; + uint8_t magic_64_le[] = {0xcf, 0xfa, 0xed, 0xfe}; + + if (memcmp(magic, magic_32_be, 4) == 0 || + memcmp(magic, magic_64_be, 4) == 0) { + fprintf(stderr, "big endian corefiles not supported\n"); + exit(1); + } + + ::fseeko(f, 0, SEEK_SET); + if (memcmp(magic, magic_32_le, 4) == 0) { + struct mach_header mh; + if (::fread(&mh, 1, sizeof(mh), f) != sizeof(mh)) { + fprintf(stderr, "error reading mach header from input file\n"); + exit(1); + } + if (mh.cputype != CPU_TYPE_X86_64) { + fprintf(stderr, + "This tool creates an x86_64 corefile but " + "the supplied binary '%s' is cputype 0x%x\n", + fn, (uint32_t)mh.cputype); + exit(1); + } + num_of_load_cmds = mh.ncmds; + size_of_load_cmds = mh.sizeofcmds; + file_offset += sizeof(struct mach_header); + } else { + struct mach_header_64 mh; + if (::fread(&mh, 1, sizeof(mh), f) != sizeof(mh)) { + fprintf(stderr, "error reading mach header from input file\n"); + exit(1); + } + if (mh.cputype != CPU_TYPE_X86_64) { + fprintf(stderr, + "This tool creates an x86_64 corefile but " + "the supplied binary '%s' is cputype 0x%x\n", + fn, (uint32_t)mh.cputype); + exit(1); + } + num_of_load_cmds = mh.ncmds; + size_of_load_cmds = mh.sizeofcmds; + file_offset += sizeof(struct mach_header_64); + } + + off_t load_cmds_offset = file_offset; + + for (int i = 0; i < num_of_load_cmds && + (file_offset - load_cmds_offset) < size_of_load_cmds; + i++) { + ::fseeko(f, file_offset, SEEK_SET); + uint32_t cmd; + uint32_t cmdsize; + ::fread(&cmd, sizeof(uint32_t), 1, f); + ::fread(&cmdsize, sizeof(uint32_t), 1, f); + if (cmd == LC_UUID) { + struct uuid_command uuidcmd; + ::fseeko(f, file_offset, SEEK_SET); + if (::fread(&uuidcmd, 1, sizeof(uuidcmd), f) != sizeof(uuidcmd)) { + fprintf(stderr, "Unable to read LC_UUID load command.\n"); + exit(1); + } + uuid_string_t uuidstr; + uuid_unparse(uuidcmd.uuid, uuidstr); + uuid = uuidstr; + break; + } + file_offset += cmdsize; + } + return uuid; +} + +int main(int argc, char **argv) { + if (argc != 4) { + fprintf(stderr, "usage: create-empty-corefile version-string|main-bin-spec " + " \n"); + fprintf( + stderr, + "Create a Mach-O corefile with an either LC_NOTE 'kern ver str' or \n"); + fprintf(stderr, "an LC_NOTE 'main bin spec' load command without an " + "address specified, depending on\n"); + fprintf(stderr, "whether the 1st arg is version-string or main-bin-spec\n"); + exit(1); + } + if (strcmp(argv[1], "version-string") != 0 && + strcmp(argv[1], "main-bin-spec") != 0) { + fprintf(stderr, "arg1 was not version-string or main-bin-spec\n"); + exit(1); + } + + std::string uuid = get_uuid_from_binary(argv[3]); + + // An array of load commands (in the form of byte arrays) + std::vector> load_commands; + + // An array of corefile contents (page data, lc_note data, etc) + std::vector payload; + + // First add all the load commands / payload so we can figure out how large + // the load commands will actually be. + load_commands.push_back(x86_lc_thread_load_command()); + if (strcmp(argv[1], "version-string") == 0) + add_lc_note_kern_ver_str_load_command(load_commands, payload, 0, uuid); + else + add_lc_note_main_bin_spec_load_command(load_commands, payload, 0, uuid); + add_lc_segment(load_commands, payload, 0); + + int size_of_load_commands = 0; + for (const auto &lc : load_commands) + size_of_load_commands += lc.size(); + + int header_and_load_cmd_room = + sizeof(struct mach_header_64) + size_of_load_commands; + + // Erase the load commands / payload now that we know how much space is + // needed, redo it. + load_commands.clear(); + payload.clear(); + + load_commands.push_back(x86_lc_thread_load_command()); + + if (strcmp(argv[1], "version-string") == 0) + add_lc_note_kern_ver_str_load_command(load_commands, payload, + header_and_load_cmd_room, uuid); + else + add_lc_note_main_bin_spec_load_command(load_commands, payload, + header_and_load_cmd_room, uuid); + + add_lc_segment(load_commands, payload, header_and_load_cmd_room); + + struct mach_header_64 mh; + mh.magic = MH_MAGIC_64; + mh.cputype = CPU_TYPE_X86_64; + + mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL; + mh.filetype = MH_CORE; + mh.ncmds = load_commands.size(); + mh.sizeofcmds = size_of_load_commands; + mh.flags = 0; + mh.reserved = 0; + + FILE *f = fopen(argv[2], "w"); + + if (f == nullptr) { + fprintf(stderr, "Unable to open file %s for writing\n", argv[2]); + exit(1); + } + + fwrite(&mh, sizeof(struct mach_header_64), 1, f); + + for (const auto &lc : load_commands) + fwrite(lc.data(), lc.size(), 1, f); + + fseek(f, header_and_load_cmd_room, SEEK_SET); + + fwrite(payload.data(), payload.size(), 1, f); + + fclose(f); +} diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/main.c b/lldb/test/API/macosx/lc-note/firmware-corefile/main.c new file mode 100644 index 0000000000000..70a72e0b80b1e --- /dev/null +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/main.c @@ -0,0 +1,2 @@ +#include +int main () { puts ("this is the lc-note test program."); } diff --git a/lldb/test/API/python_api/breakpoint/TestBreakpointAPI.py b/lldb/test/API/python_api/breakpoint/TestBreakpointAPI.py index 1c0c334fbeebf..80324ee61b70d 100644 --- a/lldb/test/API/python_api/breakpoint/TestBreakpointAPI.py +++ b/lldb/test/API/python_api/breakpoint/TestBreakpointAPI.py @@ -66,6 +66,9 @@ def test_target_delete(self): location = breakpoint.GetLocationAtIndex(0) self.assertTrue(location.IsValid()) + # Make sure the breakpoint's target is right: + self.assertEqual(target, breakpoint.GetTarget(), "Breakpoint reports its target correctly") + self.assertTrue(self.dbg.DeleteTarget(target)) self.assertFalse(breakpoint.IsValid()) self.assertFalse(location.IsValid()) diff --git a/lldb/test/API/repl/array/TestREPLArray.py b/lldb/test/API/repl/array/TestREPLArray.py index caabfff293660..8cbb966ab63ba 100644 --- a/lldb/test/API/repl/array/TestREPLArray.py +++ b/lldb/test/API/repl/array/TestREPLArray.py @@ -1,4 +1,5 @@ import lldbsuite.test.lldbinrepl as lldbinrepl import lldbsuite.test.lldbtest as lldbtest +from lldbsuite.test.decorators import * -lldbinrepl.MakeREPLTest(__file__, globals(), []) +lldbinrepl.MakeREPLTest(__file__, globals(), decorators=[swiftTest]) diff --git a/lldb/test/API/repl/cpp_exceptions/TestCPPExceptionsInREPL.py b/lldb/test/API/repl/cpp_exceptions/TestCPPExceptionsInREPL.py index f305b01bbf8ba..00c1993cecd82 100644 --- a/lldb/test/API/repl/cpp_exceptions/TestCPPExceptionsInREPL.py +++ b/lldb/test/API/repl/cpp_exceptions/TestCPPExceptionsInREPL.py @@ -26,6 +26,7 @@ class TestREPLExceptions(TestBase): NO_DEBUG_INFO_TESTCASE = True @decorators.skipUnlessDarwin + @decorators.swiftTest def test_set_repl_mode_exceptions(self): """ Test that SetREPLMode turns off trapping exceptions.""" self.build() @@ -33,6 +34,7 @@ def test_set_repl_mode_exceptions(self): self.do_repl_mode_test() @decorators.skipUnlessDarwin + @decorators.swiftTest def test_repl_exceptions(self): """ Test the lldb --repl turns off trapping exceptions.""" self.build() diff --git a/lldb/test/API/source-manager/TestSourceManager.py b/lldb/test/API/source-manager/TestSourceManager.py index 714b736da02e6..3ce056f2d0294 100644 --- a/lldb/test/API/source-manager/TestSourceManager.py +++ b/lldb/test/API/source-manager/TestSourceManager.py @@ -197,6 +197,14 @@ def test_modify_source_file_while_debugging(self): SOURCE_DISPLAYED_CORRECTLY, substrs=['Hello world']) + # Do the same thing with a file & line spec: + self.expect( + "source list -y main-copy.c:%d" % + self.line, + SOURCE_DISPLAYED_CORRECTLY, + substrs=['Hello world']) + + # The '-b' option shows the line table locations from the debug information # that indicates valid places to set source level breakpoints. diff --git a/lldb/test/API/tools/intel-features/intel-pt/test/TestIntelPTSimpleBinary.py b/lldb/test/API/tools/intel-features/intel-pt/test/TestIntelPTSimpleBinary.py index e26b9f6f487e3..8c6c9cf4fbb75 100644 --- a/lldb/test/API/tools/intel-features/intel-pt/test/TestIntelPTSimpleBinary.py +++ b/lldb/test/API/tools/intel-features/intel-pt/test/TestIntelPTSimpleBinary.py @@ -21,7 +21,7 @@ def setUp(self): if 'intel-pt' not in configuration.enabled_plugins: self.skipTest("The intel-pt test plugin is not enabled") - plugin_path = os.path.join(os.environ["LLDB_IMPLIB_DIR"], "liblldbIntelFeatures.so") + plugin_path = os.path.join(configuration.lldb_libs_dir, "liblldbIntelFeatures.so") self.runCmd("plugin load " + plugin_path) @skipIf(oslist=no_match(['linux'])) diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index afaf92c24e62d..26b96e4a63dd5 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -174,6 +174,12 @@ llvm_canonicalize_cmake_booleans( LLVM_ENABLE_SHARED_LIBS LLDB_IS_64_BITS) +# BEGIN SWIFT +llvm_canonicalize_cmake_booleans( + LLDB_ENABLE_SWIFT_SUPPORT +) +# END SWIFT + # Configure the individual test suites. add_subdirectory(API) add_subdirectory(Shell) @@ -234,7 +240,7 @@ if(LLDB_BUILT_STANDALONE) if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) # LLVM's make_paths_relative uses Python3_EXECUTABLE which isn't set in a # standalone LLDB build. - set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE}) + set(Python3_EXECUTABLE ${Python3_EXECUTABLE}) add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit) endif() endif() diff --git a/lldb/test/Shell/Commands/Inputs/stop_hook.py b/lldb/test/Shell/Commands/Inputs/stop_hook.py new file mode 100644 index 0000000000000..e319ca9ec5bc8 --- /dev/null +++ b/lldb/test/Shell/Commands/Inputs/stop_hook.py @@ -0,0 +1,10 @@ +import lldb + +class stop_handler: + def __init__(self, target, extra_args, dict): + self.extra_args = extra_args + self.target = target + + def handle_stop(self, exe_ctx, stream): + stream.Print("I did indeed run\n") + return True diff --git a/lldb/test/Shell/Commands/command-stop-hook-output.test b/lldb/test/Shell/Commands/command-stop-hook-output.test new file mode 100644 index 0000000000000..7890bb3ca5e75 --- /dev/null +++ b/lldb/test/Shell/Commands/command-stop-hook-output.test @@ -0,0 +1,19 @@ +# REQUIRES: python +# RUN: %clang_host -g %S/Inputs/main.c -o %t +# RUN: %lldb %t -O 'command script import %S/Inputs/stop_hook.py' -s %s -o exit | FileCheck %s + +b main +# CHECK-LABEL: b main +# CHECK: Breakpoint 1: where = {{.*}}`main + +target stop-hook add -P stop_hook.stop_handler +# CHECK-LABEL: target stop-hook add -P stop_hook.stop_handler +# CHECK: Stop hook #1 added. + +run +# CHECK-LABEL: run +# CHECK: I did indeed run +# CHECK: Process {{.*}} stopped +# CHECK: stop reason = breakpoint 1 +# CHECK: frame #0: {{.*}}`main at main.c + diff --git a/lldb/test/Shell/Process/Inputs/abort.c b/lldb/test/Shell/Process/Inputs/abort.c new file mode 100644 index 0000000000000..9edc9336dc3e0 --- /dev/null +++ b/lldb/test/Shell/Process/Inputs/abort.c @@ -0,0 +1,3 @@ +#include + +int main(int argc, char **argv) { abort(); } diff --git a/lldb/test/Shell/Process/TestAbortExitCode.test b/lldb/test/Shell/Process/TestAbortExitCode.test new file mode 100644 index 0000000000000..746bc915897ec --- /dev/null +++ b/lldb/test/Shell/Process/TestAbortExitCode.test @@ -0,0 +1,6 @@ +UNSUPPORTED: system-windows + +RUN: %clang_host %p/Inputs/abort.c -o %t +RUN: %lldb %t -o run -o continue | FileCheck %s + +CHECK: {{status = 6 \(0x00000006\)|status = 0 \(0x00000000\) Terminated due to signal 6}} diff --git a/lldb/test/Shell/Reproducer/Swift/TestBridging.test b/lldb/test/Shell/Reproducer/Swift/TestBridging.test index 6a146ca1e692c..bf4317d38be36 100644 --- a/lldb/test/Shell/Reproducer/Swift/TestBridging.test +++ b/lldb/test/Shell/Reproducer/Swift/TestBridging.test @@ -1,4 +1,5 @@ # UNSUPPORTED: system-windows, system-freebsd, system-linux +# REQUIRES: swift # This tests replaying a Swift reproducer with bridging. diff --git a/lldb/test/Shell/Reproducer/Swift/TestModule.test b/lldb/test/Shell/Reproducer/Swift/TestModule.test index 4e12560102b08..362261fe2b761 100644 --- a/lldb/test/Shell/Reproducer/Swift/TestModule.test +++ b/lldb/test/Shell/Reproducer/Swift/TestModule.test @@ -1,4 +1,5 @@ # UNSUPPORTED: system-windows, system-freebsd +# REQUIRES: swift # This tests replaying a Swift reproducer with bridging. diff --git a/lldb/test/Shell/Reproducer/Swift/TestSimple.test b/lldb/test/Shell/Reproducer/Swift/TestSimple.test index d13327ee77fa9..5d85f50ae6ffa 100644 --- a/lldb/test/Shell/Reproducer/Swift/TestSimple.test +++ b/lldb/test/Shell/Reproducer/Swift/TestSimple.test @@ -1,4 +1,5 @@ # UNSUPPORTED: system-windows, system-freebsd +# REQUIRES: swift # This tests replaying a simple reproducer. diff --git a/lldb/test/Shell/Reproducer/Swift/TestSwiftInterface.test b/lldb/test/Shell/Reproducer/Swift/TestSwiftInterface.test index 8bc950ec529ad..9d166bf32e922 100644 --- a/lldb/test/Shell/Reproducer/Swift/TestSwiftInterface.test +++ b/lldb/test/Shell/Reproducer/Swift/TestSwiftInterface.test @@ -1,6 +1,7 @@ # Test that reproducers can deal with .swiftinterface files. # REQUIRES: system-darwin +# REQUIRES: swift # # rdar://problem/55564275 # XFAIL: * diff --git a/lldb/test/Shell/Swift/DeserializationFailure.test b/lldb/test/Shell/Swift/DeserializationFailure.test index f1054961a7b30..7bcdb51afda85 100644 --- a/lldb/test/Shell/Swift/DeserializationFailure.test +++ b/lldb/test/Shell/Swift/DeserializationFailure.test @@ -1,4 +1,5 @@ # REQUIRES: system-darwin +# REQUIRES: swift # Tests that error messages from deserializing Swift modules are # printed to the error stream. Architecturally it is not possible to # write this as a dotest.py test. diff --git a/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test b/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test index 1b22289dbb6a6..b2e5f8b3e53ee 100644 --- a/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test +++ b/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test @@ -1,5 +1,6 @@ # REQUIRES: system-darwin # REQUIRES: rdar50667488 +# REQUIRES: swift # This testcase causes the scratch context to get destroyed by a # conflict that is triggered via dynamic type resolution. The conflict diff --git a/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift b/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift index 46f1dc92a092d..83ac5ee6604a1 100644 --- a/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift +++ b/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift @@ -16,6 +16,7 @@ func f(_ t: T) { let strct2 = S2() // CHECK-DAG: strct2 = {}{{$}} let generic = t // CHECK-DAG: (Int) generic = 23 let generic_tuple = (t, t) // CHECK-DAG: generic_tuple = (0 = 23, 1 = 23) + let word = 0._builtinWordValue // CHECK-DAG: word = 0 print(number) useTypeFromOtherModule(x: S2()) } diff --git a/lldb/test/Shell/Swift/MissingVFSOverlay.test b/lldb/test/Shell/Swift/MissingVFSOverlay.test index 2c0da83eefcc7..fbd1e2000fce0 100644 --- a/lldb/test/Shell/Swift/MissingVFSOverlay.test +++ b/lldb/test/Shell/Swift/MissingVFSOverlay.test @@ -1,5 +1,6 @@ # Test that error messages from constructing ClangImporter # are surfaced to the user. +# REQUIRES: swift # RUN: rm -rf %t && mkdir %t && cd %t # RUN: cp %p/../../API/lang/swift/deserialization_failure/Inputs/main.swift %t/main.swift diff --git a/lldb/test/Shell/Swift/No.swiftmodule-ObjC.test b/lldb/test/Shell/Swift/No.swiftmodule-ObjC.test index 5bb095f0c7384..eb206d54ed078 100644 --- a/lldb/test/Shell/Swift/No.swiftmodule-ObjC.test +++ b/lldb/test/Shell/Swift/No.swiftmodule-ObjC.test @@ -1,4 +1,5 @@ # REQUIRES: system-darwin +# REQUIRES: swift # This tests debugging without the presence of a .swiftmodule. # RUN: rm -rf %t && mkdir %t && cd %t diff --git a/lldb/test/Shell/Swift/No.swiftmodule.test b/lldb/test/Shell/Swift/No.swiftmodule.test index e5d8120add8ae..ca58778ca05e8 100644 --- a/lldb/test/Shell/Swift/No.swiftmodule.test +++ b/lldb/test/Shell/Swift/No.swiftmodule.test @@ -1,4 +1,5 @@ # This tests debugging without the presence of a .swiftmodule. +# REQUIRES: swift # RUN: rm -rf %t && mkdir %t && cd %t # diff --git a/lldb/test/Shell/Swift/RemoteASTImport.test b/lldb/test/Shell/Swift/RemoteASTImport.test index 12c8db67c4a49..06522707862a4 100644 --- a/lldb/test/Shell/Swift/RemoteASTImport.test +++ b/lldb/test/Shell/Swift/RemoteASTImport.test @@ -1,4 +1,5 @@ # REQUIRES: system-darwin +# REQUIRES: swift # This tests that RemoteAST querying the dynamic type of a variable # doesn't import any modules into a module SwiftASTContext that diff --git a/lldb/test/Shell/Swift/astcontext_error.test b/lldb/test/Shell/Swift/astcontext_error.test index 1840ee7c1bf93..cfe0692724453 100644 --- a/lldb/test/Shell/Swift/astcontext_error.test +++ b/lldb/test/Shell/Swift/astcontext_error.test @@ -1,3 +1,4 @@ +# REQUIRES: swift # RUN: rm -rf %t && mkdir %t && cd %t # RUN: %target-swiftc -g %S/Inputs/ContextError.swift # RUN: %lldb ContextError -s %s | FileCheck %S/Inputs/ContextError.swift diff --git a/lldb/test/Shell/Swift/cond-breakpoint.test b/lldb/test/Shell/Swift/cond-breakpoint.test index 3346e7306ef61..3cf5a6c60ad66 100644 --- a/lldb/test/Shell/Swift/cond-breakpoint.test +++ b/lldb/test/Shell/Swift/cond-breakpoint.test @@ -1,3 +1,4 @@ +# REQUIRES: swift # RUN: rm -rf %t && mkdir %t && cd %t # RUN: %target-swiftc -g %S/Inputs/main.swift -o a.out # RUN: %lldb a.out -b -s %s 2>&1 | FileCheck %s diff --git a/lldb/test/Shell/Swift/global.test b/lldb/test/Shell/Swift/global.test index 76e2ffe5b6969..17a1e1e7e66f8 100644 --- a/lldb/test/Shell/Swift/global.test +++ b/lldb/test/Shell/Swift/global.test @@ -1,3 +1,5 @@ +# REQUIRES: swift + # RUN: rm -rf %t && mkdir %t && cd %t # RUN: %target-swiftc -g \ # RUN: -module-cache-path %t/cache %S/Inputs/Global.swift \ diff --git a/lldb/test/Shell/Swift/runtime-initialization.test b/lldb/test/Shell/Swift/runtime-initialization.test index 5a68d976e4ef3..6589dea965caa 100644 --- a/lldb/test/Shell/Swift/runtime-initialization.test +++ b/lldb/test/Shell/Swift/runtime-initialization.test @@ -1,3 +1,4 @@ +# REQUIRES: swift # RUN: rm -rf %t && mkdir %t # RUN: %target-swiftc -g \ # RUN: -module-cache-path %t/cache %S/Inputs/RuntimeInit.swift \ diff --git a/lldb/test/Shell/SwiftREPL/Availability.test b/lldb/test/Shell/SwiftREPL/Availability.test new file mode 100644 index 0000000000000..a3e0e6d8be10f --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/Availability.test @@ -0,0 +1,15 @@ +// -*- mode: swift; -*- +// Test that the REPL is launched with the current OS as availability target. +// REQUIRES: system-darwin +// REQUIRES: swift + +// RUN: mkdir -p %t.dir +// RUN: echo '@available(macOS '>%t.dir/NewModule.swift +// RUN: sw_vers | grep ProductVersion | cut -d : -f 2 >>%t.dir/NewModule.swift +// RUN: echo ', *) public let message = "Hello"' >>%t.dir/NewModule.swift +// RUN: %target-swiftc -module-name NewModule -emit-module -emit-library -o %t.dir/libNewModule%target-shared-library-suffix %t.dir/NewModule.swift + +// RUN: %lldb --repl="-I%t.dir -L%t.dir -lNewModule" --repl-language swift < %s | FileCheck %s +import NewModule +message +// CHECK: $R0{{.*}}Hello diff --git a/lldb/test/Shell/SwiftREPL/Basic.test b/lldb/test/Shell/SwiftREPL/Basic.test index dc5b54a7dc06a..d7fba8631dc57 100644 --- a/lldb/test/Shell/SwiftREPL/Basic.test +++ b/lldb/test/Shell/SwiftREPL/Basic.test @@ -1,4 +1,5 @@ // Basic sanity checking of the REPL. +// REQUIRES: swift // RUN: %lldb --repl --repl-language swift | FileCheck %s --check-prefix=SWIFT // SWIFT: Welcome to {{.*}}Swift diff --git a/lldb/test/Shell/SwiftREPL/BreakpointSimple.test b/lldb/test/Shell/SwiftREPL/BreakpointSimple.test index d462bf6c164fd..d43ce111c14c5 100644 --- a/lldb/test/Shell/SwiftREPL/BreakpointSimple.test +++ b/lldb/test/Shell/SwiftREPL/BreakpointSimple.test @@ -1,5 +1,5 @@ // Test that we can set breakpoints in the REPL. - +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s func foo() -> Int { diff --git a/lldb/test/Shell/SwiftREPL/CFString.test b/lldb/test/Shell/SwiftREPL/CFString.test index 721febb3d9517..2d7b9985dc154 100644 --- a/lldb/test/Shell/SwiftREPL/CFString.test +++ b/lldb/test/Shell/SwiftREPL/CFString.test @@ -1,5 +1,6 @@ // Test that CFString works in the REPL. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s // CHECK: Welcome to {{.*}}Swift diff --git a/lldb/test/Shell/SwiftREPL/Class.test b/lldb/test/Shell/SwiftREPL/Class.test index ed051ba0ff0d5..e649f989f13e0 100644 --- a/lldb/test/Shell/SwiftREPL/Class.test +++ b/lldb/test/Shell/SwiftREPL/Class.test @@ -1,4 +1,5 @@ // Test that we can define and use a basic class. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ComputedProperties.test b/lldb/test/Shell/SwiftREPL/ComputedProperties.test index cb90047417023..6539cf3efbea6 100644 --- a/lldb/test/Shell/SwiftREPL/ComputedProperties.test +++ b/lldb/test/Shell/SwiftREPL/ComputedProperties.test @@ -1,4 +1,5 @@ // Check that we print computed properties correctly. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/CrashArgs.test b/lldb/test/Shell/SwiftREPL/CrashArgs.test index eebd222bb1aea..f503dbfe465ed 100644 --- a/lldb/test/Shell/SwiftREPL/CrashArgs.test +++ b/lldb/test/Shell/SwiftREPL/CrashArgs.test @@ -1,4 +1,5 @@ // Make sure we don't crash if we pass args to the repl. +// REQUIRES: swift // RUN: %lldb --repl="-some-argument" | FileCheck %s --check-prefix=SWIFT // SWIFT: Welcome to {{.*}}Swift diff --git a/lldb/test/Shell/SwiftREPL/Deadlock.test b/lldb/test/Shell/SwiftREPL/Deadlock.test index b203428d39681..fa996871d59ad 100644 --- a/lldb/test/Shell/SwiftREPL/Deadlock.test +++ b/lldb/test/Shell/SwiftREPL/Deadlock.test @@ -1,3 +1,5 @@ +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s // From https://bugs.swift.org/browse/SR-7114 @@ -5,11 +7,11 @@ let a = 9007199254740991.0 // CHECK: a: Double = 9007199254740991 -(a * a - a * a).squareRoot() +(a * a - a * a).squareRoot() // CHECK: (Double) = { // CHECK-NEXT: _value = 0 // CHECK-NEXT: } (a * a).addingProduct(-a, a).squareRoot() // CHECK: (Double) = { -// CHECK-NEXT: _value = NaN +// CHECK-NEXT: _value = NaN // CHECK-NEXT: } diff --git a/lldb/test/Shell/SwiftREPL/DeferredNSArray.test b/lldb/test/Shell/SwiftREPL/DeferredNSArray.test index fc994f14622a5..b32633363a583 100644 --- a/lldb/test/Shell/SwiftREPL/DeferredNSArray.test +++ b/lldb/test/Shell/SwiftREPL/DeferredNSArray.test @@ -1,5 +1,6 @@ // Test that NSDeferredArray data formatter works. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/DeploymentTarget.test b/lldb/test/Shell/SwiftREPL/DeploymentTarget.test index 62fed643676f1..ab18d90ba577c 100644 --- a/lldb/test/Shell/SwiftREPL/DeploymentTarget.test +++ b/lldb/test/Shell/SwiftREPL/DeploymentTarget.test @@ -1,5 +1,6 @@ // Test that the REPL can call a *really* new function. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: echo -n "@available(macOS " >%t.swift // RUN: python -c 'from __future__ import print_function; import platform; print(platform.mac_ver()[0],end="")' >>%t.swift diff --git a/lldb/test/Shell/SwiftREPL/Dict.test b/lldb/test/Shell/SwiftREPL/Dict.test index dd6b9ead68a11..3e1ef2b9ac76c 100644 --- a/lldb/test/Shell/SwiftREPL/Dict.test +++ b/lldb/test/Shell/SwiftREPL/Dict.test @@ -1,4 +1,5 @@ // Test that the dictionary data formatter works in the REPL. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=DICT diff --git a/lldb/test/Shell/SwiftREPL/DictBridging.test b/lldb/test/Shell/SwiftREPL/DictBridging.test index e7bae8548e94c..68ad3f2ea026c 100644 --- a/lldb/test/Shell/SwiftREPL/DictBridging.test +++ b/lldb/test/Shell/SwiftREPL/DictBridging.test @@ -1,6 +1,8 @@ // -*- mode: swift; -*- // Test formatters on bridged dictionaries in the REPL. // REQUIRES: system-darwin +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=DICT import Foundation diff --git a/lldb/test/Shell/SwiftREPL/ErrorReturn.test b/lldb/test/Shell/SwiftREPL/ErrorReturn.test index 025bb92f88d0d..e61733687b4b5 100644 --- a/lldb/test/Shell/SwiftREPL/ErrorReturn.test +++ b/lldb/test/Shell/SwiftREPL/ErrorReturn.test @@ -1,6 +1,7 @@ // XFAIL: powerpc64le // SR-10212 // Test that we can handle errors. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ErrorReturnObjC.test b/lldb/test/Shell/SwiftREPL/ErrorReturnObjC.test index 304cc136329b5..718958d6490ce 100644 --- a/lldb/test/Shell/SwiftREPL/ErrorReturnObjC.test +++ b/lldb/test/Shell/SwiftREPL/ErrorReturnObjC.test @@ -2,6 +2,7 @@ // types when they're stored in REPL-defined globals. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ExclusivityREPL.test b/lldb/test/Shell/SwiftREPL/ExclusivityREPL.test index 030187700d52d..e8f1ed47ac7eb 100644 --- a/lldb/test/Shell/SwiftREPL/ExclusivityREPL.test +++ b/lldb/test/Shell/SwiftREPL/ExclusivityREPL.test @@ -1,4 +1,5 @@ // Runtime checks for exclusive access should be enabled in the REPL. +// REQUIRES: swift // RUN: %lldb --repl < %s 2>&1 | FileCheck %s // CHECK: modification requires exclusive access diff --git a/lldb/test/Shell/SwiftREPL/FoundationTypes.test b/lldb/test/Shell/SwiftREPL/FoundationTypes.test index e25acce3fb266..a39d8c95daf47 100644 --- a/lldb/test/Shell/SwiftREPL/FoundationTypes.test +++ b/lldb/test/Shell/SwiftREPL/FoundationTypes.test @@ -2,6 +2,7 @@ // types when they're stored in REPL-defined globals. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/FrameworkPath.test b/lldb/test/Shell/SwiftREPL/FrameworkPath.test index b6e73e11af21f..95d0019ce41e4 100644 --- a/lldb/test/Shell/SwiftREPL/FrameworkPath.test +++ b/lldb/test/Shell/SwiftREPL/FrameworkPath.test @@ -1,5 +1,6 @@ // Test target.swift-framework-search-paths works in the REPL. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb -O "settings set target.swift-framework-search-paths %S/Inputs/Frameworks" --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/GLKIT.test b/lldb/test/Shell/SwiftREPL/GLKIT.test index 8260006a82654..ddeaa1b5bd92f 100644 --- a/lldb/test/Shell/SwiftREPL/GLKIT.test +++ b/lldb/test/Shell/SwiftREPL/GLKIT.test @@ -1,5 +1,6 @@ // Test formatters for Accelerate/simd. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/GenericTypealias.test b/lldb/test/Shell/SwiftREPL/GenericTypealias.test index bbd0792ff948c..032aacd9f7eb8 100644 --- a/lldb/test/Shell/SwiftREPL/GenericTypealias.test +++ b/lldb/test/Shell/SwiftREPL/GenericTypealias.test @@ -1,4 +1,6 @@ // Test that generic typealiases are reconstructed correctly. +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s class Tinky { diff --git a/lldb/test/Shell/SwiftREPL/Generics.test b/lldb/test/Shell/SwiftREPL/Generics.test index 9674453acedfe..eaf8598a1c3b9 100644 --- a/lldb/test/Shell/SwiftREPL/Generics.test +++ b/lldb/test/Shell/SwiftREPL/Generics.test @@ -1,4 +1,5 @@ // Test that generics work in the REPL. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ImportCocoa.test b/lldb/test/Shell/SwiftREPL/ImportCocoa.test index 3d15ad2874b6f..ce2f4f20aaf84 100644 --- a/lldb/test/Shell/SwiftREPL/ImportCocoa.test +++ b/lldb/test/Shell/SwiftREPL/ImportCocoa.test @@ -1,5 +1,6 @@ // Test that importing Cocoa works. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s 2>&1 | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ImportDispatch.test b/lldb/test/Shell/SwiftREPL/ImportDispatch.test index b36eae691b2aa..b1cc611245063 100644 --- a/lldb/test/Shell/SwiftREPL/ImportDispatch.test +++ b/lldb/test/Shell/SwiftREPL/ImportDispatch.test @@ -1,5 +1,6 @@ // Test that importing Dispatch works. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s 2>&1 | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ImportError.test b/lldb/test/Shell/SwiftREPL/ImportError.test index 44fe179103c57..435f3554014c0 100644 --- a/lldb/test/Shell/SwiftREPL/ImportError.test +++ b/lldb/test/Shell/SwiftREPL/ImportError.test @@ -1,4 +1,5 @@ // Test that importing non-existing module fails. +// REQUIRES: swift // RUN: %lldb --repl < %s 2>&1 | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ImportFoundation.test b/lldb/test/Shell/SwiftREPL/ImportFoundation.test index a3b481bdad897..751f83ccbb533 100644 --- a/lldb/test/Shell/SwiftREPL/ImportFoundation.test +++ b/lldb/test/Shell/SwiftREPL/ImportFoundation.test @@ -1,5 +1,6 @@ // Test that type lookup chooses the right language. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/InitFile.test b/lldb/test/Shell/SwiftREPL/InitFile.test index b3363df20d4a8..a3fefab62c919 100644 --- a/lldb/test/Shell/SwiftREPL/InitFile.test +++ b/lldb/test/Shell/SwiftREPL/InitFile.test @@ -1,5 +1,7 @@ // Test that the Swift REPL init file works. // REQUIRES: system-darwin +// REQUIRES: swift + // RUN: export HOME=%t // RUN: mkdir -p %t // RUN: echo 'br set -f main.c -l 123' > ~/.lldbinit diff --git a/lldb/test/Shell/SwiftREPL/Inputs/A.swift b/lldb/test/Shell/SwiftREPL/Inputs/A.swift index 887eb06b3efb5..e2f8d0920a868 100644 --- a/lldb/test/Shell/SwiftREPL/Inputs/A.swift +++ b/lldb/test/Shell/SwiftREPL/Inputs/A.swift @@ -1,6 +1,5 @@ public class Foo { public static func foo() -> String { - print("A") return "A" } } diff --git a/lldb/test/Shell/SwiftREPL/Inputs/Test.swift b/lldb/test/Shell/SwiftREPL/Inputs/Test.swift new file mode 100644 index 0000000000000..25d1dbead4ce2 --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/Inputs/Test.swift @@ -0,0 +1,11 @@ +public struct Bar { + public init(baz: Int) { self.baz = baz } + + var baz : Int +} + +struct Foo { + init(bar: Int) { self.bar = bar } + + var bar : Int +} diff --git a/lldb/test/Shell/SwiftREPL/LookupAfterImport.test b/lldb/test/Shell/SwiftREPL/LookupAfterImport.test index d067501e5f155..ae763e2bb5895 100644 --- a/lldb/test/Shell/SwiftREPL/LookupAfterImport.test +++ b/lldb/test/Shell/SwiftREPL/LookupAfterImport.test @@ -1,5 +1,6 @@ // Make sure we properly load in new extension members after an import. // rdar://64040436 +// REQUIRES: swift // RUN: rm -rf %t // RUN: mkdir %t diff --git a/lldb/test/Shell/SwiftREPL/LookupWithAttributedImport.test b/lldb/test/Shell/SwiftREPL/LookupWithAttributedImport.test new file mode 100644 index 0000000000000..6308ad81454d6 --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/LookupWithAttributedImport.test @@ -0,0 +1,24 @@ +// Make sure import attributes are taken into consideration at every evaluation +// rdar://65319954 +// REQUIRES: swift + +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: %target-swiftc -emit-library %S/Inputs/Test.swift -module-name Test -emit-module-path %t/Test.swiftmodule -o %t/libTest%target-shared-library-suffix -Onone -g -enable-testing + +// RUN: %lldb --repl="-I%t -L%t -lTest" < %s 2>&1 | FileCheck %s + +import Test + +let y = Bar(baz: 123) +// CHECK: y: Test.Bar = { +// CHECK: baz = 123 + +let x = Foo(bar:42) +// CHECK: error: repl.swift:{{.*}}: error: cannot find 'Foo' in scope + +@testable import Test + +let x = Foo(bar:42) +// CHECK: x: Test.Foo = { +// CHECK: bar = 42 diff --git a/lldb/test/Shell/SwiftREPL/MetatypeRepl.test b/lldb/test/Shell/SwiftREPL/MetatypeRepl.test index ad88d7dae1f30..979286e442b37 100644 --- a/lldb/test/Shell/SwiftREPL/MetatypeRepl.test +++ b/lldb/test/Shell/SwiftREPL/MetatypeRepl.test @@ -1,3 +1,5 @@ +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s let x = [Double.self] diff --git a/lldb/test/Shell/SwiftREPL/NSObjectSubclass.test b/lldb/test/Shell/SwiftREPL/NSObjectSubclass.test index 0b9784527f96a..fbf8db07d531a 100644 --- a/lldb/test/Shell/SwiftREPL/NSObjectSubclass.test +++ b/lldb/test/Shell/SwiftREPL/NSObjectSubclass.test @@ -1,5 +1,6 @@ // Test that the REPL allows defining subclasses of NSObject. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/NSString.test b/lldb/test/Shell/SwiftREPL/NSString.test index 34fa250947a79..f31a73eb4481d 100644 --- a/lldb/test/Shell/SwiftREPL/NSString.test +++ b/lldb/test/Shell/SwiftREPL/NSString.test @@ -1,5 +1,6 @@ // Test that NSString works in the REPL. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=NSSTRING diff --git a/lldb/test/Shell/SwiftREPL/OpenClass.test b/lldb/test/Shell/SwiftREPL/OpenClass.test index e8d1401565c22..b27d8e17cf37c 100644 --- a/lldb/test/Shell/SwiftREPL/OpenClass.test +++ b/lldb/test/Shell/SwiftREPL/OpenClass.test @@ -1,6 +1,7 @@ // TODO(TF-493): Re-enable // RUN: echo "disabled" // UN: %lldb --repl < %s 2>&1 | FileCheck %s +// REQUIRES: swift class Foo { // Don't make any of these 'open'. diff --git a/lldb/test/Shell/SwiftREPL/Optional.test b/lldb/test/Shell/SwiftREPL/Optional.test index b6d3ac77b12c1..47e9749f190e8 100644 --- a/lldb/test/Shell/SwiftREPL/Optional.test +++ b/lldb/test/Shell/SwiftREPL/Optional.test @@ -1,4 +1,5 @@ // RUN: %lldb --repl < %s | FileCheck %s +// REQUIRES: swift enum Patatino { case first diff --git a/lldb/test/Shell/SwiftREPL/OptionalUnowned.test b/lldb/test/Shell/SwiftREPL/OptionalUnowned.test index 4d3e8aa2e9e19..c855e97868e43 100644 --- a/lldb/test/Shell/SwiftREPL/OptionalUnowned.test +++ b/lldb/test/Shell/SwiftREPL/OptionalUnowned.test @@ -1,3 +1,5 @@ +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s class C diff --git a/lldb/test/Shell/SwiftREPL/OptionalWithDynamicType.test b/lldb/test/Shell/SwiftREPL/OptionalWithDynamicType.test index 56f8499931864..a52a53766b4ee 100644 --- a/lldb/test/Shell/SwiftREPL/OptionalWithDynamicType.test +++ b/lldb/test/Shell/SwiftREPL/OptionalWithDynamicType.test @@ -2,6 +2,7 @@ // optional. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s 2>&1 | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/PropertyWrapperPrivate.test b/lldb/test/Shell/SwiftREPL/PropertyWrapperPrivate.test index 4e982cbb97463..af9c34fd4a4a8 100644 --- a/lldb/test/Shell/SwiftREPL/PropertyWrapperPrivate.test +++ b/lldb/test/Shell/SwiftREPL/PropertyWrapperPrivate.test @@ -1,5 +1,6 @@ // Test that we don't crash when SILGen(ing) property wrappers // [private]. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/PropertyWrapperPublic.test b/lldb/test/Shell/SwiftREPL/PropertyWrapperPublic.test index 2da16b84ac186..5d0cade5b25cd 100644 --- a/lldb/test/Shell/SwiftREPL/PropertyWrapperPublic.test +++ b/lldb/test/Shell/SwiftREPL/PropertyWrapperPublic.test @@ -1,5 +1,6 @@ // Test that we don't crash when SILGen(ing) property wrappers // [public]. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/PropertyWrapperTopLevel.test b/lldb/test/Shell/SwiftREPL/PropertyWrapperTopLevel.test index 3ad2007532aed..99dee0ae85957 100644 --- a/lldb/test/Shell/SwiftREPL/PropertyWrapperTopLevel.test +++ b/lldb/test/Shell/SwiftREPL/PropertyWrapperTopLevel.test @@ -1,3 +1,5 @@ +// REQUIRES: swift + // RUN: %lldb --repl < %s 2>&1 | FileCheck %s @propertyWrapper struct A { diff --git a/lldb/test/Shell/SwiftREPL/RecursiveClass.test b/lldb/test/Shell/SwiftREPL/RecursiveClass.test index c002c7580d5d3..f36ed92d6ada9 100644 --- a/lldb/test/Shell/SwiftREPL/RecursiveClass.test +++ b/lldb/test/Shell/SwiftREPL/RecursiveClass.test @@ -1,4 +1,5 @@ // Test that recursive class instances work in the REPL. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/Redefinition.test b/lldb/test/Shell/SwiftREPL/Redefinition.test index 11aebcd36f768..a265e92756b64 100644 --- a/lldb/test/Shell/SwiftREPL/Redefinition.test +++ b/lldb/test/Shell/SwiftREPL/Redefinition.test @@ -1,4 +1,5 @@ // Test that we can set breakpoints in the REPL. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/RedirectInput.test b/lldb/test/Shell/SwiftREPL/RedirectInput.test new file mode 100644 index 0000000000000..eadb5d7ef3566 --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/RedirectInput.test @@ -0,0 +1,18 @@ +// Test that input can be redirected from A.swift +// REQUIRES: swift + +// RUN: mkdir -p %t +// RUN: cp %S/Inputs/A.swift %t/A.swift +// RUN: cd %t +// RUN: %lldb --repl < %s | FileCheck %s + +< A.swift + +Foo.foo() +// CHECK: ${{R0}}: String = "A" + +let y = MyPoint(x: 2, y: 2) +// CHECK: {{^}}y: MyPoint = { + +y.magnitudeSquared +// CHECK: {{^}}${{R1}}: Int = 8 diff --git a/lldb/test/Shell/SwiftREPL/RedirectInputNoSuchFile.test b/lldb/test/Shell/SwiftREPL/RedirectInputNoSuchFile.test new file mode 100644 index 0000000000000..c76364138ba55 --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/RedirectInputNoSuchFile.test @@ -0,0 +1,9 @@ +// Test that input can't be redirected from non-existent file A.swift +// REQUIRES: swift + +// RUN: mkdir -p %t +// RUN: cd %t +// RUN: %lldb --repl < %s 2>&1 | FileCheck %s --check-prefix=LLDB + +< A.swift +// LLDB: no such file at path 'A.swift' diff --git a/lldb/test/Shell/SwiftREPL/RedirectInputUnreadable.test b/lldb/test/Shell/SwiftREPL/RedirectInputUnreadable.test new file mode 100644 index 0000000000000..8f74532d1bded --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/RedirectInputUnreadable.test @@ -0,0 +1,11 @@ +// Test that input can't be redirected from unreadable A.swift +// REQUIRES: swift + +// RUN: mkdir -p %t +// RUN: cp %S/Inputs/A.swift %t/A.swift +// RUN: chmod -r %t/A.swift +// RUN: cd %t +// RUN: %lldb --repl < %s 2>&1 | FileCheck %s --check-prefix=LLDB + +< A.swift +// LLDB: could not read file at path 'A.swift' diff --git a/lldb/test/Shell/SwiftREPL/ResilientArray.test b/lldb/test/Shell/SwiftREPL/ResilientArray.test index 38d3fbdebe6c2..dbf9006cd2b2b 100644 --- a/lldb/test/Shell/SwiftREPL/ResilientArray.test +++ b/lldb/test/Shell/SwiftREPL/ResilientArray.test @@ -1,4 +1,6 @@ // REQUIRES: system-darwin +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s import Foundation diff --git a/lldb/test/Shell/SwiftREPL/ResilientDict.test b/lldb/test/Shell/SwiftREPL/ResilientDict.test index 0b7eea68d73c0..6be96a29ec12e 100644 --- a/lldb/test/Shell/SwiftREPL/ResilientDict.test +++ b/lldb/test/Shell/SwiftREPL/ResilientDict.test @@ -1,4 +1,6 @@ // REQUIRES: system-darwin +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=DICT // The dictionary order isn't deterministic, so print the dictionary @@ -6,14 +8,14 @@ import Foundation -let x : [URL:Int] = [URL(string: "https://github.com")!: 4, URL(string: "https://apple.com")!: 23] +let x : [URL:Int] = [URL(string: "https://github.com")!: 4, URL(string: "https://apple.com")!: 23] // DICT-LABEL: {{x}}: [URL : Int] = 2 key/value pairs { // DICT: [{{[0-1]}}] = { // DICT: key = "https://apple.com" // DICT-NEXT: value = 23 // DICT-NEXT: } -let y : [URL:Int] = [URL(string: "https://github.com")!: 4, URL(string: "https://apple.com")!: 23] +let y : [URL:Int] = [URL(string: "https://github.com")!: 4, URL(string: "https://apple.com")!: 23] // DICT-LABEL: {{y}}: [URL : Int] = 2 key/value pairs { // DICT: [{{[0-1]}}] = { // DICT: key = "https://github.com" diff --git a/lldb/test/Shell/SwiftREPL/SIMD.test b/lldb/test/Shell/SwiftREPL/SIMD.test index 708b944ef4b45..c4fb14c7ccf71 100644 --- a/lldb/test/Shell/SwiftREPL/SIMD.test +++ b/lldb/test/Shell/SwiftREPL/SIMD.test @@ -1,5 +1,6 @@ // Test formatters for SIMD. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/SetBridging.test b/lldb/test/Shell/SwiftREPL/SetBridging.test index 4c7aca292f144..98d70e13e2853 100644 --- a/lldb/test/Shell/SwiftREPL/SetBridging.test +++ b/lldb/test/Shell/SwiftREPL/SetBridging.test @@ -1,6 +1,8 @@ // -*- mode: swift; -*- // Test formatters on bridged sets in the REPL. // REQUIRES: system-darwin +// REQUIRES: swift + // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=SET import Foundation diff --git a/lldb/test/Shell/SwiftREPL/SimpleExpressions.test b/lldb/test/Shell/SwiftREPL/SimpleExpressions.test index 5b65ddb500dab..8331973801a05 100644 --- a/lldb/test/Shell/SwiftREPL/SimpleExpressions.test +++ b/lldb/test/Shell/SwiftREPL/SimpleExpressions.test @@ -1,5 +1,6 @@ // Test that we can define and use basic functions/expressions in the REPL. // Note: All of this should work on all supported platforms. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/SleepREPL.test b/lldb/test/Shell/SwiftREPL/SleepREPL.test index 13f254520f0ab..0f480afc41862 100644 --- a/lldb/test/Shell/SwiftREPL/SleepREPL.test +++ b/lldb/test/Shell/SwiftREPL/SleepREPL.test @@ -1,5 +1,6 @@ // Test that we can sleep in the repl // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=SLEEP diff --git a/lldb/test/Shell/SwiftREPL/String.test b/lldb/test/Shell/SwiftREPL/String.test index 3aaa00ca964b1..2d5e50ccd0057 100644 --- a/lldb/test/Shell/SwiftREPL/String.test +++ b/lldb/test/Shell/SwiftREPL/String.test @@ -1,5 +1,6 @@ // Test that String works in the REPL. // REQUIRES: system-darwin +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=STRING diff --git a/lldb/test/Shell/SwiftREPL/Struct.test b/lldb/test/Shell/SwiftREPL/Struct.test index 842125f91d7bc..5f86fa6759bc9 100644 --- a/lldb/test/Shell/SwiftREPL/Struct.test +++ b/lldb/test/Shell/SwiftREPL/Struct.test @@ -1,4 +1,5 @@ // Test that we can define and use structs in the REPL. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/Subclassing.test b/lldb/test/Shell/SwiftREPL/Subclassing.test index fb81821a22df3..c99bdb43d70ac 100644 --- a/lldb/test/Shell/SwiftREPL/Subclassing.test +++ b/lldb/test/Shell/SwiftREPL/Subclassing.test @@ -1,4 +1,5 @@ // Test that subclassing works in the repl. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/SwiftInterface.test b/lldb/test/Shell/SwiftREPL/SwiftInterface.test index 558d3598d5702..37e9bfcddc879 100644 --- a/lldb/test/Shell/SwiftREPL/SwiftInterface.test +++ b/lldb/test/Shell/SwiftREPL/SwiftInterface.test @@ -1,4 +1,5 @@ // Test that .swiftinterface files can be loaded via the repl. +// REQUIRES: swift // RUN: rm -rf %t // RUN: mkdir %t diff --git a/lldb/test/Shell/SwiftREPL/SwiftInterfaceForceModuleLoadMode.test b/lldb/test/Shell/SwiftREPL/SwiftInterfaceForceModuleLoadMode.test index 41601ff0d0e23..65a87802fab02 100644 --- a/lldb/test/Shell/SwiftREPL/SwiftInterfaceForceModuleLoadMode.test +++ b/lldb/test/Shell/SwiftREPL/SwiftInterfaceForceModuleLoadMode.test @@ -3,6 +3,7 @@ // Note: It intentionally does not check the only-interface or prefer-interface // modes as this also causes the Swift stdlib to be loaded via its module // interface file, which slows down this test considerably. +// REQUIRES: swift // RUN: rm -rf %t && mkdir %t diff --git a/lldb/test/Shell/SwiftREPL/SwiftTypeLookup.test b/lldb/test/Shell/SwiftREPL/SwiftTypeLookup.test index 0a5d67c75cd74..d320a4c1a3066 100644 --- a/lldb/test/Shell/SwiftREPL/SwiftTypeLookup.test +++ b/lldb/test/Shell/SwiftREPL/SwiftTypeLookup.test @@ -1,4 +1,5 @@ // Test that we don't crash when looking up types. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=TYPE diff --git a/lldb/test/Shell/SwiftREPL/UninitVariables.test b/lldb/test/Shell/SwiftREPL/UninitVariables.test index f30dd331da692..e35a1fb9b8abb 100644 --- a/lldb/test/Shell/SwiftREPL/UninitVariables.test +++ b/lldb/test/Shell/SwiftREPL/UninitVariables.test @@ -1,4 +1,5 @@ // Document the way we handle uninitialized variables. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/ZeroSizeStruct.test b/lldb/test/Shell/SwiftREPL/ZeroSizeStruct.test index d30a4cc5b13a7..add267619f50a 100644 --- a/lldb/test/Shell/SwiftREPL/ZeroSizeStruct.test +++ b/lldb/test/Shell/SwiftREPL/ZeroSizeStruct.test @@ -1,4 +1,5 @@ // Test that we can define and use zero-sized struct in the repl. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s diff --git a/lldb/test/Shell/SwiftREPL/enum-singlecase.test b/lldb/test/Shell/SwiftREPL/enum-singlecase.test index ced4eb9c8a957..aec724705f2da 100644 --- a/lldb/test/Shell/SwiftREPL/enum-singlecase.test +++ b/lldb/test/Shell/SwiftREPL/enum-singlecase.test @@ -1,4 +1,5 @@ // RUN: %lldb --repl < %s 2>&1 | FileCheck %s +// REQUIRES: swift enum Foo: String { case patatino diff --git a/lldb/test/Shell/SwiftREPL/one-char-string.test b/lldb/test/Shell/SwiftREPL/one-char-string.test index 9c98f4fafd3c1..2afb920b8f0b9 100644 --- a/lldb/test/Shell/SwiftREPL/one-char-string.test +++ b/lldb/test/Shell/SwiftREPL/one-char-string.test @@ -1,5 +1,6 @@ // rdar://30147367 // Make sure that single character strings are displayed correctly. +// REQUIRES: swift // RUN: %lldb --repl < %s | FileCheck %s --check-prefix=STRING diff --git a/lldb/test/Shell/SymbolFile/DWARF/DW_AT_location-DW_AT_const_value.s b/lldb/test/Shell/SymbolFile/DWARF/DW_AT_location-DW_AT_const_value.s new file mode 100644 index 0000000000000..08ee77175f770 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/DW_AT_location-DW_AT_const_value.s @@ -0,0 +1,144 @@ +## Test that we don't get confused by variables with both location and +## const_value attributes. Such values are produced in C++ for class-level +## static constexpr variables. + +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux %s -o %t +# RUN: %lldb %t -o "target variable A::x A::y" -o exit | FileCheck %s + +# CHECK-LABEL: target variable +# CHECK: (const int) A::x = 142 +# CHECK: (const int) A::y = 242 + + .section .rodata,"a",@progbits + .p2align 2 +_ZN1A1xE: + .long 142 +_ZN1A1yE: + .long 242 + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 8 # DW_FORM_string + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 19 # DW_TAG_structure_type + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 13 # DW_TAG_member + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 28 # DW_AT_const_value + .byte 13 # DW_FORM_sdata + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 71 # DW_AT_specification + .byte 19 # DW_FORM_ref4 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) +## This deliberately inverts the order of the specification and location +## attributes. + .byte 8 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 71 # DW_AT_specification + .byte 19 # DW_FORM_ref4 + .byte 110 # DW_AT_linkage_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev DW_TAG_compile_unit + .asciz "Hand-written DWARF" # DW_AT_producer + .asciz "a.cc" # DW_AT_name + .byte 7 # Abbrev DW_TAG_variable + .long .LA__x-.Lcu_begin0 # DW_AT_specification + .byte 9 # DW_AT_location + .byte 3 + .quad _ZN1A1xE + .asciz "_ZN1A1xE" # DW_AT_linkage_name + .byte 8 # Abbrev DW_TAG_variable + .byte 9 # DW_AT_location + .byte 3 + .quad _ZN1A1yE + .long .LA__y-.Lcu_begin0 # DW_AT_specification + .asciz "_ZN1A1yE" # DW_AT_linkage_name + .byte 3 # Abbrev DW_TAG_structure_type + .asciz "A" # DW_AT_name + .byte 1 # DW_AT_byte_size +.LA__x: + .byte 4 # Abbrev DW_TAG_member + .asciz "x" # DW_AT_name + .long .Lconst_int-.Lcu_begin0 # DW_AT_type + # DW_AT_declaration + .sleb128 147 # DW_AT_const_value +.LA__y: + .byte 4 # Abbrev DW_TAG_member + .asciz "y" # DW_AT_name + .long .Lconst_int-.Lcu_begin0 # DW_AT_type + # DW_AT_declaration + .sleb128 247 # DW_AT_const_value + .byte 0 # End Of Children Mark +.Lconst_int: + .byte 5 # Abbrev DW_TAG_const_type + .long .Lint-.Lcu_begin0 # DW_AT_type +.Lint: + .byte 6 # Abbrev DW_TAG_base_type + .asciz "int" # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: diff --git a/lldb/test/Shell/lit.cfg.py b/lldb/test/Shell/lit.cfg.py index ef4d9f6dc7ec1..f36bbfa6e01f8 100644 --- a/lldb/test/Shell/lit.cfg.py +++ b/lldb/test/Shell/lit.cfg.py @@ -121,6 +121,9 @@ def calculate_arch_features(arch_string): if config.lldb_enable_lua: config.available_features.add('lua') +if config.lldb_enable_swift: + config.available_features.add('swift') + if config.lldb_enable_lzma: config.available_features.add('lzma') diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in index de8fd1280b202..04800cfb0c828 100644 --- a/lldb/test/Shell/lit.site.cfg.py.in +++ b/lldb/test/Shell/lit.site.cfg.py.in @@ -6,6 +6,7 @@ config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" config.llvm_libs_dir = "@LLVM_LIBS_DIR@" config.llvm_shlib_dir = "@SHLIBDIR@" config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" +config.lldb_src_root = "@LLDB_SOURCE_DIR@" config.lldb_obj_root = "@LLDB_BINARY_DIR@" config.lldb_libs_dir = "@LLDB_LIBS_DIR@" config.lldb_tools_dir = "@LLDB_TOOLS_DIR@" @@ -13,8 +14,9 @@ config.lldb_tools_dir = "@LLDB_TOOLS_DIR@" # should not need to be escaped. config.lldb_lit_tools_dir = r"@LLDB_LIT_TOOLS_DIR@" config.target_triple = "@TARGET_TRIPLE@" -config.python_executable = "@PYTHON_EXECUTABLE@" +config.python_executable = "@Python3_EXECUTABLE@" config.swiftc = "@LLDB_SWIFTC@" +config.lldb_enable_swift = @LLDB_ENABLE_SWIFT_SUPPORT@ config.have_zlib = @LLVM_ENABLE_ZLIB@ config.lldb_enable_lzma = @LLDB_ENABLE_LZMA@ config.host_triple = "@LLVM_HOST_TRIPLE@" @@ -43,4 +45,4 @@ import lit.llvm lit.llvm.initialize(lit_config, config) # Let the main config do the real work. -lit_config.load_config(config, "@LLDB_SOURCE_DIR@/test/Shell/lit.cfg.py") +lit_config.load_config(config, os.path.join(config.lldb_src_root, "test", "Shell", "lit.cfg.py")) diff --git a/lldb/test/Unit/lit.site.cfg.py.in b/lldb/test/Unit/lit.site.cfg.py.in index 9d9bcd4ba628d..c0627b772362f 100644 --- a/lldb/test/Unit/lit.site.cfg.py.in +++ b/lldb/test/Unit/lit.site.cfg.py.in @@ -10,7 +10,7 @@ config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" config.lldb_obj_root = "@LLDB_BINARY_DIR@" config.lldb_src_root = "@LLDB_SOURCE_DIR@" config.target_triple = "@TARGET_TRIPLE@" -config.python_executable = "@PYTHON_EXECUTABLE@" +config.python_executable = "@Python3_EXECUTABLE@" # Support substitution of the tools and libs dirs with user parameters. This is # used when we can't determine the tool dir at configuration time. @@ -26,4 +26,4 @@ import lit.llvm lit.llvm.initialize(lit_config, config) # Let the main config do the real work. -lit_config.load_config(config, "@LLDB_SOURCE_DIR@/test/Unit/lit.cfg.py") +lit_config.load_config(config, os.path.join(config.lldb_src_root, "test", "Unit", "lit.cfg.py")) diff --git a/lldb/test/lit.site.cfg.py.in b/lldb/test/lit.site.cfg.py.in index 49d789d42d9a1..24c0a4d5aa04c 100644 --- a/lldb/test/lit.site.cfg.py.in +++ b/lldb/test/lit.site.cfg.py.in @@ -10,7 +10,7 @@ config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" config.lldb_obj_root = "@LLDB_BINARY_DIR@" config.lldb_src_root = "@LLDB_SOURCE_DIR@" config.target_triple = "@TARGET_TRIPLE@" -config.python_executable = "@PYTHON_EXECUTABLE@" +config.python_executable = "@Python3_EXECUTABLE@" # Support substitution of the tools and libs dirs with user parameters. This is # used when we can't determine the tool dir at configuration time. diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 5e2512731f39c..b66cc8f583e8e 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -3066,7 +3066,7 @@ rnb_err_t RNBRemote::HandlePacket_last_signal(const char *unused) { WEXITSTATUS(pid_status)); else if (WIFSIGNALED(pid_status)) snprintf(pid_exited_packet, sizeof(pid_exited_packet), "X%02x", - WEXITSTATUS(pid_status)); + WTERMSIG(pid_status)); else if (WIFSTOPPED(pid_status)) snprintf(pid_exited_packet, sizeof(pid_exited_packet), "S%02x", WSTOPSIG(pid_status)); diff --git a/lldb/tools/intel-features/CMakeLists.txt b/lldb/tools/intel-features/CMakeLists.txt index efba2f74904f7..e4979ad5256d9 100644 --- a/lldb/tools/intel-features/CMakeLists.txt +++ b/lldb/tools/intel-features/CMakeLists.txt @@ -56,7 +56,7 @@ add_lldb_library(lldbIntelFeatures SHARED LINK_LIBS ${FEATURE_LIBS} - ${PYTHON_LIBRARY} + ${Python3_LIBRARIES} ) # Add link dependencies for python wrapper diff --git a/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py b/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py index f571252e26f79..5431abcdbca57 100644 --- a/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py +++ b/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py @@ -30,9 +30,7 @@ def test_show_command(self): """Test 'mpx-table show' command""" self.build() - lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"] - lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib") - plugin_file = os.path.join(lldb_lib_dir, "liblldbIntelFeatures.so") + plugin_file = os.path.join(configuration.lldb_libs_dir, "liblldbIntelFeatures.so") if not os.path.isfile(plugin_file): self.skipTest("features plugin missing.") plugin_command = " " @@ -122,9 +120,7 @@ def test_set_command(self): """Test 'mpx-table set' command""" self.build() - lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"] - lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib") - plugin_file = os.path.join(lldb_lib_dir, "liblldbIntelFeatures.so") + plugin_file = os.path.join(configuration.lldb_libs_dir, "liblldbIntelFeatures.so") if not os.path.isfile(plugin_file): self.skipTest("features plugin missing.") plugin_command = " " diff --git a/lldb/tools/lldb-test/CMakeLists.txt b/lldb/tools/lldb-test/CMakeLists.txt index 2edbd8e56d6ed..562905760e2c8 100644 --- a/lldb/tools/lldb-test/CMakeLists.txt +++ b/lldb/tools/lldb-test/CMakeLists.txt @@ -24,9 +24,9 @@ add_lldb_tool(lldb-test Support ) -if(PYTHON_RPATH) - set_property(TARGET lldb-test APPEND PROPERTY INSTALL_RPATH "${PYTHON_RPATH}") - set_property(TARGET lldb-test APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") +if(Python3_RPATH) + set_property(TARGET lldb-test APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}") + set_property(TARGET lldb-test APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") endif() target_include_directories(lldb-test PRIVATE ${LLDB_SOURCE_DIR}/source) diff --git a/lldb/tools/repl/swift/CMakeLists.txt b/lldb/tools/repl/swift/CMakeLists.txt index 16dd41c928c76..46989e7c25b5a 100644 --- a/lldb/tools/repl/swift/CMakeLists.txt +++ b/lldb/tools/repl/swift/CMakeLists.txt @@ -6,10 +6,15 @@ if (CMAKE_HOST_APPLE AND APPLE) endif() # Requires system-provided Swift libs. -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14.4) +if(NOT APPLE_EMBEDDED) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14.4) +endif() add_lldb_tool(repl_swift ADD_TO_FRAMEWORK main.c + + ENTITLEMENTS + "${CMAKE_CURRENT_SOURCE_DIR}/get-task-allow-entitlements.plist" ) target_link_libraries(repl_swift PRIVATE ${CMAKE_DL_LIBS}) if(CMAKE_SYSTEM_NAME STREQUAL Windows) diff --git a/lldb/tools/repl/swift/get-task-allow-entitlements.plist b/lldb/tools/repl/swift/get-task-allow-entitlements.plist new file mode 100644 index 0000000000000..9acd12816c913 --- /dev/null +++ b/lldb/tools/repl/swift/get-task-allow-entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.security.get-task-allow + + + diff --git a/lldb/tools/repl/swift/repl_swift.xcodeproj/project.pbxproj b/lldb/tools/repl/swift/repl_swift.xcodeproj/project.pbxproj deleted file mode 100644 index 2282c933559bc..0000000000000 --- a/lldb/tools/repl/swift/repl_swift.xcodeproj/project.pbxproj +++ /dev/null @@ -1,357 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 942829751A8975A600521B30 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942829741A8975A600521B30 /* main.swift */; }; - 9428297D1A8975CC00521B30 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9428297C1A8975CC00521B30 /* Foundation.framework */; }; - 942829871A8975E400521B30 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942829741A8975A600521B30 /* main.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 942829621A89754E00521B30 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 942829781A8975CC00521B30 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 942829641A89754E00521B30 /* repl_swift */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = repl_swift; sourceTree = BUILT_PRODUCTS_DIR; }; - 942829741A8975A600521B30 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = SOURCE_ROOT; }; - 9428297A1A8975CC00521B30 /* repl_swift_ios */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = repl_swift_ios; sourceTree = BUILT_PRODUCTS_DIR; }; - 9428297C1A8975CC00521B30 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 942829611A89754E00521B30 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 942829771A8975CC00521B30 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9428297D1A8975CC00521B30 /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9428295B1A89754E00521B30 = { - isa = PBXGroup; - children = ( - 942829661A89754E00521B30 /* repl_swift */, - 9428297B1A8975CC00521B30 /* Frameworks */, - 942829651A89754E00521B30 /* Products */, - ); - sourceTree = ""; - }; - 942829651A89754E00521B30 /* Products */ = { - isa = PBXGroup; - children = ( - 942829641A89754E00521B30 /* repl_swift */, - 9428297A1A8975CC00521B30 /* repl_swift_ios */, - ); - name = Products; - sourceTree = ""; - }; - 942829661A89754E00521B30 /* repl_swift */ = { - isa = PBXGroup; - children = ( - 942829741A8975A600521B30 /* main.swift */, - ); - path = repl_swift; - sourceTree = ""; - }; - 9428297B1A8975CC00521B30 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 9428297C1A8975CC00521B30 /* Foundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 942829631A89754E00521B30 /* repl_swift */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9428296B1A89754E00521B30 /* Build configuration list for PBXNativeTarget "repl_swift" */; - buildPhases = ( - 942829601A89754E00521B30 /* Sources */, - 942829611A89754E00521B30 /* Frameworks */, - 942829621A89754E00521B30 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = repl_swift; - productName = repl_swift; - productReference = 942829641A89754E00521B30 /* repl_swift */; - productType = "com.apple.product-type.tool"; - }; - 942829791A8975CC00521B30 /* repl_swift_ios */ = { - isa = PBXNativeTarget; - buildConfigurationList = 942829831A8975CC00521B30 /* Build configuration list for PBXNativeTarget "repl_swift_ios" */; - buildPhases = ( - 942829B81A897ABB00521B30 /* ShellScript */, - 942829761A8975CC00521B30 /* Sources */, - 942829771A8975CC00521B30 /* Frameworks */, - 942829781A8975CC00521B30 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = repl_swift_ios; - productName = repl_swift_ios; - productReference = 9428297A1A8975CC00521B30 /* repl_swift_ios */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 9428295C1A89754E00521B30 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0700; - ORGANIZATIONNAME = lldb; - TargetAttributes = { - 942829631A89754E00521B30 = { - CreatedOnToolsVersion = 7.0; - }; - 942829791A8975CC00521B30 = { - CreatedOnToolsVersion = 7.0; - }; - }; - }; - buildConfigurationList = 9428295F1A89754E00521B30 /* Build configuration list for PBXProject "repl_swift" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 9428295B1A89754E00521B30; - productRefGroup = 942829651A89754E00521B30 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 942829631A89754E00521B30 /* repl_swift */, - 942829791A8975CC00521B30 /* repl_swift_ios */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXShellScriptBuildPhase section */ - 942829B81A897ABB00521B30 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = ""; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 942829601A89754E00521B30 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 942829751A8975A600521B30 /* main.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 942829761A8975CC00521B30 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 942829871A8975E400521B30 /* main.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 942829691A89754E00521B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 9428296A1A89754E00521B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - }; - name = Release; - }; - 9428296C1A89754E00521B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - COPY_PHASE_STRIP = YES; - LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../../../../../usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 9428296D1A89754E00521B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - COPY_PHASE_STRIP = YES; - LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../../../../../usr/lib/swift/macosx"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 942829841A8975CC00521B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../../../../../usr/lib/swift/iphonesimulator"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos.internal; - }; - name = Debug; - }; - 942829851A8975CC00521B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../../../../../usr/lib/swift/iphonesimulator"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos.internal; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 9428295F1A89754E00521B30 /* Build configuration list for PBXProject "repl_swift" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 942829691A89754E00521B30 /* Debug */, - 9428296A1A89754E00521B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9428296B1A89754E00521B30 /* Build configuration list for PBXNativeTarget "repl_swift" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9428296C1A89754E00521B30 /* Debug */, - 9428296D1A89754E00521B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 942829831A8975CC00521B30 /* Build configuration list for PBXNativeTarget "repl_swift_ios" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 942829841A8975CC00521B30 /* Debug */, - 942829851A8975CC00521B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - }; -/* End XCConfigurationList section */ - }; - rootObject = 9428295C1A89754E00521B30 /* Project object */; -} diff --git a/lldb/tools/repl/swift/repl_swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/lldb/tools/repl/swift/repl_swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index a03ff818d6f3b..0000000000000 --- a/lldb/tools/repl/swift/repl_swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/lldb/unittests/API/CMakeLists.txt b/lldb/unittests/API/CMakeLists.txt index 308249b63add1..2f066f26d8aaf 100644 --- a/lldb/unittests/API/CMakeLists.txt +++ b/lldb/unittests/API/CMakeLists.txt @@ -5,6 +5,6 @@ add_lldb_unittest(APITests liblldb ) -if(PYTHON_RPATH) - set_property(TARGET APITests APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") +if(Python3_RPATH) + set_property(TARGET APITests APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") endif() diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 78c400c33d4e3..8f18f2453ad39 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -221,6 +221,14 @@ TEST(DWARFExpression, DW_OP_piece) { llvm::HasValue(GetScalar(16, 0xff00, true))); } +TEST(DWARFExpression, DW_OP_implicit_value) { + unsigned char bytes = 4; + + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}), + llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true))); +} + TEST(DWARFExpression, DW_OP_unknown) { EXPECT_THAT_EXPECTED( Evaluate({0xff}), diff --git a/lldb/unittests/Interpreter/CMakeLists.txt b/lldb/unittests/Interpreter/CMakeLists.txt index 0de5b0b72488e..28663ec02a2a9 100644 --- a/lldb/unittests/Interpreter/CMakeLists.txt +++ b/lldb/unittests/Interpreter/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(InterpreterTests TestCompletion.cpp TestOptionArgParser.cpp + TestOptionValueFileColonLine.cpp LINK_LIBS lldbInterpreter diff --git a/lldb/unittests/Interpreter/TestOptionValueFileColonLine.cpp b/lldb/unittests/Interpreter/TestOptionValueFileColonLine.cpp new file mode 100644 index 0000000000000..e5b2c77a16162 --- /dev/null +++ b/lldb/unittests/Interpreter/TestOptionValueFileColonLine.cpp @@ -0,0 +1,57 @@ +//===-- ArgsTest.cpp ------------------------------------------------------===// +// +// 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 "lldb/Interpreter/OptionValueFileColonLine.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +void CheckSetting(const char *input, bool success, const char *path = nullptr, + uint32_t line_number = LLDB_INVALID_ADDRESS, + uint32_t column_number = 0) { + + OptionValueFileColonLine value; + Status error; + llvm::StringRef s_ref(input); + error = value.SetValueFromString(s_ref); + ASSERT_EQ(error.Success(), success); + + // If we were meant to fail, we don't need to do more checks: + if (!success) + return; + + ASSERT_EQ(value.GetLineNumber(), line_number); + ASSERT_EQ(value.GetColumnNumber(), column_number); + std::string value_path = value.GetFileSpec().GetPath(); + ASSERT_STREQ(value_path.c_str(), path); +} + +TEST(OptionValueFileColonLine, setFromString) { + OptionValueFileColonLine value; + Status error; + + // Make sure a default constructed value is invalid: + ASSERT_EQ(value.GetLineNumber(), LLDB_INVALID_LINE_NUMBER); + ASSERT_EQ(value.GetColumnNumber(), 0); + ASSERT_FALSE(value.GetFileSpec()); + + // Make sure it is an error to pass a specifier with no line number: + CheckSetting("foo.c", false); + + // Now try with just a file & line: + CheckSetting("foo.c:12", true, "foo.c", 12); + CheckSetting("foo.c:12:20", true, "foo.c", 12, 20); + // Make sure a colon doesn't mess us up: + CheckSetting("foo:bar.c:12", true, "foo:bar.c", 12); + CheckSetting("foo:bar.c:12:20", true, "foo:bar.c", 12, 20); + // Try errors in the line number: + CheckSetting("foo.c:12c", false); + CheckSetting("foo.c:12:20c", false); +} diff --git a/lldb/unittests/Process/Linux/CMakeLists.txt b/lldb/unittests/Process/Linux/CMakeLists.txt index 31e9a57a4e46e..bf71f2b55b85b 100644 --- a/lldb/unittests/Process/Linux/CMakeLists.txt +++ b/lldb/unittests/Process/Linux/CMakeLists.txt @@ -5,4 +5,4 @@ add_lldb_unittest(ProcessorTraceTests LINK_LIBS lldbPluginProcessLinux - ) \ No newline at end of file + ) diff --git a/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt index aa8a95c7c54c0..e030070a140f0 100644 --- a/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt +++ b/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt @@ -9,4 +9,4 @@ add_lldb_unittest(ScriptInterpreterLuaTests LLVMTestingSupport LINK_COMPONENTS Support - ) \ No newline at end of file + ) diff --git a/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt index 913bd629526d7..90a53bf175105 100644 --- a/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt @@ -10,6 +10,6 @@ add_lldb_unittest(ScriptInterpreterPythonTests Support ) -if(PYTHON_RPATH) - set_property(TARGET ScriptInterpreterPythonTests APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") -endif() \ No newline at end of file +if(Python3_RPATH) + set_property(TARGET ScriptInterpreterPythonTests APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") +endif() diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp index f661835d191b1..58ddf0c40a267 100644 --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -254,3 +254,17 @@ LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting, const lldb::TargetSP &target_sp) { return nullptr; } + +extern "C" void *LLDBSwigPythonCreateScriptedStopHook( + lldb::TargetSP target_sp, const char *python_class_name, + const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, Status &error) { + return nullptr; +} + +extern "C" bool +LLDBSwigPythonStopHookCallHandleStop(void *implementor, + lldb::ExecutionContextRefSP exc_ctx_sp, + lldb::StreamSP stream) { + return false; +} diff --git a/lldb/unittests/Symbol/CMakeLists.txt b/lldb/unittests/Symbol/CMakeLists.txt index 0e9a62bedc900..ec07c6b6311a1 100644 --- a/lldb/unittests/Symbol/CMakeLists.txt +++ b/lldb/unittests/Symbol/CMakeLists.txt @@ -2,9 +2,13 @@ set(SWIFT_SOURCES TestSwiftASTContext.cpp TestTypeSystemSwiftTypeRef.cpp ) +set(SWIFT_LIBS + lldbPluginTypeSystemSwift +) set(LLVM_OPTIONAL_SOURCES ${SWIFT_SOURCES}) if (NOT LLDB_ENABLE_SWIFT_SUPPORT) unset(SWIFT_SOURCES) + unset(SWIFT_LIBS) endif() add_lldb_unittest(SymbolTests @@ -27,7 +31,7 @@ add_lldb_unittest(SymbolTests lldbPluginSymbolFileDWARF lldbPluginSymbolFileSymtab lldbPluginTypeSystemClang - lldbPluginTypeSystemSwift + ${SWIFT_LIBS} LLVMTestingSupport ) diff --git a/lldb/unittests/Symbol/TestSwiftASTContext.cpp b/lldb/unittests/Symbol/TestSwiftASTContext.cpp index 9bc2e5741570d..4ce31c9ea00a7 100644 --- a/lldb/unittests/Symbol/TestSwiftASTContext.cpp +++ b/lldb/unittests/Symbol/TestSwiftASTContext.cpp @@ -145,7 +145,6 @@ TEST_F(TestSwiftASTContext, ResourceDir) { llvm::sys::path::append(tc_rdir, "/Xcode.app/Contents/Developer/Toolchains/" "XcodeDefault.xctoolchain/usr/lib/swift"); - llvm::StringRef rdir; auto GetResourceDir = [&](const char *triple_string, llvm::StringRef sdk_path) { llvm::Triple host("x86_64-apple-macosx10.14"); @@ -157,7 +156,7 @@ TEST_F(TestSwiftASTContext, ResourceDir) { std::string(toolchain), std::string(cl_tools)); }; - EXPECT_EQ(GetResourceDir({"x86_64-apple-macosx10.14"}, macosx_sdk), + EXPECT_EQ(GetResourceDir("x86_64-apple-macosx10.14", macosx_sdk), tc_rdir.str()); EXPECT_EQ(GetResourceDir("x86_64-apple-darwin", macosx_sdk), tc_rdir); EXPECT_EQ(GetResourceDir("aarch64-apple-ios11.3", ios_sdk), tc_rdir); diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index c5f4f3e0ff1fc..6bac7e019f81f 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -126,7 +126,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { CompilerType void_void = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(void_void.IsFunctionType(nullptr)); ASSERT_TRUE(void_void.IsFunctionPointerType()); - ASSERT_EQ(void_void.GetNumberOfFunctionArguments(), 0); + ASSERT_EQ(void_void.GetNumberOfFunctionArguments(), 0UL); } { NodePointer n = b.GlobalType( @@ -134,7 +134,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"))); CompilerType impl_void_void = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(impl_void_void.IsFunctionType(nullptr)); - ASSERT_EQ(impl_void_void.GetNumberOfFunctionArguments(), 0); + ASSERT_EQ(impl_void_void.GetNumberOfFunctionArguments(), 0UL); } { NodePointer n = b.GlobalType(b.Node( @@ -147,7 +147,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::Tuple)))); CompilerType impl_two_args = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(impl_two_args.IsFunctionType(nullptr)); - ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2); + ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2UL); ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(0), int_type); ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(1), void_type); ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(0), int_type); @@ -167,7 +167,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))))); CompilerType two_args = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(two_args.IsFunctionType(nullptr)); - ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2); + ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2UL); ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(0), int_type); ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(1), void_type); ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(0), int_type); @@ -306,7 +306,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Scalar) { uint32_t count = 99; bool is_complex = true; ASSERT_FALSE(int_type.IsFloatingPointType(count, is_complex)); - ASSERT_EQ(count, 0); + ASSERT_EQ(count, 0UL); ASSERT_EQ(is_complex, false); bool is_signed = true; ASSERT_TRUE(int_type.IsIntegerType(is_signed)); @@ -318,7 +318,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Scalar) { uint32_t count = 99; bool is_complex = true; ASSERT_TRUE(float_type.IsFloatingPointType(count, is_complex)); - ASSERT_EQ(count, 1); + ASSERT_EQ(count, 1UL); ASSERT_EQ(is_complex, false); bool is_signed = true; ASSERT_FALSE(float_type.IsIntegerType(is_signed)); @@ -364,6 +364,60 @@ TEST_F(TestTypeSystemSwiftTypeRef, LanguageVersion) { } } +TEST_F(TestTypeSystemSwiftTypeRef, Tuple) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + + auto makeElement = [&](NodePointer type, + const char *name = + nullptr) -> TypeSystemSwift::TupleElement { + auto *node = b.GlobalTypeMangling(type); + return {ConstString(name), GetCompilerType(b.Mangle(node))}; + }; + + { + // Test unnamed tuple elements. + auto int_element = makeElement(b.IntType()); + auto float_element = makeElement(b.FloatType()); + auto int_float_tuple = + m_swift_ts.CreateTupleType({int_element, float_element}); + ASSERT_EQ(int_float_tuple.GetMangledTypeName(), + "$ss0016BuiltinInt_gCJAcV_s0019BuiltinFPIEEE_CJEEdVtD"); + auto float_int_tuple = + m_swift_ts.CreateTupleType({float_element, int_element}); + ASSERT_EQ(float_int_tuple.GetMangledTypeName(), + "$ss0019BuiltinFPIEEE_CJEEdV_s0016BuiltinInt_gCJAcVtD"); + } + { + // Test named tuple elements. + auto int_element = makeElement(b.IntType(), "i"); + auto float_element = makeElement(b.FloatType(), "f"); + auto int_float_tuple = + m_swift_ts.CreateTupleType({int_element, float_element}); + ASSERT_EQ(int_float_tuple.GetMangledTypeName(), + "$ss0016BuiltinInt_gCJAcV1i_s0019BuiltinFPIEEE_CJEEdV1ftD"); + auto float_int_tuple = + m_swift_ts.CreateTupleType({float_element, int_element}); + ASSERT_EQ(float_int_tuple.GetMangledTypeName(), + "$ss0019BuiltinFPIEEE_CJEEdV1f_s0016BuiltinInt_gCJAcV1itD"); + } + { + NodePointer n = b.GlobalType( + b.Node(Node::Kind::Tuple, + b.Node(Node::Kind::TupleElement, + b.Node(Node::Kind::TupleElementName, "x"), b.IntType()), + b.Node(Node::Kind::TupleElement, b.IntType()), + b.Node(Node::Kind::TupleElement, + b.Node(Node::Kind::TupleElementName, "z"), b.IntType()))); + CompilerType t = GetCompilerType(b.Mangle(n)); + lldb::opaque_compiler_type_t o = t.GetOpaqueQualType(); + ASSERT_EQ(m_swift_ts.GetTupleElementName(o, 0), "x"); + ASSERT_EQ(m_swift_ts.GetTupleElementName(o, 1), "1"); + ASSERT_EQ(m_swift_ts.GetTupleElementName(o, 2), "z"); + } +} + TEST_F(TestTypeSystemSwiftTypeRef, TypeClass) { using namespace swift::Demangle; Demangler dem; diff --git a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp index 8bf019ea9ed65..4898b94413cab 100644 --- a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp @@ -19,6 +19,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugAranges.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" @@ -70,7 +71,7 @@ TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) { TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { // Test that if we have a .debug_abbrev that contains ordered abbreviation // codes that start at 1, that we get O(1) access. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -81,7 +82,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(2); // Abbrev code 2 encoder.PutULEB128(DW_TAG_subprogram); encoder.PutHex8(DW_CHILDREN_no); @@ -89,9 +90,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -101,7 +102,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { // Make sure we have O(1) access to each abbreviation by making sure the // index offset is 1 and not UINT32_MAX EXPECT_EQ(abbrev_set.GetIndexOffset(), 1u); - + auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(1); EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); EXPECT_TRUE(abbrev1->HasChildren()); @@ -115,7 +116,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { // Test that if we have a .debug_abbrev that contains ordered abbreviation // codes that start at 5, that we get O(1) access. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -126,7 +127,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(6); // Abbrev code 6 encoder.PutULEB128(DW_TAG_subprogram); encoder.PutHex8(DW_CHILDREN_no); @@ -134,9 +135,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -146,7 +147,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { // Make sure we have O(1) access to each abbreviation by making sure the // index offset is 5 and not UINT32_MAX EXPECT_EQ(abbrev_set.GetIndexOffset(), 5u); - + auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(5); EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); EXPECT_TRUE(abbrev1->HasChildren()); @@ -160,7 +161,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { // Test that if we have a .debug_abbrev that contains unordered abbreviation // codes, that we can access the information correctly. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -171,7 +172,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(1); // Abbrev code 1 encoder.PutULEB128(DW_TAG_subprogram); encoder.PutHex8(DW_CHILDREN_no); @@ -179,9 +180,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -191,7 +192,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { // Make sure we don't have O(1) access to each abbreviation by making sure // the index offset is UINT32_MAX EXPECT_EQ(abbrev_set.GetIndexOffset(), UINT32_MAX); - + auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(2); EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); EXPECT_TRUE(abbrev1->HasChildren()); @@ -205,7 +206,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { // Test that we detect when an abbreviation has a NULL tag and that we get // an error when decoding. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -214,9 +215,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { encoder.PutHex8(DW_CHILDREN_no); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -232,7 +233,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { // Test that we detect when an abbreviation has a NULL attribute and a non // NULL form and that we get an error when decoding. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -245,7 +246,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { encoder.PutULEB128(0); encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -255,13 +256,12 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { EXPECT_TRUE(bool(error)); EXPECT_EQ("malformed abbreviation declaration attribute", llvm::toString(std::move(error))); - } TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) { // Test that we detect when an abbreviation has a valid attribute and a // NULL form and that we get an error when decoding. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -272,9 +272,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) { encoder.PutULEB128(0); // NULL form encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -290,7 +290,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) { // Test that we detect when an abbreviation has a valid attribute and a // form, but is missing the NULL attribute and form that terminates an // abbreviation - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -300,7 +300,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) { encoder.PutULEB128(DW_AT_name); encoder.PutULEB128(DW_FORM_strp); // Don't add the NULL DW_AT and NULL DW_FORM terminator - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -346,3 +346,42 @@ TEST_F(SymbolFileDWARFTests, ParseArangesNonzeroSegmentSize) { llvm::toString(std::move(error))); EXPECT_EQ(off, 12U); // Parser should read no further than the segment size } + +TEST_F(SymbolFileDWARFTests, ParseAranges) { + // Test we can successfully parse a DWARFDebugAranges. The initial error + // checking code had a bug where it would always return an empty address + // ranges for everything in .debug_aranges and no error. + const unsigned char binary_data[] = { + 60, 0, 0, 0, // unit_length + 2, 0, // DWARF version number + 255, 0, 0, 0, // offset into the .debug_info_table + 8, // address size + 0, // segment size + 0, 0, 0, 0, // pad bytes + // BEGIN TUPLES + // First tuple: [0x1000-0x1100) + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x1000 + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100 + // Second tuple: [0x2000-0x2100) + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x2000 + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100 + // Terminating tuple + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Terminator + }; + DWARFDataExtractor data; + data.SetData(static_cast(binary_data), sizeof binary_data, + lldb::ByteOrder::eByteOrderLittle); + DWARFDebugAranges debug_aranges; + llvm::Error error = debug_aranges.extract(data); + ASSERT_FALSE(bool(error)); + EXPECT_EQ(debug_aranges.GetNumRanges(), 2u); + EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET); +} diff --git a/lldb/utils/lldb-dotest/CMakeLists.txt b/lldb/utils/lldb-dotest/CMakeLists.txt index 0ef60c1427610..799cea8f58bb4 100644 --- a/lldb/utils/lldb-dotest/CMakeLists.txt +++ b/lldb/utils/lldb-dotest/CMakeLists.txt @@ -21,36 +21,48 @@ if(LLDB_BUILT_STANDALONE) string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} config_runtime_output_dir ${LLVM_RUNTIME_OUTPUT_INTDIR}) string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_FRAMEWORK_DIR_CONFIGURED "${LLDB_FRAMEWORK_DIR}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_TRACE_DIRECTORY_CONFIGURED "${LLDB_TEST_TRACE_DIRECTORY}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_SERVER_CONFIGURED "${LLDB_TEST_SERVER}") + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_SWIFTC_CONFIGURED "${LLDB_SWIFTC}") # Remaining ones must be paths to the provided LLVM build-tree. if(${config_type} IN_LIST LLVM_CONFIGURATION_TYPES) # Multi-configuration generator like Xcode (with a matching config). string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_FRAMEWORK_DIR_CONFIGURED "${LLDB_FRAMEWORK_DIR}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_TRACE_DIRECTORY_CONFIGURED "${LLDB_TEST_TRACE_DIRECTORY}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_SERVER_CONFIGURED "${LLDB_TEST_SERVER}") string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_SWIFTC_CONFIGURED "${LLDB_SWIFTC}") else() # Single-configuration generator like Ninja. string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") + string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_FRAMEWORK_DIR_CONFIGURED "${LLDB_FRAMEWORK_DIR}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") + string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_TRACE_DIRECTORY_CONFIGURED "${LLDB_TEST_TRACE_DIRECTORY}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ_CONFIGURED}") + string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") + string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_SERVER_CONFIGURED "${LLDB_TEST_SERVER}") string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_SWIFTC_CONFIGURED "${LLDB_SWIFTC}") endif() configure_file( @@ -63,13 +75,17 @@ elseif(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_DOTEST_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_FRAMEWORK_DIR_CONFIGURED "${LLDB_FRAMEWORK_DIR}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_TRACE_DIRECTORY_CONFIGURED "${LLDB_TEST_TRACE_DIRECTORY}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_SERVER_CONFIGURED "${LLDB_TEST_SERVER}") string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_SWIFTC_CONFIGURED "${LLDB_SWIFTC}") configure_file( lldb-dotest.in @@ -79,13 +95,17 @@ elseif(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") else() set(LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") set(LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") + set(LLDB_FRAMEWORK_DIR_CONFIGURED "${LLDB_FRAMEWORK_DIR}") set(LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") + set(LLDB_TEST_TRACE_DIRECTORY_CONFIGURED "${LLDB_TEST_TRACE_DIRECTORY}") set(LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") set(LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") set(LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") set(LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") set(LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") + set(LLDB_TEST_SERVER_CONFIGURED "${LLDB_TEST_SERVER}") set(LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + set(LLDB_SWIFTC_CONFIGURED "${LLDB_SWIFTC}") configure_file( lldb-dotest.in diff --git a/lldb/utils/lldb-dotest/lldb-dotest.in b/lldb/utils/lldb-dotest/lldb-dotest.in index ee0ea6dff748c..48bcb79fda151 100755 --- a/lldb/utils/lldb-dotest/lldb-dotest.in +++ b/lldb/utils/lldb-dotest/lldb-dotest.in @@ -1,18 +1,22 @@ -#!@PYTHON_EXECUTABLE@ +#!@Python3_EXECUTABLE@ import subprocess import sys dotest_path = '@LLDB_SOURCE_DIR_CONFIGURED@/test/API/dotest.py' -build_dir = '@LLDB_TEST_BUILD_DIRECTORY_CONFIGURED@' dotest_args_str = '@LLDB_DOTEST_ARGS_CONFIGURED@' arch = '@LLDB_TEST_ARCH@' executable = '@LLDB_TEST_EXECUTABLE_CONFIGURED@' compiler = '@LLDB_TEST_COMPILER_CONFIGURED@' +swift_compiler = '@LLDB_SWIFTC@' dsymutil = '@LLDB_TEST_DSYMUTIL_CONFIGURED@' filecheck = '@LLDB_TEST_FILECHECK_CONFIGURED@' yaml2obj = '@LLDB_TEST_YAML2OBJ_CONFIGURED@' -lldb_libs_dir = "@LLDB_LIBS_DIR_CONFIGURED@" +server = '@LLDB_TEST_SERVER_CONFIGURED@' +lldb_build_dir = '@LLDB_TEST_BUILD_DIRECTORY_CONFIGURED@' lldb_build_intel_pt = "@LLDB_BUILD_INTEL_PT@" +lldb_framework_dir = "@LLDB_FRAMEWORK_DIR_CONFIGURED@" +lldb_libs_dir = "@LLDB_LIBS_DIR_CONFIGURED@" +lldb_trace_dir = '@LLDB_TEST_TRACE_DIRECTORY_CONFIGURED@' if __name__ == '__main__': wrapper_args = sys.argv[1:] @@ -21,13 +25,20 @@ if __name__ == '__main__': cmd = [sys.executable, dotest_path] cmd.extend(['--arch', arch]) cmd.extend(dotest_args) - cmd.extend(['--build-dir', build_dir]) + cmd.extend(['-s', lldb_trace_dir]) + cmd.extend(['--build-dir', lldb_build_dir]) cmd.extend(['--executable', executable]) cmd.extend(['--compiler', compiler]) cmd.extend(['--dsymutil', dsymutil]) cmd.extend(['--yaml2obj', yaml2obj]) cmd.extend(['--filecheck', filecheck]) cmd.extend(['--lldb-libs-dir', lldb_libs_dir]) + if swift_compiler: + cmd.extend(['--swift-compiler', swift_compiler]) + if server: + cmd.extend(['--server', server]) + if lldb_framework_dir: + cmd.extend(['--framework', lldb_framework_dir]) if lldb_build_intel_pt == "1": cmd.extend(['--enable-plugin', 'intel-pt']) cmd.extend(wrapper_args) diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 038139a24090c..0bdabc216f08f 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -402,7 +402,6 @@ set(LLVM_TARGETS_TO_BUILD list(REMOVE_DUPLICATES LLVM_TARGETS_TO_BUILD) option(LLVM_ENABLE_PIC "Build Position-Independent Code" ON) -option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON) option(LLVM_ENABLE_MODULES "Compile with C++ modules enabled." OFF) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") option(LLVM_ENABLE_MODULE_DEBUGGING "Compile with -gmodules." ON) diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake index 333167bfb6b0d..e171698a8d9fb 100644 --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -1226,7 +1226,7 @@ macro(add_llvm_utility name) add_llvm_executable(${name} DISABLE_LLVM_LINK_LLVM_DYLIB ${ARGN}) set_target_properties(${name} PROPERTIES FOLDER "Utils") - if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) + if ( ${name} IN_LIST LLVM_TOOLCHAIN_UTILITIES OR NOT LLVM_INSTALL_TOOLCHAIN_ONLY) if (LLVM_INSTALL_UTILS AND LLVM_BUILD_UTILS) set(export_to_llvmexports) if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR @@ -1669,8 +1669,9 @@ function(get_llvm_lit_path base_dir file_name) set(${file_name} ${LIT_FILE_NAME} PARENT_SCOPE) set(${base_dir} ${LIT_BASE_DIR} PARENT_SCOPE) return() - else() + elseif (NOT DEFINED CACHE{LLVM_EXTERNAL_LIT_MISSING_WARNED_ONCE}) message(WARNING "LLVM_EXTERNAL_LIT set to ${LLVM_EXTERNAL_LIT}, but the path does not exist.") + set(LLVM_EXTERNAL_LIT_MISSING_WARNED_ONCE YES CACHE INTERNAL "") endif() endif() endif() @@ -2037,9 +2038,10 @@ function(llvm_codesign name) set(ARG_BUNDLE_PATH $) endif() - if(ARG_FORCE) - set(force_flag "-f") - endif() + # ld64 now always codesigns the binaries it creates. Apply the force arg + # unconditionally so that we can - for example - add entitlements to the + # targets that need it. + set(force_flag "-f") add_custom_command( TARGET ${name} POST_BUILD diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake index acab85a53140c..0b5400757e41c 100644 --- a/llvm/cmake/modules/HandleLLVMOptions.cmake +++ b/llvm/cmake/modules/HandleLLVMOptions.cmake @@ -400,6 +400,8 @@ elseif(MINGW) # FIXME: Also cygwin? endif() endif() +option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON) + if( MSVC ) include(ChooseMSVCCRT) diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in index 4d8e33711d27b..f1f76b63a6936 100644 --- a/llvm/cmake/modules/LLVMConfig.cmake.in +++ b/llvm/cmake/modules/LLVMConfig.cmake.in @@ -16,6 +16,8 @@ set(LLVM_USE_CRT_MINSIZEREL @LLVM_USE_CRT_MINSIZEREL@) set(LLVM_USE_CRT_RELEASE @LLVM_USE_CRT_RELEASE@) set(LLVM_USE_CRT_RELWITHDEBINFO @LLVM_USE_CRT_RELWITHDEBINFO@) +set(LLVM_USE_SPLIT_DWARF @LLVM_USE_SPLIT_DWARF@) + set(LLVM_COMMON_DEPENDS @LLVM_COMMON_DEPENDS@) set(LLVM_AVAILABLE_LIBS @LLVM_AVAILABLE_LIBS@) @@ -36,6 +38,8 @@ set(TARGET_TRIPLE "@TARGET_TRIPLE@") set(LLVM_ABI_BREAKING_CHECKS @LLVM_ABI_BREAKING_CHECKS@) +set(LLVM_ENABLE_WARNINGS @LLVM_ENABLE_WARNINGS@) + set(LLVM_ENABLE_EXPENSIVE_CHECKS @LLVM_ENABLE_EXPENSIVE_CHECKS@) set(LLVM_ENABLE_ASSERTIONS @LLVM_ENABLE_ASSERTIONS@) diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index 2af813fda1aa9..f5f50cbf01587 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -85,6 +85,22 @@ Changes to building LLVM Python 3 as Python 2 has been end-of-life'd by the Python Software Foundation. +Changes to the JIT infrastructure +--------------------------------- + +* LLJIT now supports execution of static inits / deinits via the + LLJIT::initialize and LLJIT::deinitialize methods + +* Static libraries can now be added to a JITDylib using the + StaticLibraryDefinitionGenerator class + +* A C API has been added for OrcV2 (llvm-project/llvm/include/llvm-c/Orc.h) + +* Several OrcV2 example projects have been added to + llvm-project/llvm/examples/OrcV2Examples + +* Many bug fixes and API improvements + Changes to the AArch64 Backend ------------------------------ @@ -149,6 +165,9 @@ Changes to the ARM Backend * Added support for Cortex-M55, Cortex-A77, Cortex-A78 and Cortex-X1 cores. +* The Machine Outliner is now supported for ARM and Thumb2, it is not + turned on by default and can be enabled with the ``-moutline`` clang flag. + Changes to the PowerPC Target ----------------------------- @@ -162,24 +181,33 @@ Optimization: Codegen: * POWER10 support -* Added PC Relative addressing -* Added __int128 vector bool support + + * Added PC Relative addressing + * Added __int128 vector bool support + * Security enhancement via probe-stack attribute support to protect against stack clash * Floating point support enhancements -* Improved half precision and quad precision support, including GLIBC -* constrained FP operation support for arithmetic/rounding/max/min -* cleaning up fast math flags checks in DAGCombine, Legalizer, and Lowering + + * Improved half precision and quad precision support, including GLIBC + * constrained FP operation support for arithmetic/rounding/max/min + * cleaning up fast math flags checks in DAGCombine, Legalizer, and Lowering + * Performance improvements from instruction exploitation, especially for vector permute on LE * Scheduling enhancements -* Added MacroFusion for POWER8 -* Added post-ra heuristics for POWER9 + + * Added MacroFusion for POWER8 + * Added post-ra heuristics for POWER9 + * Target dependent passes tuning -* Updated LoopStrengthReduce to use instruction number as first priority -* Enhanced MachineCombiner to expose more ILP + + * Updated LoopStrengthReduce to use instruction number as first priority + * Enhanced MachineCombiner to expose more ILP + * Code quality and maintenance enhancements -* Enabled more machine verification passes -* Added ability to parse and emit additional extended mnemonics -* Numerous bug fixes + + * Enabled more machine verification passes + * Added ability to parse and emit additional extended mnemonics + * Numerous bug fixes AIX Support Improvements: @@ -241,6 +269,21 @@ Bug fixes: * The correct libcall is now emitted for converting a float/double to a 32-bit signed or unsigned integer on RV64 targets lacking the F or D extensions. +Changes to the SystemZ Target +----------------------------- + +* Added support for the MemorySanitizer and the LeakSanitizer. +* Added support for the ``-fstack-clash-protection`` command line option. +* Enhanced the assembler parser to allow using `%r0` even in an address + register context, and to allow specifying registers using plain integer + numbers instead of register names everywhere. +* Fixed wrong code generation violating the platform ABI when passing + a C++ class (not struct) type having only a single member of + floating-point type. +* Fixed wrong code generation when using the `vec_store_len_r` or + `vec_load_len_r` intrinsics with an immediate length argument of + 16 or larger. +* Miscellaneous codegen enhancements, in particular to improve vector code. Changes to the X86 Target ------------------------- @@ -342,6 +385,21 @@ Changes to the LLVM tools * llvm-lib supports adding import library objects in addition to regular object files +External Open Source Projects Using LLVM 11 +=========================================== + +Zig Programming Language +------------------------ + +`Zig `_ is a general-purpose programming language and +toolchain for maintaining robust, optimal, and reusable software. In addition +to supporting LLVM as an optional backend, Zig links Clang and LLD to provide +an out-of-the-box cross compilation experience, not only for Zig code but for +C and C++ code as well. Using a sophisticated caching system, Zig lazily builds +from source compiler-rt, mingw-w64, musl, glibc, libcxx, libcxxabi, and +libunwind for the selected target - a "batteries included" drop-in for GCC/Clang +that works the same on every platform. + Additional Information ====================== diff --git a/llvm/docs/tutorial/BuildingAJIT4.rst b/llvm/docs/tutorial/BuildingAJIT4.rst index 3d3f81e438584..6eb3d52ccb8ab 100644 --- a/llvm/docs/tutorial/BuildingAJIT4.rst +++ b/llvm/docs/tutorial/BuildingAJIT4.rst @@ -1,6 +1,6 @@ -=========================================================================== -Building a JIT: Extreme Laziness - Using Compile Callbacks to JIT from ASTs -=========================================================================== +======================================================================= +Building a JIT: Extreme Laziness - Using LazyReexports to JIT from ASTs +======================================================================= .. contents:: :local: @@ -13,9 +13,9 @@ Chapter 4 Introduction ====================== Welcome to Chapter 4 of the "Building an ORC-based JIT in LLVM" tutorial. This -chapter introduces the Compile Callbacks and Indirect Stubs APIs and shows how -they can be used to replace the CompileOnDemand layer from -`Chapter 3 `_ with a custom lazy-JITing scheme that JITs +chapter introduces custom MaterializationUnits and Layers, and the lazy +reexports API. Together these will be used to replace the CompileOnDemandLayer +from `Chapter 3 `_ with a custom lazy-JITing scheme that JITs directly from Kaleidoscope ASTs. **To be done:** diff --git a/llvm/docs/tutorial/BuildingAJIT5.rst b/llvm/docs/tutorial/BuildingAJIT5.rst deleted file mode 100644 index 0fda8610efbf1..0000000000000 --- a/llvm/docs/tutorial/BuildingAJIT5.rst +++ /dev/null @@ -1,57 +0,0 @@ -============================================================================= -Building a JIT: Remote-JITing -- Process Isolation and Laziness at a Distance -============================================================================= - -.. contents:: - :local: - -**This tutorial is under active development. It is incomplete and details may -change frequently.** Nonetheless we invite you to try it out as it stands, and -we welcome any feedback. - -Chapter 5 Introduction -====================== - -Welcome to Chapter 5 of the "Building an ORC-based JIT in LLVM" tutorial. This -chapter introduces the ORC RemoteJIT Client/Server APIs and shows how to use -them to build a JIT stack that will execute its code via a communications -channel with a different process. This can be a separate process on the same -machine, a process on a different machine, or even a process on a different -platform/architecture. The code builds on top of the lazy-AST-compiling JIT -stack from `Chapter 4 `_. - -**To be done -- this is going to be a long one:** - -**(1) Introduce channels, RPC, RemoteJIT Client and Server APIs** - -**(2) Describe the client code in greater detail. Discuss modifications of the -KaleidoscopeJIT class, and the REPL itself.** - -**(3) Describe the server code.** - -**(4) Describe how to run the demo.** - -Full Code Listing -================= - -Here is the complete code listing for our running example that JITs lazily from -Kaleidoscope ASTS. To build this example, use: - -.. code-block:: bash - - # Compile - clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy - clang++ -g Server/server.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orcjit native` -O3 -o toy-server - # Run - ./toy-server & - ./toy - -Here is the code for the modified KaleidoscopeJIT: - -.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h - :language: c++ - -And the code for the JIT server: - -.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp - :language: c++ diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt b/llvm/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt index 947b5a3a3271e..dc516ab459ca1 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt @@ -3,6 +3,6 @@ add_subdirectory(Chapter2) add_subdirectory(Chapter3) add_subdirectory(Chapter4) -if (NOT WIN32) - add_subdirectory(Chapter5) -endif() +# if (NOT WIN32) +# add_subdirectory(Chapter5) +# endif() diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h index adb6be4366601..9b35456a70412 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h @@ -21,6 +21,7 @@ #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" @@ -31,53 +32,67 @@ namespace orc { class KaleidoscopeJIT { private: - ExecutionSession ES; - RTDyldObjectLinkingLayer ObjectLayer; - IRCompileLayer CompileLayer; + std::unique_ptr TPC; + std::unique_ptr ES; DataLayout DL; MangleAndInterner Mangle; - ThreadSafeContext Ctx; + + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; JITDylib &MainJD; public: - KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL) - : ObjectLayer(ES, + KaleidoscopeJIT(std::unique_ptr TPC, + std::unique_ptr ES, + JITTargetMachineBuilder JTMB, DataLayout DL) + : TPC(std::move(TPC)), ES(std::move(ES)), DL(std::move(DL)), + Mangle(*this->ES, this->DL), + ObjectLayer(*this->ES, []() { return std::make_unique(); }), - CompileLayer(ES, ObjectLayer, + CompileLayer(*this->ES, ObjectLayer, std::make_unique(std::move(JTMB))), - DL(std::move(DL)), Mangle(ES, this->DL), - Ctx(std::make_unique()), - MainJD(ES.createBareJITDylib("
")) { + MainJD(this->ES->createBareJITDylib("
")) { MainJD.addGenerator( cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( DL.getGlobalPrefix()))); } + ~KaleidoscopeJIT() { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); + } + static Expected> Create() { - auto JTMB = JITTargetMachineBuilder::detectHost(); + auto TPC = SelfTargetProcessControl::Create(); + if (!TPC) + return TPC.takeError(); + + auto ES = std::make_unique(); - if (!JTMB) - return JTMB.takeError(); + JITTargetMachineBuilder JTMB((*TPC)->getTargetTriple()); - auto DL = JTMB->getDefaultDataLayoutForTarget(); + auto DL = JTMB.getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); - return std::make_unique(std::move(*JTMB), std::move(*DL)); + return std::make_unique(std::move(*TPC), std::move(ES), + std::move(JTMB), std::move(*DL)); } const DataLayout &getDataLayout() const { return DL; } - LLVMContext &getContext() { return *Ctx.getContext(); } + JITDylib &getMainJITDylib() { return MainJD; } - Error addModule(std::unique_ptr M) { - return CompileLayer.add(MainJD, ThreadSafeModule(std::move(M), Ctx)); + Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + return CompileLayer.add(RT, std::move(TSM)); } Expected lookup(StringRef Name) { - return ES.lookup({&MainJD}, Mangle(Name.str())); + return ES->lookup({&MainJD}, Mangle(Name.str())); } }; diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp index ad942d1e45e72..2a405aebf3f1c 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp @@ -676,11 +676,11 @@ static std::unique_ptr ParseDefinition() { } /// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr(unsigned ExprCount) { +static std::unique_ptr ParseTopLevelExpr() { if (auto E = ParseExpression()) { // Make an anonymous proto. - auto Proto = std::make_unique - (("__anon_expr" + Twine(ExprCount)).str(), std::vector()); + auto Proto = std::make_unique("__anon_expr", + std::vector()); return std::make_unique(std::move(Proto), std::move(E)); } return nullptr; @@ -697,7 +697,7 @@ static std::unique_ptr ParseExtern() { //===----------------------------------------------------------------------===// static std::unique_ptr TheJIT; -static LLVMContext *TheContext; +static std::unique_ptr TheContext; static std::unique_ptr> Builder; static std::unique_ptr TheModule; static std::map NamedValues; @@ -1102,7 +1102,8 @@ Function *FunctionAST::codegen() { //===----------------------------------------------------------------------===// static void InitializeModule() { - // Open a new module. + // Open a new context and module. + TheContext = std::make_unique(); TheModule = std::make_unique("my cool jit", *TheContext); TheModule->setDataLayout(TheJIT->getDataLayout()); @@ -1116,7 +1117,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - ExitOnErr(TheJIT->addModule(std::move(TheModule))); + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM))); InitializeModule(); } } else { @@ -1140,27 +1142,27 @@ static void HandleExtern() { } static void HandleTopLevelExpression() { - static unsigned ExprCount = 0; - - // Update ExprCount. This number will be added to anonymous expressions to - // prevent them from clashing. - ++ExprCount; - // Evaluate a top-level expression into an anonymous function. - if (auto FnAST = ParseTopLevelExpr(ExprCount)) { + if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - ExitOnErr(TheJIT->addModule(std::move(TheModule))); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModule(); // Get the anonymous expression's JITSymbol. - auto Sym = - ExitOnErr(TheJIT->lookup(("__anon_expr" + Twine(ExprCount)).str())); + auto Sym = ExitOnErr(TheJIT->lookup("__anon_expr")); + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. auto *FP = (double (*)())(intptr_t)Sym.getAddress(); - assert(FP && "Failed to codegen function"); fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -1229,8 +1231,6 @@ int main() { getNextToken(); TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); - TheContext = &TheJIT->getContext(); - InitializeModule(); // Run the main "interpreter loop" now. diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h index 28649ffe49105..cc3700b71faa0 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h @@ -22,6 +22,7 @@ #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" @@ -36,54 +37,70 @@ namespace orc { class KaleidoscopeJIT { private: - ExecutionSession ES; - RTDyldObjectLinkingLayer ObjectLayer; - IRCompileLayer CompileLayer; - IRTransformLayer OptimizeLayer; + std::unique_ptr TPC; + std::unique_ptr ES; DataLayout DL; MangleAndInterner Mangle; - ThreadSafeContext Ctx; + + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + IRTransformLayer OptimizeLayer; JITDylib &MainJD; public: - KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL) - : ObjectLayer(ES, + KaleidoscopeJIT(std::unique_ptr TPC, + std::unique_ptr ES, + JITTargetMachineBuilder JTMB, DataLayout DL) + : TPC(std::move(TPC)), ES(std::move(ES)), DL(std::move(DL)), + Mangle(*this->ES, this->DL), + ObjectLayer(*this->ES, []() { return std::make_unique(); }), - CompileLayer(ES, ObjectLayer, + CompileLayer(*this->ES, ObjectLayer, std::make_unique(std::move(JTMB))), - OptimizeLayer(ES, CompileLayer, optimizeModule), DL(std::move(DL)), - Mangle(ES, this->DL), Ctx(std::make_unique()), - MainJD(ES.createBareJITDylib("
")) { + OptimizeLayer(*this->ES, CompileLayer, optimizeModule), + MainJD(this->ES->createBareJITDylib("
")) { MainJD.addGenerator( cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( DL.getGlobalPrefix()))); } - const DataLayout &getDataLayout() const { return DL; } - - LLVMContext &getContext() { return *Ctx.getContext(); } + ~KaleidoscopeJIT() { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); + } static Expected> Create() { - auto JTMB = JITTargetMachineBuilder::detectHost(); + auto TPC = SelfTargetProcessControl::Create(); + if (!TPC) + return TPC.takeError(); - if (!JTMB) - return JTMB.takeError(); + auto ES = std::make_unique(); - auto DL = JTMB->getDefaultDataLayoutForTarget(); + JITTargetMachineBuilder JTMB((*TPC)->getTargetTriple()); + + auto DL = JTMB.getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); - return std::make_unique(std::move(*JTMB), std::move(*DL)); + return std::make_unique(std::move(*TPC), std::move(ES), + std::move(JTMB), std::move(*DL)); } - Error addModule(std::unique_ptr M) { - return OptimizeLayer.add(MainJD, ThreadSafeModule(std::move(M), Ctx)); + const DataLayout &getDataLayout() const { return DL; } + + JITDylib &getMainJITDylib() { return MainJD; } + + Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + + return OptimizeLayer.add(RT, std::move(TSM)); } Expected lookup(StringRef Name) { - return ES.lookup({&MainJD}, Mangle(Name.str())); + return ES->lookup({&MainJD}, Mangle(Name.str())); } private: diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp index 136ae9636c56e..2a405aebf3f1c 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp @@ -676,11 +676,11 @@ static std::unique_ptr ParseDefinition() { } /// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr(unsigned ExprCount) { +static std::unique_ptr ParseTopLevelExpr() { if (auto E = ParseExpression()) { // Make an anonymous proto. - auto Proto = std::make_unique( - ("__anon_expr" + Twine(ExprCount)).str(), std::vector()); + auto Proto = std::make_unique("__anon_expr", + std::vector()); return std::make_unique(std::move(Proto), std::move(E)); } return nullptr; @@ -697,7 +697,7 @@ static std::unique_ptr ParseExtern() { //===----------------------------------------------------------------------===// static std::unique_ptr TheJIT; -static LLVMContext *TheContext; +static std::unique_ptr TheContext; static std::unique_ptr> Builder; static std::unique_ptr TheModule; static std::map NamedValues; @@ -1102,7 +1102,8 @@ Function *FunctionAST::codegen() { //===----------------------------------------------------------------------===// static void InitializeModule() { - // Open a new module. + // Open a new context and module. + TheContext = std::make_unique(); TheModule = std::make_unique("my cool jit", *TheContext); TheModule->setDataLayout(TheJIT->getDataLayout()); @@ -1116,7 +1117,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - ExitOnErr(TheJIT->addModule(std::move(TheModule))); + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM))); InitializeModule(); } } else { @@ -1140,27 +1142,27 @@ static void HandleExtern() { } static void HandleTopLevelExpression() { - static unsigned ExprCount = 0; - - // Update ExprCount. This number will be added to anonymous expressions to - // prevent them from clashing. - ++ExprCount; - // Evaluate a top-level expression into an anonymous function. - if (auto FnAST = ParseTopLevelExpr(ExprCount)) { + if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - ExitOnErr(TheJIT->addModule(std::move(TheModule))); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModule(); // Get the anonymous expression's JITSymbol. - auto Sym = - ExitOnErr(TheJIT->lookup(("__anon_expr" + Twine(ExprCount)).str())); + auto Sym = ExitOnErr(TheJIT->lookup("__anon_expr")); + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. auto *FP = (double (*)())(intptr_t)Sym.getAddress(); - assert(FP && "Failed to codegen function"); fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -1229,8 +1231,6 @@ int main() { getNextToken(); TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); - TheContext = &TheJIT->getContext(); - InitializeModule(); // Run the main "interpreter loop" now. diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h index 34c4b96835726..810a4cd48e30d 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h @@ -13,139 +13,143 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -#include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h" +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Mangler.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" -#include -#include #include -#include -#include -#include namespace llvm { namespace orc { class KaleidoscopeJIT { private: - ExecutionSession ES; - std::map> Resolvers; - std::unique_ptr TM; - const DataLayout DL; - LegacyRTDyldObjectLinkingLayer ObjectLayer; - LegacyIRCompileLayer CompileLayer; + std::unique_ptr TPC; + std::unique_ptr ES; + std::unique_ptr TPCIU; - using OptimizeFunction = - std::function(std::unique_ptr)>; + DataLayout DL; + MangleAndInterner Mangle; - LegacyIRTransformLayer OptimizeLayer; + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + IRTransformLayer OptimizeLayer; + CompileOnDemandLayer CODLayer; - std::unique_ptr CompileCallbackManager; - LegacyCompileOnDemandLayer CODLayer; + JITDylib &MainJD; + + static void handleLazyCallThroughError() { + errs() << "LazyCallThrough error: Could not find function body"; + exit(1); + } public: - KaleidoscopeJIT() - : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), - ObjectLayer(AcknowledgeORCv1Deprecation, ES, - [this](VModuleKey K) { - return LegacyRTDyldObjectLinkingLayer::Resources{ - std::make_shared(), - Resolvers[K]}; - }), - CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer, - SimpleCompiler(*TM)), - OptimizeLayer(AcknowledgeORCv1Deprecation, CompileLayer, - [this](std::unique_ptr M) { - return optimizeModule(std::move(M)); - }), - CompileCallbackManager(cantFail(orc::createLocalCompileCallbackManager( - TM->getTargetTriple(), ES, 0))), - CODLayer( - AcknowledgeORCv1Deprecation, ES, OptimizeLayer, - [&](orc::VModuleKey K) { return Resolvers[K]; }, - [&](orc::VModuleKey K, std::shared_ptr R) { - Resolvers[K] = std::move(R); - }, - [](Function &F) { return std::set({&F}); }, - *CompileCallbackManager, - orc::createLocalIndirectStubsManagerBuilder( - TM->getTargetTriple())) { - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + KaleidoscopeJIT(std::unique_ptr TPC, + std::unique_ptr ES, + std::unique_ptr TPCIU, + JITTargetMachineBuilder JTMB, DataLayout DL) + : TPC(std::move(TPC)), ES(std::move(ES)), TPCIU(std::move(TPCIU)), + DL(std::move(DL)), Mangle(*this->ES, this->DL), + ObjectLayer(*this->ES, + []() { return std::make_unique(); }), + CompileLayer(*this->ES, ObjectLayer, + std::make_unique(std::move(JTMB))), + OptimizeLayer(*this->ES, CompileLayer, optimizeModule), + CODLayer(*this->ES, OptimizeLayer, + this->TPCIU->getLazyCallThroughManager(), + [this] { return this->TPCIU->createIndirectStubsManager(); }), + MainJD(this->ES->createBareJITDylib("
")) { + MainJD.addGenerator( + cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()))); + } + + ~KaleidoscopeJIT() { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); + if (auto Err = TPCIU->cleanup()) + ES->reportError(std::move(Err)); } - TargetMachine &getTargetMachine() { return *TM; } - - VModuleKey addModule(std::unique_ptr M) { - // Create a new VModuleKey. - VModuleKey K = ES.allocateVModule(); - - // Build a resolver and associate it with the new key. - Resolvers[K] = createLegacyLookupResolver( - ES, - [this](StringRef Name) -> JITSymbol { - if (auto Sym = CompileLayer.findSymbol(std::string(Name), false)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess( - std::string(Name))) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); - return nullptr; - }, - [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); }); - - // Add the module to the JIT with the new key. - cantFail(CODLayer.addModule(K, std::move(M))); - return K; + static Expected> Create() { + auto TPC = SelfTargetProcessControl::Create(); + if (!TPC) + return TPC.takeError(); + + auto ES = std::make_unique(); + + auto TPCIU = TPCIndirectionUtils::Create(**TPC); + if (!TPCIU) + return TPCIU.takeError(); + + (*TPCIU)->createLazyCallThroughManager( + *ES, pointerToJITTargetAddress(&handleLazyCallThroughError)); + + if (auto Err = setUpInProcessLCTMReentryViaTPCIU(**TPCIU)) + return std::move(Err); + + JITTargetMachineBuilder JTMB((*TPC)->getTargetTriple()); + + auto DL = JTMB.getDefaultDataLayoutForTarget(); + if (!DL) + return DL.takeError(); + + return std::make_unique(std::move(*TPC), std::move(ES), + std::move(*TPCIU), std::move(JTMB), + std::move(*DL)); } - JITSymbol findSymbol(const std::string Name) { - std::string MangledName; - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - return CODLayer.findSymbol(MangledNameStream.str(), true); + const DataLayout &getDataLayout() const { return DL; } + + JITDylib &getMainJITDylib() { return MainJD; } + + Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + + return OptimizeLayer.add(RT, std::move(TSM)); } - void removeModule(VModuleKey K) { - cantFail(CODLayer.removeModule(K)); + Expected lookup(StringRef Name) { + return ES->lookup({&MainJD}, Mangle(Name.str())); } private: - std::unique_ptr optimizeModule(std::unique_ptr M) { - // Create a function pass manager. - auto FPM = std::make_unique(M.get()); - - // Add some optimizations. - FPM->add(createInstructionCombiningPass()); - FPM->add(createReassociatePass()); - FPM->add(createGVNPass()); - FPM->add(createCFGSimplificationPass()); - FPM->doInitialization(); - - // Run the optimizations over all functions in the module being added to - // the JIT. - for (auto &F : *M) - FPM->run(F); - - return M; + static Expected + optimizeModule(ThreadSafeModule TSM, const MaterializationResponsibility &R) { + TSM.withModuleDo([](Module &M) { + // Create a function pass manager. + auto FPM = std::make_unique(&M); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : M) + FPM->run(F); + }); + + return std::move(TSM); } }; diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp index d082e510e291e..2a405aebf3f1c 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp @@ -680,7 +680,7 @@ static std::unique_ptr ParseTopLevelExpr() { if (auto E = ParseExpression()) { // Make an anonymous proto. auto Proto = std::make_unique("__anon_expr", - std::vector()); + std::vector()); return std::make_unique(std::move(Proto), std::move(E)); } return nullptr; @@ -696,12 +696,13 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheJIT; +static std::unique_ptr TheContext; +static std::unique_ptr> Builder; static std::unique_ptr TheModule; static std::map NamedValues; -static std::unique_ptr TheJIT; static std::map> FunctionProtos; +static ExitOnError ExitOnErr; Value *LogErrorV(const char *Str) { LogError(Str); @@ -729,11 +730,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, StringRef VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); + return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -743,7 +744,7 @@ Value *VariableExprAST::codegen() { return LogErrorV("Unknown variable name"); // Load the value. - return Builder.CreateLoad(V, Name.c_str()); + return Builder->CreateLoad(V, Name.c_str()); } Value *UnaryExprAST::codegen() { @@ -755,7 +756,7 @@ Value *UnaryExprAST::codegen() { if (!F) return LogErrorV("Unknown unary operator"); - return Builder.CreateCall(F, OperandV, "unop"); + return Builder->CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { @@ -778,7 +779,7 @@ Value *BinaryExprAST::codegen() { if (!Variable) return LogErrorV("Unknown variable name"); - Builder.CreateStore(Val, Variable); + Builder->CreateStore(Val, Variable); return Val; } @@ -789,15 +790,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: break; } @@ -808,7 +809,7 @@ Value *BinaryExprAST::codegen() { assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); + return Builder->CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { @@ -828,7 +829,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -837,46 +838,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -903,7 +904,7 @@ Value *IfExprAST::codegen() { // br endcond, loop, endloop // outloop: Value *ForExprAST::codegen() { - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -914,17 +915,17 @@ Value *ForExprAST::codegen() { return nullptr; // Store the value into the alloca. - Builder.CreateStore(StartVal, Alloca); + Builder->CreateStore(StartVal, Alloca); // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. @@ -945,7 +946,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } // Compute the end condition. @@ -955,23 +956,23 @@ Value *ForExprAST::codegen() { // Reload, increment, and restore the alloca. This handles the case where // the body of the loop mutates the variable. - Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); - Builder.CreateStore(NextVar, Alloca); + Value *CurVar = Builder->CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar"); + Builder->CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Restore the unshadowed variable. if (OldVal) @@ -980,13 +981,13 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Value *VarExprAST::codegen() { std::vector OldBindings; - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { @@ -1004,11 +1005,11 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + InitVal = ConstantFP::get(*TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - Builder.CreateStore(InitVal, Alloca); + Builder->CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. @@ -1033,9 +1034,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1062,8 +1063,8 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -1072,7 +1073,7 @@ Function *FunctionAST::codegen() { AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); // Store the initial value into the alloca. - Builder.CreateStore(&Arg, Alloca); + Builder->CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. NamedValues[std::string(Arg.getName())] = Alloca; @@ -1080,7 +1081,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -1101,9 +1102,13 @@ Function *FunctionAST::codegen() { //===----------------------------------------------------------------------===// static void InitializeModule() { - // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + // Open a new context and module. + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); } static void HandleDefinition() { @@ -1112,7 +1117,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - TheJIT->addModule(std::move(TheModule)); + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM))); InitializeModule(); } } else { @@ -1139,22 +1145,24 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModule(); - // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); + // Get the anonymous expression's JITSymbol. + auto Sym = ExitOnErr(TheJIT->lookup("__anon_expr")); // Get the symbol's address and cast it to the right type (takes no // arguments, returns a double) so we can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); + auto *FP = (double (*)())(intptr_t)Sym.getAddress(); fprintf(stderr, "Evaluated to %f\n", FP()); // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -1222,8 +1230,7 @@ int main() { fprintf(stderr, "ready> "); getNextToken(); - TheJIT = std::make_unique(); - + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModule(); // Run the main "interpreter loop" now. diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h index c87565737f2de..ba63e7cf9ca55 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h @@ -13,34 +13,26 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -#include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" -#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h" +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Mangler.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" -#include -#include -#include -#include #include -#include -#include class PrototypeAST; class ExprAST; @@ -64,164 +56,191 @@ class FunctionAST { /// suffix (needed to prevent a name-clash with the function's stub), /// and then take ownership of the module that the function was compiled /// into. -std::unique_ptr -irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix); +llvm::orc::ThreadSafeModule irgenAndTakeOwnership(FunctionAST &FnAST, + const std::string &Suffix); namespace llvm { namespace orc { -class KaleidoscopeJIT { -private: - ExecutionSession ES; - std::shared_ptr Resolver; - std::unique_ptr TM; - const DataLayout DL; - LegacyRTDyldObjectLinkingLayer ObjectLayer; - LegacyIRCompileLayer CompileLayer; +class KaleidoscopeASTLayer; +class KaleidoscopeJIT; + +class KaleidoscopeASTMaterializationUnit : public MaterializationUnit { +public: + KaleidoscopeASTMaterializationUnit(KaleidoscopeASTLayer &L, + std::unique_ptr F); + + StringRef getName() const override { + return "KaleidoscopeASTMaterializationUnit"; + } - using OptimizeFunction = - std::function(std::unique_ptr)>; + void materialize(std::unique_ptr R) override; - LegacyIRTransformLayer OptimizeLayer; +private: + void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override { + llvm_unreachable("Kaleidoscope functions are not overridable"); + } - std::unique_ptr CompileCallbackMgr; - std::unique_ptr IndirectStubsMgr; + KaleidoscopeASTLayer &L; + std::unique_ptr F; +}; +class KaleidoscopeASTLayer { public: - KaleidoscopeJIT() - : Resolver(createLegacyLookupResolver( - ES, - [this](StringRef Name) -> JITSymbol { - if (auto Sym = IndirectStubsMgr->findStub(Name, false)) - return Sym; - if (auto Sym = OptimizeLayer.findSymbol(std::string(Name), false)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess( - std::string(Name))) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); - return nullptr; - }, - [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), - TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), - ObjectLayer(AcknowledgeORCv1Deprecation, ES, - [this](VModuleKey K) { - return LegacyRTDyldObjectLinkingLayer::Resources{ - std::make_shared(), Resolver}; - }), - CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer, - SimpleCompiler(*TM)), - OptimizeLayer(AcknowledgeORCv1Deprecation, CompileLayer, - [this](std::unique_ptr M) { - return optimizeModule(std::move(M)); - }), - CompileCallbackMgr(cantFail(orc::createLocalCompileCallbackManager( - TM->getTargetTriple(), ES, 0))) { - auto IndirectStubsMgrBuilder = - orc::createLocalIndirectStubsManagerBuilder(TM->getTargetTriple()); - IndirectStubsMgr = IndirectStubsMgrBuilder(); - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + KaleidoscopeASTLayer(IRLayer &BaseLayer, const DataLayout &DL) + : BaseLayer(BaseLayer), DL(DL) {} + + Error add(ResourceTrackerSP RT, std::unique_ptr F) { + return RT->getJITDylib().define( + std::make_unique(*this, + std::move(F)), + RT); } - TargetMachine &getTargetMachine() { return *TM; } + void emit(std::unique_ptr MR, + std::unique_ptr F) { + BaseLayer.emit(std::move(MR), irgenAndTakeOwnership(*F, "")); + } - VModuleKey addModule(std::unique_ptr M) { - // Add the module to the JIT with a new VModuleKey. - auto K = ES.allocateVModule(); - cantFail(OptimizeLayer.addModule(K, std::move(M))); - return K; + SymbolFlagsMap getInterface(FunctionAST &F) { + MangleAndInterner Mangle(BaseLayer.getExecutionSession(), DL); + SymbolFlagsMap Symbols; + Symbols[Mangle(F.getName())] = + JITSymbolFlags(JITSymbolFlags::Exported | JITSymbolFlags::Callable); + return Symbols; } - Error addFunctionAST(std::unique_ptr FnAST) { - // Move ownership of FnAST to a shared pointer - C++11 lambdas don't support - // capture-by-move, which is be required for unique_ptr. - auto SharedFnAST = std::shared_ptr(std::move(FnAST)); - - // Set the action to compile our AST. This lambda will be run if/when - // execution hits the compile callback (via the stub). - // - // The steps to compile are: - // (1) IRGen the function. - // (2) Add the IR module to the JIT to make it executable like any other - // module. - // (3) Use findSymbol to get the address of the compiled function. - // (4) Update the stub pointer to point at the implementation so that - /// subsequent calls go directly to it and bypass the compiler. - // (5) Return the address of the implementation: this lambda will actually - // be run inside an attempted call to the function, and we need to - // continue on to the implementation to complete the attempted call. - // The JIT runtime (the resolver block) will use the return address of - // this function as the address to continue at once it has reset the - // CPU state to what it was immediately before the call. - auto CompileAction = [this, SharedFnAST]() { - auto M = irgenAndTakeOwnership(*SharedFnAST, "$impl"); - addModule(std::move(M)); - auto Sym = findSymbol(SharedFnAST->getName() + "$impl"); - assert(Sym && "Couldn't find compiled function?"); - JITTargetAddress SymAddr = cantFail(Sym.getAddress()); - if (auto Err = IndirectStubsMgr->updatePointer( - mangle(SharedFnAST->getName()), SymAddr)) { - logAllUnhandledErrors(std::move(Err), errs(), - "Error updating function pointer: "); - exit(1); - } - - return SymAddr; - }; - - // Create a CompileCallback using the CompileAction - this is the re-entry - // point into the compiler for functions that haven't been compiled yet. - auto CCAddr = cantFail( - CompileCallbackMgr->getCompileCallback(std::move(CompileAction))); - - // Create an indirect stub. This serves as the functions "canonical - // definition" - an unchanging (constant address) entry point to the - // function implementation. - // Initially we point the stub's function-pointer at the compile callback - // that we just created. When the compile action for the callback is run we - // will update the stub's function pointer to point at the function - // implementation that we just implemented. - if (auto Err = IndirectStubsMgr->createStub( - mangle(SharedFnAST->getName()), CCAddr, JITSymbolFlags::Exported)) - return Err; - - return Error::success(); +private: + IRLayer &BaseLayer; + const DataLayout &DL; +}; + +KaleidoscopeASTMaterializationUnit::KaleidoscopeASTMaterializationUnit( + KaleidoscopeASTLayer &L, std::unique_ptr F) + : MaterializationUnit(L.getInterface(*F), nullptr), L(L), F(std::move(F)) {} + +void KaleidoscopeASTMaterializationUnit::materialize( + std::unique_ptr R) { + L.emit(std::move(R), std::move(F)); +} + +class KaleidoscopeJIT { +private: + std::unique_ptr TPC; + std::unique_ptr ES; + std::unique_ptr TPCIU; + + DataLayout DL; + MangleAndInterner Mangle; + + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + IRTransformLayer OptimizeLayer; + KaleidoscopeASTLayer ASTLayer; + + JITDylib &MainJD; + + static void handleLazyCallThroughError() { + errs() << "LazyCallThrough error: Could not find function body"; + exit(1); } - JITSymbol findSymbol(const std::string Name) { - return OptimizeLayer.findSymbol(mangle(Name), true); +public: + KaleidoscopeJIT(std::unique_ptr TPC, + std::unique_ptr ES, + std::unique_ptr TPCIU, + JITTargetMachineBuilder JTMB, DataLayout DL) + : TPC(std::move(TPC)), ES(std::move(ES)), TPCIU(std::move(TPCIU)), + DL(std::move(DL)), Mangle(*this->ES, this->DL), + ObjectLayer(*this->ES, + []() { return std::make_unique(); }), + CompileLayer(*this->ES, ObjectLayer, + std::make_unique(std::move(JTMB))), + OptimizeLayer(*this->ES, CompileLayer, optimizeModule), + ASTLayer(OptimizeLayer, this->DL), + MainJD(this->ES->createBareJITDylib("
")) { + MainJD.addGenerator( + cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()))); } - void removeModule(VModuleKey K) { - cantFail(OptimizeLayer.removeModule(K)); + ~KaleidoscopeJIT() { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); + if (auto Err = TPCIU->cleanup()) + ES->reportError(std::move(Err)); } -private: - std::string mangle(const std::string &Name) { - std::string MangledName; - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - return MangledNameStream.str(); + static Expected> Create() { + auto TPC = SelfTargetProcessControl::Create(); + if (!TPC) + return TPC.takeError(); + + auto ES = std::make_unique(); + + auto TPCIU = TPCIndirectionUtils::Create(**TPC); + if (!TPCIU) + return TPCIU.takeError(); + + (*TPCIU)->createLazyCallThroughManager( + *ES, pointerToJITTargetAddress(&handleLazyCallThroughError)); + + if (auto Err = setUpInProcessLCTMReentryViaTPCIU(**TPCIU)) + return std::move(Err); + + JITTargetMachineBuilder JTMB((*TPC)->getTargetTriple()); + + auto DL = JTMB.getDefaultDataLayoutForTarget(); + if (!DL) + return DL.takeError(); + + return std::make_unique(std::move(*TPC), std::move(ES), + std::move(*TPCIU), std::move(JTMB), + std::move(*DL)); } - std::unique_ptr optimizeModule(std::unique_ptr M) { - // Create a function pass manager. - auto FPM = std::make_unique(M.get()); + const DataLayout &getDataLayout() const { return DL; } - // Add some optimizations. - FPM->add(createInstructionCombiningPass()); - FPM->add(createReassociatePass()); - FPM->add(createGVNPass()); - FPM->add(createCFGSimplificationPass()); - FPM->doInitialization(); + JITDylib &getMainJITDylib() { return MainJD; } - // Run the optimizations over all functions in the module being added to - // the JIT. - for (auto &F : *M) - FPM->run(F); + Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); - return M; + return OptimizeLayer.add(RT, std::move(TSM)); + } + + Error addAST(std::unique_ptr F, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + return ASTLayer.add(RT, std::move(F)); + } + + Expected lookup(StringRef Name) { + return ES->lookup({&MainJD}, Mangle(Name.str())); + } + +private: + static Expected + optimizeModule(ThreadSafeModule TSM, const MaterializationResponsibility &R) { + TSM.withModuleDo([](Module &M) { + // Create a function pass manager. + auto FPM = std::make_unique(&M); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : M) + FPM->run(F); + }); + + return std::move(TSM); } }; diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp index e39e8a94d0377..dc6d9da87c7e6 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp @@ -10,8 +10,6 @@ #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" #include "KaleidoscopeJIT.h" @@ -665,7 +663,7 @@ static std::unique_ptr ParseTopLevelExpr() { if (auto E = ParseExpression()) { // Make an anonymous proto. auto Proto = std::make_unique("__anon_expr", - std::vector()); + std::vector()); return std::make_unique(std::move(Proto), std::move(E)); } return nullptr; @@ -681,11 +679,11 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheJIT; +static std::unique_ptr TheContext; +static std::unique_ptr> Builder; static std::unique_ptr TheModule; static std::map NamedValues; -static std::unique_ptr TheJIT; static std::map> FunctionProtos; static ExitOnError ExitOnErr; @@ -715,11 +713,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, StringRef VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); + return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -729,7 +727,7 @@ Value *VariableExprAST::codegen() { return LogErrorV("Unknown variable name"); // Load the value. - return Builder.CreateLoad(V, Name.c_str()); + return Builder->CreateLoad(V, Name.c_str()); } Value *UnaryExprAST::codegen() { @@ -741,7 +739,7 @@ Value *UnaryExprAST::codegen() { if (!F) return LogErrorV("Unknown unary operator"); - return Builder.CreateCall(F, OperandV, "unop"); + return Builder->CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { @@ -764,7 +762,7 @@ Value *BinaryExprAST::codegen() { if (!Variable) return LogErrorV("Unknown variable name"); - Builder.CreateStore(Val, Variable); + Builder->CreateStore(Val, Variable); return Val; } @@ -775,15 +773,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: break; } @@ -794,7 +792,7 @@ Value *BinaryExprAST::codegen() { assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); + return Builder->CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { @@ -814,7 +812,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -823,46 +821,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -889,7 +887,7 @@ Value *IfExprAST::codegen() { // br endcond, loop, endloop // outloop: Value *ForExprAST::codegen() { - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -900,17 +898,17 @@ Value *ForExprAST::codegen() { return nullptr; // Store the value into the alloca. - Builder.CreateStore(StartVal, Alloca); + Builder->CreateStore(StartVal, Alloca); // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. @@ -931,7 +929,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } // Compute the end condition. @@ -941,23 +939,23 @@ Value *ForExprAST::codegen() { // Reload, increment, and restore the alloca. This handles the case where // the body of the loop mutates the variable. - Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); - Builder.CreateStore(NextVar, Alloca); + Value *CurVar = Builder->CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar"); + Builder->CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Restore the unshadowed variable. if (OldVal) @@ -966,13 +964,13 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Value *VarExprAST::codegen() { std::vector OldBindings; - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { @@ -990,11 +988,11 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + InitVal = ConstantFP::get(*TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - Builder.CreateStore(InitVal, Alloca); + Builder->CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. @@ -1019,9 +1017,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1046,6 +1044,7 @@ Function *FunctionAST::codegen() { // Transfer ownership of the prototype to the FunctionProtos map, but keep a // reference to it for use below. auto &P = *Proto; + FunctionProtos[Proto->getName()] = std::move(Proto); Function *TheFunction = getFunction(P.getName()); if (!TheFunction) return nullptr; @@ -1055,8 +1054,8 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -1065,7 +1064,7 @@ Function *FunctionAST::codegen() { AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); // Store the initial value into the alloca. - Builder.CreateStore(&Arg, Alloca); + Builder->CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. NamedValues[std::string(Arg.getName())] = Alloca; @@ -1073,7 +1072,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -1085,7 +1084,7 @@ Function *FunctionAST::codegen() { TheFunction->eraseFromParent(); if (P.isBinaryOp()) - BinopPrecedence.erase(Proto->getOperatorName()); + BinopPrecedence.erase(P.getOperatorName()); return nullptr; } @@ -1094,19 +1093,23 @@ Function *FunctionAST::codegen() { //===----------------------------------------------------------------------===// static void InitializeModule() { - // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + // Open a new context and module. + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); } -std::unique_ptr -irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix) { +ThreadSafeModule irgenAndTakeOwnership(FunctionAST &FnAST, + const std::string &Suffix) { if (auto *F = FnAST.codegen()) { F->setName(F->getName() + Suffix); - auto M = std::move(TheModule); + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); // Start a new module. InitializeModule(); - return M; + return TSM; } else report_fatal_error("Couldn't compile lazily JIT'd function"); } @@ -1115,7 +1118,7 @@ static void HandleDefinition() { if (auto FnAST = ParseDefinition()) { FunctionProtos[FnAST->getProto().getName()] = std::make_unique(FnAST->getProto()); - ExitOnErr(TheJIT->addFunctionAST(std::move(FnAST))); + ExitOnErr(TheJIT->addAST(std::move(FnAST))); } else { // Skip token for error recovery. getNextToken(); @@ -1139,25 +1142,25 @@ static void HandleExtern() { static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { - FunctionProtos[FnAST->getName()] = - std::make_unique(FnAST->getProto()); if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModule(); - // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); + // Get the anonymous expression's JITSymbol. + auto Sym = ExitOnErr(TheJIT->lookup("__anon_expr")); // Get the symbol's address and cast it to the right type (takes no // arguments, returns a double) so we can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); + auto *FP = (double (*)())(intptr_t)Sym.getAddress(); fprintf(stderr, "Evaluated to %f\n", FP()); // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -1213,8 +1216,6 @@ int main() { InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); - ExitOnErr.setBanner("Kaleidoscope: "); - // Install standard binary operators. // 1 is lowest precedence. BinopPrecedence['='] = 2; @@ -1227,8 +1228,7 @@ int main() { fprintf(stderr, "ready> "); getNextToken(); - TheJIT = std::make_unique(); - + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModule(); // Run the main "interpreter loop" now. diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/CMakeLists.txt b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/CMakeLists.txt deleted file mode 100644 index 48d729966364d..0000000000000 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -add_subdirectory(Server) - -set(LLVM_LINK_COMPONENTS - Analysis - Core - ExecutionEngine - InstCombine - Object - OrcError - OrcJIT - RuntimeDyld - ScalarOpts - Support - TransformUtils - native - ) - -add_kaleidoscope_chapter(BuildingAJIT-Ch5 - toy.cpp - ) - -export_executable_symbols(BuildingAJIT-Ch5) diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h deleted file mode 100644 index d22f893ac6113..0000000000000 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h +++ /dev/null @@ -1,248 +0,0 @@ -//===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Contains a simple JIT definition for use in the kaleidoscope tutorials. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H - -#include "RemoteJITUtils.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" -#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Mangler.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/InstCombine/InstCombine.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Scalar/GVN.h" -#include -#include -#include -#include -#include -#include -#include - -class PrototypeAST; -class ExprAST; - -/// FunctionAST - This class represents a function definition itself. -class FunctionAST { - std::unique_ptr Proto; - std::unique_ptr Body; - -public: - FunctionAST(std::unique_ptr Proto, - std::unique_ptr Body) - : Proto(std::move(Proto)), Body(std::move(Body)) {} - - const PrototypeAST& getProto() const; - const std::string& getName() const; - llvm::Function *codegen(); -}; - -/// This will compile FnAST to IR, rename the function to add the given -/// suffix (needed to prevent a name-clash with the function's stub), -/// and then take ownership of the module that the function was compiled -/// into. -std::unique_ptr -irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix); - -namespace llvm { -namespace orc { - -// Typedef the remote-client API. -using MyRemote = remote::OrcRemoteTargetClient; - -class KaleidoscopeJIT { -private: - ExecutionSession &ES; - std::shared_ptr Resolver; - std::unique_ptr TM; - const DataLayout DL; - LegacyRTDyldObjectLinkingLayer ObjectLayer; - LegacyIRCompileLayer CompileLayer; - - using OptimizeFunction = - std::function(std::unique_ptr)>; - - LegacyIRTransformLayer OptimizeLayer; - - JITCompileCallbackManager *CompileCallbackMgr; - std::unique_ptr IndirectStubsMgr; - MyRemote &Remote; - -public: - KaleidoscopeJIT(ExecutionSession &ES, MyRemote &Remote) - : ES(ES), - Resolver(createLegacyLookupResolver( - ES, - [this](StringRef Name) -> JITSymbol { - if (auto Sym = IndirectStubsMgr->findStub(Name, false)) - return Sym; - if (auto Sym = OptimizeLayer.findSymbol(std::string(Name), false)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - if (auto Addr = cantFail(this->Remote.getSymbolAddress(Name))) - return JITSymbol(Addr, JITSymbolFlags::Exported); - return nullptr; - }, - [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), - TM(EngineBuilder().selectTarget(Triple(Remote.getTargetTriple()), "", - "", SmallVector())), - DL(TM->createDataLayout()), - ObjectLayer(AcknowledgeORCv1Deprecation, ES, - [this](VModuleKey K) { - return LegacyRTDyldObjectLinkingLayer::Resources{ - cantFail(this->Remote.createRemoteMemoryManager()), - Resolver}; - }), - CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer, - SimpleCompiler(*TM)), - OptimizeLayer(AcknowledgeORCv1Deprecation, CompileLayer, - [this](std::unique_ptr M) { - return optimizeModule(std::move(M)); - }), - Remote(Remote) { - auto CCMgrOrErr = Remote.enableCompileCallbacks(0); - if (!CCMgrOrErr) { - logAllUnhandledErrors(CCMgrOrErr.takeError(), errs(), - "Error enabling remote compile callbacks:"); - exit(1); - } - CompileCallbackMgr = &*CCMgrOrErr; - IndirectStubsMgr = cantFail(Remote.createIndirectStubsManager()); - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); - } - - TargetMachine &getTargetMachine() { return *TM; } - - VModuleKey addModule(std::unique_ptr M) { - // Add the module with a new VModuleKey. - auto K = ES.allocateVModule(); - cantFail(OptimizeLayer.addModule(K, std::move(M))); - return K; - } - - Error addFunctionAST(std::unique_ptr FnAST) { - // Move ownership of FnAST to a shared pointer - C++11 lambdas don't support - // capture-by-move, which is be required for unique_ptr. - auto SharedFnAST = std::shared_ptr(std::move(FnAST)); - - // Set the action to compile our AST. This lambda will be run if/when - // execution hits the compile callback (via the stub). - // - // The steps to compile are: - // (1) IRGen the function. - // (2) Add the IR module to the JIT to make it executable like any other - // module. - // (3) Use findSymbol to get the address of the compiled function. - // (4) Update the stub pointer to point at the implementation so that - /// subsequent calls go directly to it and bypass the compiler. - // (5) Return the address of the implementation: this lambda will actually - // be run inside an attempted call to the function, and we need to - // continue on to the implementation to complete the attempted call. - // The JIT runtime (the resolver block) will use the return address of - // this function as the address to continue at once it has reset the - // CPU state to what it was immediately before the call. - auto CompileAction = [this, SharedFnAST]() { - auto M = irgenAndTakeOwnership(*SharedFnAST, "$impl"); - addModule(std::move(M)); - auto Sym = findSymbol(SharedFnAST->getName() + "$impl"); - assert(Sym && "Couldn't find compiled function?"); - JITTargetAddress SymAddr = cantFail(Sym.getAddress()); - if (auto Err = IndirectStubsMgr->updatePointer( - mangle(SharedFnAST->getName()), SymAddr)) { - logAllUnhandledErrors(std::move(Err), errs(), - "Error updating function pointer: "); - exit(1); - } - - return SymAddr; - }; - - // Create a CompileCallback suing the CompileAction - this is the re-entry - // point into the compiler for functions that haven't been compiled yet. - auto CCAddr = cantFail( - CompileCallbackMgr->getCompileCallback(std::move(CompileAction))); - - // Create an indirect stub. This serves as the functions "canonical - // definition" - an unchanging (constant address) entry point to the - // function implementation. - // Initially we point the stub's function-pointer at the compile callback - // that we just created. In the compile action for the callback we will - // update the stub's function pointer to point at the function - // implementation that we just implemented. - if (auto Err = IndirectStubsMgr->createStub( - mangle(SharedFnAST->getName()), CCAddr, JITSymbolFlags::Exported)) - return Err; - - return Error::success(); - } - - Error executeRemoteExpr(JITTargetAddress ExprAddr) { - return Remote.callVoidVoid(ExprAddr); - } - - JITSymbol findSymbol(const std::string Name) { - return OptimizeLayer.findSymbol(mangle(Name), true); - } - - void removeModule(VModuleKey K) { - cantFail(OptimizeLayer.removeModule(K)); - } - -private: - std::string mangle(const std::string &Name) { - std::string MangledName; - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - return MangledNameStream.str(); - } - - std::unique_ptr optimizeModule(std::unique_ptr M) { - // Create a function pass manager. - auto FPM = std::make_unique(M.get()); - - // Add some optimizations. - FPM->add(createInstructionCombiningPass()); - FPM->add(createReassociatePass()); - FPM->add(createGVNPass()); - FPM->add(createCFGSimplificationPass()); - FPM->doInitialization(); - - // Run the optimizations over all functions in the module being added to - // the JIT. - for (auto &F : *M) - FPM->run(F); - - return M; - } -}; - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h deleted file mode 100644 index c7d15bb8dd971..0000000000000 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h +++ /dev/null @@ -1,75 +0,0 @@ -//===-- RemoteJITUtils.h - Utilities for remote-JITing with LLI -*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Utilities for remote-JITing with LLI. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H -#define LLVM_TOOLS_LLI_REMOTEJITUTILS_H - -#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h" -#include "llvm/Support/Error.h" -#include -#include -#include - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#else -#include -#endif - -/// RPC channel that reads from and writes from file descriptors. -class FDRPCChannel final : public llvm::orc::rpc::RawByteChannel { -public: - FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {} - - llvm::Error readBytes(char *Dst, unsigned Size) override { - assert(Dst && "Attempt to read into null."); - ssize_t Completed = 0; - while (Completed < static_cast(Size)) { - ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); - if (Read <= 0) { - auto ErrNo = errno; - if (ErrNo == EAGAIN || ErrNo == EINTR) - continue; - else - return llvm::errorCodeToError( - std::error_code(errno, std::generic_category())); - } - Completed += Read; - } - return llvm::Error::success(); - } - - llvm::Error appendBytes(const char *Src, unsigned Size) override { - assert(Src && "Attempt to append from null."); - ssize_t Completed = 0; - while (Completed < static_cast(Size)) { - ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); - if (Written < 0) { - auto ErrNo = errno; - if (ErrNo == EAGAIN || ErrNo == EINTR) - continue; - else - return llvm::errorCodeToError( - std::error_code(errno, std::generic_category())); - } - Completed += Written; - } - return llvm::Error::success(); - } - - llvm::Error send() override { return llvm::Error::success(); } - -private: - int InFD, OutFD; -}; - -#endif // LLVM_TOOLS_LLI_REMOTEJITUTILS_H diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/CMakeLists.txt b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/CMakeLists.txt deleted file mode 100644 index c7252ae14c6a6..0000000000000 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Analysis - Core - ExecutionEngine - InstCombine - Object - OrcError - OrcJIT - RuntimeDyld - ScalarOpts - Support - TransformUtils - native - ) - -add_kaleidoscope_chapter(BuildingAJIT-Ch5-Server - server.cpp - ) - -export_executable_symbols(BuildingAJIT-Ch5-Server) diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp deleted file mode 100644 index e50a7ecf96bcd..0000000000000 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "../RemoteJITUtils.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h" -#include "llvm/ExecutionEngine/Orc/OrcABISupport.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/TargetSelect.h" -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::orc; - -// Command line argument for TCP port. -cl::opt Port("port", - cl::desc("TCP port to listen on"), - cl::init(20000)); - -ExitOnError ExitOnErr; - -using MainFun = int (*)(int, const char*[]); - -template -NativePtrT MakeNative(uint64_t P) { - return reinterpret_cast(static_cast(P)); -} - -extern "C" -void printExprResult(double Val) { - printf("Expression evaluated to: %f\n", Val); -} - -// --- LAZY COMPILE TEST --- -int main(int argc, char* argv[]) { - if (argc == 0) - ExitOnErr.setBanner("jit_server: "); - else - ExitOnErr.setBanner(std::string(argv[0]) + ": "); - - // --- Initialize LLVM --- - cl::ParseCommandLineOptions(argc, argv, "LLVM lazy JIT example.\n"); - - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { - errs() << "Error loading program symbols.\n"; - return 1; - } - - // --- Initialize remote connection --- - - int sockfd = socket(PF_INET, SOCK_STREAM, 0); - sockaddr_in servAddr, clientAddr; - socklen_t clientAddrLen = sizeof(clientAddr); - memset(&servAddr, 0, sizeof(servAddr)); - servAddr.sin_family = PF_INET; - servAddr.sin_family = INADDR_ANY; - servAddr.sin_port = htons(Port); - - { - // avoid "Address already in use" error. - int yes = 1; - if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { - errs() << "Error calling setsockopt.\n"; - return 1; - } - } - - if (bind(sockfd, reinterpret_cast(&servAddr), - sizeof(servAddr)) < 0) { - errs() << "Error on binding.\n"; - return 1; - } - listen(sockfd, 1); - int newsockfd = accept(sockfd, reinterpret_cast(&clientAddr), - &clientAddrLen); - - auto SymbolLookup = - [](const std::string &Name) { - return RTDyldMemoryManager::getSymbolAddressInProcess(Name); - }; - - auto RegisterEHFrames = - [](uint8_t *Addr, uint32_t Size) { - RTDyldMemoryManager::registerEHFramesInProcess(Addr, Size); - }; - - auto DeregisterEHFrames = - [](uint8_t *Addr, uint32_t Size) { - RTDyldMemoryManager::deregisterEHFramesInProcess(Addr, Size); - }; - - FDRPCChannel TCPChannel(newsockfd, newsockfd); - - using MyServerT = remote::OrcRemoteTargetServer; - - MyServerT Server(TCPChannel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames); - - while (!Server.receivedTerminate()) - ExitOnErr(Server.handleOne()); - - return 0; -} diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp deleted file mode 100644 index b9819327f8430..0000000000000 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Target/TargetMachine.h" -#include "KaleidoscopeJIT.h" -#include "RemoteJITUtils.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::orc; - -// Command line argument for TCP hostname. -cl::opt HostName("hostname", - cl::desc("TCP hostname to connect to"), - cl::init("localhost")); - -// Command line argument for TCP port. -cl::opt Port("port", - cl::desc("TCP port to connect to"), - cl::init(20000)); - -//===----------------------------------------------------------------------===// -// Lexer -//===----------------------------------------------------------------------===// - -// The lexer returns tokens [0-255] if it is an unknown character, otherwise one -// of these for known things. -enum Token { - tok_eof = -1, - - // commands - tok_def = -2, - tok_extern = -3, - - // primary - tok_identifier = -4, - tok_number = -5, - - // control - tok_if = -6, - tok_then = -7, - tok_else = -8, - tok_for = -9, - tok_in = -10, - - // operators - tok_binary = -11, - tok_unary = -12, - - // var definition - tok_var = -13 -}; - -static std::string IdentifierStr; // Filled in if tok_identifier -static double NumVal; // Filled in if tok_number - -/// gettok - Return the next token from standard input. -static int gettok() { - static int LastChar = ' '; - - // Skip any whitespace. - while (isspace(LastChar)) - LastChar = getchar(); - - if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* - IdentifierStr = LastChar; - while (isalnum((LastChar = getchar()))) - IdentifierStr += LastChar; - - if (IdentifierStr == "def") - return tok_def; - if (IdentifierStr == "extern") - return tok_extern; - if (IdentifierStr == "if") - return tok_if; - if (IdentifierStr == "then") - return tok_then; - if (IdentifierStr == "else") - return tok_else; - if (IdentifierStr == "for") - return tok_for; - if (IdentifierStr == "in") - return tok_in; - if (IdentifierStr == "binary") - return tok_binary; - if (IdentifierStr == "unary") - return tok_unary; - if (IdentifierStr == "var") - return tok_var; - return tok_identifier; - } - - if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ - std::string NumStr; - do { - NumStr += LastChar; - LastChar = getchar(); - } while (isdigit(LastChar) || LastChar == '.'); - - NumVal = strtod(NumStr.c_str(), nullptr); - return tok_number; - } - - if (LastChar == '#') { - // Comment until end of line. - do - LastChar = getchar(); - while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); - - if (LastChar != EOF) - return gettok(); - } - - // Check for end of file. Don't eat the EOF. - if (LastChar == EOF) - return tok_eof; - - // Otherwise, just return the character as its ascii value. - int ThisChar = LastChar; - LastChar = getchar(); - return ThisChar; -} - -//===----------------------------------------------------------------------===// -// Abstract Syntax Tree (aka Parse Tree) -//===----------------------------------------------------------------------===// - -/// ExprAST - Base class for all expression nodes. -class ExprAST { -public: - virtual ~ExprAST() = default; - - virtual Value *codegen() = 0; -}; - -/// NumberExprAST - Expression class for numeric literals like "1.0". -class NumberExprAST : public ExprAST { - double Val; - -public: - NumberExprAST(double Val) : Val(Val) {} - - Value *codegen() override; -}; - -/// VariableExprAST - Expression class for referencing a variable, like "a". -class VariableExprAST : public ExprAST { - std::string Name; - -public: - VariableExprAST(const std::string &Name) : Name(Name) {} - - Value *codegen() override; - const std::string &getName() const { return Name; } -}; - -/// UnaryExprAST - Expression class for a unary operator. -class UnaryExprAST : public ExprAST { - char Opcode; - std::unique_ptr Operand; - -public: - UnaryExprAST(char Opcode, std::unique_ptr Operand) - : Opcode(Opcode), Operand(std::move(Operand)) {} - - Value *codegen() override; -}; - -/// BinaryExprAST - Expression class for a binary operator. -class BinaryExprAST : public ExprAST { - char Op; - std::unique_ptr LHS, RHS; - -public: - BinaryExprAST(char Op, std::unique_ptr LHS, - std::unique_ptr RHS) - : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} - - Value *codegen() override; -}; - -/// CallExprAST - Expression class for function calls. -class CallExprAST : public ExprAST { - std::string Callee; - std::vector> Args; - -public: - CallExprAST(const std::string &Callee, - std::vector> Args) - : Callee(Callee), Args(std::move(Args)) {} - - Value *codegen() override; -}; - -/// IfExprAST - Expression class for if/then/else. -class IfExprAST : public ExprAST { - std::unique_ptr Cond, Then, Else; - -public: - IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, - std::unique_ptr Else) - : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} - - Value *codegen() override; -}; - -/// ForExprAST - Expression class for for/in. -class ForExprAST : public ExprAST { - std::string VarName; - std::unique_ptr Start, End, Step, Body; - -public: - ForExprAST(const std::string &VarName, std::unique_ptr Start, - std::unique_ptr End, std::unique_ptr Step, - std::unique_ptr Body) - : VarName(VarName), Start(std::move(Start)), End(std::move(End)), - Step(std::move(Step)), Body(std::move(Body)) {} - - Value *codegen() override; -}; - -/// VarExprAST - Expression class for var/in -class VarExprAST : public ExprAST { - std::vector>> VarNames; - std::unique_ptr Body; - -public: - VarExprAST( - std::vector>> VarNames, - std::unique_ptr Body) - : VarNames(std::move(VarNames)), Body(std::move(Body)) {} - - Value *codegen() override; -}; - -/// PrototypeAST - This class represents the "prototype" for a function, -/// which captures its name, and its argument names (thus implicitly the number -/// of arguments the function takes), as well as if it is an operator. -class PrototypeAST { - std::string Name; - std::vector Args; - bool IsOperator; - unsigned Precedence; // Precedence if a binary op. - -public: - PrototypeAST(const std::string &Name, std::vector Args, - bool IsOperator = false, unsigned Prec = 0) - : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), - Precedence(Prec) {} - - Function *codegen(); - const std::string &getName() const { return Name; } - - bool isUnaryOp() const { return IsOperator && Args.size() == 1; } - bool isBinaryOp() const { return IsOperator && Args.size() == 2; } - - char getOperatorName() const { - assert(isUnaryOp() || isBinaryOp()); - return Name[Name.size() - 1]; - } - - unsigned getBinaryPrecedence() const { return Precedence; } -}; - -//===----------------------------------------------------------------------===// -// Parser -//===----------------------------------------------------------------------===// - -/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current -/// token the parser is looking at. getNextToken reads another token from the -/// lexer and updates CurTok with its results. -static int CurTok; -static int getNextToken() { return CurTok = gettok(); } - -/// BinopPrecedence - This holds the precedence for each binary operator that is -/// defined. -static std::map BinopPrecedence; - -/// GetTokPrecedence - Get the precedence of the pending binary operator token. -static int GetTokPrecedence() { - if (!isascii(CurTok)) - return -1; - - // Make sure it's a declared binop. - int TokPrec = BinopPrecedence[CurTok]; - if (TokPrec <= 0) - return -1; - return TokPrec; -} - -/// LogError* - These are little helper functions for error handling. -std::unique_ptr LogError(const char *Str) { - fprintf(stderr, "Error: %s\n", Str); - return nullptr; -} - -std::unique_ptr LogErrorP(const char *Str) { - LogError(Str); - return nullptr; -} - -static std::unique_ptr ParseExpression(); - -/// numberexpr ::= number -static std::unique_ptr ParseNumberExpr() { - auto Result = std::make_unique(NumVal); - getNextToken(); // consume the number - return std::move(Result); -} - -/// parenexpr ::= '(' expression ')' -static std::unique_ptr ParseParenExpr() { - getNextToken(); // eat (. - auto V = ParseExpression(); - if (!V) - return nullptr; - - if (CurTok != ')') - return LogError("expected ')'"); - getNextToken(); // eat ). - return V; -} - -/// identifierexpr -/// ::= identifier -/// ::= identifier '(' expression* ')' -static std::unique_ptr ParseIdentifierExpr() { - std::string IdName = IdentifierStr; - - getNextToken(); // eat identifier. - - if (CurTok != '(') // Simple variable ref. - return std::make_unique(IdName); - - // Call. - getNextToken(); // eat ( - std::vector> Args; - if (CurTok != ')') { - while (true) { - if (auto Arg = ParseExpression()) - Args.push_back(std::move(Arg)); - else - return nullptr; - - if (CurTok == ')') - break; - - if (CurTok != ',') - return LogError("Expected ')' or ',' in argument list"); - getNextToken(); - } - } - - // Eat the ')'. - getNextToken(); - - return std::make_unique(IdName, std::move(Args)); -} - -/// ifexpr ::= 'if' expression 'then' expression 'else' expression -static std::unique_ptr ParseIfExpr() { - getNextToken(); // eat the if. - - // condition. - auto Cond = ParseExpression(); - if (!Cond) - return nullptr; - - if (CurTok != tok_then) - return LogError("expected then"); - getNextToken(); // eat the then - - auto Then = ParseExpression(); - if (!Then) - return nullptr; - - if (CurTok != tok_else) - return LogError("expected else"); - - getNextToken(); - - auto Else = ParseExpression(); - if (!Else) - return nullptr; - - return std::make_unique(std::move(Cond), std::move(Then), - std::move(Else)); -} - -/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression -static std::unique_ptr ParseForExpr() { - getNextToken(); // eat the for. - - if (CurTok != tok_identifier) - return LogError("expected identifier after for"); - - std::string IdName = IdentifierStr; - getNextToken(); // eat identifier. - - if (CurTok != '=') - return LogError("expected '=' after for"); - getNextToken(); // eat '='. - - auto Start = ParseExpression(); - if (!Start) - return nullptr; - if (CurTok != ',') - return LogError("expected ',' after for start value"); - getNextToken(); - - auto End = ParseExpression(); - if (!End) - return nullptr; - - // The step value is optional. - std::unique_ptr Step; - if (CurTok == ',') { - getNextToken(); - Step = ParseExpression(); - if (!Step) - return nullptr; - } - - if (CurTok != tok_in) - return LogError("expected 'in' after for"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (!Body) - return nullptr; - - return std::make_unique(IdName, std::move(Start), std::move(End), - std::move(Step), std::move(Body)); -} - -/// varexpr ::= 'var' identifier ('=' expression)? -// (',' identifier ('=' expression)?)* 'in' expression -static std::unique_ptr ParseVarExpr() { - getNextToken(); // eat the var. - - std::vector>> VarNames; - - // At least one variable name is required. - if (CurTok != tok_identifier) - return LogError("expected identifier after var"); - - while (true) { - std::string Name = IdentifierStr; - getNextToken(); // eat identifier. - - // Read the optional initializer. - std::unique_ptr Init = nullptr; - if (CurTok == '=') { - getNextToken(); // eat the '='. - - Init = ParseExpression(); - if (!Init) - return nullptr; - } - - VarNames.push_back(std::make_pair(Name, std::move(Init))); - - // End of var list, exit loop. - if (CurTok != ',') - break; - getNextToken(); // eat the ','. - - if (CurTok != tok_identifier) - return LogError("expected identifier list after var"); - } - - // At this point, we have to have 'in'. - if (CurTok != tok_in) - return LogError("expected 'in' keyword after 'var'"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (!Body) - return nullptr; - - return std::make_unique(std::move(VarNames), std::move(Body)); -} - -/// primary -/// ::= identifierexpr -/// ::= numberexpr -/// ::= parenexpr -/// ::= ifexpr -/// ::= forexpr -/// ::= varexpr -static std::unique_ptr ParsePrimary() { - switch (CurTok) { - default: - return LogError("unknown token when expecting an expression"); - case tok_identifier: - return ParseIdentifierExpr(); - case tok_number: - return ParseNumberExpr(); - case '(': - return ParseParenExpr(); - case tok_if: - return ParseIfExpr(); - case tok_for: - return ParseForExpr(); - case tok_var: - return ParseVarExpr(); - } -} - -/// unary -/// ::= primary -/// ::= '!' unary -static std::unique_ptr ParseUnary() { - // If the current token is not an operator, it must be a primary expr. - if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') - return ParsePrimary(); - - // If this is a unary operator, read it. - int Opc = CurTok; - getNextToken(); - if (auto Operand = ParseUnary()) - return std::make_unique(Opc, std::move(Operand)); - return nullptr; -} - -/// binoprhs -/// ::= ('+' unary)* -static std::unique_ptr ParseBinOpRHS(int ExprPrec, - std::unique_ptr LHS) { - // If this is a binop, find its precedence. - while (true) { - int TokPrec = GetTokPrecedence(); - - // If this is a binop that binds at least as tightly as the current binop, - // consume it, otherwise we are done. - if (TokPrec < ExprPrec) - return LHS; - - // Okay, we know this is a binop. - int BinOp = CurTok; - getNextToken(); // eat binop - - // Parse the unary expression after the binary operator. - auto RHS = ParseUnary(); - if (!RHS) - return nullptr; - - // If BinOp binds less tightly with RHS than the operator after RHS, let - // the pending operator take RHS as its LHS. - int NextPrec = GetTokPrecedence(); - if (TokPrec < NextPrec) { - RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); - if (!RHS) - return nullptr; - } - - // Merge LHS/RHS. - LHS = - std::make_unique(BinOp, std::move(LHS), std::move(RHS)); - } -} - -/// expression -/// ::= unary binoprhs -/// -static std::unique_ptr ParseExpression() { - auto LHS = ParseUnary(); - if (!LHS) - return nullptr; - - return ParseBinOpRHS(0, std::move(LHS)); -} - -/// prototype -/// ::= id '(' id* ')' -/// ::= binary LETTER number? (id, id) -/// ::= unary LETTER (id) -static std::unique_ptr ParsePrototype() { - std::string FnName; - - unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. - unsigned BinaryPrecedence = 30; - - switch (CurTok) { - default: - return LogErrorP("Expected function name in prototype"); - case tok_identifier: - FnName = IdentifierStr; - Kind = 0; - getNextToken(); - break; - case tok_unary: - getNextToken(); - if (!isascii(CurTok)) - return LogErrorP("Expected unary operator"); - FnName = "unary"; - FnName += (char)CurTok; - Kind = 1; - getNextToken(); - break; - case tok_binary: - getNextToken(); - if (!isascii(CurTok)) - return LogErrorP("Expected binary operator"); - FnName = "binary"; - FnName += (char)CurTok; - Kind = 2; - getNextToken(); - - // Read the precedence if present. - if (CurTok == tok_number) { - if (NumVal < 1 || NumVal > 100) - return LogErrorP("Invalid precedecnce: must be 1..100"); - BinaryPrecedence = (unsigned)NumVal; - getNextToken(); - } - break; - } - - if (CurTok != '(') - return LogErrorP("Expected '(' in prototype"); - - std::vector ArgNames; - while (getNextToken() == tok_identifier) - ArgNames.push_back(IdentifierStr); - if (CurTok != ')') - return LogErrorP("Expected ')' in prototype"); - - // success. - getNextToken(); // eat ')'. - - // Verify right number of names for operator. - if (Kind && ArgNames.size() != Kind) - return LogErrorP("Invalid number of operands for operator"); - - return std::make_unique(FnName, ArgNames, Kind != 0, - BinaryPrecedence); -} - -/// definition ::= 'def' prototype expression -static std::unique_ptr ParseDefinition() { - getNextToken(); // eat def. - auto Proto = ParsePrototype(); - if (!Proto) - return nullptr; - - if (auto E = ParseExpression()) - return std::make_unique(std::move(Proto), std::move(E)); - return nullptr; -} - -/// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr() { - if (auto E = ParseExpression()) { - - auto PEArgs = std::vector>(); - PEArgs.push_back(std::move(E)); - auto PrintExpr = - std::make_unique("printExprResult", std::move(PEArgs)); - - // Make an anonymous proto. - auto Proto = std::make_unique("__anon_expr", - std::vector()); - return std::make_unique(std::move(Proto), - std::move(PrintExpr)); - } - return nullptr; -} - -/// external ::= 'extern' prototype -static std::unique_ptr ParseExtern() { - getNextToken(); // eat extern. - return ParsePrototype(); -} - -//===----------------------------------------------------------------------===// -// Code Generation -//===----------------------------------------------------------------------===// - -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); -static std::unique_ptr TheModule; -static std::map NamedValues; -static std::unique_ptr TheJIT; -static std::map> FunctionProtos; -static ExitOnError ExitOnErr; - -Value *LogErrorV(const char *Str) { - LogError(Str); - return nullptr; -} - -Function *getFunction(std::string Name) { - // First, see if the function has already been added to the current module. - if (auto *F = TheModule->getFunction(Name)) - return F; - - // If not, check whether we can codegen the declaration from some existing - // prototype. - auto FI = FunctionProtos.find(Name); - if (FI != FunctionProtos.end()) - return FI->second->codegen(); - - // If no existing prototype exists, return null. - return nullptr; -} - -/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of -/// the function. This is used for mutable variables etc. -static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, - StringRef VarName) { - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), - TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); -} - -Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); -} - -Value *VariableExprAST::codegen() { - // Look this variable up in the function. - Value *V = NamedValues[Name]; - if (!V) - return LogErrorV("Unknown variable name"); - - // Load the value. - return Builder.CreateLoad(V, Name.c_str()); -} - -Value *UnaryExprAST::codegen() { - Value *OperandV = Operand->codegen(); - if (!OperandV) - return nullptr; - - Function *F = getFunction(std::string("unary") + Opcode); - if (!F) - return LogErrorV("Unknown unary operator"); - - return Builder.CreateCall(F, OperandV, "unop"); -} - -Value *BinaryExprAST::codegen() { - // Special case '=' because we don't want to emit the LHS as an expression. - if (Op == '=') { - // Assignment requires the LHS to be an identifier. - // This assume we're building without RTTI because LLVM builds that way by - // default. If you build LLVM with RTTI this can be changed to a - // dynamic_cast for automatic error checking. - VariableExprAST *LHSE = static_cast(LHS.get()); - if (!LHSE) - return LogErrorV("destination of '=' must be a variable"); - // Codegen the RHS. - Value *Val = RHS->codegen(); - if (!Val) - return nullptr; - - // Look up the name. - Value *Variable = NamedValues[LHSE->getName()]; - if (!Variable) - return LogErrorV("Unknown variable name"); - - Builder.CreateStore(Val, Variable); - return Val; - } - - Value *L = LHS->codegen(); - Value *R = RHS->codegen(); - if (!L || !R) - return nullptr; - - switch (Op) { - case '+': - return Builder.CreateFAdd(L, R, "addtmp"); - case '-': - return Builder.CreateFSub(L, R, "subtmp"); - case '*': - return Builder.CreateFMul(L, R, "multmp"); - case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); - // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); - default: - break; - } - - // If it wasn't a builtin binary operator, it must be a user defined one. Emit - // a call to it. - Function *F = getFunction(std::string("binary") + Op); - assert(F && "binary operator not found!"); - - Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); -} - -Value *CallExprAST::codegen() { - // Look up the name in the global module table. - Function *CalleeF = getFunction(Callee); - if (!CalleeF) - return LogErrorV("Unknown function referenced"); - - // If argument mismatch error. - if (CalleeF->arg_size() != Args.size()) - return LogErrorV("Incorrect # arguments passed"); - - std::vector ArgsV; - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - ArgsV.push_back(Args[i]->codegen()); - if (!ArgsV.back()) - return nullptr; - } - - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); -} - -Value *IfExprAST::codegen() { - Value *CondV = Cond->codegen(); - if (!CondV) - return nullptr; - - // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); - - Function *TheFunction = Builder.GetInsertBlock()->getParent(); - - // Create blocks for the then and else cases. Insert the 'then' block at the - // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); - - Builder.CreateCondBr(CondV, ThenBB, ElseBB); - - // Emit then value. - Builder.SetInsertPoint(ThenBB); - - Value *ThenV = Then->codegen(); - if (!ThenV) - return nullptr; - - Builder.CreateBr(MergeBB); - // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); - - // Emit else block. - TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); - - Value *ElseV = Else->codegen(); - if (!ElseV) - return nullptr; - - Builder.CreateBr(MergeBB); - // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); - - // Emit merge block. - TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); - - PN->addIncoming(ThenV, ThenBB); - PN->addIncoming(ElseV, ElseBB); - return PN; -} - -// Output for-loop as: -// var = alloca double -// ... -// start = startexpr -// store start -> var -// goto loop -// loop: -// ... -// bodyexpr -// ... -// loopend: -// step = stepexpr -// endcond = endexpr -// -// curvar = load var -// nextvar = curvar + step -// store nextvar -> var -// br endcond, loop, endloop -// outloop: -Value *ForExprAST::codegen() { - Function *TheFunction = Builder.GetInsertBlock()->getParent(); - - // Create an alloca for the variable in the entry block. - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - - // Emit the start code first, without 'variable' in scope. - Value *StartVal = Start->codegen(); - if (!StartVal) - return nullptr; - - // Store the value into the alloca. - Builder.CreateStore(StartVal, Alloca); - - // Make the new basic block for the loop header, inserting after current - // block. - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); - - // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); - - // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); - - // Within the loop, the variable is defined equal to the PHI node. If it - // shadows an existing variable, we have to restore it, so save it now. - AllocaInst *OldVal = NamedValues[VarName]; - NamedValues[VarName] = Alloca; - - // Emit the body of the loop. This, like any other expr, can change the - // current BB. Note that we ignore the value computed by the body, but don't - // allow an error. - if (!Body->codegen()) - return nullptr; - - // Emit the step value. - Value *StepVal = nullptr; - if (Step) { - StepVal = Step->codegen(); - if (!StepVal) - return nullptr; - } else { - // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); - } - - // Compute the end condition. - Value *EndCond = End->codegen(); - if (!EndCond) - return nullptr; - - // Reload, increment, and restore the alloca. This handles the case where - // the body of the loop mutates the variable. - Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); - Builder.CreateStore(NextVar, Alloca); - - // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); - - // Create the "after loop" block and insert it. - BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); - - // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); - - // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); - - // Restore the unshadowed variable. - if (OldVal) - NamedValues[VarName] = OldVal; - else - NamedValues.erase(VarName); - - // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); -} - -Value *VarExprAST::codegen() { - std::vector OldBindings; - - Function *TheFunction = Builder.GetInsertBlock()->getParent(); - - // Register all variables and emit their initializer. - for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { - const std::string &VarName = VarNames[i].first; - ExprAST *Init = VarNames[i].second.get(); - - // Emit the initializer before adding the variable to scope, this prevents - // the initializer from referencing the variable itself, and permits stuff - // like this: - // var a = 1 in - // var a = a in ... # refers to outer 'a'. - Value *InitVal; - if (Init) { - InitVal = Init->codegen(); - if (!InitVal) - return nullptr; - } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(TheContext, APFloat(0.0)); - } - - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - Builder.CreateStore(InitVal, Alloca); - - // Remember the old variable binding so that we can restore the binding when - // we unrecurse. - OldBindings.push_back(NamedValues[VarName]); - - // Remember this binding. - NamedValues[VarName] = Alloca; - } - - // Codegen the body, now that all vars are in scope. - Value *BodyVal = Body->codegen(); - if (!BodyVal) - return nullptr; - - // Pop all our variables from scope. - for (unsigned i = 0, e = VarNames.size(); i != e; ++i) - NamedValues[VarNames[i].first] = OldBindings[i]; - - // Return the body computation. - return BodyVal; -} - -Function *PrototypeAST::codegen() { - // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); - FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); - - Function *F = - Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); - - // Set names for all arguments. - unsigned Idx = 0; - for (auto &Arg : F->args()) - Arg.setName(Args[Idx++]); - - return F; -} - -const PrototypeAST& FunctionAST::getProto() const { - return *Proto; -} - -const std::string& FunctionAST::getName() const { - return Proto->getName(); -} - -Function *FunctionAST::codegen() { - // Transfer ownership of the prototype to the FunctionProtos map, but keep a - // reference to it for use below. - auto &P = *Proto; - Function *TheFunction = getFunction(P.getName()); - if (!TheFunction) - return nullptr; - - // If this is an operator, install it. - if (P.isBinaryOp()) - BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); - - // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); - - // Record the function arguments in the NamedValues map. - NamedValues.clear(); - for (auto &Arg : TheFunction->args()) { - // Create an alloca for this variable. - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); - - // Store the initial value into the alloca. - Builder.CreateStore(&Arg, Alloca); - - // Add arguments to variable symbol table. - NamedValues[std::string(Arg.getName())] = Alloca; - } - - if (Value *RetVal = Body->codegen()) { - // Finish off the function. - Builder.CreateRet(RetVal); - - // Validate the generated code, checking for consistency. - verifyFunction(*TheFunction); - - return TheFunction; - } - - // Error reading body, remove function. - TheFunction->eraseFromParent(); - - if (P.isBinaryOp()) - BinopPrecedence.erase(Proto->getOperatorName()); - return nullptr; -} - -//===----------------------------------------------------------------------===// -// Top-Level parsing and JIT Driver -//===----------------------------------------------------------------------===// - -static void InitializeModule() { - // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); -} - -std::unique_ptr -irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix) { - if (auto *F = FnAST.codegen()) { - F->setName(F->getName() + Suffix); - auto M = std::move(TheModule); - // Start a new module. - InitializeModule(); - return M; - } else - report_fatal_error("Couldn't compile lazily JIT'd function"); -} - -static void HandleDefinition() { - if (auto FnAST = ParseDefinition()) { - FunctionProtos[FnAST->getProto().getName()] = - std::make_unique(FnAST->getProto()); - ExitOnErr(TheJIT->addFunctionAST(std::move(FnAST))); - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleExtern() { - if (auto ProtoAST = ParseExtern()) { - if (auto *FnIR = ProtoAST->codegen()) { - fprintf(stderr, "Read extern: "); - FnIR->print(errs()); - fprintf(stderr, "\n"); - FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleTopLevelExpression() { - // Evaluate a top-level expression into an anonymous function. - if (auto FnAST = ParseTopLevelExpr()) { - FunctionProtos[FnAST->getName()] = - std::make_unique(FnAST->getProto()); - if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); - InitializeModule(); - - // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); - - // Get the symbol's address and cast it to the right type (takes no - // arguments, returns a double) so we can call it as a native function. - ExitOnErr(TheJIT->executeRemoteExpr(cantFail(ExprSymbol.getAddress()))); - - // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -/// top ::= definition | external | expression | ';' -static void MainLoop() { - while (true) { - fprintf(stderr, "ready> "); - switch (CurTok) { - case tok_eof: - return; - case ';': // ignore top-level semicolons. - getNextToken(); - break; - case tok_def: - HandleDefinition(); - break; - case tok_extern: - HandleExtern(); - break; - default: - HandleTopLevelExpression(); - break; - } - } -} - -//===----------------------------------------------------------------------===// -// "Library" functions that can be "extern'd" from user code. -//===----------------------------------------------------------------------===// - -/// putchard - putchar that takes a double and returns 0. -extern "C" double putchard(double X) { - fputc((char)X, stderr); - return 0; -} - -/// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" double printd(double X) { - fprintf(stderr, "%f\n", X); - return 0; -} - -//===----------------------------------------------------------------------===// -// TCP / Connection setup code. -//===----------------------------------------------------------------------===// - -std::unique_ptr connect() { - int sockfd = socket(PF_INET, SOCK_STREAM, 0); - hostent *server = gethostbyname(HostName.c_str()); - - if (!server) { - errs() << "Could not find host " << HostName << "\n"; - exit(1); - } - - sockaddr_in servAddr; - memset(&servAddr, 0, sizeof(servAddr)); - servAddr.sin_family = PF_INET; - char *src; - memcpy(&src, &server->h_addr, sizeof(char *)); - memcpy(&servAddr.sin_addr.s_addr, src, server->h_length); - servAddr.sin_port = htons(Port); - if (connect(sockfd, reinterpret_cast(&servAddr), - sizeof(servAddr)) < 0) { - errs() << "Failure to connect.\n"; - exit(1); - } - - return std::make_unique(sockfd, sockfd); -} - -//===----------------------------------------------------------------------===// -// Main driver code. -//===----------------------------------------------------------------------===// - -int main(int argc, char *argv[]) { - // Parse the command line options. - cl::ParseCommandLineOptions(argc, argv, "Building A JIT - Client.\n"); - - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - ExitOnErr.setBanner("Kaleidoscope: "); - - // Install standard binary operators. - // 1 is lowest precedence. - BinopPrecedence['='] = 2; - BinopPrecedence['<'] = 10; - BinopPrecedence['+'] = 20; - BinopPrecedence['-'] = 20; - BinopPrecedence['*'] = 40; // highest. - - ExecutionSession ES; - auto TCPChannel = connect(); - auto Remote = ExitOnErr(MyRemote::Create(*TCPChannel, ES)); - TheJIT = std::make_unique(ES, *Remote); - - // Automatically inject a definition for 'printExprResult'. - FunctionProtos["printExprResult"] = - std::make_unique("printExprResult", - std::vector({"Val"})); - - // Prime the first token. - fprintf(stderr, "ready> "); - getNextToken(); - - InitializeModule(); - - // Run the main "interpreter loop" now. - MainLoop(); - - // Delete the JIT before the Remote and Channel go out of scope, otherwise - // we'll crash in the JIT destructor when it tries to release remote - // resources over a channel that no longer exists. - TheJIT = nullptr; - - // Send a terminate message to the remote to tell it to exit cleanly. - ExitOnErr(Remote->terminateSession()); - - return 0; -} diff --git a/llvm/examples/Kaleidoscope/Chapter3/toy.cpp b/llvm/examples/Kaleidoscope/Chapter3/toy.cpp index 557780df7b379..61adfbc6af3b1 100644 --- a/llvm/examples/Kaleidoscope/Chapter3/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter3/toy.cpp @@ -399,9 +399,9 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheContext; static std::unique_ptr TheModule; +static std::unique_ptr> Builder; static std::map NamedValues; Value *LogErrorV(const char *Str) { @@ -410,7 +410,7 @@ Value *LogErrorV(const char *Str) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -429,15 +429,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); } @@ -460,14 +460,14 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -491,8 +491,8 @@ Function *FunctionAST::codegen() { return nullptr; // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -501,7 +501,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -518,12 +518,24 @@ Function *FunctionAST::codegen() { // Top-Level parsing and JIT Driver //===----------------------------------------------------------------------===// +static void InitializeModule() { + // Open a new context and module. + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); +} + static void HandleDefinition() { if (auto FnAST = ParseDefinition()) { if (auto *FnIR = FnAST->codegen()) { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); + + // Reset the module. + InitializeModule(); } } else { // Skip token for error recovery. @@ -551,6 +563,9 @@ static void HandleTopLevelExpression() { fprintf(stderr, "Read top-level expression:"); FnIR->print(errs()); fprintf(stderr, "\n"); + + // Reset the module. + InitializeModule(); } } else { // Skip token for error recovery. @@ -598,7 +613,7 @@ int main() { getNextToken(); // Make the module, which holds all the code. - TheModule = std::make_unique("my cool jit", TheContext); + InitializeModule(); // Run the main "interpreter loop" now. MainLoop(); diff --git a/llvm/examples/Kaleidoscope/Chapter4/toy.cpp b/llvm/examples/Kaleidoscope/Chapter4/toy.cpp index f9321f8ea98a9..20aec1a352016 100644 --- a/llvm/examples/Kaleidoscope/Chapter4/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter4/toy.cpp @@ -409,13 +409,14 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheContext; static std::unique_ptr TheModule; +static std::unique_ptr> Builder; static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; static std::map> FunctionProtos; +static ExitOnError ExitOnErr; Value *LogErrorV(const char *Str) { LogError(Str); @@ -438,7 +439,7 @@ Function *getFunction(std::string Name) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -457,15 +458,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); } @@ -488,14 +489,14 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -518,8 +519,8 @@ Function *FunctionAST::codegen() { return nullptr; // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -528,7 +529,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -549,9 +550,13 @@ Function *FunctionAST::codegen() { //===----------------------------------------------------------------------===// static void InitializeModuleAndPassManager() { - // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + // Open a new context and module. + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); // Create a new pass manager attached to it. TheFPM = std::make_unique(TheModule.get()); @@ -574,7 +579,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - TheJIT->addModule(std::move(TheModule)); + ExitOnErr(TheJIT->addModule( + ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); InitializeModuleAndPassManager(); } } else { @@ -601,22 +607,24 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModuleAndPassManager(); // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); + auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); // Get the symbol's address and cast it to the right type (takes no // arguments, returns a double) so we can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); fprintf(stderr, "Evaluated to %f\n", FP()); // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -689,7 +697,7 @@ int main() { fprintf(stderr, "ready> "); getNextToken(); - TheJIT = std::make_unique(); + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModuleAndPassManager(); diff --git a/llvm/examples/Kaleidoscope/Chapter5/toy.cpp b/llvm/examples/Kaleidoscope/Chapter5/toy.cpp index 22bec97b312a5..0790407b73b6e 100644 --- a/llvm/examples/Kaleidoscope/Chapter5/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter5/toy.cpp @@ -536,13 +536,14 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheContext; static std::unique_ptr TheModule; +static std::unique_ptr> Builder; static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; static std::map> FunctionProtos; +static ExitOnError ExitOnErr; Value *LogErrorV(const char *Str) { LogError(Str); @@ -565,7 +566,7 @@ Function *getFunction(std::string Name) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -584,15 +585,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); } @@ -615,7 +616,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -624,46 +625,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -693,19 +694,19 @@ Value *ForExprAST::codegen() { // Make the new basic block for the loop header, inserting after current // block. - Function *TheFunction = Builder.GetInsertBlock()->getParent(); - BasicBlock *PreheaderBB = Builder.GetInsertBlock(); - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + BasicBlock *PreheaderBB = Builder->GetInsertBlock(); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. PHINode *Variable = - Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName); + Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, VarName); Variable->addIncoming(StartVal, PreheaderBB); // Within the loop, the variable is defined equal to the PHI node. If it @@ -727,10 +728,10 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } - Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); + Value *NextVar = Builder->CreateFAdd(Variable, StepVal, "nextvar"); // Compute the end condition. Value *EndCond = End->codegen(); @@ -738,19 +739,19 @@ Value *ForExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. - BasicBlock *LoopEndBB = Builder.GetInsertBlock(); + BasicBlock *LoopEndBB = Builder->GetInsertBlock(); BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Add a new entry to the PHI node for the backedge. Variable->addIncoming(NextVar, LoopEndBB); @@ -762,14 +763,14 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -792,8 +793,8 @@ Function *FunctionAST::codegen() { return nullptr; // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -802,7 +803,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -824,8 +825,12 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); // Create a new pass manager attached to it. TheFPM = std::make_unique(TheModule.get()); @@ -848,7 +853,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - TheJIT->addModule(std::move(TheModule)); + ExitOnErr(TheJIT->addModule( + ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); InitializeModuleAndPassManager(); } } else { @@ -875,22 +881,24 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModuleAndPassManager(); // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); + auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); // Get the symbol's address and cast it to the right type (takes no // arguments, returns a double) so we can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); fprintf(stderr, "Evaluated to %f\n", FP()); // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -963,7 +971,7 @@ int main() { fprintf(stderr, "ready> "); getNextToken(); - TheJIT = std::make_unique(); + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModuleAndPassManager(); diff --git a/llvm/examples/Kaleidoscope/Chapter6/toy.cpp b/llvm/examples/Kaleidoscope/Chapter6/toy.cpp index 2a7dedc510aca..2538221538aca 100644 --- a/llvm/examples/Kaleidoscope/Chapter6/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter6/toy.cpp @@ -628,13 +628,14 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheContext; static std::unique_ptr TheModule; +static std::unique_ptr> Builder; static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; static std::map> FunctionProtos; +static ExitOnError ExitOnErr; Value *LogErrorV(const char *Str) { LogError(Str); @@ -657,7 +658,7 @@ Function *getFunction(std::string Name) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -677,7 +678,7 @@ Value *UnaryExprAST::codegen() { if (!F) return LogErrorV("Unknown unary operator"); - return Builder.CreateCall(F, OperandV, "unop"); + return Builder->CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { @@ -688,15 +689,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: break; } @@ -707,7 +708,7 @@ Value *BinaryExprAST::codegen() { assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); + return Builder->CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { @@ -727,7 +728,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -736,46 +737,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -805,19 +806,19 @@ Value *ForExprAST::codegen() { // Make the new basic block for the loop header, inserting after current // block. - Function *TheFunction = Builder.GetInsertBlock()->getParent(); - BasicBlock *PreheaderBB = Builder.GetInsertBlock(); - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + BasicBlock *PreheaderBB = Builder->GetInsertBlock(); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. PHINode *Variable = - Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName); + Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, VarName); Variable->addIncoming(StartVal, PreheaderBB); // Within the loop, the variable is defined equal to the PHI node. If it @@ -839,10 +840,10 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } - Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); + Value *NextVar = Builder->CreateFAdd(Variable, StepVal, "nextvar"); // Compute the end condition. Value *EndCond = End->codegen(); @@ -850,19 +851,19 @@ Value *ForExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. - BasicBlock *LoopEndBB = Builder.GetInsertBlock(); + BasicBlock *LoopEndBB = Builder->GetInsertBlock(); BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Add a new entry to the PHI node for the backedge. Variable->addIncoming(NextVar, LoopEndBB); @@ -874,14 +875,14 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -908,8 +909,8 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -918,7 +919,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -943,8 +944,12 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); // Create a new pass manager attached to it. TheFPM = std::make_unique(TheModule.get()); @@ -967,7 +972,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - TheJIT->addModule(std::move(TheModule)); + ExitOnErr(TheJIT->addModule( + ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); InitializeModuleAndPassManager(); } } else { @@ -994,22 +1000,24 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModuleAndPassManager(); // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); + auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); // Get the symbol's address and cast it to the right type (takes no // arguments, returns a double) so we can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); fprintf(stderr, "Evaluated to %f\n", FP()); // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -1082,7 +1090,7 @@ int main() { fprintf(stderr, "ready> "); getNextToken(); - TheJIT = std::make_unique(); + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModuleAndPassManager(); diff --git a/llvm/examples/Kaleidoscope/Chapter7/toy.cpp b/llvm/examples/Kaleidoscope/Chapter7/toy.cpp index 317b602765e07..f2d4cbb80486b 100644 --- a/llvm/examples/Kaleidoscope/Chapter7/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter7/toy.cpp @@ -701,13 +701,14 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheContext; static std::unique_ptr TheModule; +static std::unique_ptr> Builder; static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; static std::map> FunctionProtos; +static ExitOnError ExitOnErr; Value *LogErrorV(const char *Str) { LogError(Str); @@ -735,11 +736,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, StringRef VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); + return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -749,7 +750,7 @@ Value *VariableExprAST::codegen() { return LogErrorV("Unknown variable name"); // Load the value. - return Builder.CreateLoad(V, Name.c_str()); + return Builder->CreateLoad(V, Name.c_str()); } Value *UnaryExprAST::codegen() { @@ -761,7 +762,7 @@ Value *UnaryExprAST::codegen() { if (!F) return LogErrorV("Unknown unary operator"); - return Builder.CreateCall(F, OperandV, "unop"); + return Builder->CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { @@ -784,7 +785,7 @@ Value *BinaryExprAST::codegen() { if (!Variable) return LogErrorV("Unknown variable name"); - Builder.CreateStore(Val, Variable); + Builder->CreateStore(Val, Variable); return Val; } @@ -795,15 +796,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: break; } @@ -814,7 +815,7 @@ Value *BinaryExprAST::codegen() { assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); + return Builder->CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { @@ -834,7 +835,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -843,46 +844,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -909,7 +910,7 @@ Value *IfExprAST::codegen() { // br endcond, loop, endloop // outloop: Value *ForExprAST::codegen() { - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -920,17 +921,17 @@ Value *ForExprAST::codegen() { return nullptr; // Store the value into the alloca. - Builder.CreateStore(StartVal, Alloca); + Builder->CreateStore(StartVal, Alloca); // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. @@ -951,7 +952,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } // Compute the end condition. @@ -961,23 +962,23 @@ Value *ForExprAST::codegen() { // Reload, increment, and restore the alloca. This handles the case where // the body of the loop mutates the variable. - Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); - Builder.CreateStore(NextVar, Alloca); + Value *CurVar = Builder->CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar"); + Builder->CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing non-equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Restore the unshadowed variable. if (OldVal) @@ -986,13 +987,13 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Value *VarExprAST::codegen() { std::vector OldBindings; - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { @@ -1010,11 +1011,11 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + InitVal = ConstantFP::get(*TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - Builder.CreateStore(InitVal, Alloca); + Builder->CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. @@ -1039,9 +1040,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1068,8 +1069,8 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -1078,7 +1079,7 @@ Function *FunctionAST::codegen() { AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); // Store the initial value into the alloca. - Builder.CreateStore(&Arg, Alloca); + Builder->CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. NamedValues[std::string(Arg.getName())] = Alloca; @@ -1086,7 +1087,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -1111,8 +1112,12 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); // Create a new pass manager attached to it. TheFPM = std::make_unique(TheModule.get()); @@ -1137,7 +1142,8 @@ static void HandleDefinition() { fprintf(stderr, "Read function definition:"); FnIR->print(errs()); fprintf(stderr, "\n"); - TheJIT->addModule(std::move(TheModule)); + ExitOnErr(TheJIT->addModule( + ThreadSafeModule(std::move(TheModule), std::move(TheContext)))); InitializeModuleAndPassManager(); } } else { @@ -1164,22 +1170,24 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so - // we can free it later. - auto H = TheJIT->addModule(std::move(TheModule)); + // Create a ResourceTracker to track JIT'd memory allocated to our + // anonymous expression -- that way we can free it after executing. + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + ExitOnErr(TheJIT->addModule(std::move(TSM), RT)); InitializeModuleAndPassManager(); // Search the JIT for the __anon_expr symbol. - auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); - assert(ExprSymbol && "Function not found"); + auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr")); // Get the symbol's address and cast it to the right type (takes no // arguments, returns a double) so we can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); fprintf(stderr, "Evaluated to %f\n", FP()); // Delete the anonymous expression module from the JIT. - TheJIT->removeModule(H); + ExitOnErr(RT->remove()); } } else { // Skip token for error recovery. @@ -1253,7 +1261,7 @@ int main() { fprintf(stderr, "ready> "); getNextToken(); - TheJIT = std::make_unique(); + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModuleAndPassManager(); diff --git a/llvm/examples/Kaleidoscope/Chapter8/toy.cpp b/llvm/examples/Kaleidoscope/Chapter8/toy.cpp index 92903741f2106..a1fe89a9f8440 100644 --- a/llvm/examples/Kaleidoscope/Chapter8/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter8/toy.cpp @@ -702,11 +702,12 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheContext; static std::unique_ptr TheModule; +static std::unique_ptr> Builder; static std::map NamedValues; static std::map> FunctionProtos; +static ExitOnError ExitOnErr; Value *LogErrorV(const char *Str) { LogError(Str); @@ -734,11 +735,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, StringRef VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); + return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -748,7 +749,7 @@ Value *VariableExprAST::codegen() { return LogErrorV("Unknown variable name"); // Load the value. - return Builder.CreateLoad(V, Name.c_str()); + return Builder->CreateLoad(V, Name.c_str()); } Value *UnaryExprAST::codegen() { @@ -760,7 +761,7 @@ Value *UnaryExprAST::codegen() { if (!F) return LogErrorV("Unknown unary operator"); - return Builder.CreateCall(F, OperandV, "unop"); + return Builder->CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { @@ -783,7 +784,7 @@ Value *BinaryExprAST::codegen() { if (!Variable) return LogErrorV("Unknown variable name"); - Builder.CreateStore(Val, Variable); + Builder->CreateStore(Val, Variable); return Val; } @@ -794,15 +795,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: break; } @@ -813,7 +814,7 @@ Value *BinaryExprAST::codegen() { assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); + return Builder->CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { @@ -833,7 +834,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -842,46 +843,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -908,7 +909,7 @@ Value *IfExprAST::codegen() { // br endcond, loop, endloop // outloop: Value *ForExprAST::codegen() { - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -919,17 +920,17 @@ Value *ForExprAST::codegen() { return nullptr; // Store the value into the alloca. - Builder.CreateStore(StartVal, Alloca); + Builder->CreateStore(StartVal, Alloca); // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. @@ -950,7 +951,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } // Compute the end condition. @@ -960,23 +961,23 @@ Value *ForExprAST::codegen() { // Reload, increment, and restore the alloca. This handles the case where // the body of the loop mutates the variable. - Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); - Builder.CreateStore(NextVar, Alloca); + Value *CurVar = Builder->CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar"); + Builder->CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing non-equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Restore the unshadowed variable. if (OldVal) @@ -985,13 +986,13 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Value *VarExprAST::codegen() { std::vector OldBindings; - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { @@ -1009,11 +1010,11 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + InitVal = ConstantFP::get(*TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - Builder.CreateStore(InitVal, Alloca); + Builder->CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. @@ -1038,9 +1039,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1067,8 +1068,8 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Record the function arguments in the NamedValues map. NamedValues.clear(); @@ -1077,7 +1078,7 @@ Function *FunctionAST::codegen() { AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); // Store the initial value into the alloca. - Builder.CreateStore(&Arg, Alloca); + Builder->CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. NamedValues[std::string(Arg.getName())] = Alloca; @@ -1085,7 +1086,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -1107,7 +1108,11 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); } static void HandleDefinition() { diff --git a/llvm/examples/Kaleidoscope/Chapter9/toy.cpp b/llvm/examples/Kaleidoscope/Chapter9/toy.cpp index 7b33dae6e13a2..29a4ee14fc011 100644 --- a/llvm/examples/Kaleidoscope/Chapter9/toy.cpp +++ b/llvm/examples/Kaleidoscope/Chapter9/toy.cpp @@ -88,8 +88,7 @@ namespace { class PrototypeAST; class ExprAST; } -static LLVMContext TheContext; -static IRBuilder<> Builder(TheContext); + struct DebugInfo { DICompileUnit *TheCU; DIType *DblTy; @@ -814,6 +813,19 @@ static std::unique_ptr ParseExtern() { return ParsePrototype(); } +//===----------------------------------------------------------------------===// +// Code Generation Globals +//===----------------------------------------------------------------------===// + +static std::unique_ptr TheContext; +static std::unique_ptr TheModule; +static std::unique_ptr> Builder; +static ExitOnError ExitOnErr; + +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; + //===----------------------------------------------------------------------===// // Debug Info Support //===----------------------------------------------------------------------===// @@ -830,13 +842,13 @@ DIType *DebugInfo::getDoubleTy() { void DebugInfo::emitLocation(ExprAST *AST) { if (!AST) - return Builder.SetCurrentDebugLocation(DebugLoc()); + return Builder->SetCurrentDebugLocation(DebugLoc()); DIScope *Scope; if (LexicalBlocks.empty()) Scope = TheCU; else Scope = LexicalBlocks.back(); - Builder.SetCurrentDebugLocation( + Builder->SetCurrentDebugLocation( DebugLoc::get(AST->getLine(), AST->getCol(), Scope)); } @@ -857,11 +869,6 @@ static DISubroutineType *CreateFunctionType(unsigned NumArgs, DIFile *Unit) { // Code Generation //===----------------------------------------------------------------------===// -static std::unique_ptr TheModule; -static std::map NamedValues; -static std::unique_ptr TheJIT; -static std::map> FunctionProtos; - Value *LogErrorV(const char *Str) { LogError(Str); return nullptr; @@ -888,12 +895,12 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, StringRef VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); + return TmpB.CreateAlloca(Type::getDoubleTy(*TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { KSDbgInfo.emitLocation(this); - return ConstantFP::get(TheContext, APFloat(Val)); + return ConstantFP::get(*TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -904,7 +911,7 @@ Value *VariableExprAST::codegen() { KSDbgInfo.emitLocation(this); // Load the value. - return Builder.CreateLoad(V, Name.c_str()); + return Builder->CreateLoad(V, Name.c_str()); } Value *UnaryExprAST::codegen() { @@ -917,7 +924,7 @@ Value *UnaryExprAST::codegen() { return LogErrorV("Unknown unary operator"); KSDbgInfo.emitLocation(this); - return Builder.CreateCall(F, OperandV, "unop"); + return Builder->CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { @@ -942,7 +949,7 @@ Value *BinaryExprAST::codegen() { if (!Variable) return LogErrorV("Unknown variable name"); - Builder.CreateStore(Val, Variable); + Builder->CreateStore(Val, Variable); return Val; } @@ -953,15 +960,15 @@ Value *BinaryExprAST::codegen() { switch (Op) { case '+': - return Builder.CreateFAdd(L, R, "addtmp"); + return Builder->CreateFAdd(L, R, "addtmp"); case '-': - return Builder.CreateFSub(L, R, "subtmp"); + return Builder->CreateFSub(L, R, "subtmp"); case '*': - return Builder.CreateFMul(L, R, "multmp"); + return Builder->CreateFMul(L, R, "multmp"); case '<': - L = Builder.CreateFCmpULT(L, R, "cmptmp"); + L = Builder->CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); default: break; } @@ -972,7 +979,7 @@ Value *BinaryExprAST::codegen() { assert(F && "binary operator not found!"); Value *Ops[] = {L, R}; - return Builder.CreateCall(F, Ops, "binop"); + return Builder->CreateCall(F, Ops, "binop"); } Value *CallExprAST::codegen() { @@ -994,7 +1001,7 @@ Value *CallExprAST::codegen() { return nullptr; } - return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); } Value *IfExprAST::codegen() { @@ -1005,46 +1012,46 @@ Value *IfExprAST::codegen() { return nullptr; // Convert condition to a bool by comparing non-equal to 0.0. - CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + CondV = Builder->CreateFCmpONE( + CondV, ConstantFP::get(*TheContext, APFloat(0.0)), "ifcond"); - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); - BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont"); - Builder.CreateCondBr(CondV, ThenBB, ElseBB); + Builder->CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. - Builder.SetInsertPoint(ThenBB); + Builder->SetInsertPoint(ThenBB); Value *ThenV = Then->codegen(); if (!ThenV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = Builder.GetInsertBlock(); + ThenBB = Builder->GetInsertBlock(); // Emit else block. TheFunction->getBasicBlockList().push_back(ElseBB); - Builder.SetInsertPoint(ElseBB); + Builder->SetInsertPoint(ElseBB); Value *ElseV = Else->codegen(); if (!ElseV) return nullptr; - Builder.CreateBr(MergeBB); + Builder->CreateBr(MergeBB); // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = Builder.GetInsertBlock(); + ElseBB = Builder->GetInsertBlock(); // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); - Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + Builder->SetInsertPoint(MergeBB); + PHINode *PN = Builder->CreatePHI(Type::getDoubleTy(*TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -1071,7 +1078,7 @@ Value *IfExprAST::codegen() { // br endcond, loop, endloop // outloop: Value *ForExprAST::codegen() { - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1084,17 +1091,17 @@ Value *ForExprAST::codegen() { return nullptr; // Store the value into the alloca. - Builder.CreateStore(StartVal, Alloca); + Builder->CreateStore(StartVal, Alloca); // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. - Builder.CreateBr(LoopBB); + Builder->CreateBr(LoopBB); // Start insertion in LoopBB. - Builder.SetInsertPoint(LoopBB); + Builder->SetInsertPoint(LoopBB); // Within the loop, the variable is defined equal to the PHI node. If it // shadows an existing variable, we have to restore it, so save it now. @@ -1115,7 +1122,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + StepVal = ConstantFP::get(*TheContext, APFloat(1.0)); } // Compute the end condition. @@ -1125,23 +1132,23 @@ Value *ForExprAST::codegen() { // Reload, increment, and restore the alloca. This handles the case where // the body of the loop mutates the variable. - Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); - Builder.CreateStore(NextVar, Alloca); + Value *CurVar = Builder->CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder->CreateFAdd(CurVar, StepVal, "nextvar"); + Builder->CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing non-equal to 0.0. - EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + EndCond = Builder->CreateFCmpONE( + EndCond, ConstantFP::get(*TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(TheContext, "afterloop", TheFunction); + BasicBlock::Create(*TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. - Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + Builder->CreateCondBr(EndCond, LoopBB, AfterBB); // Any new code will be inserted in AfterBB. - Builder.SetInsertPoint(AfterBB); + Builder->SetInsertPoint(AfterBB); // Restore the unshadowed variable. if (OldVal) @@ -1150,13 +1157,13 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(TheContext)); + return Constant::getNullValue(Type::getDoubleTy(*TheContext)); } Value *VarExprAST::codegen() { std::vector OldBindings; - Function *TheFunction = Builder.GetInsertBlock()->getParent(); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Register all variables and emit their initializer. for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { @@ -1174,11 +1181,11 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + InitVal = ConstantFP::get(*TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - Builder.CreateStore(InitVal, Alloca); + Builder->CreateStore(InitVal, Alloca); // Remember the old variable binding so that we can restore the binding when // we unrecurse. @@ -1205,9 +1212,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1234,8 +1241,8 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); - Builder.SetInsertPoint(BB); + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); // Create a subprogram DIE for this function. DIFile *Unit = DBuilder->createFile(KSDbgInfo.TheCU->getFilename(), @@ -1271,10 +1278,10 @@ Function *FunctionAST::codegen() { DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(), DebugLoc::get(LineNo, 0, SP), - Builder.GetInsertBlock()); + Builder->GetInsertBlock()); // Store the initial value into the alloca. - Builder.CreateStore(&Arg, Alloca); + Builder->CreateStore(&Arg, Alloca); // Add arguments to variable symbol table. NamedValues[std::string(Arg.getName())] = Alloca; @@ -1284,7 +1291,7 @@ Function *FunctionAST::codegen() { if (Value *RetVal = Body->codegen()) { // Finish off the function. - Builder.CreateRet(RetVal); + Builder->CreateRet(RetVal); // Pop off the lexical block for the function. KSDbgInfo.LexicalBlocks.pop_back(); @@ -1314,8 +1321,11 @@ Function *FunctionAST::codegen() { static void InitializeModule() { // Open a new module. - TheModule = std::make_unique("my cool jit", TheContext); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + Builder = std::make_unique>(*TheContext); } static void HandleDefinition() { @@ -1416,7 +1426,7 @@ int main() { // Prime the first token. getNextToken(); - TheJIT = std::make_unique(); + TheJIT = ExitOnErr(KaleidoscopeJIT::Create()); InitializeModule(); diff --git a/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h index 86fdc1ed4fe98..9b35456a70412 100644 --- a/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h @@ -13,126 +13,87 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/Mangler.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include -#include +#include "llvm/IR/LLVMContext.h" #include -#include -#include namespace llvm { namespace orc { class KaleidoscopeJIT { -public: - using ObjLayerT = LegacyRTDyldObjectLinkingLayer; - using CompileLayerT = LegacyIRCompileLayer; - - KaleidoscopeJIT() - : Resolver(createLegacyLookupResolver( - ES, - [this](StringRef Name) { - return findMangledSymbol(std::string(Name)); - }, - [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), - TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), - ObjectLayer(AcknowledgeORCv1Deprecation, ES, - [this](VModuleKey) { - return ObjLayerT::Resources{ - std::make_shared(), Resolver}; - }), - CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer, - SimpleCompiler(*TM)) { - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); - } +private: + std::unique_ptr TPC; + std::unique_ptr ES; - TargetMachine &getTargetMachine() { return *TM; } + DataLayout DL; + MangleAndInterner Mangle; - VModuleKey addModule(std::unique_ptr M) { - auto K = ES.allocateVModule(); - cantFail(CompileLayer.addModule(K, std::move(M))); - ModuleKeys.push_back(K); - return K; - } + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; - void removeModule(VModuleKey K) { - ModuleKeys.erase(find(ModuleKeys, K)); - cantFail(CompileLayer.removeModule(K)); + JITDylib &MainJD; + +public: + KaleidoscopeJIT(std::unique_ptr TPC, + std::unique_ptr ES, + JITTargetMachineBuilder JTMB, DataLayout DL) + : TPC(std::move(TPC)), ES(std::move(ES)), DL(std::move(DL)), + Mangle(*this->ES, this->DL), + ObjectLayer(*this->ES, + []() { return std::make_unique(); }), + CompileLayer(*this->ES, ObjectLayer, + std::make_unique(std::move(JTMB))), + MainJD(this->ES->createBareJITDylib("
")) { + MainJD.addGenerator( + cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()))); } - JITSymbol findSymbol(const std::string Name) { - return findMangledSymbol(mangle(Name)); + ~KaleidoscopeJIT() { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); } -private: - std::string mangle(const std::string &Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; + static Expected> Create() { + auto TPC = SelfTargetProcessControl::Create(); + if (!TPC) + return TPC.takeError(); + + auto ES = std::make_unique(); + + JITTargetMachineBuilder JTMB((*TPC)->getTargetTriple()); + + auto DL = JTMB.getDefaultDataLayoutForTarget(); + if (!DL) + return DL.takeError(); + + return std::make_unique(std::move(*TPC), std::move(ES), + std::move(JTMB), std::move(*DL)); } - JITSymbol findMangledSymbol(const std::string &Name) { -#ifdef _WIN32 - // The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported - // flag to decide whether a symbol will be visible or not, when we call - // IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true. - // - // But for Windows COFF objects, this flag is currently never set. - // For a potential solution see: https://reviews.llvm.org/rL258665 - // For now, we allow non-exported symbols on Windows as a workaround. - const bool ExportedSymbolsOnly = false; -#else - const bool ExportedSymbolsOnly = true; -#endif - - // Search modules in reverse order: from last added to first added. - // This is the opposite of the usual search order for dlsym, but makes more - // sense in a REPL where we want to bind to the newest available definition. - for (auto H : make_range(ModuleKeys.rbegin(), ModuleKeys.rend())) - if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly)) - return Sym; - - // If we can't find the symbol in the JIT, try looking in the host process. - if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name)) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); - -#ifdef _WIN32 - // For Windows retry without "_" at beginning, as RTDyldMemoryManager uses - // GetProcAddress and standard libraries like msvcrt.dll use names - // with and without "_" (for example "_itoa" but "sin"). - if (Name.length() > 2 && Name[0] == '_') - if (auto SymAddr = - RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1))) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); -#endif - - return nullptr; + const DataLayout &getDataLayout() const { return DL; } + + JITDylib &getMainJITDylib() { return MainJD; } + + Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + return CompileLayer.add(RT, std::move(TSM)); } - ExecutionSession ES; - std::shared_ptr Resolver; - std::unique_ptr TM; - const DataLayout DL; - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; - std::vector ModuleKeys; + Expected lookup(StringRef Name) { + return ES->lookup({&MainJD}, Mangle(Name.str())); + } }; } // end namespace orc diff --git a/llvm/examples/OrcV2Examples/CMakeLists.txt b/llvm/examples/OrcV2Examples/CMakeLists.txt index 74a90aa07f131..bed277e59e0bb 100644 --- a/llvm/examples/OrcV2Examples/CMakeLists.txt +++ b/llvm/examples/OrcV2Examples/CMakeLists.txt @@ -1,12 +1,14 @@ add_subdirectory(LLJITDumpObjects) -add_subdirectory(LLJITWithChildProcess) add_subdirectory(LLJITWithCustomObjectLinkingLayer) add_subdirectory(LLJITWithGDBRegistrationListener) add_subdirectory(LLJITWithInitializers) add_subdirectory(LLJITWithLazyReexports) add_subdirectory(LLJITWithObjectCache) add_subdirectory(LLJITWithObjectLinkingLayerPlugin) +add_subdirectory(LLJITWithOptimizingIRTransform) add_subdirectory(LLJITWithTargetProcessControl) +add_subdirectory(LLJITWithThinLTOSummaries) add_subdirectory(OrcV2CBindingsAddObjectFile) add_subdirectory(OrcV2CBindingsBasicUsage) add_subdirectory(OrcV2CBindingsReflectProcessSymbols) +add_subdirectory(OrcV2CBindingsRemovableCode) diff --git a/llvm/examples/OrcV2Examples/LLJITWithChildProcess/LLJITWithChildProcess.cpp b/llvm/examples/OrcV2Examples/LLJITWithChildProcess/LLJITWithChildProcess.cpp deleted file mode 100644 index 11e125c9cf755..0000000000000 --- a/llvm/examples/OrcV2Examples/LLJITWithChildProcess/LLJITWithChildProcess.cpp +++ /dev/null @@ -1,128 +0,0 @@ -//===--- LLJITWithLazyReexports.cpp - LLJIT example with custom laziness --===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// In this example we will execute JITed code in a child process: -// -// 1. Launch a remote process. -// 2. Create a JITLink-compatible remote memory manager. -// 3. Use LLJITBuilder to create a (greedy) LLJIT instance. -// 4. Add the Add1Example module and execute add1(). -// 5. Terminate the remote target session. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" -#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" -#include "llvm/ExecutionEngine/Orc/LLJIT.h" -#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/InitLLVM.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/raw_ostream.h" - -#include "../ExampleModules.h" -#include "RemoteJITUtils.h" - -#include -#include - -#define DEBUG_TYPE "orc" - -using namespace llvm; -using namespace llvm::orc; - -// Executable running in the child process for remote execution. It communicates -// via stdin/stdout pipes. -cl::opt - ChildExecPath("remote-process", cl::Required, - cl::desc("Specify the filename of the process to launch for " - "remote JITing."), - cl::value_desc("filename")); - -int main(int argc, char *argv[]) { - InitLLVM X(argc, argv); - - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - - cl::ParseCommandLineOptions(argc, argv, "LLJITWithChildProcess"); - - ExitOnError ExitOnErr; - ExitOnErr.setBanner(std::string(argv[0]) + ": "); - - if (!sys::fs::can_execute(ChildExecPath)) { - WithColor::error(errs(), argv[0]) - << "Child executable invalid: '" << ChildExecPath << "'\n"; - return -1; - } - - ExecutionSession ES; - ES.setErrorReporter([&](Error Err) { ExitOnErr(std::move(Err)); }); - - // Launch the remote process and get a channel to it. - pid_t ChildPID; - std::unique_ptr Ch = launchRemote(ChildExecPath, ChildPID); - if (!Ch) { - WithColor::error(errs(), argv[0]) << "Failed to launch remote JIT.\n"; - exit(1); - } - - LLVM_DEBUG({ - dbgs() - << "Launched executable in subprocess " << ChildPID << ":\n" - << ChildExecPath << "\n\n" - << "You may want to attach a debugger now. Press enter to continue.\n"; - fflush(stdin); - getchar(); - }); - - std::unique_ptr Client = - ExitOnErr(remote::OrcRemoteTargetClient::Create(*Ch, ES)); - - // Create a JITLink-compatible remote memory manager. - using MemManager = remote::OrcRemoteTargetClient::RemoteJITLinkMemoryManager; - std::unique_ptr RemoteMM = - ExitOnErr(Client->createRemoteJITLinkMemoryManager()); - - // Our remote target is running on the host system. - auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost()); - JTMB.setCodeModel(CodeModel::Small); - - // Create an LLJIT instance with a JITLink ObjectLinkingLayer. - auto J = ExitOnErr( - LLJITBuilder() - .setJITTargetMachineBuilder(std::move(JTMB)) - .setObjectLinkingLayerCreator( - [&](ExecutionSession &ES, - const Triple &TT) -> std::unique_ptr { - return std::make_unique(ES, *RemoteMM); - }) - .create()); - - auto M = ExitOnErr(parseExampleModule(Add1Example, "add1")); - - ExitOnErr(J->addIRModule(std::move(M))); - - // Look up the JIT'd function. - auto Add1Sym = ExitOnErr(J->lookup("add1")); - - // Run in child target. - Expected Result = Client->callIntInt(Add1Sym.getAddress(), 42); - if (Result) - outs() << "add1(42) = " << *Result << "\n"; - else - ES.reportError(Result.takeError()); - - // Signal the remote target that we're done JITing. - ExitOnErr(Client->terminateSession()); - LLVM_DEBUG(dbgs() << "Subprocess terminated\n"); - - return 0; -} diff --git a/llvm/examples/OrcV2Examples/LLJITWithChildProcess/RemoteJITUtils.h b/llvm/examples/OrcV2Examples/LLJITWithChildProcess/RemoteJITUtils.h deleted file mode 100644 index 9e3f1d417b816..0000000000000 --- a/llvm/examples/OrcV2Examples/LLJITWithChildProcess/RemoteJITUtils.h +++ /dev/null @@ -1,121 +0,0 @@ -//===-- RemoteJITUtils.h - Utilities for remote-JITing ----------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Utilities for remote-JITing -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXAMPLES_ORCV2EXAMPLES_LLJITWITHCHILDPROCESS_REMOTEJITUTILS_H -#define LLVM_EXAMPLES_ORCV2EXAMPLES_LLJITWITHCHILDPROCESS_REMOTEJITUTILS_H - -#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h" -#include - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#else -#include -#endif - -/// RPC channel that reads from and writes from file descriptors. -class FDRawChannel final : public llvm::orc::rpc::RawByteChannel { -public: - FDRawChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {} - - llvm::Error readBytes(char *Dst, unsigned Size) override { - assert(Dst && "Attempt to read into null."); - ssize_t Completed = 0; - while (Completed < static_cast(Size)) { - ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); - if (Read <= 0) { - auto ErrNo = errno; - if (ErrNo == EAGAIN || ErrNo == EINTR) - continue; - else - return llvm::errorCodeToError( - std::error_code(errno, std::generic_category())); - } - Completed += Read; - } - return llvm::Error::success(); - } - - llvm::Error appendBytes(const char *Src, unsigned Size) override { - assert(Src && "Attempt to append from null."); - ssize_t Completed = 0; - while (Completed < static_cast(Size)) { - ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); - if (Written < 0) { - auto ErrNo = errno; - if (ErrNo == EAGAIN || ErrNo == EINTR) - continue; - else - return llvm::errorCodeToError( - std::error_code(errno, std::generic_category())); - } - Completed += Written; - } - return llvm::Error::success(); - } - - llvm::Error send() override { return llvm::Error::success(); } - -private: - int InFD, OutFD; -}; - -// Launch child process and return a channel to it. -std::unique_ptr launchRemote(std::string ExecPath, - pid_t &ChildPID) { - // Create two pipes. - int PipeFD[2][2]; - if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0) - perror("Error creating pipe: "); - - ChildPID = fork(); - - if (ChildPID == 0) { - // In the child... - - // Close the parent ends of the pipes - close(PipeFD[0][1]); - close(PipeFD[1][0]); - - // Execute the child process. - std::unique_ptr ChildPath, ChildIn, ChildOut; - { - ChildPath.reset(new char[ExecPath.size() + 1]); - std::copy(ExecPath.begin(), ExecPath.end(), &ChildPath[0]); - ChildPath[ExecPath.size()] = '\0'; - std::string ChildInStr = llvm::utostr(PipeFD[0][0]); - ChildIn.reset(new char[ChildInStr.size() + 1]); - std::copy(ChildInStr.begin(), ChildInStr.end(), &ChildIn[0]); - ChildIn[ChildInStr.size()] = '\0'; - std::string ChildOutStr = llvm::utostr(PipeFD[1][1]); - ChildOut.reset(new char[ChildOutStr.size() + 1]); - std::copy(ChildOutStr.begin(), ChildOutStr.end(), &ChildOut[0]); - ChildOut[ChildOutStr.size()] = '\0'; - } - - char *const args[] = {&ChildPath[0], &ChildIn[0], &ChildOut[0], nullptr}; - int rc = execv(ExecPath.c_str(), args); - if (rc != 0) - perror("Error executing child process: "); - llvm_unreachable("Error executing child process"); - } - // else we're the parent... - - // Close the child ends of the pipes - close(PipeFD[0][0]); - close(PipeFD[1][1]); - - // Return an RPC channel connected to our end of the pipes. - return std::make_unique(PipeFD[1][0], PipeFD[0][1]); -} - -#endif diff --git a/llvm/examples/OrcV2Examples/LLJITWithInitializers/LLJITWithInitializers.cpp b/llvm/examples/OrcV2Examples/LLJITWithInitializers/LLJITWithInitializers.cpp index 063b9f6060e06..4fd55c414659b 100644 --- a/llvm/examples/OrcV2Examples/LLJITWithInitializers/LLJITWithInitializers.cpp +++ b/llvm/examples/OrcV2Examples/LLJITWithInitializers/LLJITWithInitializers.cpp @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { int32_t InitializersRunFlag = 0; int32_t DeinitializersRunFlag = 0; - ExitOnErr(J->define(absoluteSymbols( + ExitOnErr(J->getMainJITDylib().define(absoluteSymbols( {{J->mangleAndIntern("InitializersRunFlag"), JITEvaluatedSymbol::fromPointer(&InitializersRunFlag)}, {J->mangleAndIntern("DeinitializersRunFlag"), diff --git a/llvm/examples/OrcV2Examples/LLJITWithObjectLinkingLayerPlugin/LLJITWithObjectLinkingLayerPlugin.cpp b/llvm/examples/OrcV2Examples/LLJITWithObjectLinkingLayerPlugin/LLJITWithObjectLinkingLayerPlugin.cpp index 9bb6daa01da76..f349ce900e619 100644 --- a/llvm/examples/OrcV2Examples/LLJITWithObjectLinkingLayerPlugin/LLJITWithObjectLinkingLayerPlugin.cpp +++ b/llvm/examples/OrcV2Examples/LLJITWithObjectLinkingLayerPlugin/LLJITWithObjectLinkingLayerPlugin.cpp @@ -72,6 +72,17 @@ class MyPlugin : public ObjectLinkingLayer::Plugin { return Error::success(); } + Error notifyFailed(MaterializationResponsibility &MR) override { + return Error::success(); + } + + Error notifyRemovingResources(ResourceKey K) override { + return Error::success(); + } + + void notifyTransferringResources(ResourceKey DstKey, + ResourceKey SrcKey) override {} + private: void printLinkGraph(jitlink::LinkGraph &G, StringRef Title) { constexpr JITTargetAddress LineWidth = 16; diff --git a/llvm/examples/OrcV2Examples/LLJITWithOptimizingIRTransform/CMakeLists.txt b/llvm/examples/OrcV2Examples/LLJITWithOptimizingIRTransform/CMakeLists.txt new file mode 100644 index 0000000000000..a9cd91ad596ad --- /dev/null +++ b/llvm/examples/OrcV2Examples/LLJITWithOptimizingIRTransform/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS + Core + ExecutionEngine + IPO + IRReader + OrcJIT + ScalarOpts + Support + nativecodegen + ) + +add_llvm_example(LLJITWithOptimizingIRTransform + LLJITWithOptimizingIRTransform.cpp + ) diff --git a/llvm/examples/OrcV2Examples/LLJITWithOptimizingIRTransform/LLJITWithOptimizingIRTransform.cpp b/llvm/examples/OrcV2Examples/LLJITWithOptimizingIRTransform/LLJITWithOptimizingIRTransform.cpp new file mode 100644 index 0000000000000..7ebf3e8e9a077 --- /dev/null +++ b/llvm/examples/OrcV2Examples/LLJITWithOptimizingIRTransform/LLJITWithOptimizingIRTransform.cpp @@ -0,0 +1,122 @@ +//===-- LLJITWithOptimizingIRTransform.cpp -- LLJIT with IR optimization --===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// In this example we will use an IR transform to optimize a module as it +// passes through LLJIT's IRTransformLayer. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Scalar.h" + +#include "../ExampleModules.h" + +using namespace llvm; +using namespace llvm::orc; + +ExitOnError ExitOnErr; + +// Example IR module. +// +// This IR contains a recursive definition of the factorial function: +// +// fac(n) | n == 0 = 1 +// | otherwise = n * fac(n - 1) +// +// It also contains an entry function which calls the factorial function with +// an input value of 5. +// +// We expect the IR optimization transform that we build below to transform +// this into a non-recursive factorial function and an entry function that +// returns a constant value of 5!, or 120. + +const llvm::StringRef MainMod = + R"( + + define i32 @fac(i32 %n) { + entry: + %tobool = icmp eq i32 %n, 0 + br i1 %tobool, label %return, label %if.then + + if.then: ; preds = %entry + %arg = add nsw i32 %n, -1 + %call_result = call i32 @fac(i32 %arg) + %result = mul nsw i32 %n, %call_result + br label %return + + return: ; preds = %entry, %if.then + %final_result = phi i32 [ %result, %if.then ], [ 1, %entry ] + ret i32 %final_result + } + + define i32 @entry() { + entry: + %result = call i32 @fac(i32 5) + ret i32 %result + } + +)"; + +// A function object that creates a simple pass pipeline to apply to each +// module as it passes through the IRTransformLayer. +class MyOptimizationTransform { +public: + MyOptimizationTransform() : PM(std::make_unique()) { + PM->add(createTailCallEliminationPass()); + PM->add(createFunctionInliningPass()); + PM->add(createIndVarSimplifyPass()); + PM->add(createCFGSimplificationPass()); + } + + Expected operator()(ThreadSafeModule TSM, + MaterializationResponsibility &R) { + TSM.withModuleDo([this](Module &M) { + dbgs() << "--- BEFORE OPTIMIZATION ---\n" << M << "\n"; + PM->run(M); + dbgs() << "--- AFTER OPTIMIZATION ---\n" << M << "\n"; + }); + return std::move(TSM); + } + +private: + std::unique_ptr PM; +}; + +int main(int argc, char *argv[]) { + // Initialize LLVM. + InitLLVM X(argc, argv); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + + ExitOnErr.setBanner(std::string(argv[0]) + ": "); + + // (1) Create LLJIT instance. + auto J = ExitOnErr(LLJITBuilder().create()); + + // (2) Install transform to optimize modules when they're materialized. + J->getIRTransformLayer().setTransform(MyOptimizationTransform()); + + // (3) Add modules. + ExitOnErr(J->addIRModule(ExitOnErr(parseExampleModule(MainMod, "MainMod")))); + + // (4) Look up the JIT'd function and call it. + auto EntrySym = ExitOnErr(J->lookup("entry")); + auto *Entry = (int (*)())EntrySym.getAddress(); + + int Result = Entry(); + outs() << "--- Result ---\n" + << "entry() = " << Result << "\n"; + + return 0; +} diff --git a/llvm/examples/OrcV2Examples/LLJITWithChildProcess/CMakeLists.txt b/llvm/examples/OrcV2Examples/LLJITWithThinLTOSummaries/CMakeLists.txt similarity index 51% rename from llvm/examples/OrcV2Examples/LLJITWithChildProcess/CMakeLists.txt rename to llvm/examples/OrcV2Examples/LLJITWithThinLTOSummaries/CMakeLists.txt index d96bfc0163088..175e655007050 100644 --- a/llvm/examples/OrcV2Examples/LLJITWithChildProcess/CMakeLists.txt +++ b/llvm/examples/OrcV2Examples/LLJITWithThinLTOSummaries/CMakeLists.txt @@ -1,12 +1,12 @@ set(LLVM_LINK_COMPONENTS + BitReader Core ExecutionEngine - IRReader OrcJIT Support nativecodegen ) -add_llvm_example(LLJITInChildProcess - LLJITWithChildProcess.cpp +add_llvm_example(LLJITWithThinLTOSummaries + LLJITWithThinLTOSummaries.cpp ) diff --git a/llvm/examples/OrcV2Examples/LLJITWithThinLTOSummaries/LLJITWithThinLTOSummaries.cpp b/llvm/examples/OrcV2Examples/LLJITWithThinLTOSummaries/LLJITWithThinLTOSummaries.cpp new file mode 100644 index 0000000000000..25a899b70c88f --- /dev/null +++ b/llvm/examples/OrcV2Examples/LLJITWithThinLTOSummaries/LLJITWithThinLTOSummaries.cpp @@ -0,0 +1,240 @@ +//===--- LLJITWithThinLTOSummaries.cpp - Module summaries as LLJIT input --===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// In this example we will use a module summary index file produced for ThinLTO +// to (A) find the module that defines the main entry point and (B) find all +// extra modules that we need. We will do this in five steps: +// +// (1) Read the index file and parse the module summary index. +// (2) Find the path of the module that defines "main". +// (3) Parse the main module and create a matching LLJIT. +// (4) Add all modules to the LLJIT that are covered by the index. +// (5) Look up and run the JIT'd function. +// +// The index file name must be passed in as command line argument. Please find +// this test for instructions on creating the index file: +// +// llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test +// +// If you use "build" as the build directory, you can run the test from the root +// of the monorepo like this: +// +// > build/bin/llvm-lit -a \ +// llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +using namespace llvm; +using namespace llvm::orc; + +// Path of the module summary index file. +cl::opt IndexFile{cl::desc(""), + cl::Positional, cl::init("-")}; + +// Describe a fail state that is caused by the given ModuleSummaryIndex +// providing multiple definitions of the given global value name. It will dump +// name and GUID for the global value and list the paths of the modules covered +// by the index. +class DuplicateDefinitionInSummary + : public ErrorInfo { +public: + static char ID; + + DuplicateDefinitionInSummary(std::string GlobalValueName, ValueInfo VI) + : GlobalValueName(std::move(GlobalValueName)) { + ModulePaths.reserve(VI.getSummaryList().size()); + for (const auto &S : VI.getSummaryList()) + ModulePaths.push_back(S->modulePath().str()); + llvm::sort(ModulePaths); + } + + void log(raw_ostream &OS) const override { + OS << "Duplicate symbol for global value '" << GlobalValueName + << "' (GUID: " << GlobalValue::getGUID(GlobalValueName) << ") in:\n"; + for (const std::string &Path : ModulePaths) { + OS << " " << Path << "\n"; + } + } + + std::error_code convertToErrorCode() const override { + return inconvertibleErrorCode(); + } + +private: + std::string GlobalValueName; + std::vector ModulePaths; +}; + +// Describe a fail state where the given global value name was not found in the +// given ModuleSummaryIndex. It will dump name and GUID for the global value and +// list the paths of the modules covered by the index. +class DefinitionNotFoundInSummary + : public ErrorInfo { +public: + static char ID; + + DefinitionNotFoundInSummary(std::string GlobalValueName, + ModuleSummaryIndex &Index) + : GlobalValueName(std::move(GlobalValueName)) { + ModulePaths.reserve(Index.modulePaths().size()); + for (const auto &Entry : Index.modulePaths()) + ModulePaths.push_back(Entry.first().str()); + llvm::sort(ModulePaths); + } + + void log(raw_ostream &OS) const override { + OS << "No symbol for global value '" << GlobalValueName + << "' (GUID: " << GlobalValue::getGUID(GlobalValueName) << ") in:\n"; + for (const std::string &Path : ModulePaths) { + OS << " " << Path << "\n"; + } + } + + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + +private: + std::string GlobalValueName; + std::vector ModulePaths; +}; + +char DuplicateDefinitionInSummary::ID = 0; +char DefinitionNotFoundInSummary::ID = 0; + +// Lookup the a function in the ModuleSummaryIndex and return the path of the +// module that defines it. Paths in the ModuleSummaryIndex are relative to the +// build directory of the covered modules. +Expected getMainModulePath(StringRef FunctionName, + ModuleSummaryIndex &Index) { + // Summaries use unmangled names. + GlobalValue::GUID G = GlobalValue::getGUID(FunctionName); + ValueInfo VI = Index.getValueInfo(G); + + // We need a unique definition, otherwise don't try further. + if (!VI || VI.getSummaryList().empty()) + return make_error(FunctionName.str(), Index); + if (VI.getSummaryList().size() > 1) + return make_error(FunctionName.str(), VI); + + GlobalValueSummary *S = VI.getSummaryList().front()->getBaseObject(); + if (!isa(S)) + return createStringError(inconvertibleErrorCode(), + "Entry point is not a function: " + FunctionName); + + // Return a reference. ModuleSummaryIndex owns the module paths. + return S->modulePath(); +} + +// Parse the bitcode module from the given path into a ThreadSafeModule. +Expected loadModule(StringRef Path, + orc::ThreadSafeContext TSCtx) { + outs() << "About to load module: " << Path << "\n"; + + Expected> BitcodeBuffer = + errorOrToExpected(MemoryBuffer::getFile(Path)); + if (!BitcodeBuffer) + return BitcodeBuffer.takeError(); + + MemoryBufferRef BitcodeBufferRef = (**BitcodeBuffer).getMemBufferRef(); + Expected> M = + parseBitcodeFile(BitcodeBufferRef, *TSCtx.getContext()); + if (!M) + return M.takeError(); + + return ThreadSafeModule(std::move(*M), std::move(TSCtx)); +} + +int main(int Argc, char *Argv[]) { + InitLLVM X(Argc, Argv); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + + cl::ParseCommandLineOptions(Argc, Argv, "LLJITWithThinLTOSummaries"); + + ExitOnError ExitOnErr; + ExitOnErr.setBanner(std::string(Argv[0]) + ": "); + + // (1) Read the index file and parse the module summary index. + std::unique_ptr SummaryBuffer = + ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(IndexFile))); + + std::unique_ptr SummaryIndex = + ExitOnErr(getModuleSummaryIndex(SummaryBuffer->getMemBufferRef())); + + // (2) Find the path of the module that defines "main". + std::string MainFunctionName = "main"; + StringRef MainModulePath = + ExitOnErr(getMainModulePath(MainFunctionName, *SummaryIndex)); + + // (3) Parse the main module and create a matching LLJIT. + ThreadSafeContext TSCtx(std::make_unique()); + ThreadSafeModule MainModule = ExitOnErr(loadModule(MainModulePath, TSCtx)); + + auto Builder = LLJITBuilder(); + + MainModule.withModuleDo([&](Module &M) { + if (M.getTargetTriple().empty()) { + Builder.setJITTargetMachineBuilder( + ExitOnErr(JITTargetMachineBuilder::detectHost())); + } else { + Builder.setJITTargetMachineBuilder( + JITTargetMachineBuilder(Triple(M.getTargetTriple()))); + } + if (!M.getDataLayout().getStringRepresentation().empty()) + Builder.setDataLayout(M.getDataLayout()); + }); + + auto J = ExitOnErr(Builder.create()); + + // (4) Add all modules to the LLJIT that are covered by the index. + JITDylib &JD = J->getMainJITDylib(); + + for (const auto &Entry : SummaryIndex->modulePaths()) { + StringRef Path = Entry.first(); + ThreadSafeModule M = (Path == MainModulePath) + ? std::move(MainModule) + : ExitOnErr(loadModule(Path, TSCtx)); + ExitOnErr(J->addIRModule(JD, std::move(M))); + } + + // (5) Look up and run the JIT'd function. + auto MainSym = ExitOnErr(J->lookup(MainFunctionName)); + + using MainFnPtr = int (*)(int, char *[]); + MainFnPtr MainFunction = + jitTargetAddressToFunction(MainSym.getAddress()); + + int Result = runAsMain(MainFunction, {}, MainModulePath); + outs() << "'" << MainFunctionName << "' finished with exit code: " << Result + << "\n"; + + return 0; +} diff --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsAddObjectFile/OrcV2CBindingsAddObjectFile.c b/llvm/examples/OrcV2Examples/OrcV2CBindingsAddObjectFile/OrcV2CBindingsAddObjectFile.c index 49eca25b07a8b..fca3c7522b85b 100644 --- a/llvm/examples/OrcV2Examples/OrcV2CBindingsAddObjectFile/OrcV2CBindingsAddObjectFile.c +++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsAddObjectFile/OrcV2CBindingsAddObjectFile.c @@ -9,7 +9,7 @@ #include "llvm-c/Core.h" #include "llvm-c/Error.h" #include "llvm-c/Initialization.h" -#include "llvm-c/Orc.h" +#include "llvm-c/LLJIT.h" #include "llvm-c/Support.h" #include "llvm-c/Target.h" #include "llvm-c/TargetMachine.h" diff --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsBasicUsage/OrcV2CBindingsBasicUsage.c b/llvm/examples/OrcV2Examples/OrcV2CBindingsBasicUsage/OrcV2CBindingsBasicUsage.c index cc54cc49ec242..d499518943604 100644 --- a/llvm/examples/OrcV2Examples/OrcV2CBindingsBasicUsage/OrcV2CBindingsBasicUsage.c +++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsBasicUsage/OrcV2CBindingsBasicUsage.c @@ -9,7 +9,7 @@ #include "llvm-c/Core.h" #include "llvm-c/Error.h" #include "llvm-c/Initialization.h" -#include "llvm-c/Orc.h" +#include "llvm-c/LLJIT.h" #include "llvm-c/Support.h" #include "llvm-c/Target.h" diff --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsReflectProcessSymbols/OrcV2CBindingsReflectProcessSymbols.c b/llvm/examples/OrcV2Examples/OrcV2CBindingsReflectProcessSymbols/OrcV2CBindingsReflectProcessSymbols.c index 790f153260eec..455e5eacec9ee 100644 --- a/llvm/examples/OrcV2Examples/OrcV2CBindingsReflectProcessSymbols/OrcV2CBindingsReflectProcessSymbols.c +++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsReflectProcessSymbols/OrcV2CBindingsReflectProcessSymbols.c @@ -9,7 +9,7 @@ #include "llvm-c/Core.h" #include "llvm-c/Error.h" #include "llvm-c/Initialization.h" -#include "llvm-c/Orc.h" +#include "llvm-c/LLJIT.h" #include "llvm-c/Support.h" #include "llvm-c/Target.h" @@ -27,7 +27,7 @@ int32_t add(int32_t X, int32_t Y) { return X + Y; } int32_t mul(int32_t X, int32_t Y) { return X * Y; } -int allowedSymbols(LLVMOrcSymbolStringPoolEntryRef Sym, void *Ctx) { +int allowedSymbols(void *Ctx, LLVMOrcSymbolStringPoolEntryRef Sym) { assert(Ctx && "Cannot call allowedSymbols with a null context"); LLVMOrcSymbolStringPoolEntryRef *AllowList = @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) { LLVMOrcLLJITMangleAndIntern(J, "add"), 0}; { - LLVMOrcJITDylibDefinitionGeneratorRef ProcessSymbolsGenerator = 0; + LLVMOrcDefinitionGeneratorRef ProcessSymbolsGenerator = 0; LLVMErrorRef Err; if ((Err = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( &ProcessSymbolsGenerator, LLVMOrcLLJITGetGlobalPrefix(J), diff --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsRemovableCode/CMakeLists.txt b/llvm/examples/OrcV2Examples/OrcV2CBindingsRemovableCode/CMakeLists.txt new file mode 100644 index 0000000000000..5b737557bb1ef --- /dev/null +++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsRemovableCode/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS + Core + ExecutionEngine + IRReader + JITLink + MC + OrcJIT + Support + Target + nativecodegen + ) + +add_llvm_example(OrcV2CBindingsRemovableCode + OrcV2CBindingsRemovableCode.c + ) diff --git a/llvm/examples/OrcV2Examples/OrcV2CBindingsRemovableCode/OrcV2CBindingsRemovableCode.c b/llvm/examples/OrcV2Examples/OrcV2CBindingsRemovableCode/OrcV2CBindingsRemovableCode.c new file mode 100644 index 0000000000000..5cfc626a5e2dc --- /dev/null +++ b/llvm/examples/OrcV2Examples/OrcV2CBindingsRemovableCode/OrcV2CBindingsRemovableCode.c @@ -0,0 +1,176 @@ +//===-------- BasicOrcV2CBindings.c - Basic OrcV2 C Bindings Demo ---------===// +// +// 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-c/Core.h" +#include "llvm-c/Error.h" +#include "llvm-c/Initialization.h" +#include "llvm-c/LLJIT.h" +#include "llvm-c/Support.h" +#include "llvm-c/Target.h" + +#include + +int handleError(LLVMErrorRef Err) { + char *ErrMsg = LLVMGetErrorMessage(Err); + fprintf(stderr, "Error: %s\n", ErrMsg); + LLVMDisposeErrorMessage(ErrMsg); + return 1; +} + +LLVMOrcThreadSafeModuleRef createDemoModule() { + // Create a new ThreadSafeContext and underlying LLVMContext. + LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext(); + + // Get a reference to the underlying LLVMContext. + LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx); + + // Create a new LLVM module. + LLVMModuleRef M = LLVMModuleCreateWithNameInContext("demo", Ctx); + + // Add a "sum" function": + // - Create the function type and function instance. + LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()}; + LLVMTypeRef SumFunctionType = + LLVMFunctionType(LLVMInt32Type(), ParamTypes, 2, 0); + LLVMValueRef SumFunction = LLVMAddFunction(M, "sum", SumFunctionType); + + // - Add a basic block to the function. + LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(SumFunction, "entry"); + + // - Add an IR builder and point it at the end of the basic block. + LLVMBuilderRef Builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(Builder, EntryBB); + + // - Get the two function arguments and use them co construct an "add" + // instruction. + LLVMValueRef SumArg0 = LLVMGetParam(SumFunction, 0); + LLVMValueRef SumArg1 = LLVMGetParam(SumFunction, 1); + LLVMValueRef Result = LLVMBuildAdd(Builder, SumArg0, SumArg1, "result"); + + // - Build the return instruction. + LLVMBuildRet(Builder, Result); + + // Our demo module is now complete. Wrap it and our ThreadSafeContext in a + // ThreadSafeModule. + LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx); + + // Dispose of our local ThreadSafeContext value. The underlying LLVMContext + // will be kept alive by our ThreadSafeModule, TSM. + LLVMOrcDisposeThreadSafeContext(TSCtx); + + // Return the result. + return TSM; +} + +int main(int argc, char *argv[]) { + + int MainResult = 0; + + // Parse command line arguments and initialize LLVM Core. + LLVMParseCommandLineOptions(argc, (const char **)argv, ""); + LLVMInitializeCore(LLVMGetGlobalPassRegistry()); + + // Initialize native target codegen and asm printer. + LLVMInitializeNativeTarget(); + LLVMInitializeNativeAsmPrinter(); + + // Create the JIT instance. + LLVMOrcLLJITRef J; + { + LLVMErrorRef Err; + if ((Err = LLVMOrcCreateLLJIT(&J, 0))) { + MainResult = handleError(Err); + goto llvm_shutdown; + } + } + + // Create our demo module. + LLVMOrcThreadSafeModuleRef TSM = createDemoModule(); + LLVMOrcResourceTrackerRef RT; + + // Add our demo module to the JIT. + { + LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J); + RT = LLVMOrcJITDylibCreateResourceTracker(MainJD); + LLVMErrorRef Err; + if ((Err = LLVMOrcLLJITAddLLVMIRModuleWithRT(J, RT, TSM))) { + // If adding the ThreadSafeModule fails then we need to clean it up + // ourselves. If adding it succeeds the JIT will manage the memory. + LLVMOrcDisposeThreadSafeModule(TSM); + MainResult = handleError(Err); + goto jit_cleanup; + } + } + + // Look up the address of our demo entry point. + printf("Looking up before removal...\n"); + LLVMOrcJITTargetAddress SumAddr; + { + LLVMErrorRef Err; + if ((Err = LLVMOrcLLJITLookup(J, &SumAddr, "sum"))) { + MainResult = handleError(Err); + goto jit_cleanup; + } + } + + // If we made it here then everything succeeded. Execute our JIT'd code. + int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr; + int32_t Result = Sum(1, 2); + + // Print the result. + printf("1 + 2 = %i\n", Result); + + // Remove the code. + { + LLVMErrorRef Err; + if ((Err = LLVMOrcResourceTrackerRemove(RT))) { + MainResult = handleError(Err); + goto jit_cleanup; + } + } + + // Attempt a second lookup. Here we expect an error as the code and symbols + // should have been removed. + printf("Attempting to remove code / symbols...\n"); + { + LLVMOrcJITTargetAddress ThrowAwayAddress; + LLVMErrorRef Err = LLVMOrcLLJITLookup(J, &ThrowAwayAddress, "sum"); + if (Err) { + printf("Received error as expected:\n"); + handleError(Err); + } else { + printf("Failure: Second lookup should have generated an error.\n"); + MainResult = 1; + } + } + +jit_cleanup: + // Destroy our JIT instance. This will clean up any memory that the JIT has + // taken ownership of. This operation is non-trivial (e.g. it may need to + // JIT static destructors) and may also fail. In that case we want to render + // the error to stderr, but not overwrite any existing return value. + + printf("Releasing resource tracker...\n"); + LLVMOrcReleaseResourceTracker(RT); + + printf("Destroying LLJIT instance and exiting.\n"); + { + LLVMErrorRef Err; + if ((Err = LLVMOrcDisposeLLJIT(J))) { + int NewFailureResult = handleError(Err); + if (MainResult == 0) + MainResult = NewFailureResult; + } + } + +llvm_shutdown: + // Shut down LLVM. + LLVMShutdown(); + + return MainResult; +} diff --git a/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp b/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp index 4de4897053c1b..24cf0847558f9 100644 --- a/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp +++ b/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp @@ -113,14 +113,13 @@ class SpeculativeJIT { this->CODLayer.setImplMap(&Imps); this->ES->setDispatchMaterialization( [this](std::unique_ptr MU, - MaterializationResponsibility MR) { - // FIXME: Switch to move capture once we have C++14. - auto SharedMU = std::shared_ptr(std::move(MU)); - auto SharedMR = - std::make_shared(std::move(MR)); - CompileThreads.async([SharedMU, SharedMR]() { - SharedMU->materialize(std::move(*SharedMR)); - }); + std::unique_ptr MR) { + CompileThreads.async( + [UnownedMU = MU.release(), UnownedMR = MR.release()]() { + std::unique_ptr MU(UnownedMU); + std::unique_ptr MR(UnownedMR); + MU->materialize(std::move(MR)); + }); }); ExitOnErr(S.addSpeculationRuntime(MainJD, Mangle)); LocalCXXRuntimeOverrides CXXRuntimeoverrides; diff --git a/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.cpp b/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.cpp index 345bfd8dd8705..df844bf19b9cc 100644 --- a/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.cpp +++ b/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.cpp @@ -120,8 +120,8 @@ void ThinLtoInstrumentationLayer::nudgeIntoDiscovery( LLVM_DEBUG(dbgs() << "Nudged " << Count << " new functions into discovery\n"); } -void ThinLtoInstrumentationLayer::emit(MaterializationResponsibility R, - ThreadSafeModule TSM) { +void ThinLtoInstrumentationLayer::emit( + std::unique_ptr R, ThreadSafeModule TSM) { TSM.withModuleDo([this](Module &M) { std::vector FunctionsToInstrument; diff --git a/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.h b/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.h index cd87207894745..25006b40607fe 100644 --- a/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.h +++ b/llvm/examples/ThinLtoJIT/ThinLtoInstrumentationLayer.h @@ -34,7 +34,8 @@ class ThinLtoInstrumentationLayer : public IRLayer { ~ThinLtoInstrumentationLayer() override; - void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override; + void emit(std::unique_ptr R, + ThreadSafeModule TSM) override; unsigned reserveDiscoveryFlags(unsigned Count); void registerDiscoveryFlagOwners(std::vector Guids, diff --git a/llvm/examples/ThinLtoJIT/ThinLtoJIT.cpp b/llvm/examples/ThinLtoJIT/ThinLtoJIT.cpp index f5c2b0696f55c..e668be7d11b7e 100644 --- a/llvm/examples/ThinLtoJIT/ThinLtoJIT.cpp +++ b/llvm/examples/ThinLtoJIT/ThinLtoJIT.cpp @@ -267,19 +267,18 @@ void ThinLtoJIT::setupLayers(JITTargetMachineBuilder JTMB, llvm::hardware_concurrency(NumCompileThreads)); ES.setDispatchMaterialization( [this](std::unique_ptr MU, - MaterializationResponsibility MR) { + std::unique_ptr MR) { if (IsTrivialModule(MU.get())) { // This should be quick and we may save a few session locks. MU->materialize(std::move(MR)); } else { // FIXME: Drop the std::shared_ptr workaround once ThreadPool::async() // accepts llvm::unique_function to define jobs. - auto SharedMU = std::shared_ptr(std::move(MU)); - auto SharedMR = - std::make_shared(std::move(MR)); CompileThreads->async( - [MU = std::move(SharedMU), MR = std::move(SharedMR)]() { - MU->materialize(std::move(*MR)); + [UnownedMU = MU.release(), UnownedMR = MR.release()]() { + std::unique_ptr MU(UnownedMU); + std::unique_ptr MR(UnownedMR); + MU->materialize(std::move(MR)); }); } }); diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h index 2c7b4c6eff107..c8a6f970419b3 100644 --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -3636,7 +3636,7 @@ void LLVMAddDestination(LLVMValueRef IndirectBr, LLVMBasicBlockRef Dest); /* Get the number of clauses on the landingpad instruction */ unsigned LLVMGetNumClauses(LLVMValueRef LandingPad); -/* Get the value of the clause at idnex Idx on the landingpad instruction */ +/* Get the value of the clause at index Idx on the landingpad instruction */ LLVMValueRef LLVMGetClause(LLVMValueRef LandingPad, unsigned Idx); /* Add a catch or filter clause to the landingpad instruction */ @@ -3937,6 +3937,26 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMAtomicOrdering FailureOrdering, LLVMBool SingleThread); +/** + * Get the number of elements in the mask of a ShuffleVector instruction. + */ +unsigned LLVMGetNumMaskElements(LLVMValueRef ShuffleVectorInst); + +/** + * \returns a constant that specifies that the result of a \c ShuffleVectorInst + * is undefined. + */ +int LLVMGetUndefMaskElem(void); + +/** + * Get the mask value at position Elt in the mask of a ShuffleVector + * instruction. + * + * \Returns the result of \c LLVMGetUndefMaskElem() if the mask value is undef + * at that position. + */ +int LLVMGetMaskValue(LLVMValueRef ShuffleVectorInst, unsigned Elt); + LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst); void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread); diff --git a/llvm/include/llvm-c/LLJIT.h b/llvm/include/llvm-c/LLJIT.h new file mode 100644 index 0000000000000..28eb8bbff96ba --- /dev/null +++ b/llvm/include/llvm-c/LLJIT.h @@ -0,0 +1,213 @@ +/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings --------*- C++ -*-===*\ +|* *| +|* 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to the LLJIT class in *| +|* libLLVMOrcJIT.a, which provides a simple MCJIT-like ORC JIT. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +|* Note: This interface is experimental. It is *NOT* stable, and may be *| +|* changed without warning. Only C API usage documentation is *| +|* provided. See the C++ documentation for all higher level ORC API *| +|* details. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_LLJIT_H +#define LLVM_C_LLJIT_H + +#include "llvm-c/Error.h" +#include "llvm-c/Orc.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" + +LLVM_C_EXTERN_C_BEGIN + +/** + * A function for constructing an ObjectLinkingLayer instance to be used + * by an LLJIT instance. + * + * Clients can call LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator to + * set the creator function to use when constructing an LLJIT instance. + * This can be used to override the default linking layer implementation + * that would otherwise be chosen by LLJITBuilder. + * + * Object linking layers returned by this function will become owned by the + * LLJIT instance. The client is not responsible for managing their lifetimes + * after the function returns. + */ +typedef LLVMOrcObjectLayerRef ( + *LLVMOrcLLJITBuilderObjectLinkingLayerCreatorFunction)( + void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple); + +/** + * A reference to an orc::LLJITBuilder instance. + */ +typedef struct LLVMOrcOpaqueLLJITBuilder *LLVMOrcLLJITBuilderRef; + +/** + * A reference to an orc::LLJIT instance. + */ +typedef struct LLVMOrcOpaqueLLJIT *LLVMOrcLLJITRef; + +/** + * Create an LLVMOrcLLJITBuilder. + * + * The client owns the resulting LLJITBuilder and should dispose of it using + * LLVMOrcDisposeLLJITBuilder once they are done with it. + */ +LLVMOrcLLJITBuilderRef LLVMOrcCreateLLJITBuilder(void); + +/** + * Dispose of an LLVMOrcLLJITBuilderRef. This should only be called if ownership + * has not been passed to LLVMOrcCreateLLJIT (e.g. because some error prevented + * that function from being called). + */ +void LLVMOrcDisposeLLJITBuilder(LLVMOrcLLJITBuilderRef Builder); + +/** + * Set the JITTargetMachineBuilder to be used when constructing the LLJIT + * instance. Calling this function is optional: if it is not called then the + * LLJITBuilder will use JITTargeTMachineBuilder::detectHost to construct a + * JITTargetMachineBuilder. + */ +void LLVMOrcLLJITBuilderSetJITTargetMachineBuilder( + LLVMOrcLLJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMB); + +/** + * Set an ObjectLinkingLayer creator function for this LLJIT instance. + */ +void LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator( + LLVMOrcLLJITBuilderRef Builder, + LLVMOrcLLJITBuilderObjectLinkingLayerCreatorFunction F, void *Ctx); + +/** + * Create an LLJIT instance from an LLJITBuilder. + * + * This operation takes ownership of the Builder argument: clients should not + * dispose of the builder after calling this function (even if the function + * returns an error). If a null Builder argument is provided then a + * default-constructed LLJITBuilder will be used. + * + * On success the resulting LLJIT instance is uniquely owned by the client and + * automatically manages the memory of all JIT'd code and all modules that are + * transferred to it (e.g. via LLVMOrcLLJITAddLLVMIRModule). Disposing of the + * LLJIT instance will free all memory managed by the JIT, including JIT'd code + * and not-yet compiled modules. + */ +LLVMErrorRef LLVMOrcCreateLLJIT(LLVMOrcLLJITRef *Result, + LLVMOrcLLJITBuilderRef Builder); + +/** + * Dispose of an LLJIT instance. + */ +LLVMErrorRef LLVMOrcDisposeLLJIT(LLVMOrcLLJITRef J); + +/** + * Get a reference to the ExecutionSession for this LLJIT instance. + * + * The ExecutionSession is owned by the LLJIT instance. The client is not + * responsible for managing its memory. + */ +LLVMOrcExecutionSessionRef LLVMOrcLLJITGetExecutionSession(LLVMOrcLLJITRef J); + +/** + * Return a reference to the Main JITDylib. + * + * The JITDylib is owned by the LLJIT instance. The client is not responsible + * for managing its memory. + */ +LLVMOrcJITDylibRef LLVMOrcLLJITGetMainJITDylib(LLVMOrcLLJITRef J); + +/** + * Return the target triple for this LLJIT instance. This string is owned by + * the LLJIT instance and should not be freed by the client. + */ +const char *LLVMOrcLLJITGetTripleString(LLVMOrcLLJITRef J); + +/** + * Returns the global prefix character according to the LLJIT's DataLayout. + */ +char LLVMOrcLLJITGetGlobalPrefix(LLVMOrcLLJITRef J); + +/** + * Mangles the given string according to the LLJIT instance's DataLayout, then + * interns the result in the SymbolStringPool and returns a reference to the + * pool entry. Clients should call LLVMOrcReleaseSymbolStringPoolEntry to + * decrement the ref-count on the pool entry once they are finished with this + * value. + */ +LLVMOrcSymbolStringPoolEntryRef +LLVMOrcLLJITMangleAndIntern(LLVMOrcLLJITRef J, const char *UnmangledName); + +/** + * Add a buffer representing an object file to the given JITDylib in the given + * LLJIT instance. This operation transfers ownership of the buffer to the + * LLJIT instance. The buffer should not be disposed of or referenced once this + * function returns. + * + * Resources associated with the given object will be tracked by the given + * JITDylib's default resource tracker. + */ +LLVMErrorRef LLVMOrcLLJITAddObjectFile(LLVMOrcLLJITRef J, LLVMOrcJITDylibRef JD, + LLVMMemoryBufferRef ObjBuffer); + +/** + * Add a buffer representing an object file to the given ResourceTracker's + * JITDylib in the given LLJIT instance. This operation transfers ownership of + * the buffer to the LLJIT instance. The buffer should not be disposed of or + * referenced once this function returns. + * + * Resources associated with the given object will be tracked by ResourceTracker + * RT. + */ +LLVMErrorRef LLVMOrcLLJITAddObjectFileWithRT(LLVMOrcLLJITRef J, + LLVMOrcResourceTrackerRef RT, + LLVMMemoryBufferRef ObjBuffer); + +/** + * Add an IR module to the given JITDylib in the given LLJIT instance. This + * operation transfers ownership of the TSM argument to the LLJIT instance. + * The TSM argument should not be disposed of or referenced once this + * function returns. + * + * Resources associated with the given Module will be tracked by the given + * JITDylib's default resource tracker. + */ +LLVMErrorRef LLVMOrcLLJITAddLLVMIRModule(LLVMOrcLLJITRef J, + LLVMOrcJITDylibRef JD, + LLVMOrcThreadSafeModuleRef TSM); + +/** + * Add an IR module to the given ResourceTracker's JITDylib in the given LLJIT + * instance. This operation transfers ownership of the TSM argument to the LLJIT + * instance. The TSM argument should not be disposed of or referenced once this + * function returns. + * + * Resources associated with the given Module will be tracked by ResourceTracker + * RT. + */ +LLVMErrorRef LLVMOrcLLJITAddLLVMIRModuleWithRT(LLVMOrcLLJITRef J, + LLVMOrcResourceTrackerRef JD, + LLVMOrcThreadSafeModuleRef TSM); + +/** + * Look up the given symbol in the main JITDylib of the given LLJIT instance. + * + * This operation does not take ownership of the Name argument. + */ +LLVMErrorRef LLVMOrcLLJITLookup(LLVMOrcLLJITRef J, + LLVMOrcJITTargetAddress *Result, + const char *Name); + +LLVM_C_EXTERN_C_END + +#endif /* LLVM_C_LLJIT_H */ diff --git a/llvm/include/llvm-c/Orc.h b/llvm/include/llvm-c/Orc.h index 09a058846108a..183107c148a6d 100644 --- a/llvm/include/llvm-c/Orc.h +++ b/llvm/include/llvm-c/Orc.h @@ -38,33 +38,201 @@ LLVM_C_EXTERN_C_BEGIN */ typedef uint64_t LLVMOrcJITTargetAddress; +/** + * Represents generic linkage flags for a symbol definition. + */ +typedef enum { + LLVMJITSymbolGenericFlagsExported = 1U << 0, + LLVMJITSymbolGenericFlagsWeak = 1U << 1 +} LLVMJITSymbolGenericFlags; + +/** + * Represents target specific flags for a symbol definition. + */ +typedef uint8_t LLVMJITTargetSymbolFlags; + +/** + * Represents the linkage flags for a symbol definition. + */ +typedef struct { + uint8_t GenericFlags; + uint8_t TargetFlags; +} LLVMJITSymbolFlags; + +/** + * Represents an evaluated symbol address and flags. + */ +typedef struct { + LLVMOrcJITTargetAddress Address; + LLVMJITSymbolFlags Flags; +} LLVMJITEvaluatedSymbol; + /** * A reference to an orc::ExecutionSession instance. */ typedef struct LLVMOrcOpaqueExecutionSession *LLVMOrcExecutionSessionRef; +/** + * Error reporter function. + */ +typedef void (*LLVMOrcErrorReporterFunction)(void *Ctx, LLVMErrorRef Err); + +/** + * A reference to an orc::SymbolStringPool. + */ +typedef struct LLVMOrcOpaqueSymbolStringPool *LLVMOrcSymbolStringPoolRef; + /** * A reference to an orc::SymbolStringPool table entry. */ -typedef struct LLVMOrcQuaqueSymbolStringPoolEntryPtr +typedef struct LLVMOrcOpaqueSymbolStringPoolEntry *LLVMOrcSymbolStringPoolEntryRef; +/** + * Represents a pair of a symbol name and an evaluated symbol. + */ +typedef struct { + LLVMOrcSymbolStringPoolEntryRef Name; + LLVMJITEvaluatedSymbol Sym; +} LLVMJITCSymbolMapPair; + +/** + * Represents a list of (SymbolStringPtr, JITEvaluatedSymbol) pairs that can be + * used to construct a SymbolMap. + */ +typedef LLVMJITCSymbolMapPair *LLVMOrcCSymbolMapPairs; + +/** + * Lookup kind. This can be used by definition generators when deciding whether + * to produce a definition for a requested symbol. + * + * This enum should be kept in sync with llvm::orc::LookupKind. + */ +typedef enum { + LLVMOrcLookupKindStatic, + LLVMOrcLookupKindDLSym +} LLVMOrcLookupKind; + +/** + * JITDylib lookup flags. This can be used by definition generators when + * deciding whether to produce a definition for a requested symbol. + * + * This enum should be kept in sync with llvm::orc::JITDylibLookupFlags. + */ +typedef enum { + LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly, + LLVMOrcJITDylibLookupFlagsMatchAllSymbols +} LLVMOrcJITDylibLookupFlags; + +/** + * Symbol lookup flags for lookup sets. This should be kept in sync with + * llvm::orc::SymbolLookupFlags. + */ +typedef enum { + LLVMOrcSymbolLookupFlagsRequiredSymbol, + LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol +} LLVMOrcSymbolLookupFlags; + +/** + * An element type for a symbol lookup set. + */ +typedef struct { + LLVMOrcSymbolStringPoolEntryRef Name; + LLVMOrcSymbolLookupFlags LookupFlags; +} LLVMOrcCLookupSetElement; + +/** + * A set of symbols to look up / generate. + * + * The list is terminated with an element containing a null pointer for the + * Name field. + * + * If a client creates an instance of this type then they are responsible for + * freeing it, and for ensuring that all strings have been retained over the + * course of its life. Clients receiving a copy from a callback are not + * responsible for managing lifetime or retain counts. + */ +typedef LLVMOrcCLookupSetElement *LLVMOrcCLookupSet; + +/** + * A reference to an orc::MaterializationUnit. + */ +typedef struct LLVMOrcOpaqueMaterializationUnit *LLVMOrcMaterializationUnitRef; + /** * A reference to an orc::JITDylib instance. */ typedef struct LLVMOrcOpaqueJITDylib *LLVMOrcJITDylibRef; /** - * A reference to an orc::JITDylib::DefinitionGenerator. + * A reference to an orc::ResourceTracker instance. + */ +typedef struct LLVMOrcOpaqueResourceTracker *LLVMOrcResourceTrackerRef; + +/** + * A reference to an orc::DefinitionGenerator. + */ +typedef struct LLVMOrcOpaqueDefinitionGenerator + *LLVMOrcDefinitionGeneratorRef; + +/** + * An opaque lookup state object. Instances of this type can be captured to + * suspend a lookup while a custom generator function attempts to produce a + * definition. + * + * If a client captures a lookup state object then they must eventually call + * LLVMOrcLookupStateContinueLookup to restart the lookup. This is required + * in order to release memory allocated for the lookup state, even if errors + * have occurred while the lookup was suspended (if these errors have made the + * lookup impossible to complete then it will issue its own error before + * destruction). + */ +typedef struct LLVMOrcOpaqueLookupState *LLVMOrcLookupStateRef; + +/** + * A custom generator function. This can be used to create a custom generator + * object using LLVMOrcCreateCustomCAPIDefinitionGenerator. The resulting + * object can be attached to a JITDylib, via LLVMOrcJITDylibAddGenerator, to + * receive callbacks when lookups fail to match existing definitions. + * + * GeneratorObj will contain the address of the custom generator object. + * + * Ctx will contain the context object passed to + * LLVMOrcCreateCustomCAPIDefinitionGenerator. + * + * LookupState will contain a pointer to an LLVMOrcLookupStateRef object. This + * can optionally be modified to make the definition generation process + * asynchronous: If the LookupStateRef value is copied, and the original + * LLVMOrcLookupStateRef set to null, the lookup will be suspended. Once the + * asynchronous definition process has been completed clients must call + * LLVMOrcLookupStateContinueLookup to continue the lookup (this should be + * done unconditionally, even if errors have occurred in the mean time, to + * free the lookup state memory and notify the query object of the failures. If + * LookupState is captured this function must return LLVMErrorSuccess. + * + * The Kind argument can be inspected to determine the lookup kind (e.g. + * as-if-during-static-link, or as-if-during-dlsym). + * + * The JD argument specifies which JITDylib the definitions should be generated + * into. + * + * The JDLookupFlags argument can be inspected to determine whether the original + * lookup included non-exported symobls. + * + * Finally, the LookupSet argument contains the set of symbols that could not + * be found in JD already (the set of generation candidates). */ -typedef struct LLVMOrcOpaqueJITDylibDefinitionGenerator - *LLVMOrcJITDylibDefinitionGeneratorRef; +typedef LLVMErrorRef (*LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction)( + LLVMOrcDefinitionGeneratorRef GeneratorObj, void *Ctx, + LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind, + LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags, + LLVMOrcCLookupSet LookupSet, size_t LookupSetSize); /** * Predicate function for SymbolStringPoolEntries. */ -typedef int (*LLVMOrcSymbolPredicate)(LLVMOrcSymbolStringPoolEntryRef Sym, - void *Ctx); +typedef int (*LLVMOrcSymbolPredicate)(void *Ctx, + LLVMOrcSymbolStringPoolEntryRef Sym); /** * A reference to an orc::ThreadSafeContext instance. @@ -83,14 +251,43 @@ typedef struct LLVMOrcOpaqueJITTargetMachineBuilder *LLVMOrcJITTargetMachineBuilderRef; /** - * A reference to an orc::LLJITBuilder instance. + * A reference to an orc::ObjectLayer instance. + */ +typedef struct LLVMOrcOpaqueObjectLayer *LLVMOrcObjectLayerRef; + +/** + * Attach a custom error reporter function to the ExecutionSession. + * + * The error reporter will be called to deliver failure notices that can not be + * directly reported to a caller. For example, failure to resolve symbols in + * the JIT linker is typically reported via the error reporter (callers + * requesting definitions from the JIT will typically be delivered a + * FailureToMaterialize error instead). + */ +void LLVMOrcExecutionSessionSetErrorReporter( + LLVMOrcExecutionSessionRef ES, LLVMOrcErrorReporterFunction ReportError, + void *Ctx); + +/** + * Return a reference to the SymbolStringPool for an ExecutionSession. + * + * Ownership of the pool remains with the ExecutionSession: The caller is + * not required to free the pool. */ -typedef struct LLVMOrcOpaqueLLJITBuilder *LLVMOrcLLJITBuilderRef; +LLVMOrcSymbolStringPoolRef +LLVMOrcExecutionSessionGetSymbolStringPool(LLVMOrcExecutionSessionRef ES); /** - * A reference to an orc::LLJIT instance. + * Clear all unreferenced symbol string pool entries. + * + * This can be called at any time to release unused entries in the + * ExecutionSession's string pool. Since it locks the pool (preventing + * interning of any new strings) it is recommended that it only be called + * infrequently, ideally when the caller has reason to believe that some + * entries will have become unreferenced, e.g. after removing a module or + * closing a JITDylib. */ -typedef struct LLVMOrcOpaqueLLJIT *LLVMOrcLLJITRef; +void LLVMOrcSymbolStringPoolClearDeadEntries(LLVMOrcSymbolStringPoolRef SSP); /** * Intern a string in the ExecutionSession's SymbolStringPool and return a @@ -107,27 +304,138 @@ typedef struct LLVMOrcOpaqueLLJIT *LLVMOrcLLJITRef; LLVMOrcSymbolStringPoolEntryRef LLVMOrcExecutionSessionIntern(LLVMOrcExecutionSessionRef ES, const char *Name); +/** + * Increments the ref-count for a SymbolStringPool entry. + */ +void LLVMOrcRetainSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S); + /** * Reduces the ref-count for of a SymbolStringPool entry. */ void LLVMOrcReleaseSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S); +const char *LLVMOrcSymbolStringPoolEntryStr(LLVMOrcSymbolStringPoolEntryRef S); + +/** + * Reduces the ref-count of a ResourceTracker. + */ +void LLVMOrcReleaseResourceTracker(LLVMOrcResourceTrackerRef RT); + +/** + * Transfers tracking of all resources associated with resource tracker SrcRT + * to resource tracker DstRT. + */ +void LLVMOrcResourceTrackerTransferTo(LLVMOrcResourceTrackerRef SrcRT, + LLVMOrcResourceTrackerRef DstRT); + +/** + * Remove all resources associated with the given tracker. See + * ResourceTracker::remove(). + */ +LLVMErrorRef LLVMOrcResourceTrackerRemove(LLVMOrcResourceTrackerRef RT); + /** * Dispose of a JITDylib::DefinitionGenerator. This should only be called if * ownership has not been passed to a JITDylib (e.g. because some error * prevented the client from calling LLVMOrcJITDylibAddGenerator). */ -void LLVMOrcDisposeJITDylibDefinitionGenerator( - LLVMOrcJITDylibDefinitionGeneratorRef DG); +void LLVMOrcDisposeDefinitionGenerator( + LLVMOrcDefinitionGeneratorRef DG); /** - * Add a JITDylib::DefinitionGenerator to the given JITDylib. + * Dispose of a MaterializationUnit. + */ +void LLVMOrcDisposeMaterializationUnit(LLVMOrcMaterializationUnitRef MU); + +/** + * Create a MaterializationUnit to define the given symbols as pointing to + * the corresponding raw addresses. + */ +LLVMOrcMaterializationUnitRef +LLVMOrcAbsoluteSymbols(LLVMOrcCSymbolMapPairs Syms, size_t NumPairs); + +/** + * Create a "bare" JITDylib. + * + * The client is responsible for ensuring that the JITDylib's name is unique, + * e.g. by calling LLVMOrcExecutionSessionGetJTIDylibByName first. + * + * This call does not install any library code or symbols into the newly + * created JITDylib. The client is responsible for all configuration. + */ +LLVMOrcJITDylibRef +LLVMOrcExecutionSessionCreateBareJITDylib(LLVMOrcExecutionSessionRef ES, + const char *Name); + +/** + * Create a JITDylib. + * + * The client is responsible for ensuring that the JITDylib's name is unique, + * e.g. by calling LLVMOrcExecutionSessionGetJTIDylibByName first. + * + * If a Platform is attached to the ExecutionSession then + * Platform::setupJITDylib will be called to install standard platform symbols + * (e.g. standard library interposes). If no Platform is installed then this + * call is equivalent to LLVMExecutionSessionRefCreateBareJITDylib and will + * always return success. + */ +LLVMErrorRef +LLVMOrcExecutionSessionCreateJITDylib(LLVMOrcExecutionSessionRef ES, + LLVMOrcJITDylibRef *Result, + const char *Name); + +/** + * Returns the JITDylib with the given name, or NULL if no such JITDylib + * exists. + */ +LLVMOrcJITDylibRef LLVMOrcExecutionSessionGetJITDylibByName(const char *Name); + +/** + * Return a reference to a newly created resource tracker associated with JD. + * The tracker is returned with an initial ref-count of 1, and must be released + * with LLVMOrcReleaseResourceTracker when no longer needed. + */ +LLVMOrcResourceTrackerRef +LLVMOrcJITDylibCreateResourceTracker(LLVMOrcJITDylibRef JD); + +/** + * Return a reference to the default resource tracker for the given JITDylib. + * This operation will increase the retain count of the tracker: Clients should + * call LLVMOrcReleaseResourceTracker when the result is no longer needed. + */ +LLVMOrcResourceTrackerRef +LLVMOrcJITDylibGetDefaultResourceTracker(LLVMOrcJITDylibRef JD); + +/** + * Add the given MaterializationUnit to the given JITDylib. + * + * If this operation succeeds then JITDylib JD will take ownership of MU. + * If the operation fails then ownership remains with the caller who should + * call LLVMOrcDisposeMaterializationUnit to destroy it. + */ +LLVMErrorRef LLVMOrcJITDylibDefine(LLVMOrcJITDylibRef JD, + LLVMOrcMaterializationUnitRef MU); + +/** + * Calls remove on all trackers associated with this JITDylib, see + * JITDylib::clear(). + */ +LLVMErrorRef LLVMOrcJITDylibClear(LLVMOrcJITDylibRef JD); + +/** + * Add a DefinitionGenerator to the given JITDylib. * * The JITDylib will take ownership of the given generator: The client is no * longer responsible for managing its memory. */ void LLVMOrcJITDylibAddGenerator(LLVMOrcJITDylibRef JD, - LLVMOrcJITDylibDefinitionGeneratorRef DG); + LLVMOrcDefinitionGeneratorRef DG); + +/** + * Create a custom generator. + */ +LLVMOrcDefinitionGeneratorRef LLVMOrcCreateCustomCAPIDefinitionGenerator( + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction F, void *Ctx); /** * Get a DynamicLibrarySearchGenerator that will reflect process symbols into @@ -148,7 +456,7 @@ void LLVMOrcJITDylibAddGenerator(LLVMOrcJITDylibRef JD, * the global prefix if present. */ LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( - LLVMOrcJITDylibDefinitionGeneratorRef *Result, char GlobalPrefx, + LLVMOrcDefinitionGeneratorRef *Result, char GlobalPrefx, LLVMOrcSymbolPredicate Filter, void *FilterCtx); /** @@ -156,7 +464,7 @@ LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( * * Ownership of the underlying ThreadSafeContext data is shared: Clients * can and should dispose of their ThreadSafeContext as soon as they no longer - * need to refer to it directly. Other references (e.g. from ThreadSafeModules + * need to refer to it directly. Other references (e.g. from ThreadSafeModules) * will keep the data alive as long as it is needed. */ LLVMOrcThreadSafeContextRef LLVMOrcCreateNewThreadSafeContext(void); @@ -178,7 +486,7 @@ void LLVMOrcDisposeThreadSafeContext(LLVMOrcThreadSafeContextRef TSCtx); * after this function returns. * * Ownership of the ThreadSafeModule is unique: If it is transferred to the JIT - * (e.g. by LLVMOrcLLJITAddLLVMIRModule), in which case the client is no longer + * (e.g. by LLVMOrcLLJITAddLLVMIRModule) then the client is no longer * responsible for it. If it is not transferred to the JIT then the client * should call LLVMOrcDisposeThreadSafeModule to dispose of it. */ @@ -221,114 +529,9 @@ void LLVMOrcDisposeJITTargetMachineBuilder( LLVMOrcJITTargetMachineBuilderRef JTMB); /** - * Create an LLJITTargetMachineBuilder. - * - * The client owns the resulting LLJITBuilder and should dispose of it using - * LLVMOrcDisposeLLJITBuilder once they are done with it. - */ -LLVMOrcLLJITBuilderRef LLVMOrcCreateLLJITBuilder(void); - -/** - * Dispose of an LLVMOrcLLJITBuilderRef. This should only be called if ownership - * has not been passed to LLVMOrcCreateLLJIT (e.g. because some error prevented - * that function from being called). - */ -void LLVMOrcDisposeLLJITBuilder(LLVMOrcLLJITBuilderRef Builder); - -/** - * Set the JITTargetMachineBuilder to be used when constructing the LLJIT - * instance. Calling this function is optional: if it is not called then the - * LLJITBuilder will use JITTargeTMachineBuilder::detectHost to construct a - * JITTargetMachineBuilder. - */ -void LLVMOrcLLJITBuilderSetJITTargetMachineBuilder( - LLVMOrcLLJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMB); - -/** - * Create an LLJIT instance from an LLJITBuilder. - * - * This operation takes ownership of the Builder argument: clients should not - * dispose of the builder after calling this function (even if the function - * returns an error). If a null Builder argument is provided then a - * default-constructed LLJITBuilder will be used. - * - * On success the resulting LLJIT instance is uniquely owned by the client and - * automatically manages the memory of all JIT'd code and all modules that are - * transferred to it (e.g. via LLVMOrcLLJITAddLLVMIRModule). Disposing of the - * LLJIT instance will free all memory managed by the JIT, including JIT'd code - * and not-yet compiled modules. - */ -LLVMErrorRef LLVMOrcCreateLLJIT(LLVMOrcLLJITRef *Result, - LLVMOrcLLJITBuilderRef Builder); - -/** - * Dispose of an LLJIT instance. - */ -LLVMErrorRef LLVMOrcDisposeLLJIT(LLVMOrcLLJITRef J); - -/** - * Get a reference to the ExecutionSession for this LLJIT instance. - * - * The ExecutionSession is owned by the LLJIT instance. The client is not - * responsible for managing its memory. - */ -LLVMOrcExecutionSessionRef LLVMOrcLLJITGetExecutionSession(LLVMOrcLLJITRef J); - -/** - * Return a reference to the Main JITDylib. - * - * The JITDylib is owned by the LLJIT instance. The client is not responsible - * for managing its memory. - */ -LLVMOrcJITDylibRef LLVMOrcLLJITGetMainJITDylib(LLVMOrcLLJITRef J); - -/** - * Return the target triple for this LLJIT instance. This string is owned by - * the LLJIT instance and should not be freed by the client. - */ -const char *LLVMOrcLLJITGetTripleString(LLVMOrcLLJITRef J); - -/** - * Returns the global prefix character according to the LLJIT's DataLayout. - */ -char LLVMOrcLLJITGetGlobalPrefix(LLVMOrcLLJITRef J); - -/** - * Mangles the given string according to the LLJIT instance's DataLayout, then - * interns the result in the SymbolStringPool and returns a reference to the - * pool entry. Clients should call LLVMOrcReleaseSymbolStringPoolEntry to - * decrement the ref-count on the pool entry once they are finished with this - * value. - */ -LLVMOrcSymbolStringPoolEntryRef -LLVMOrcLLJITMangleAndIntern(LLVMOrcLLJITRef J, const char *UnmangledName); - -/** - * Add a buffer representing an object file to the given JITDylib in the given - * LLJIT instance. This operation transfers ownership of the buffer to the - * LLJIT instance. The buffer should not be disposed of or referenced once this - * function returns. - */ -LLVMErrorRef LLVMOrcLLJITAddObjectFile(LLVMOrcLLJITRef J, LLVMOrcJITDylibRef JD, - LLVMMemoryBufferRef ObjBuffer); - -/** - * Add an IR module to the given JITDylib of the given LLJIT instance. This - * operation transfers ownership of the TSM argument to the LLJIT instance. - * The TSM argument should not be 3disposed of or referenced once this - * function returns. - */ -LLVMErrorRef LLVMOrcLLJITAddLLVMIRModule(LLVMOrcLLJITRef J, - LLVMOrcJITDylibRef JD, - LLVMOrcThreadSafeModuleRef TSM); -/** - * Look up the given symbol in the main JITDylib of the given LLJIT instance. - * - * This operation does not take ownership of the Name argument. + * Dispose of an ObjectLayer. */ -LLVMErrorRef LLVMOrcLLJITLookup(LLVMOrcLLJITRef J, - LLVMOrcJITTargetAddress *Result, - const char *Name); +void LLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer); LLVM_C_EXTERN_C_END diff --git a/llvm/include/llvm-c/OrcBindings.h b/llvm/include/llvm-c/OrcBindings.h deleted file mode 100644 index 11cdade7c26fc..0000000000000 --- a/llvm/include/llvm-c/OrcBindings.h +++ /dev/null @@ -1,169 +0,0 @@ -/*===----------- llvm-c/OrcBindings.h - Orc Lib C Iface ---------*- C++ -*-===*\ -|* *| -|* 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 *| -|* *| -|*===----------------------------------------------------------------------===*| -|* *| -|* This header declares the C interface to libLLVMOrcJIT.a, which implements *| -|* JIT compilation of LLVM IR. *| -|* *| -|* Many exotic languages can interoperate with C code but have a harder time *| -|* with C++ due to name mangling. So in addition to C, this interface enables *| -|* tools written in such languages. *| -|* *| -|* Note: This interface is experimental. It is *NOT* stable, and may be *| -|* changed without warning. *| -|* *| -\*===----------------------------------------------------------------------===*/ - -#ifndef LLVM_C_ORCBINDINGS_H -#define LLVM_C_ORCBINDINGS_H - -#include "llvm-c/Error.h" -#include "llvm-c/ExternC.h" -#include "llvm-c/Object.h" -#include "llvm-c/TargetMachine.h" - -LLVM_C_EXTERN_C_BEGIN - -typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef; -typedef uint64_t LLVMOrcModuleHandle; -typedef uint64_t LLVMOrcTargetAddress; -typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx); -typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack, - void *CallbackCtx); - -/** - * Create an ORC JIT stack. - * - * The client owns the resulting stack, and must call OrcDisposeInstance(...) - * to destroy it and free its memory. The JIT stack will take ownership of the - * TargetMachine, which will be destroyed when the stack is destroyed. The - * client should not attempt to dispose of the Target Machine, or it will result - * in a double-free. - */ -LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM); - -/** - * Get the error message for the most recent error (if any). - * - * This message is owned by the ORC JIT Stack and will be freed when the stack - * is disposed of by LLVMOrcDisposeInstance. - */ -const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack); - -/** - * Mangle the given symbol. - * Memory will be allocated for MangledSymbol to hold the result. The client - */ -void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol, - const char *Symbol); - -/** - * Dispose of a mangled symbol. - */ -void LLVMOrcDisposeMangledSymbol(char *MangledSymbol); - -/** - * Create a lazy compile callback. - */ -LLVMErrorRef LLVMOrcCreateLazyCompileCallback( - LLVMOrcJITStackRef JITStack, LLVMOrcTargetAddress *RetAddr, - LLVMOrcLazyCompileCallbackFn Callback, void *CallbackCtx); - -/** - * Create a named indirect call stub. - */ -LLVMErrorRef LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, - const char *StubName, - LLVMOrcTargetAddress InitAddr); - -/** - * Set the pointer for the given indirect stub. - */ -LLVMErrorRef LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, - const char *StubName, - LLVMOrcTargetAddress NewAddr); - -/** - * Add module to be eagerly compiled. - */ -LLVMErrorRef LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle *RetHandle, - LLVMModuleRef Mod, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx); - -/** - * Add module to be lazily compiled one function at a time. - */ -LLVMErrorRef LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle *RetHandle, - LLVMModuleRef Mod, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx); - -/** - * Add an object file. - * - * This method takes ownership of the given memory buffer and attempts to add - * it to the JIT as an object file. - * Clients should *not* dispose of the 'Obj' argument: the JIT will manage it - * from this call onwards. - */ -LLVMErrorRef LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle *RetHandle, - LLVMMemoryBufferRef Obj, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx); - -/** - * Remove a module set from the JIT. - * - * This works for all modules that can be added via OrcAdd*, including object - * files. - */ -LLVMErrorRef LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle H); - -/** - * Get symbol address from JIT instance. - */ -LLVMErrorRef LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack, - LLVMOrcTargetAddress *RetAddr, - const char *SymbolName); - -/** - * Get symbol address from JIT instance, searching only the specified - * handle. - */ -LLVMErrorRef LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack, - LLVMOrcTargetAddress *RetAddr, - LLVMOrcModuleHandle H, - const char *SymbolName); - -/** - * Dispose of an ORC JIT stack. - */ -LLVMErrorRef LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack); - -/** - * Register a JIT Event Listener. - * - * A NULL listener is ignored. - */ -void LLVMOrcRegisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L); - -/** - * Unegister a JIT Event Listener. - * - * A NULL listener is ignored. - */ -void LLVMOrcUnregisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L); - -LLVM_C_EXTERN_C_END - -#endif /* LLVM_C_ORCBINDINGS_H */ diff --git a/llvm/include/llvm-c/OrcEE.h b/llvm/include/llvm-c/OrcEE.h new file mode 100644 index 0000000000000..2435e7421a42b --- /dev/null +++ b/llvm/include/llvm-c/OrcEE.h @@ -0,0 +1,55 @@ +/*===-- llvm-c/OrcEE.h - OrcV2 C bindings ExecutionEngine utils -*- C++ -*-===*\ +|* *| +|* 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to ExecutionEngine based utils, e.g. *| +|* RTDyldObjectLinkingLayer (based on RuntimeDyld) in Orc. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +|* Note: This interface is experimental. It is *NOT* stable, and may be *| +|* changed without warning. Only C API usage documentation is *| +|* provided. See the C++ documentation for all higher level ORC API *| +|* details. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_ORCEE_H +#define LLVM_C_ORCEE_H + +#include "llvm-c/Error.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm-c/Orc.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" + +LLVM_C_EXTERN_C_BEGIN + +/** + * Create a RTDyldObjectLinkingLayer instance using the standard + * SectionMemoryManager for memory management. + */ +LLVMOrcObjectLayerRef +LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager( + LLVMOrcExecutionSessionRef ES); + +/** + * Add the given listener to the given RTDyldObjectLinkingLayer. + * + * Note: Layer must be an RTDyldObjectLinkingLayer instance or + * behavior is undefined. + */ +void LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener( + LLVMOrcObjectLayerRef RTDyldObjLinkingLayer, + LLVMJITEventListenerRef Listener); + +LLVM_C_EXTERN_C_END + +#endif /* LLVM_C_ORCEE_H */ diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h index be3c5ebcadaeb..2fb61b9edf559 100644 --- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h @@ -202,9 +202,9 @@ using UnitListTy = std::vector>; /// this class represents DWARF information for source file /// and it`s address map. -class DwarfFile { +class DWARFFile { public: - DwarfFile(StringRef Name, DWARFContext *Dwarf, AddressesMap *Addresses, + DWARFFile(StringRef Name, DWARFContext *Dwarf, AddressesMap *Addresses, const std::vector &Warnings) : FileName(Name), Dwarf(Dwarf), Addresses(Addresses), Warnings(Warnings) { } @@ -222,7 +222,7 @@ class DwarfFile { typedef std::function messageHandler; -typedef std::function(StringRef ContainerName, +typedef std::function(StringRef ContainerName, StringRef Path)> objFileLoader; typedef std::map swiftInterfacesMap; @@ -249,7 +249,7 @@ class DWARFLinker { : TheDwarfEmitter(Emitter), DwarfLinkerClientID(ClientID) {} /// Add object file to be linked. - void addObjectFile(DwarfFile &File); + void addObjectFile(DWARFFile &File); /// Link debug info for added objFiles. Object /// files are linked all together. @@ -376,13 +376,13 @@ class DWARFLinker { /// returns true if we need to translate strings. bool needToTranslateStrings() { return StringsTranslator != nullptr; } - void reportWarning(const Twine &Warning, const DwarfFile &File, + void reportWarning(const Twine &Warning, const DWARFFile &File, const DWARFDie *DIE = nullptr) const { if (Options.WarningHandler != nullptr) Options.WarningHandler(Warning, File.FileName, DIE); } - void reportError(const Twine &Warning, const DwarfFile &File, + void reportError(const Twine &Warning, const DWARFFile &File, const DWARFDie *DIE = nullptr) const { if (Options.ErrorHandler != nullptr) Options.ErrorHandler(Warning, File.FileName, DIE); @@ -398,18 +398,18 @@ class DWARFLinker { void updateAccelKind(DWARFContext &Dwarf); /// Emit warnings as Dwarf compile units to leave a trail after linking. - bool emitPaperTrailWarnings(const DwarfFile &File, + bool emitPaperTrailWarnings(const DWARFFile &File, OffsetsStringPool &StringPool); void copyInvariantDebugSection(DWARFContext &Dwarf); /// Keeps track of data associated with one object during linking. struct LinkContext { - DwarfFile &File; + DWARFFile &File; UnitListTy CompileUnits; bool Skip = false; - LinkContext(DwarfFile &File) : File(File) {} + LinkContext(DWARFFile &File) : File(File) {} /// Clear part of the context that's no longer needed when we're done with /// the debug object. @@ -438,7 +438,7 @@ class DWARFLinker { /// kept. All DIEs referenced though attributes should be kept. void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, unsigned Flags, const UnitListTy &Units, - const DwarfFile &File, + const DWARFFile &File, SmallVectorImpl &Worklist); /// \defgroup FindRootDIEs Find DIEs corresponding to Address map entries. @@ -450,7 +450,7 @@ class DWARFLinker { /// The return value indicates whether the DIE is incomplete. void lookForDIEsToKeep(AddressesMap &RelocMgr, RangesTy &Ranges, const UnitListTy &Units, const DWARFDie &DIE, - const DwarfFile &File, CompileUnit &CU, + const DWARFFile &File, CompileUnit &CU, unsigned Flags); /// If this compile unit is really a skeleton CU that points to a @@ -460,7 +460,7 @@ class DWARFLinker { /// pointing to the module, and a DW_AT_gnu_dwo_id with the module /// hash. bool registerModuleReference(DWARFDie CUDie, const DWARFUnit &Unit, - const DwarfFile &File, + const DWARFFile &File, OffsetsStringPool &OffsetsStringPool, UniquingStringPool &UniquingStringPoolStringPool, DeclContextTree &ODRContexts, @@ -473,7 +473,7 @@ class DWARFLinker { /// to Units. Error loadClangModule(DWARFDie CUDie, StringRef FilePath, StringRef ModuleName, uint64_t DwoId, - const DwarfFile &File, + const DWARFFile &File, OffsetsStringPool &OffsetsStringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, uint64_t ModulesEndOffset, @@ -484,11 +484,11 @@ class DWARFLinker { void keepDIEAndDependencies(AddressesMap &RelocMgr, RangesTy &Ranges, const UnitListTy &Units, const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo, - const DwarfFile &File, CompileUnit &CU, + const DWARFFile &File, CompileUnit &CU, bool UseODR); unsigned shouldKeepDIE(AddressesMap &RelocMgr, RangesTy &Ranges, - const DWARFDie &DIE, const DwarfFile &File, + const DWARFDie &DIE, const DWARFFile &File, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); @@ -499,7 +499,7 @@ class DWARFLinker { CompileUnit::DIEInfo &MyInfo, unsigned Flags); unsigned shouldKeepSubprogramDIE(AddressesMap &RelocMgr, RangesTy &Ranges, - const DWARFDie &DIE, const DwarfFile &File, + const DWARFDie &DIE, const DWARFFile &File, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags); @@ -508,7 +508,7 @@ class DWARFLinker { /// RefValue. The resulting DIE might be in another CompileUnit which is /// stored into \p ReferencedCU. \returns null if resolving fails for any /// reason. - DWARFDie resolveDIEReference(const DwarfFile &File, const UnitListTy &Units, + DWARFDie resolveDIEReference(const DWARFFile &File, const UnitListTy &Units, const DWARFFormValue &RefValue, const DWARFDie &DIE, CompileUnit *&RefCU); @@ -523,7 +523,7 @@ class DWARFLinker { class DIECloner { DWARFLinker &Linker; DwarfEmitter *Emitter; - DwarfFile &ObjFile; + DWARFFile &ObjFile; /// Allocator used for all the DIEValue objects. BumpPtrAllocator &DIEAlloc; @@ -533,7 +533,7 @@ class DWARFLinker { bool Update; public: - DIECloner(DWARFLinker &Linker, DwarfEmitter *Emitter, DwarfFile &ObjFile, + DIECloner(DWARFLinker &Linker, DwarfEmitter *Emitter, DWARFFile &ObjFile, BumpPtrAllocator &DIEAlloc, std::vector> &CompileUnits, bool Update) @@ -551,7 +551,7 @@ class DWARFLinker { /// applied to the entry point of the function to get the linked address. /// \param Die the output DIE to use, pass NULL to create one. /// \returns the root of the cloned tree or null if nothing was selected. - DIE *cloneDIE(const DWARFDie &InputDIE, const DwarfFile &File, + DIE *cloneDIE(const DWARFDie &InputDIE, const DWARFFile &File, CompileUnit &U, OffsetsStringPool &StringPool, int64_t PCOffset, uint32_t OutOffset, unsigned Flags, bool IsLittleEndian, DIE *Die = nullptr); @@ -560,7 +560,7 @@ class DWARFLinker { /// chose to keep above. If there are no valid relocs, then there's /// nothing to clone/emit. uint64_t cloneAllCompileUnits(DWARFContext &DwarfContext, - const DwarfFile &File, + const DWARFFile &File, OffsetsStringPool &StringPool, bool IsLittleEndian); @@ -606,7 +606,7 @@ class DWARFLinker { /// Helper for cloneDIE. unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE, - const DwarfFile &File, CompileUnit &U, + const DWARFFile &File, CompileUnit &U, OffsetsStringPool &StringPool, const DWARFFormValue &Val, const AttributeSpec AttrSpec, unsigned AttrSize, @@ -627,18 +627,18 @@ class DWARFLinker { AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val, - const DwarfFile &File, + const DWARFFile &File, CompileUnit &Unit); /// Clone a DWARF expression that may be referencing another DIE. void cloneExpression(DataExtractor &Data, DWARFExpression Expression, - const DwarfFile &File, CompileUnit &Unit, + const DWARFFile &File, CompileUnit &Unit, SmallVectorImpl &OutputBuffer); /// Clone an attribute referencing another DIE and add /// it to \p Die. /// \returns the size of the new attribute. - unsigned cloneBlockAttribute(DIE &Die, const DwarfFile &File, + unsigned cloneBlockAttribute(DIE &Die, const DWARFFile &File, CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, bool IsLittleEndian); @@ -654,7 +654,7 @@ class DWARFLinker { /// Clone a scalar attribute and add it to \p Die. /// \returns the size of the new attribute. unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE, - const DwarfFile &File, CompileUnit &U, + const DWARFFile &File, CompileUnit &U, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, AttributesInfo &Info); @@ -670,7 +670,7 @@ class DWARFLinker { void copyAbbrev(const DWARFAbbreviationDeclaration &Abbrev, bool hasODR); uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, - const DwarfFile &File, + const DWARFFile &File, int RecurseDepth = 0); /// Helper for cloneDIE. @@ -685,7 +685,7 @@ class DWARFLinker { /// Compute and emit debug_ranges section for \p Unit, and /// patch the attributes referencing it. void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf, - const DwarfFile &File) const; + const DWARFFile &File) const; /// Generate and emit the DW_AT_ranges attribute for a compile_unit if it had /// one. @@ -695,7 +695,7 @@ class DWARFLinker { /// parts according to the linked function ranges and emit the result in the /// debug_line section. void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf, - const DwarfFile &File); + const DWARFFile &File); /// Emit the accelerator entries for \p Unit. void emitAcceleratorEntriesForUnit(CompileUnit &Unit); @@ -703,7 +703,7 @@ class DWARFLinker { void emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit); /// Patch the frame info for an object file and emit it. - void patchFrameInfoForObject(const DwarfFile &, RangesTy &Ranges, + void patchFrameInfoForObject(const DWARFFile &, RangesTy &Ranges, DWARFContext &, unsigned AddressSize); /// FoldingSet that uniques the abbreviations. diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h index 2982146f960c9..88849d024c233 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -42,7 +42,6 @@ class StringRef; class raw_ostream; namespace pdb { -class IPDBRawSymbol; class IPDBSession; #define DECLARE_PDB_SYMBOL_CONCRETE_TYPE(TagValue) \ diff --git a/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h b/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h index 2562da7cf60b4..2e386518f0bfa 100644 --- a/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -142,11 +142,6 @@ class ExecutionEngine { std::shared_ptr SR, std::unique_ptr TM); - static ExecutionEngine *(*OrcMCJITReplacementCtor)( - std::string *ErrorStr, std::shared_ptr MM, - std::shared_ptr SR, - std::unique_ptr TM); - static ExecutionEngine *(*InterpCtor)(std::unique_ptr M, std::string *ErrorStr); @@ -552,7 +547,6 @@ class EngineBuilder { std::string MCPU; SmallVector MAttrs; bool VerifyModules; - bool UseOrcMCJITReplacement; bool EmulatedTLS = true; public: @@ -648,17 +642,6 @@ class EngineBuilder { return *this; } - // Use OrcMCJITReplacement instead of MCJIT. Off by default. - LLVM_ATTRIBUTE_DEPRECATED( - inline void setUseOrcMCJITReplacement(bool UseOrcMCJITReplacement), - "ORCv1 utilities (including OrcMCJITReplacement) are deprecated. Please " - "use ORCv2/LLJIT instead (see docs/ORCv2.rst)"); - - void setUseOrcMCJITReplacement(ORCv1DeprecationAcknowledgement, - bool UseOrcMCJITReplacement) { - this->UseOrcMCJITReplacement = UseOrcMCJITReplacement; - } - void setEmulatedTLS(bool EmulatedTLS) { this->EmulatedTLS = EmulatedTLS; } @@ -679,10 +662,6 @@ class EngineBuilder { ExecutionEngine *create(TargetMachine *TM); }; -void EngineBuilder::setUseOrcMCJITReplacement(bool UseOrcMCJITReplacement) { - this->UseOrcMCJITReplacement = UseOrcMCJITReplacement; -} - // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionEngine, LLVMExecutionEngineRef) diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h index 72687682f606c..72394d7c99854 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h @@ -42,32 +42,11 @@ class EHFrameRegistrar { /// Registers / Deregisters EH-frames in the current process. class InProcessEHFrameRegistrar final : public EHFrameRegistrar { public: - /// Get a reference to the InProcessEHFrameRegistrar singleton. - static InProcessEHFrameRegistrar &getInstance(); - - InProcessEHFrameRegistrar(const InProcessEHFrameRegistrar &) = delete; - InProcessEHFrameRegistrar & - operator=(const InProcessEHFrameRegistrar &) = delete; - - InProcessEHFrameRegistrar(InProcessEHFrameRegistrar &&) = delete; - InProcessEHFrameRegistrar &operator=(InProcessEHFrameRegistrar &&) = delete; - Error registerEHFrames(JITTargetAddress EHFrameSectionAddr, - size_t EHFrameSectionSize) override { - return registerEHFrameSection( - jitTargetAddressToPointer(EHFrameSectionAddr), - EHFrameSectionSize); - } + size_t EHFrameSectionSize) override; Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr, - size_t EHFrameSectionSize) override { - return deregisterEHFrameSection( - jitTargetAddressToPointer(EHFrameSectionAddr), - EHFrameSectionSize); - } - -private: - InProcessEHFrameRegistrar(); + size_t EHFrameSectionSize) override; }; using StoreFrameRangeFunction = diff --git a/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 9ecc0464dec1b..67aa09b2f1a74 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -20,10 +20,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/Layer.h" #include "llvm/ExecutionEngine/Orc/LazyReexports.h" -#include "llvm/ExecutionEngine/Orc/Legacy.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" #include "llvm/ExecutionEngine/Orc/Speculation.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" @@ -96,7 +94,8 @@ class CompileOnDemandLayer : public IRLayer { /// Emits the given module. This should not be called by clients: it will be /// called by the JIT when a definition added via the add method is requested. - void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override; + void emit(std::unique_ptr R, + ThreadSafeModule TSM) override; private: struct PerDylibResources { @@ -120,7 +119,8 @@ class CompileOnDemandLayer : public IRLayer { void expandPartition(GlobalValueSet &Partition); - void emitPartition(MaterializationResponsibility R, ThreadSafeModule TSM, + void emitPartition(std::unique_ptr R, + ThreadSafeModule TSM, IRMaterializationUnit::SymbolNameToDefinitionMap Defs); mutable std::mutex CODLayerMutex; @@ -134,635 +134,6 @@ class CompileOnDemandLayer : public IRLayer { ImplSymbolMap *AliaseeImpls = nullptr; }; -/// Compile-on-demand layer. -/// -/// When a module is added to this layer a stub is created for each of its -/// function definitions. The stubs and other global values are immediately -/// added to the layer below. When a stub is called it triggers the extraction -/// of the function body from the original module. The extracted body is then -/// compiled and executed. -template -class LegacyCompileOnDemandLayer { -private: - template - class LambdaMaterializer final : public ValueMaterializer { - public: - LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} - - Value *materialize(Value *V) final { return M(V); } - - private: - MaterializerFtor M; - }; - - template - LambdaMaterializer - createLambdaMaterializer(MaterializerFtor M) { - return LambdaMaterializer(std::move(M)); - } - - // Provide type-erasure for the Modules and MemoryManagers. - template - class ResourceOwner { - public: - ResourceOwner() = default; - ResourceOwner(const ResourceOwner &) = delete; - ResourceOwner &operator=(const ResourceOwner &) = delete; - virtual ~ResourceOwner() = default; - - virtual ResourceT& getResource() const = 0; - }; - - template - class ResourceOwnerImpl : public ResourceOwner { - public: - ResourceOwnerImpl(ResourcePtrT ResourcePtr) - : ResourcePtr(std::move(ResourcePtr)) {} - - ResourceT& getResource() const override { return *ResourcePtr; } - - private: - ResourcePtrT ResourcePtr; - }; - - template - std::unique_ptr> - wrapOwnership(ResourcePtrT ResourcePtr) { - using RO = ResourceOwnerImpl; - return std::make_unique(std::move(ResourcePtr)); - } - - struct LogicalDylib { - struct SourceModuleEntry { - std::unique_ptr SourceMod; - std::set StubsToClone; - }; - - using SourceModulesList = std::vector; - using SourceModuleHandle = typename SourceModulesList::size_type; - - LogicalDylib() = default; - - LogicalDylib(VModuleKey K, std::shared_ptr BackingResolver, - std::unique_ptr StubsMgr) - : K(std::move(K)), BackingResolver(std::move(BackingResolver)), - StubsMgr(std::move(StubsMgr)) {} - - SourceModuleHandle addSourceModule(std::unique_ptr M) { - SourceModuleHandle H = SourceModules.size(); - SourceModules.push_back(SourceModuleEntry()); - SourceModules.back().SourceMod = std::move(M); - return H; - } - - Module& getSourceModule(SourceModuleHandle H) { - return *SourceModules[H].SourceMod; - } - - std::set& getStubsToClone(SourceModuleHandle H) { - return SourceModules[H].StubsToClone; - } - - JITSymbol findSymbol(BaseLayerT &BaseLayer, const std::string &Name, - bool ExportedSymbolsOnly) { - if (auto Sym = StubsMgr->findStub(Name, ExportedSymbolsOnly)) - return Sym; - for (auto BLK : BaseLayerVModuleKeys) - if (auto Sym = BaseLayer.findSymbolIn(BLK, Name, ExportedSymbolsOnly)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - return nullptr; - } - - Error removeModulesFromBaseLayer(BaseLayerT &BaseLayer) { - for (auto &BLK : BaseLayerVModuleKeys) - if (auto Err = BaseLayer.removeModule(BLK)) - return Err; - return Error::success(); - } - - VModuleKey K; - std::shared_ptr BackingResolver; - std::unique_ptr StubsMgr; - SymbolLinkagePromoter PromoteSymbols; - SourceModulesList SourceModules; - std::vector BaseLayerVModuleKeys; - }; - -public: - - /// Module partitioning functor. - using PartitioningFtor = std::function(Function&)>; - - /// Builder for IndirectStubsManagers. - using IndirectStubsManagerBuilderT = - std::function()>; - - using SymbolResolverGetter = - std::function(VModuleKey K)>; - - using SymbolResolverSetter = - std::function R)>; - - /// Construct a compile-on-demand layer instance. - LLVM_ATTRIBUTE_DEPRECATED( - LegacyCompileOnDemandLayer( - ExecutionSession &ES, BaseLayerT &BaseLayer, - SymbolResolverGetter GetSymbolResolver, - SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition, - CompileCallbackMgrT &CallbackMgr, - IndirectStubsManagerBuilderT CreateIndirectStubsManager, - bool CloneStubsIntoPartitions = true), - "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please " - "use " - "the ORCv2 LegacyCompileOnDemandLayer instead"); - - /// Legacy layer constructor with deprecation acknowledgement. - LegacyCompileOnDemandLayer( - ORCv1DeprecationAcknowledgement, ExecutionSession &ES, - BaseLayerT &BaseLayer, SymbolResolverGetter GetSymbolResolver, - SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition, - CompileCallbackMgrT &CallbackMgr, - IndirectStubsManagerBuilderT CreateIndirectStubsManager, - bool CloneStubsIntoPartitions = true) - : ES(ES), BaseLayer(BaseLayer), - GetSymbolResolver(std::move(GetSymbolResolver)), - SetSymbolResolver(std::move(SetSymbolResolver)), - Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr), - CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)), - CloneStubsIntoPartitions(CloneStubsIntoPartitions) {} - - ~LegacyCompileOnDemandLayer() { - // FIXME: Report error on log. - while (!LogicalDylibs.empty()) - consumeError(removeModule(LogicalDylibs.begin()->first)); - } - - /// Add a module to the compile-on-demand layer. - Error addModule(VModuleKey K, std::unique_ptr M) { - - assert(!LogicalDylibs.count(K) && "VModuleKey K already in use"); - auto I = LogicalDylibs.insert( - LogicalDylibs.end(), - std::make_pair(K, LogicalDylib(K, GetSymbolResolver(K), - CreateIndirectStubsManager()))); - - return addLogicalModule(I->second, std::move(M)); - } - - /// Add extra modules to an existing logical module. - Error addExtraModule(VModuleKey K, std::unique_ptr M) { - return addLogicalModule(LogicalDylibs[K], std::move(M)); - } - - /// Remove the module represented by the given key. - /// - /// This will remove all modules in the layers below that were derived from - /// the module represented by K. - Error removeModule(VModuleKey K) { - auto I = LogicalDylibs.find(K); - assert(I != LogicalDylibs.end() && "VModuleKey K not valid here"); - auto Err = I->second.removeModulesFromBaseLayer(BaseLayer); - LogicalDylibs.erase(I); - return Err; - } - - /// Search for the given named symbol. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { - for (auto &KV : LogicalDylibs) { - if (auto Sym = KV.second.StubsMgr->findStub(Name, ExportedSymbolsOnly)) - return Sym; - if (auto Sym = - findSymbolIn(KV.first, std::string(Name), ExportedSymbolsOnly)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - } - return BaseLayer.findSymbol(std::string(Name), ExportedSymbolsOnly); - } - - /// Get the address of a symbol provided by this layer, or some layer - /// below this one. - JITSymbol findSymbolIn(VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) { - assert(LogicalDylibs.count(K) && "VModuleKey K is not valid here"); - return LogicalDylibs[K].findSymbol(BaseLayer, Name, ExportedSymbolsOnly); - } - - /// Update the stub for the given function to point at FnBodyAddr. - /// This can be used to support re-optimization. - /// @return true if the function exists and the stub is updated, false - /// otherwise. - // - // FIXME: We should track and free associated resources (unused compile - // callbacks, uncompiled IR, and no-longer-needed/reachable function - // implementations). - Error updatePointer(std::string FuncName, JITTargetAddress FnBodyAddr) { - //Find out which logical dylib contains our symbol - auto LDI = LogicalDylibs.begin(); - for (auto LDE = LogicalDylibs.end(); LDI != LDE; ++LDI) { - if (auto LMResources = - LDI->getLogicalModuleResourcesForSymbol(FuncName, false)) { - Module &SrcM = LMResources->SourceModule->getResource(); - std::string CalledFnName = mangle(FuncName, SrcM.getDataLayout()); - if (auto Err = LMResources->StubsMgr->updatePointer(CalledFnName, - FnBodyAddr)) - return Err; - return Error::success(); - } - } - return make_error(FuncName); - } - -private: - Error addLogicalModule(LogicalDylib &LD, std::unique_ptr SrcMPtr) { - - // Rename anonymous globals and promote linkage to ensure that everything - // will resolve properly after we partition SrcM. - LD.PromoteSymbols(*SrcMPtr); - - // Create a logical module handle for SrcM within the logical dylib. - Module &SrcM = *SrcMPtr; - auto LMId = LD.addSourceModule(std::move(SrcMPtr)); - - // Create stub functions. - const DataLayout &DL = SrcM.getDataLayout(); - - typename IndirectStubsMgrT::StubInitsMap StubInits; - for (auto &F : SrcM) { - // Skip declarations. - if (F.isDeclaration()) - continue; - - // Skip weak functions for which we already have definitions. - auto MangledName = mangle(F.getName(), DL); - if (F.hasWeakLinkage() || F.hasLinkOnceLinkage()) { - if (auto Sym = LD.findSymbol(BaseLayer, MangledName, false)) - continue; - else if (auto Err = Sym.takeError()) - return Err; - } - - // Record all functions defined by this module. - if (CloneStubsIntoPartitions) - LD.getStubsToClone(LMId).insert(&F); - - // Create a callback, associate it with the stub for the function, - // and set the compile action to compile the partition containing the - // function. - auto CompileAction = [this, &LD, LMId, &F]() -> JITTargetAddress { - if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F)) - return *FnImplAddrOrErr; - else { - // FIXME: Report error, return to 'abort' or something similar. - consumeError(FnImplAddrOrErr.takeError()); - return 0; - } - }; - if (auto CCAddr = - CompileCallbackMgr.getCompileCallback(std::move(CompileAction))) - StubInits[MangledName] = - std::make_pair(*CCAddr, JITSymbolFlags::fromGlobalValue(F)); - else - return CCAddr.takeError(); - } - - if (auto Err = LD.StubsMgr->createStubs(StubInits)) - return Err; - - // If this module doesn't contain any globals, aliases, or module flags then - // we can bail out early and avoid the overhead of creating and managing an - // empty globals module. - if (SrcM.global_empty() && SrcM.alias_empty() && - !SrcM.getModuleFlagsMetadata()) - return Error::success(); - - // Create the GlobalValues module. - auto GVsM = std::make_unique((SrcM.getName() + ".globals").str(), - SrcM.getContext()); - GVsM->setDataLayout(DL); - - ValueToValueMapTy VMap; - - // Clone global variable decls. - for (auto &GV : SrcM.globals()) - if (!GV.isDeclaration() && !VMap.count(&GV)) - cloneGlobalVariableDecl(*GVsM, GV, &VMap); - - // And the aliases. - for (auto &A : SrcM.aliases()) - if (!VMap.count(&A)) - cloneGlobalAliasDecl(*GVsM, A, VMap); - - // Clone the module flags. - cloneModuleFlagsMetadata(*GVsM, SrcM, VMap); - - // Now we need to clone the GV and alias initializers. - - // Initializers may refer to functions declared (but not defined) in this - // module. Build a materializer to clone decls on demand. - auto Materializer = createLambdaMaterializer( - [&LD, &GVsM](Value *V) -> Value* { - if (auto *F = dyn_cast(V)) { - // Decls in the original module just get cloned. - if (F->isDeclaration()) - return cloneFunctionDecl(*GVsM, *F); - - // Definitions in the original module (which we have emitted stubs - // for at this point) get turned into a constant alias to the stub - // instead. - const DataLayout &DL = GVsM->getDataLayout(); - std::string FName = mangle(F->getName(), DL); - unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType()); - JITTargetAddress StubAddr = - LD.StubsMgr->findStub(FName, false).getAddress(); - - ConstantInt *StubAddrCI = - ConstantInt::get(GVsM->getContext(), APInt(PtrBitWidth, StubAddr)); - Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr, - StubAddrCI, F->getType()); - return GlobalAlias::create(F->getFunctionType(), - F->getType()->getAddressSpace(), - F->getLinkage(), F->getName(), - Init, GVsM.get()); - } - // else.... - return nullptr; - }); - - // Clone the global variable initializers. - for (auto &GV : SrcM.globals()) - if (!GV.isDeclaration()) - moveGlobalVariableInitializer(GV, VMap, &Materializer); - - // Clone the global alias initializers. - for (auto &A : SrcM.aliases()) { - auto *NewA = cast(VMap[&A]); - assert(NewA && "Alias not cloned?"); - Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr, - &Materializer); - NewA->setAliasee(cast(Init)); - } - - // Build a resolver for the globals module and add it to the base layer. - auto LegacyLookup = [this, &LD](StringRef Name) -> JITSymbol { - if (auto Sym = LD.StubsMgr->findStub(Name, false)) - return Sym; - - if (auto Sym = LD.findSymbol(BaseLayer, std::string(Name), false)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - - return nullptr; - }; - - auto GVsResolver = createSymbolResolver( - [&LD, LegacyLookup](const SymbolNameSet &Symbols) { - auto RS = getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup); - - if (!RS) { - logAllUnhandledErrors( - RS.takeError(), errs(), - "CODLayer/GVsResolver responsibility set lookup failed: "); - return SymbolNameSet(); - } - - if (RS->size() == Symbols.size()) - return *RS; - - SymbolNameSet NotFoundViaLegacyLookup; - for (auto &S : Symbols) - if (!RS->count(S)) - NotFoundViaLegacyLookup.insert(S); - auto RS2 = - LD.BackingResolver->getResponsibilitySet(NotFoundViaLegacyLookup); - - for (auto &S : RS2) - (*RS).insert(S); - - return *RS; - }, - [this, &LD, - LegacyLookup](std::shared_ptr Query, - SymbolNameSet Symbols) { - auto NotFoundViaLegacyLookup = - lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup); - return LD.BackingResolver->lookup(Query, NotFoundViaLegacyLookup); - }); - - SetSymbolResolver(LD.K, std::move(GVsResolver)); - - if (auto Err = BaseLayer.addModule(LD.K, std::move(GVsM))) - return Err; - - LD.BaseLayerVModuleKeys.push_back(LD.K); - - return Error::success(); - } - - static std::string mangle(StringRef Name, const DataLayout &DL) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; - } - - Expected - extractAndCompile(LogicalDylib &LD, - typename LogicalDylib::SourceModuleHandle LMId, - Function &F) { - Module &SrcM = LD.getSourceModule(LMId); - - // If F is a declaration we must already have compiled it. - if (F.isDeclaration()) - return 0; - - // Grab the name of the function being called here. - std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout()); - - JITTargetAddress CalledAddr = 0; - auto Part = Partition(F); - if (auto PartKeyOrErr = emitPartition(LD, LMId, Part)) { - auto &PartKey = *PartKeyOrErr; - for (auto *SubF : Part) { - std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout()); - if (auto FnBodySym = BaseLayer.findSymbolIn(PartKey, FnName, false)) { - if (auto FnBodyAddrOrErr = FnBodySym.getAddress()) { - JITTargetAddress FnBodyAddr = *FnBodyAddrOrErr; - - // If this is the function we're calling record the address so we can - // return it from this function. - if (SubF == &F) - CalledAddr = FnBodyAddr; - - // Update the function body pointer for the stub. - if (auto EC = LD.StubsMgr->updatePointer(FnName, FnBodyAddr)) - return 0; - - } else - return FnBodyAddrOrErr.takeError(); - } else if (auto Err = FnBodySym.takeError()) - return std::move(Err); - else - llvm_unreachable("Function not emitted for partition"); - } - - LD.BaseLayerVModuleKeys.push_back(PartKey); - } else - return PartKeyOrErr.takeError(); - - return CalledAddr; - } - - template - Expected - emitPartition(LogicalDylib &LD, - typename LogicalDylib::SourceModuleHandle LMId, - const PartitionT &Part) { - Module &SrcM = LD.getSourceModule(LMId); - - // Create the module. - std::string NewName(SrcM.getName()); - for (auto *F : Part) { - NewName += "."; - NewName += F->getName(); - } - - auto M = std::make_unique(NewName, SrcM.getContext()); - M->setDataLayout(SrcM.getDataLayout()); - ValueToValueMapTy VMap; - - auto Materializer = createLambdaMaterializer([&LD, &LMId, - &M](Value *V) -> Value * { - if (auto *GV = dyn_cast(V)) - return cloneGlobalVariableDecl(*M, *GV); - - if (auto *F = dyn_cast(V)) { - // Check whether we want to clone an available_externally definition. - if (!LD.getStubsToClone(LMId).count(F)) - return cloneFunctionDecl(*M, *F); - - // Ok - we want an inlinable stub. For that to work we need a decl - // for the stub pointer. - auto *StubPtr = createImplPointer(*F->getType(), *M, - F->getName() + "$stub_ptr", nullptr); - auto *ClonedF = cloneFunctionDecl(*M, *F); - makeStub(*ClonedF, *StubPtr); - ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage); - ClonedF->addFnAttr(Attribute::AlwaysInline); - return ClonedF; - } - - if (auto *A = dyn_cast(V)) { - auto *Ty = A->getValueType(); - if (Ty->isFunctionTy()) - return Function::Create(cast(Ty), - GlobalValue::ExternalLinkage, A->getName(), - M.get()); - - return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, - nullptr, A->getName(), nullptr, - GlobalValue::NotThreadLocal, - A->getType()->getAddressSpace()); - } - - return nullptr; - }); - - // Create decls in the new module. - for (auto *F : Part) - cloneFunctionDecl(*M, *F, &VMap); - - // Move the function bodies. - for (auto *F : Part) - moveFunctionBody(*F, VMap, &Materializer); - - auto K = ES.allocateVModule(); - - auto LegacyLookup = [this, &LD](StringRef Name) -> JITSymbol { - return LD.findSymbol(BaseLayer, std::string(Name), false); - }; - - // Create memory manager and symbol resolver. - auto Resolver = createSymbolResolver( - [&LD, LegacyLookup](const SymbolNameSet &Symbols) { - auto RS = getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup); - if (!RS) { - logAllUnhandledErrors( - RS.takeError(), errs(), - "CODLayer/SubResolver responsibility set lookup failed: "); - return SymbolNameSet(); - } - - if (RS->size() == Symbols.size()) - return *RS; - - SymbolNameSet NotFoundViaLegacyLookup; - for (auto &S : Symbols) - if (!RS->count(S)) - NotFoundViaLegacyLookup.insert(S); - - auto RS2 = - LD.BackingResolver->getResponsibilitySet(NotFoundViaLegacyLookup); - - for (auto &S : RS2) - (*RS).insert(S); - - return *RS; - }, - [this, &LD, LegacyLookup](std::shared_ptr Q, - SymbolNameSet Symbols) { - auto NotFoundViaLegacyLookup = - lookupWithLegacyFn(ES, *Q, Symbols, LegacyLookup); - return LD.BackingResolver->lookup(Q, - std::move(NotFoundViaLegacyLookup)); - }); - SetSymbolResolver(K, std::move(Resolver)); - - if (auto Err = BaseLayer.addModule(std::move(K), std::move(M))) - return std::move(Err); - - return K; - } - - ExecutionSession &ES; - BaseLayerT &BaseLayer; - SymbolResolverGetter GetSymbolResolver; - SymbolResolverSetter SetSymbolResolver; - PartitioningFtor Partition; - CompileCallbackMgrT &CompileCallbackMgr; - IndirectStubsManagerBuilderT CreateIndirectStubsManager; - - std::map LogicalDylibs; - bool CloneStubsIntoPartitions; -}; - -template -LegacyCompileOnDemandLayer:: - LegacyCompileOnDemandLayer( - ExecutionSession &ES, BaseLayerT &BaseLayer, - SymbolResolverGetter GetSymbolResolver, - SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition, - CompileCallbackMgrT &CallbackMgr, - IndirectStubsManagerBuilderT CreateIndirectStubsManager, - bool CloneStubsIntoPartitions) - : ES(ES), BaseLayer(BaseLayer), - GetSymbolResolver(std::move(GetSymbolResolver)), - SetSymbolResolver(std::move(SetSymbolResolver)), - Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr), - CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)), - CloneStubsIntoPartitions(CloneStubsIntoPartitions) {} - } // end namespace orc } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h index 8376d163d57a5..c7ba57228ab71 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -28,8 +28,6 @@ class TargetMachine; namespace orc { -class JITTargetMachineBuilder; - IRSymbolMapper::ManglingOptions irManglingOptionsFromTargetOptions(const TargetOptions &Opts); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index 101017f89def1..94b7c5e4be3d0 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -16,11 +16,13 @@ #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/ExecutionEngine/OrcV1Deprecation.h" #include "llvm/Support/Debug.h" +#include #include #include @@ -33,11 +35,67 @@ class ExecutionSession; class MaterializationUnit; class MaterializationResponsibility; class JITDylib; +class ResourceTracker; +class InProgressLookupState; + enum class SymbolState : uint8_t; -/// VModuleKey provides a unique identifier (allocated and managed by -/// ExecutionSessions) for a module added to the JIT. -using VModuleKey = uint64_t; +using ResourceTrackerSP = IntrusiveRefCntPtr; +using JITDylibSP = IntrusiveRefCntPtr; + +using ResourceKey = uintptr_t; + +/// API to remove / transfer ownership of JIT resources. +class ResourceTracker : public ThreadSafeRefCountedBase { +private: + friend class ExecutionSession; + friend class JITDylib; + friend class MaterializationResponsibility; + +public: + ResourceTracker(const ResourceTracker &) = delete; + ResourceTracker &operator=(const ResourceTracker &) = delete; + ResourceTracker(ResourceTracker &&) = delete; + ResourceTracker &operator=(ResourceTracker &&) = delete; + + ~ResourceTracker(); + + /// Return the JITDylib targeted by this tracker. + JITDylib &getJITDylib() const { + return *reinterpret_cast(JDAndFlag.load() & + ~static_cast(1)); + } + + /// Remove all resources associated with this key. + Error remove(); + + /// Transfer all resources associated with this key to the given + /// tracker, which must target the same JITDylib as this one. + void transferTo(ResourceTracker &DstRT); + + /// Return true if this tracker has become defunct. + bool isDefunct() const { return JDAndFlag.load() & 0x1; } + + /// Returns the key associated with this tracker. + /// This method should not be used except for debug logging: there is no + /// guarantee that the returned value will remain valid. + ResourceKey getKeyUnsafe() const { return reinterpret_cast(this); } + +private: + ResourceTracker(JITDylibSP JD); + + void makeDefunct(); + + std::atomic_uintptr_t JDAndFlag; +}; + +/// Listens for ResourceTracker operations. +class ResourceManager { +public: + virtual ~ResourceManager(); + virtual Error handleRemoveResources(ResourceKey K) = 0; + virtual void handleTransferResources(ResourceKey DstK, ResourceKey SrcK) = 0; +}; /// A set of symbol names (represented by SymbolStringPtrs for // efficiency). @@ -158,9 +216,19 @@ class SymbolLookupSet { /// Add an element to the set. The client is responsible for checking that /// duplicates are not added. - void add(SymbolStringPtr Name, - SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { + SymbolLookupSet & + add(SymbolStringPtr Name, + SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { Symbols.push_back(std::make_pair(std::move(Name), Flags)); + return *this; + } + + /// Quickly append one lookup set to another. + SymbolLookupSet &append(SymbolLookupSet Other) { + Symbols.reserve(Symbols.size() + Other.size()); + for (auto &KV : Other) + Symbols.push_back(std::move(KV)); + return *this; } bool empty() const { return Symbols.empty(); } @@ -318,6 +386,18 @@ using RegisterDependenciesFunction = /// are no dependants to register with. extern RegisterDependenciesFunction NoDependenciesToRegister; +class ResourceTrackerDefunct : public ErrorInfo { +public: + static char ID; + + ResourceTrackerDefunct(ResourceTrackerSP RT); + std::error_code convertToErrorCode() const override; + void log(raw_ostream &OS) const override; + +private: + ResourceTrackerSP RT; +}; + /// Used to notify a JITDylib that the given set of symbols failed to /// materialize. class FailedToMaterialize : public ErrorInfo { @@ -408,9 +488,10 @@ class UnexpectedSymbolDefinitions : public ErrorInfo Error withResourceKeyDo(Func &&F) const; + /// Returns the target JITDylib that these symbols are being materialized /// into. JITDylib &getTargetJITDylib() const { return *JD; } - /// Returns the VModuleKey for this instance. - VModuleKey getVModuleKey() const { return K; } + /// Returns the ExecutionSession for this instance. + ExecutionSession &getExecutionSession(); /// Returns the symbol flags map for this responsibility instance. /// Note: The returned flags may have transient flags (Lazy, Materializing) @@ -509,13 +593,13 @@ class MaterializationResponsibility { /// materializers to break up work based on run-time information (e.g. /// by introspecting which symbols have actually been looked up and /// materializing only those). - void replace(std::unique_ptr MU); + Error replace(std::unique_ptr MU); /// Delegates responsibility for the given symbols to the returned /// materialization responsibility. Useful for breaking up work between /// threads, or different kinds of materialization processes. - MaterializationResponsibility delegate(const SymbolNameSet &Symbols, - VModuleKey NewKey = VModuleKey()); + Expected> + delegate(const SymbolNameSet &Symbols); void addDependencies(const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies); @@ -526,19 +610,17 @@ class MaterializationResponsibility { private: /// Create a MaterializationResponsibility for the given JITDylib and /// initial symbols. - MaterializationResponsibility(std::shared_ptr JD, - SymbolFlagsMap SymbolFlags, - SymbolStringPtr InitSymbol, VModuleKey K) + MaterializationResponsibility(JITDylibSP JD, SymbolFlagsMap SymbolFlags, + SymbolStringPtr InitSymbol) : JD(std::move(JD)), SymbolFlags(std::move(SymbolFlags)), - InitSymbol(std::move(InitSymbol)), K(std::move(K)) { - assert(this->JD && "Cannot initialize with null JD"); + InitSymbol(std::move(InitSymbol)) { + assert(this->JD && "Cannot initialize with null JITDylib"); assert(!this->SymbolFlags.empty() && "Materializing nothing?"); } - std::shared_ptr JD; + JITDylibSP JD; SymbolFlagsMap SymbolFlags; SymbolStringPtr InitSymbol; - VModuleKey K; }; /// A MaterializationUnit represents a set of symbol definitions that can @@ -555,9 +637,9 @@ class MaterializationUnit { public: MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, - SymbolStringPtr InitSymbol, VModuleKey K) + SymbolStringPtr InitSymbol) : SymbolFlags(std::move(InitalSymbolFlags)), - InitSymbol(std::move(InitSymbol)), K(std::move(K)) { + InitSymbol(std::move(InitSymbol)) { assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) && "If set, InitSymbol should appear in InitialSymbolFlags map"); } @@ -577,7 +659,8 @@ class MaterializationUnit { /// Implementations of this method should materialize all symbols /// in the materialzation unit, except for those that have been /// previously discarded. - virtual void materialize(MaterializationResponsibility R) = 0; + virtual void + materialize(std::unique_ptr R) = 0; /// Called by JITDylibs to notify MaterializationUnits that the given symbol /// has been overridden. @@ -589,17 +672,10 @@ class MaterializationUnit { protected: SymbolFlagsMap SymbolFlags; SymbolStringPtr InitSymbol; - VModuleKey K; private: virtual void anchor(); - MaterializationResponsibility - createMaterializationResponsibility(std::shared_ptr JD) { - return MaterializationResponsibility(std::move(JD), std::move(SymbolFlags), - std::move(InitSymbol), K); - } - /// Implementations of this method should discard the given symbol /// from the source (e.g. if the source is an LLVM IR Module and the /// symbol is a function, delete the function body or mark it available @@ -607,21 +683,18 @@ class MaterializationUnit { virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0; }; -using MaterializationUnitList = - std::vector>; - /// A MaterializationUnit implementation for pre-existing absolute symbols. /// /// All symbols will be resolved and marked ready as soon as the unit is /// materialized. class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { public: - AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K); + AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols); StringRef getName() const override; private: - void materialize(MaterializationResponsibility R) override; + void materialize(std::unique_ptr R) override; void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; static SymbolFlagsMap extractFlags(const SymbolMap &Symbols); @@ -639,9 +712,9 @@ class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { /// \endcode /// inline std::unique_ptr -absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) { +absoluteSymbols(SymbolMap Symbols) { return std::make_unique( - std::move(Symbols), std::move(K)); + std::move(Symbols)); } /// A materialization unit for symbol aliases. Allows existing symbols to be @@ -658,12 +731,12 @@ class ReExportsMaterializationUnit : public MaterializationUnit { /// resolved. ReExportsMaterializationUnit(JITDylib *SourceJD, JITDylibLookupFlags SourceJDLookupFlags, - SymbolAliasMap Aliases, VModuleKey K); + SymbolAliasMap Aliases); StringRef getName() const override; private: - void materialize(MaterializationResponsibility R) override; + void materialize(std::unique_ptr R) override; void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); @@ -684,10 +757,9 @@ class ReExportsMaterializationUnit : public MaterializationUnit { /// return Err; /// \endcode inline std::unique_ptr -symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) { +symbolAliases(SymbolAliasMap Aliases) { return std::make_unique( - nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases), - std::move(K)); + nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases)); } /// Create a materialization unit for re-exporting symbols from another JITDylib @@ -696,10 +768,9 @@ symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) { inline std::unique_ptr reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, JITDylibLookupFlags SourceJDLookupFlags = - JITDylibLookupFlags::MatchExportedSymbolsOnly, - VModuleKey K = VModuleKey()) { + JITDylibLookupFlags::MatchExportedSymbolsOnly) { return std::make_unique( - &SourceJD, SourceJDLookupFlags, std::move(Aliases), std::move(K)); + &SourceJD, SourceJDLookupFlags, std::move(Aliases)); } /// Build a SymbolAliasMap for the common case where you want to re-export @@ -723,8 +794,10 @@ enum class SymbolState : uint8_t { /// makes a callback when all symbols are available. class AsynchronousSymbolQuery { friend class ExecutionSession; + friend class InProgressFullLookupState; friend class JITDylib; friend class JITSymbolResolverAdapter; + friend class MaterializationResponsibility; public: /// Create a query for the given symbols. The NotifyComplete @@ -757,8 +830,6 @@ class AsynchronousSymbolQuery { void dropSymbol(const SymbolStringPtr &Name); - bool canStillFail(); - void handleFailed(Error Err); void detach(); @@ -770,34 +841,58 @@ class AsynchronousSymbolQuery { SymbolState RequiredState; }; +/// Wraps state for a lookup-in-progress. +/// DefinitionGenerators can optionally take ownership of a LookupState object +/// to suspend a lookup-in-progress while they search for definitions. +class LookupState { + friend class OrcV2CAPIHelper; + friend class ExecutionSession; + +public: + ~LookupState(); + + /// Continue the lookup. This can be called by DefinitionGenerators + /// to re-start a captured query-application operation. + void continueLookup(Error Err); + +private: + LookupState(std::unique_ptr IPLS); + + // For C API. + void reset(InProgressLookupState *IPLS); + + std::unique_ptr IPLS; +}; + +/// Definition generators can be attached to JITDylibs to generate new +/// definitions for otherwise unresolved symbols during lookup. +class DefinitionGenerator { +public: + virtual ~DefinitionGenerator(); + + /// DefinitionGenerators should override this method to insert new + /// definitions into the parent JITDylib. K specifies the kind of this + /// lookup. JD specifies the target JITDylib being searched, and + /// JDLookupFlags specifies whether the search should match against + /// hidden symbols. Finally, Symbols describes the set of unresolved + /// symbols and their associated lookup flags. + virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, + const SymbolLookupSet &LookupSet) = 0; +}; + /// A symbol table that supports asynchoronous symbol queries. /// /// Represents a virtual shared object. Instances can not be copied or moved, so /// their addresses may be used as keys for resource management. /// JITDylib state changes must be made via an ExecutionSession to guarantee /// that they are synchronized with respect to other JITDylib operations. -class JITDylib : public std::enable_shared_from_this { +class JITDylib : public ThreadSafeRefCountedBase { friend class AsynchronousSymbolQuery; friend class ExecutionSession; friend class Platform; friend class MaterializationResponsibility; public: - /// Definition generators can be attached to JITDylibs to generate new - /// definitions for otherwise unresolved symbols during lookup. - class DefinitionGenerator { - public: - virtual ~DefinitionGenerator(); - - /// DefinitionGenerators should override this method to insert new - /// definitions into the parent JITDylib. K specifies the kind of this - /// lookup. JD specifies the target JITDylib being searched, and - /// JDLookupFlags specifies whether the search should match against - /// hidden symbols. Finally, Symbols describes the set of unresolved - /// symbols and their associated lookup flags. - virtual Error tryToGenerate(LookupKind K, JITDylib &JD, - JITDylibLookupFlags JDLookupFlags, - const SymbolLookupSet &LookupSet) = 0; - }; using AsynchronousSymbolQuerySet = std::set>; @@ -813,6 +908,21 @@ class JITDylib : public std::enable_shared_from_this { /// Get a reference to the ExecutionSession for this JITDylib. ExecutionSession &getExecutionSession() const { return ES; } + /// Calls remove on all trackers currently associated with this JITDylib. + /// Does not run static deinits. + /// + /// Note that removal happens outside the session lock, so new code may be + /// added concurrently while the clear is underway, and the newly added + /// code will *not* be cleared. Adding new code concurrently with a clear + /// is usually a bug and should be avoided. + Error clear(); + + /// Get the default resource tracker for this JITDylib. + ResourceTrackerSP getDefaultResourceTracker(); + + /// Create a resource tracker for this JITDylib. + ResourceTrackerSP createResourceTracker(); + /// Adds a definition generator to this JITDylib and returns a referenece to /// it. /// @@ -873,10 +983,13 @@ class JITDylib : public std::enable_shared_from_this { /// Define all symbols provided by the materialization unit to be part of this /// JITDylib. /// + /// If RT is not specified then the default resource tracker will be used. + /// /// This overload always takes ownership of the MaterializationUnit. If any /// errors occur, the MaterializationUnit consumed. template - Error define(std::unique_ptr &&MU); + Error define(std::unique_ptr &&MU, + ResourceTrackerSP RT = nullptr); /// Define all symbols provided by the materialization unit to be part of this /// JITDylib. @@ -886,7 +999,8 @@ class JITDylib : public std::enable_shared_from_this { /// may allow the caller to modify the MaterializationUnit to correct the /// issue, then re-call define. template - Error define(std::unique_ptr &MU); + Error define(std::unique_ptr &MU, + ResourceTrackerSP RT = nullptr); /// Tries to remove the given symbols. /// @@ -900,41 +1014,47 @@ class JITDylib : public std::enable_shared_from_this { /// left unmodified (no symbols are removed). Error remove(const SymbolNameSet &Names); - /// Search the given JITDylib for the symbols in Symbols. If found, store - /// the flags for each symbol in Flags. If any required symbols are not found - /// then an error will be returned. - Expected lookupFlags(LookupKind K, - JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet LookupSet); - /// Dump current JITDylib state to OS. void dump(raw_ostream &OS); - /// FIXME: Remove this when we remove the old ORC layers. - /// Search the given JITDylibs in order for the symbols in Symbols. Results - /// (once they become available) will be returned via the given Query. - /// - /// If any symbol is not found then the unresolved symbols will be returned, - /// and the query will not be applied. The Query is not failed and can be - /// re-used in a subsequent lookup once the symbols have been added, or - /// manually failed. - Expected - legacyLookup(std::shared_ptr Q, SymbolNameSet Names); + /// Returns the given JITDylibs and all of their transitive dependencies in + /// DFS order (based on linkage relationships). Each JITDylib will appear + /// only once. + static std::vector getDFSLinkOrder(ArrayRef JDs); + + /// Returns the given JITDylibs and all of their transitive dependensies in + /// reverse DFS order (based on linkage relationships). Each JITDylib will + /// appear only once. + static std::vector + getReverseDFSLinkOrder(ArrayRef JDs); + + /// Return this JITDylib and its transitive dependencies in DFS order + /// based on linkage relationships. + std::vector getDFSLinkOrder(); + + /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order + /// based on linkage relationships. + std::vector getReverseDFSLinkOrder(); private: using AsynchronousSymbolQueryList = std::vector>; struct UnmaterializedInfo { - UnmaterializedInfo(std::unique_ptr MU) - : MU(std::move(MU)) {} + UnmaterializedInfo(std::unique_ptr MU, + ResourceTracker *RT) + : MU(std::move(MU)), RT(RT) {} std::unique_ptr MU; + ResourceTracker *RT; }; using UnmaterializedInfosMap = DenseMap>; + using UnmaterializedInfosList = + std::vector>; + struct MaterializingInfo { SymbolDependenceMap Dependants; SymbolDependenceMap UnemittedDependencies; @@ -1001,25 +1121,16 @@ class JITDylib : public std::enable_shared_from_this { JITDylib(ExecutionSession &ES, std::string Name); - Error defineImpl(MaterializationUnit &MU); - - void lookupFlagsImpl(SymbolFlagsMap &Result, LookupKind K, - JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet &Unresolved); + ResourceTrackerSP getTracker(MaterializationResponsibility &MR); + std::pair> + removeTracker(ResourceTracker &RT); - Error lodgeQuery(MaterializationUnitList &MUs, - std::shared_ptr &Q, LookupKind K, - JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet &Unresolved); + void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); - Error lodgeQueryImpl(MaterializationUnitList &MUs, - std::shared_ptr &Q, - LookupKind K, JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet &Unresolved); + Error defineImpl(MaterializationUnit &MU); - bool lookupImpl(std::shared_ptr &Q, - std::vector> &MUs, - SymbolLookupSet &Unresolved); + void installMaterializationUnit(std::unique_ptr MU, + ResourceTracker &RT); void detachQueryHelper(AsynchronousSymbolQuery &Q, const SymbolNameSet &QuerySymbols); @@ -1030,29 +1141,45 @@ class JITDylib : public std::enable_shared_from_this { Expected defineMaterializing(SymbolFlagsMap SymbolFlags); - void replace(std::unique_ptr MU); + Error replace(MaterializationResponsibility &FromMR, + std::unique_ptr MU); + + Expected> + delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags, + SymbolStringPtr InitSymbol); SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const; void addDependencies(const SymbolStringPtr &Name, const SymbolDependenceMap &Dependants); - Error resolve(const SymbolMap &Resolved); + Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved); - Error emit(const SymbolFlagsMap &Emitted); + Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted); + + void unlinkMaterializationResponsibility(MaterializationResponsibility &MR); using FailedSymbolsWorklist = std::vector>; - static void notifyFailed(FailedSymbolsWorklist FailedSymbols); + + static std::pair> + failSymbols(FailedSymbolsWorklist); ExecutionSession &ES; std::string JITDylibName; + std::mutex GeneratorsMutex; bool Open = true; SymbolTable Symbols; UnmaterializedInfosMap UnmaterializedInfos; MaterializingInfosMap MaterializingInfos; - std::vector> DefGenerators; + std::vector> DefGenerators; JITDylibSearchOrder LinkOrder; + ResourceTrackerSP DefaultTracker; + + // Map trackers to sets of symbols tracked. + DenseMap TrackerSymbols; + DenseMap MRTrackers; }; /// Platforms set up standard symbols and mediate interactions between dynamic @@ -1071,11 +1198,12 @@ class Platform { /// This method will be called under the ExecutionSession lock each time a /// MaterializationUnit is added to a JITDylib. - virtual Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU) = 0; + virtual Error notifyAdding(ResourceTracker &RT, + const MaterializationUnit &MU) = 0; /// This method will be called under the ExecutionSession lock when a - /// VModuleKey is removed. - virtual Error notifyRemoving(JITDylib &JD, VModuleKey K) = 0; + /// ResourceTracker is removed. + virtual Error notifyRemoving(ResourceTracker &RT) = 0; /// A utility function for looking up initializer symbols. Performs a blocking /// lookup for the given symbols in each of the given JITDylibs. @@ -1086,8 +1214,12 @@ class Platform { /// An ExecutionSession represents a running JIT program. class ExecutionSession { - // FIXME: Remove this when we remove the old ORC layers. + friend class InProgressLookupFlagsState; + friend class InProgressFullLookupState; friend class JITDylib; + friend class LookupState; + friend class MaterializationResponsibility; + friend class ResourceTracker; public: /// For reporting errors. @@ -1096,13 +1228,16 @@ class ExecutionSession { /// For dispatching MaterializationUnit::materialize calls. using DispatchMaterializationFunction = std::function MU, - MaterializationResponsibility MR)>; + std::unique_ptr MR)>; /// Construct an ExecutionSession. /// /// SymbolStringPools may be shared between ExecutionSessions. ExecutionSession(std::shared_ptr SSP = nullptr); + /// End the session. Closes all JITDylibs. + Error endSession(); + /// Add a symbol name to the SymbolStringPool and return a pointer to it. SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } @@ -1122,6 +1257,14 @@ class ExecutionSession { return F(); } + /// Register the given ResourceManager with this ExecutionSession. + /// Managers will be notified of events in reverse order of registration. + void registerResourceManager(ResourceManager &RM); + + /// Deregister the given ResourceManager with this ExecutionSession. + /// Manager must have been previously registered. + void deregisterResourceManager(ResourceManager &RM); + /// Return a pointer to the "name" JITDylib. /// Ownership of JITDylib remains within Execution Session JITDylib *getJITDylibByName(StringRef Name); @@ -1147,17 +1290,6 @@ class ExecutionSession { /// If no Platform is attached this call is equivalent to createBareJITDylib. Expected createJITDylib(std::string Name); - /// Allocate a module key for a new module to add to the JIT. - VModuleKey allocateVModule() { - return runSessionLocked([this]() { return ++LastKey; }); - } - - /// Return a module key to the ExecutionSession so that it can be - /// re-used. This should only be done once all resources associated - /// with the original key have been released. - void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ - } - /// Set the error reporter function. ExecutionSession &setErrorReporter(ErrorReporter ReportError) { this->ReportError = std::move(ReportError); @@ -1176,19 +1308,18 @@ class ExecutionSession { return *this; } - void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err); - - using LegacyAsyncLookupFunction = std::function Q, SymbolNameSet Names)>; + /// Search the given JITDylibs to find the flags associated with each of the + /// given symbols. + void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder, + SymbolLookupSet Symbols, + unique_function)> OnComplete); - /// A legacy lookup function for JITSymbolResolverAdapter. - /// Do not use -- this will be removed soon. - Expected - legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names, - SymbolState RequiredState, - RegisterDependenciesFunction RegisterDependencies); + /// Blocking version of lookupFlags. + Expected lookupFlags(LookupKind K, + JITDylibSearchOrder SearchOrder, + SymbolLookupSet Symbols); - /// Search the given JITDylib list for the given symbols. + /// Search the given JITDylibs for the given symbols. /// /// SearchOrder lists the JITDylibs to search. For each dylib, the associated /// boolean indicates whether the search should match against non-exported @@ -1248,10 +1379,11 @@ class ExecutionSession { SymbolState RequiredState = SymbolState::Ready); /// Materialize the given unit. - void dispatchMaterialization(std::unique_ptr MU, - MaterializationResponsibility MR) { + void + dispatchMaterialization(std::unique_ptr MU, + std::unique_ptr MR) { assert(MU && "MU must be non-null"); - DEBUG_WITH_TYPE("orc", dumpDispatchInfo(MR.getTargetJITDylib(), *MU)); + DEBUG_WITH_TYPE("orc", dumpDispatchInfo(MR->getTargetJITDylib(), *MU)); DispatchMaterialization(std::move(MU), std::move(MR)); } @@ -1263,41 +1395,124 @@ class ExecutionSession { logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); } - static void - materializeOnCurrentThread(std::unique_ptr MU, - MaterializationResponsibility MR) { + static void materializeOnCurrentThread( + std::unique_ptr MU, + std::unique_ptr MR) { MU->materialize(std::move(MR)); } - void runOutstandingMUs(); + void dispatchOutstandingMUs(); + + static std::unique_ptr + createMaterializationResponsibility(ResourceTracker &RT, + SymbolFlagsMap Symbols, + SymbolStringPtr InitSymbol) { + auto &JD = RT.getJITDylib(); + std::unique_ptr MR( + new MaterializationResponsibility(&JD, std::move(Symbols), + std::move(InitSymbol))); + JD.MRTrackers[MR.get()] = &RT; + return MR; + } + + Error removeResourceTracker(ResourceTracker &RT); + void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); + void destroyResourceTracker(ResourceTracker &RT); + + // State machine functions for query application.. + + /// IL_updateCandidatesFor is called to remove already-defined symbols that + /// match a given query from the set of candidate symbols to generate + /// definitions for (no need to generate a definition if one already exists). + Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags, + SymbolLookupSet &Candidates, + SymbolLookupSet *NonCandidates); + + /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering + /// definition generation. It is called when a lookup is performed, and again + /// each time that LookupState::continueLookup is called. + void OL_applyQueryPhase1(std::unique_ptr IPLS, + Error Err); + + /// OL_completeLookup is run once phase 1 successfully completes for a lookup + /// call. It attempts to attach the symbol to all symbol table entries and + /// collect all MaterializationUnits to dispatch. If this method fails then + /// all MaterializationUnits will be left un-materialized. + void OL_completeLookup(std::unique_ptr IPLS, + std::shared_ptr Q, + RegisterDependenciesFunction RegisterDependencies); + + /// OL_completeLookupFlags is run once phase 1 successfully completes for a + /// lookupFlags call. + void OL_completeLookupFlags( + std::unique_ptr IPLS, + unique_function)> OnComplete); + + // State machine functions for MaterializationResponsibility. + void OL_destroyMaterializationResponsibility( + MaterializationResponsibility &MR); + SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR); + Error OL_notifyResolved(MaterializationResponsibility &MR, + const SymbolMap &Symbols); + Error OL_notifyEmitted(MaterializationResponsibility &MR); + Error OL_defineMaterializing(MaterializationResponsibility &MR, + SymbolFlagsMap SymbolFlags); + void OL_notifyFailed(MaterializationResponsibility &MR); + Error OL_replace(MaterializationResponsibility &MR, + std::unique_ptr MU); + Expected> + OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols); + void OL_addDependencies(MaterializationResponsibility &MR, + const SymbolStringPtr &Name, + const SymbolDependenceMap &Dependencies); + void OL_addDependenciesForAll(MaterializationResponsibility &MR, + const SymbolDependenceMap &Dependencies); #ifndef NDEBUG void dumpDispatchInfo(JITDylib &JD, MaterializationUnit &MU); #endif // NDEBUG mutable std::recursive_mutex SessionMutex; + bool SessionOpen = true; std::shared_ptr SSP; std::unique_ptr P; - VModuleKey LastKey = 0; ErrorReporter ReportError = logErrorsToStdErr; DispatchMaterializationFunction DispatchMaterialization = materializeOnCurrentThread; - std::vector> JDs; + std::vector ResourceManagers; + + std::vector JDs; // FIXME: Remove this (and runOutstandingMUs) once the linking layer works // with callbacks from asynchronous queries. mutable std::recursive_mutex OutstandingMUsMutex; std::vector, - MaterializationResponsibility>> + std::unique_ptr>> OutstandingMUs; }; +inline ExecutionSession &MaterializationResponsibility::getExecutionSession() { + return JD->getExecutionSession(); +} + +template +Error MaterializationResponsibility::withResourceKeyDo(Func &&F) const { + return JD->getExecutionSession().runSessionLocked([&]() -> Error { + auto I = JD->MRTrackers.find(this); + assert(I != JD->MRTrackers.end() && "No tracker for this MR"); + if (I->second->isDefunct()) + return make_error(I->second); + F(I->second->getKeyUnsafe()); + return Error::success(); + }); +} + template GeneratorT &JITDylib::addGenerator(std::unique_ptr DefGenerator) { auto &G = *DefGenerator; - ES.runSessionLocked( - [&]() { DefGenerators.push_back(std::move(DefGenerator)); }); + std::lock_guard Lock(GeneratorsMutex); + DefGenerators.push_back(std::move(DefGenerator)); return G; } @@ -1308,7 +1523,8 @@ auto JITDylib::withLinkOrderDo(Func &&F) } template -Error JITDylib::define(std::unique_ptr &&MU) { +Error JITDylib::define(std::unique_ptr &&MU, + ResourceTrackerSP RT) { assert(MU && "Can not define with a null MU"); if (MU->getSymbols().empty()) { @@ -1327,22 +1543,22 @@ Error JITDylib::define(std::unique_ptr &&MU) { if (auto Err = defineImpl(*MU)) return Err; + if (!RT) + RT = getDefaultResourceTracker(); + if (auto *P = ES.getPlatform()) { - if (auto Err = P->notifyAdding(*this, *MU)) + if (auto Err = P->notifyAdding(*RT, *MU)) return Err; } - /// defineImpl succeeded. - auto UMI = std::make_shared(std::move(MU)); - for (auto &KV : UMI->MU->getSymbols()) - UnmaterializedInfos[KV.first] = UMI; - + installMaterializationUnit(std::move(MU), *RT); return Error::success(); }); } template -Error JITDylib::define(std::unique_ptr &MU) { +Error JITDylib::define(std::unique_ptr &MU, + ResourceTrackerSP RT) { assert(MU && "Can not define with a null MU"); if (MU->getSymbols().empty()) { @@ -1361,23 +1577,22 @@ Error JITDylib::define(std::unique_ptr &MU) { if (auto Err = defineImpl(*MU)) return Err; + if (!RT) + RT = getDefaultResourceTracker(); + if (auto *P = ES.getPlatform()) { - if (auto Err = P->notifyAdding(*this, *MU)) + if (auto Err = P->notifyAdding(*RT, *MU)) return Err; } - /// defineImpl succeeded. - auto UMI = std::make_shared(std::move(MU)); - for (auto &KV : UMI->MU->getSymbols()) - UnmaterializedInfos[KV.first] = UMI; - + installMaterializationUnit(std::move(MU), *RT); return Error::success(); }); } /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically /// re-export a subset of the source JITDylib's symbols in the target. -class ReexportsGenerator : public JITDylib::DefinitionGenerator { +class ReexportsGenerator : public DefinitionGenerator { public: using SymbolPredicate = std::function; @@ -1388,7 +1603,7 @@ class ReexportsGenerator : public JITDylib::DefinitionGenerator { JITDylibLookupFlags SourceJDLookupFlags, SymbolPredicate Allow = SymbolPredicate()); - Error tryToGenerate(LookupKind K, JITDylib &JD, + Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &LookupSet) override; @@ -1398,6 +1613,57 @@ class ReexportsGenerator : public JITDylib::DefinitionGenerator { SymbolPredicate Allow; }; +// --------------- IMPLEMENTATION -------------- +// Implementations for inline functions/methods. +// --------------------------------------------- + +inline MaterializationResponsibility::~MaterializationResponsibility() { + JD->getExecutionSession().OL_destroyMaterializationResponsibility(*this); +} + +inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const { + return JD->getExecutionSession().OL_getRequestedSymbols(*this); +} + +inline Error MaterializationResponsibility::notifyResolved( + const SymbolMap &Symbols) { + return JD->getExecutionSession().OL_notifyResolved(*this, Symbols); +} + +inline Error MaterializationResponsibility::notifyEmitted() { + return JD->getExecutionSession().OL_notifyEmitted(*this); +} + +inline Error MaterializationResponsibility::defineMaterializing( + SymbolFlagsMap SymbolFlags) { + return JD->getExecutionSession().OL_defineMaterializing( + *this, std::move(SymbolFlags)); +} + +inline void MaterializationResponsibility::failMaterialization() { + JD->getExecutionSession().OL_notifyFailed(*this); +} + +inline Error MaterializationResponsibility::replace( + std::unique_ptr MU) { + return JD->getExecutionSession().OL_replace(*this, std::move(MU)); +} + +inline Expected> +MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { + return JD->getExecutionSession().OL_delegate(*this, Symbols); +} + +inline void MaterializationResponsibility::addDependencies( + const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { + JD->getExecutionSession().OL_addDependencies(*this, Name, Dependencies); +} + +inline void MaterializationResponsibility::addDependenciesForAll( + const SymbolDependenceMap &Dependencies) { + JD->getExecutionSession().OL_addDependenciesForAll(*this, Dependencies); +} + } // End namespace orc } // End namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h index 3b824b83b0522..0270f8f7d68dc 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h @@ -152,56 +152,6 @@ inline iterator_range getStaticInitGVs(Module &M) { return make_range(StaticInitGVIterator(M), StaticInitGVIterator()); } -/// Convenience class for recording constructor/destructor names for -/// later execution. -template -class LegacyCtorDtorRunner { -public: - /// Construct a CtorDtorRunner for the given range using the given - /// name mangling function. - LLVM_ATTRIBUTE_DEPRECATED( - LegacyCtorDtorRunner(std::vector CtorDtorNames, - VModuleKey K), - "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. " - "Please use the ORCv2 CtorDtorRunner utility instead"); - - LegacyCtorDtorRunner(ORCv1DeprecationAcknowledgement, - std::vector CtorDtorNames, VModuleKey K) - : CtorDtorNames(std::move(CtorDtorNames)), K(K) {} - - /// Run the recorded constructors/destructors through the given JIT - /// layer. - Error runViaLayer(JITLayerT &JITLayer) const { - using CtorDtorTy = void (*)(); - - for (const auto &CtorDtorName : CtorDtorNames) { - if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) { - if (auto AddrOrErr = CtorDtorSym.getAddress()) { - CtorDtorTy CtorDtor = - reinterpret_cast(static_cast(*AddrOrErr)); - CtorDtor(); - } else - return AddrOrErr.takeError(); - } else { - if (auto Err = CtorDtorSym.takeError()) - return Err; - else - return make_error(CtorDtorName); - } - } - return Error::success(); - } - -private: - std::vector CtorDtorNames; - orc::VModuleKey K; -}; - -template -LegacyCtorDtorRunner::LegacyCtorDtorRunner( - std::vector CtorDtorNames, VModuleKey K) - : CtorDtorNames(std::move(CtorDtorNames)), K(K) {} - class CtorDtorRunner { public: CtorDtorRunner(JITDylib &JD) : JD(JD) {} @@ -250,45 +200,6 @@ class LocalCXXRuntimeOverridesBase { void *DSOHandle); }; -class LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { -public: - /// Create a runtime-overrides class. - template - LLVM_ATTRIBUTE_DEPRECATED( - LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle), - "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. " - "Please use the ORCv2 LocalCXXRuntimeOverrides utility instead"); - - template - LegacyLocalCXXRuntimeOverrides(ORCv1DeprecationAcknowledgement, - const MangleFtorT &Mangle) { - addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); - addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); - } - - /// Search overrided symbols. - JITEvaluatedSymbol searchOverrides(const std::string &Name) { - auto I = CXXRuntimeOverrides.find(Name); - if (I != CXXRuntimeOverrides.end()) - return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported); - return nullptr; - } - -private: - void addOverride(const std::string &Name, JITTargetAddress Addr) { - CXXRuntimeOverrides.insert(std::make_pair(Name, Addr)); - } - - StringMap CXXRuntimeOverrides; -}; - -template -LegacyLocalCXXRuntimeOverrides::LegacyLocalCXXRuntimeOverrides( - const MangleFtorT &Mangle) { - addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); - addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); -} - class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { public: Error enable(JITDylib &JD, MangleAndInterner &Mangler); @@ -315,7 +226,7 @@ class ItaniumCXAAtExitSupport { /// If an instance of this class is attached to a JITDylib as a fallback /// definition generator, then any symbol found in the given DynamicLibrary that /// passes the 'Allow' predicate will be added to the JITDylib. -class DynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator { +class DynamicLibrarySearchGenerator : public DefinitionGenerator { public: using SymbolPredicate = std::function; @@ -343,7 +254,7 @@ class DynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator { return Load(nullptr, GlobalPrefix, std::move(Allow)); } - Error tryToGenerate(LookupKind K, JITDylib &JD, + Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) override; @@ -358,7 +269,7 @@ class DynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator { /// If an instance of this class is attached to a JITDylib as a fallback /// definition generator, then any symbol found in the archive will result in /// the containing object being added to the JITDylib. -class StaticLibraryDefinitionGenerator : public JITDylib::DefinitionGenerator { +class StaticLibraryDefinitionGenerator : public DefinitionGenerator { public: /// Try to create a StaticLibraryDefinitionGenerator from the given path. /// @@ -381,7 +292,7 @@ class StaticLibraryDefinitionGenerator : public JITDylib::DefinitionGenerator { static Expected> Create(ObjectLayer &L, std::unique_ptr ArchiveBuffer); - Error tryToGenerate(LookupKind K, JITDylib &JD, + Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) override; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h deleted file mode 100644 index a4e43d4e1c9c2..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h +++ /dev/null @@ -1,111 +0,0 @@ -//===- GlobalMappingLayer.h - Run all IR through a functor ------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Convenience layer for injecting symbols that will appear in calls to -// findSymbol. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H -#define LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H - -#include "llvm/ExecutionEngine/JITSymbol.h" -#include -#include -#include - -namespace llvm { - -class Module; -class JITSymbolResolver; - -namespace orc { - -/// Global mapping layer. -/// -/// This layer overrides the findSymbol method to first search a local symbol -/// table that the client can define. It can be used to inject new symbol -/// mappings into the JIT. Beware, however: symbols within a single IR module or -/// object file will still resolve locally (via RuntimeDyld's symbol table) - -/// such internal references cannot be overriden via this layer. -template -class GlobalMappingLayer { -public: - - /// Handle to an added module. - using ModuleHandleT = typename BaseLayerT::ModuleHandleT; - - /// Construct an GlobalMappingLayer with the given BaseLayer - GlobalMappingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} - - /// Add the given module to the JIT. - /// @return A handle for the added modules. - Expected - addModule(std::shared_ptr M, - std::shared_ptr Resolver) { - return BaseLayer.addModule(std::move(M), std::move(Resolver)); - } - - /// Remove the module set associated with the handle H. - Error removeModule(ModuleHandleT H) { return BaseLayer.removeModule(H); } - - /// Manually set the address to return for the given symbol. - void setGlobalMapping(const std::string &Name, JITTargetAddress Addr) { - SymbolTable[Name] = Addr; - } - - /// Remove the given symbol from the global mapping. - void eraseGlobalMapping(const std::string &Name) { - SymbolTable.erase(Name); - } - - /// Search for the given named symbol. - /// - /// This method will first search the local symbol table, returning - /// any symbol found there. If the symbol is not found in the local - /// table then this call will be passed through to the base layer. - /// - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - auto I = SymbolTable.find(Name); - if (I != SymbolTable.end()) - return JITSymbol(I->second, JITSymbolFlags::Exported); - return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); - } - - /// Get the address of the given symbol in the context of the of the - /// module represented by the handle H. This call is forwarded to the - /// base layer's implementation. - /// @param H The handle for the module to search in. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it is found in the - /// given module. - JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, - bool ExportedSymbolsOnly) { - return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); - } - - /// Immediately emit and finalize the module set represented by the - /// given handle. - /// @param H Handle for module set to emit/finalize. - Error emitAndFinalize(ModuleHandleT H) { - return BaseLayer.emitAndFinalize(H); - } - -private: - BaseLayerT &BaseLayer; - std::map SymbolTable; -}; - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index eb74d283f0435..f8fdb171bbf9f 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -45,8 +45,8 @@ class IRCompileLayer : public IRLayer { IRSymbolMapper::ManglingOptions MO; }; - using NotifyCompiledFunction = - std::function; + using NotifyCompiledFunction = std::function; IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer, std::unique_ptr Compile); @@ -55,7 +55,8 @@ class IRCompileLayer : public IRLayer { void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled); - void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override; + void emit(std::unique_ptr R, + ThreadSafeModule TSM) override; private: mutable std::mutex IRLayerMutex; @@ -65,99 +66,6 @@ class IRCompileLayer : public IRLayer { NotifyCompiledFunction NotifyCompiled = NotifyCompiledFunction(); }; -/// Eager IR compiling layer. -/// -/// This layer immediately compiles each IR module added via addModule to an -/// object file and adds this module file to the layer below, which must -/// implement the object layer concept. -template -class LegacyIRCompileLayer { -public: - /// Callback type for notifications when modules are compiled. - using NotifyCompiledCallback = - std::function)>; - - /// Construct an LegacyIRCompileLayer with the given BaseLayer, which must - /// implement the ObjectLayer concept. - LLVM_ATTRIBUTE_DEPRECATED( - LegacyIRCompileLayer( - BaseLayerT &BaseLayer, CompileFtor Compile, - NotifyCompiledCallback NotifyCompiled = NotifyCompiledCallback()), - "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please " - "use " - "the ORCv2 IRCompileLayer instead"); - - /// Legacy layer constructor with deprecation acknowledgement. - LegacyIRCompileLayer( - ORCv1DeprecationAcknowledgement, BaseLayerT &BaseLayer, - CompileFtor Compile, - NotifyCompiledCallback NotifyCompiled = NotifyCompiledCallback()) - : BaseLayer(BaseLayer), Compile(std::move(Compile)), - NotifyCompiled(std::move(NotifyCompiled)) {} - - /// Get a reference to the compiler functor. - CompileFtor& getCompiler() { return Compile; } - - /// (Re)set the NotifyCompiled callback. - void setNotifyCompiled(NotifyCompiledCallback NotifyCompiled) { - this->NotifyCompiled = std::move(NotifyCompiled); - } - - /// Compile the module, and add the resulting object to the base layer - /// along with the given memory manager and symbol resolver. - Error addModule(VModuleKey K, std::unique_ptr M) { - auto Obj = Compile(*M); - if (!Obj) - return Obj.takeError(); - if (auto Err = BaseLayer.addObject(std::move(K), std::move(*Obj))) - return Err; - if (NotifyCompiled) - NotifyCompiled(std::move(K), std::move(M)); - return Error::success(); - } - - /// Remove the module associated with the VModuleKey K. - Error removeModule(VModuleKey K) { return BaseLayer.removeObject(K); } - - /// Search for the given named symbol. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); - } - - /// Get the address of the given symbol in compiled module represented - /// by the handle H. This call is forwarded to the base layer's - /// implementation. - /// @param K The VModuleKey for the module to search in. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it is found in the - /// given module. - JITSymbol findSymbolIn(VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) { - return BaseLayer.findSymbolIn(K, Name, ExportedSymbolsOnly); - } - - /// Immediately emit and finalize the module represented by the given - /// handle. - /// @param K The VModuleKey for the module to emit/finalize. - Error emitAndFinalize(VModuleKey K) { return BaseLayer.emitAndFinalize(K); } - -private: - BaseLayerT &BaseLayer; - CompileFtor Compile; - NotifyCompiledCallback NotifyCompiled; -}; - -template -LegacyIRCompileLayer::LegacyIRCompileLayer( - BaseLayerT &BaseLayer, CompileFtor Compile, - NotifyCompiledCallback NotifyCompiled) - : BaseLayer(BaseLayer), Compile(std::move(Compile)), - NotifyCompiled(std::move(NotifyCompiled)) {} - } // end namespace orc } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h index 296d74ae6b865..66966a0f87626 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h @@ -13,6 +13,7 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H #define LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H +#include "llvm/ADT/FunctionExtras.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/Layer.h" #include @@ -27,7 +28,7 @@ namespace orc { /// before operating on the module. class IRTransformLayer : public IRLayer { public: - using TransformFunction = std::function( + using TransformFunction = unique_function( ThreadSafeModule, MaterializationResponsibility &R)>; IRTransformLayer(ExecutionSession &ES, IRLayer &BaseLayer, @@ -37,7 +38,8 @@ class IRTransformLayer : public IRLayer { this->Transform = std::move(Transform); } - void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override; + void emit(std::unique_ptr R, + ThreadSafeModule TSM) override; static ThreadSafeModule identityTransform(ThreadSafeModule TSM, MaterializationResponsibility &R) { @@ -49,80 +51,6 @@ class IRTransformLayer : public IRLayer { TransformFunction Transform; }; -/// IR mutating layer. -/// -/// This layer applies a user supplied transform to each module that is added, -/// then adds the transformed module to the layer below. -template -class LegacyIRTransformLayer { -public: - - /// Construct an LegacyIRTransformLayer with the given BaseLayer - LLVM_ATTRIBUTE_DEPRECATED( - LegacyIRTransformLayer(BaseLayerT &BaseLayer, - TransformFtor Transform = TransformFtor()), - "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please " - "use " - "the ORCv2 IRTransformLayer instead"); - - /// Legacy layer constructor with deprecation acknowledgement. - LegacyIRTransformLayer(ORCv1DeprecationAcknowledgement, BaseLayerT &BaseLayer, - TransformFtor Transform = TransformFtor()) - : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} - - /// Apply the transform functor to the module, then add the module to - /// the layer below, along with the memory manager and symbol resolver. - /// - /// @return A handle for the added modules. - Error addModule(VModuleKey K, std::unique_ptr M) { - return BaseLayer.addModule(std::move(K), Transform(std::move(M))); - } - - /// Remove the module associated with the VModuleKey K. - Error removeModule(VModuleKey K) { return BaseLayer.removeModule(K); } - - /// Search for the given named symbol. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); - } - - /// Get the address of the given symbol in the context of the module - /// represented by the VModuleKey K. This call is forwarded to the base - /// layer's implementation. - /// @param K The VModuleKey for the module to search in. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it is found in the - /// given module. - JITSymbol findSymbolIn(VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) { - return BaseLayer.findSymbolIn(K, Name, ExportedSymbolsOnly); - } - - /// Immediately emit and finalize the module represented by the given - /// VModuleKey. - /// @param K The VModuleKey for the module to emit/finalize. - Error emitAndFinalize(VModuleKey K) { return BaseLayer.emitAndFinalize(K); } - - /// Access the transform functor directly. - TransformFtor& getTransform() { return Transform; } - - /// Access the mumate functor directly. - const TransformFtor& getTransform() const { return Transform; } - -private: - BaseLayerT &BaseLayer; - TransformFtor Transform; -}; - -template -LegacyIRTransformLayer::LegacyIRTransformLayer( - BaseLayerT &BaseLayer, TransformFtor Transform) - : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} - } // end namespace orc } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h index 46c91ecbcd782..354cf8ff757ef 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h @@ -86,21 +86,8 @@ class LLJIT { return ES->createJITDylib(std::move(Name)); } - /// A convenience method for defining MUs in LLJIT's Main JITDylib. This can - /// be useful for succinctly defining absolute symbols, aliases and - /// re-exports. - template - Error define(std::unique_ptr &&MU) { - return Main->define(std::move(MU)); - } - - /// A convenience method for defining MUs in LLJIT's Main JITDylib. This can - /// be usedful for succinctly defining absolute symbols, aliases and - /// re-exports. - template - Error define(std::unique_ptr &MU) { - return Main->define(MU); - } + /// Adds an IR module with the given ResourceTracker. + Error addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM); /// Adds an IR module to the given JITDylib. Error addIRModule(JITDylib &JD, ThreadSafeModule TSM); @@ -110,6 +97,9 @@ class LLJIT { return addIRModule(*Main, std::move(TSM)); } + /// Adds an object file to the given JITDylib. + Error addObjectFile(ResourceTrackerSP RT, std::unique_ptr Obj); + /// Adds an object file to the given JITDylib. Error addObjectFile(JITDylib &JD, std::unique_ptr Obj); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h deleted file mode 100644 index b31914f12a0d3..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h +++ /dev/null @@ -1,84 +0,0 @@ -//===- LambdaResolverMM - Redirect symbol lookup via a functor --*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Defines a RuntimeDyld::SymbolResolver subclass that uses a user-supplied -// functor for symbol resolution. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H -#define LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/OrcV1Deprecation.h" -#include - -namespace llvm { -namespace orc { - -template -class LambdaResolver : public LegacyJITSymbolResolver { -public: - LLVM_ATTRIBUTE_DEPRECATED( - LambdaResolver(DylibLookupFtorT DylibLookupFtor, - ExternalLookupFtorT ExternalLookupFtor), - "ORCv1 utilities (including resolvers) are deprecated and will be " - "removed " - "in the next release. Please use ORCv2 (see docs/ORCv2.rst)"); - - LambdaResolver(ORCv1DeprecationAcknowledgement, - DylibLookupFtorT DylibLookupFtor, - ExternalLookupFtorT ExternalLookupFtor) - : DylibLookupFtor(DylibLookupFtor), - ExternalLookupFtor(ExternalLookupFtor) {} - - JITSymbol findSymbolInLogicalDylib(const std::string &Name) final { - return DylibLookupFtor(Name); - } - - JITSymbol findSymbol(const std::string &Name) final { - return ExternalLookupFtor(Name); - } - -private: - DylibLookupFtorT DylibLookupFtor; - ExternalLookupFtorT ExternalLookupFtor; -}; - -template -LambdaResolver::LambdaResolver( - DylibLookupFtorT DylibLookupFtor, ExternalLookupFtorT ExternalLookupFtor) - : DylibLookupFtor(DylibLookupFtor), ExternalLookupFtor(ExternalLookupFtor) { -} - -template -std::shared_ptr> -createLambdaResolver(DylibLookupFtorT DylibLookupFtor, - ExternalLookupFtorT ExternalLookupFtor) { - using LR = LambdaResolver; - return std::make_unique(std::move(DylibLookupFtor), - std::move(ExternalLookupFtor)); -} - -template -std::shared_ptr> -createLambdaResolver(ORCv1DeprecationAcknowledgement, - DylibLookupFtorT DylibLookupFtor, - ExternalLookupFtorT ExternalLookupFtor) { - using LR = LambdaResolver; - return std::make_unique(AcknowledgeORCv1Deprecation, - std::move(DylibLookupFtor), - std::move(ExternalLookupFtor)); -} - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Layer.h b/llvm/include/llvm/ExecutionEngine/Orc/Layer.h index e843d0f562455..f9cc15583b423 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Layer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Layer.h @@ -34,15 +34,15 @@ class IRMaterializationUnit : public MaterializationUnit { /// SymbolFlags and SymbolToDefinition maps. IRMaterializationUnit(ExecutionSession &ES, const IRSymbolMapper::ManglingOptions &MO, - ThreadSafeModule TSM, VModuleKey K); + ThreadSafeModule TSM); /// Create an IRMaterializationLayer from a module, and pre-existing /// SymbolFlags and SymbolToDefinition maps. The maps must provide /// entries for each definition in M. /// This constructor is useful for delegating work from one /// IRMaterializationUnit to another. - IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K, - SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol, + IRMaterializationUnit(ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, + SymbolStringPtr InitSymbol, SymbolNameToDefinitionMap SymbolToDefinition); /// Return the ModuleIdentifier as the name for this MaterializationUnit. @@ -94,13 +94,19 @@ class IRLayer { /// Returns the current value of the CloneToNewContextOnEmit flag. bool getCloneToNewContextOnEmit() const { return CloneToNewContextOnEmit; } + /// Add a MaterializatinoUnit representing the given IR to the JITDylib + /// targeted by the given tracker. + virtual Error add(ResourceTrackerSP RT, ThreadSafeModule TSM); + /// Adds a MaterializationUnit representing the given IR to the given - /// JITDylib. - virtual Error add(JITDylib &JD, ThreadSafeModule TSM, - VModuleKey K = VModuleKey()); + /// JITDylib. If RT is not specif + Error add(JITDylib &JD, ThreadSafeModule TSM) { + return add(JD.getDefaultResourceTracker(), std::move(TSM)); + } /// Emit should materialize the given IR. - virtual void emit(MaterializationResponsibility R, ThreadSafeModule TSM) = 0; + virtual void emit(std::unique_ptr R, + ThreadSafeModule TSM) = 0; private: bool CloneToNewContextOnEmit = false; @@ -114,14 +120,12 @@ class BasicIRLayerMaterializationUnit : public IRMaterializationUnit { public: BasicIRLayerMaterializationUnit(IRLayer &L, const IRSymbolMapper::ManglingOptions &MO, - ThreadSafeModule TSM, VModuleKey K); + ThreadSafeModule TSM); private: - - void materialize(MaterializationResponsibility R) override; + void materialize(std::unique_ptr R) override; IRLayer &L; - VModuleKey K; }; /// Interface for Layers that accept object files. @@ -135,11 +139,14 @@ class ObjectLayer { /// Adds a MaterializationUnit representing the given IR to the given /// JITDylib. - virtual Error add(JITDylib &JD, std::unique_ptr O, - VModuleKey K = VModuleKey()); + virtual Error add(ResourceTrackerSP RT, std::unique_ptr O); + + Error add(JITDylib &JD, std::unique_ptr O) { + return add(JD.getDefaultResourceTracker(), std::move(O)); + } /// Emit should materialize the given IR. - virtual void emit(MaterializationResponsibility R, + virtual void emit(std::unique_ptr R, std::unique_ptr O) = 0; private: @@ -151,9 +158,9 @@ class ObjectLayer { class BasicObjectLayerMaterializationUnit : public MaterializationUnit { public: static Expected> - Create(ObjectLayer &L, VModuleKey K, std::unique_ptr O); + Create(ObjectLayer &L, std::unique_ptr O); - BasicObjectLayerMaterializationUnit(ObjectLayer &L, VModuleKey K, + BasicObjectLayerMaterializationUnit(ObjectLayer &L, std::unique_ptr O, SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol); @@ -162,8 +169,7 @@ class BasicObjectLayerMaterializationUnit : public MaterializationUnit { StringRef getName() const override; private: - - void materialize(MaterializationResponsibility R) override; + void materialize(std::unique_ptr R) override; void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; ObjectLayer &L; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h deleted file mode 100644 index 84f5e0350c2ec..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h +++ /dev/null @@ -1,267 +0,0 @@ -//===- LazyEmittingLayer.h - Lazily emit IR to lower JIT layers -*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Contains the definition for a lazy-emitting layer for the JIT. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H -#define LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/Core.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include - -namespace llvm { -namespace orc { - -/// Lazy-emitting IR layer. -/// -/// This layer accepts LLVM IR Modules (via addModule) but does not -/// immediately emit them the layer below. Instead, emission to the base layer -/// is deferred until the first time the client requests the address (via -/// JITSymbol::getAddress) for a symbol contained in this layer. -template class LazyEmittingLayer { -private: - class EmissionDeferredModule { - public: - EmissionDeferredModule(VModuleKey K, std::unique_ptr M) - : K(std::move(K)), M(std::move(M)) {} - - JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) { - switch (EmitState) { - case NotEmitted: - if (auto GV = searchGVs(Name, ExportedSymbolsOnly)) { - JITSymbolFlags Flags = JITSymbolFlags::fromGlobalValue(*GV); - auto GetAddress = [this, ExportedSymbolsOnly, Name = Name.str(), - &B]() -> Expected { - if (this->EmitState == Emitting) - return 0; - else if (this->EmitState == NotEmitted) { - this->EmitState = Emitting; - if (auto Err = this->emitToBaseLayer(B)) - return std::move(Err); - this->EmitState = Emitted; - } - if (auto Sym = B.findSymbolIn(K, Name, ExportedSymbolsOnly)) - return Sym.getAddress(); - else if (auto Err = Sym.takeError()) - return std::move(Err); - else - llvm_unreachable("Successful symbol lookup should return " - "definition address here"); - }; - return JITSymbol(std::move(GetAddress), Flags); - } else - return nullptr; - case Emitting: - // Calling "emit" can trigger a recursive call to 'find' (e.g. to check - // for pre-existing definitions of common-symbol), but any symbol in - // this module would already have been found internally (in the - // RuntimeDyld that did the lookup), so just return a nullptr here. - return nullptr; - case Emitted: - return B.findSymbolIn(K, std::string(Name), ExportedSymbolsOnly); - } - llvm_unreachable("Invalid emit-state."); - } - - Error removeModuleFromBaseLayer(BaseLayerT& BaseLayer) { - return EmitState != NotEmitted ? BaseLayer.removeModule(K) - : Error::success(); - } - - void emitAndFinalize(BaseLayerT &BaseLayer) { - assert(EmitState != Emitting && - "Cannot emitAndFinalize while already emitting"); - if (EmitState == NotEmitted) { - EmitState = Emitting; - emitToBaseLayer(BaseLayer); - EmitState = Emitted; - } - BaseLayer.emitAndFinalize(K); - } - - private: - - const GlobalValue* searchGVs(StringRef Name, - bool ExportedSymbolsOnly) const { - // FIXME: We could clean all this up if we had a way to reliably demangle - // names: We could just demangle name and search, rather than - // mangling everything else. - - // If we have already built the mangled name set then just search it. - if (MangledSymbols) { - auto VI = MangledSymbols->find(Name); - if (VI == MangledSymbols->end()) - return nullptr; - auto GV = VI->second; - if (!ExportedSymbolsOnly || GV->hasDefaultVisibility()) - return GV; - return nullptr; - } - - // If we haven't built the mangled name set yet, try to build it. As an - // optimization this will leave MangledNames set to nullptr if we find - // Name in the process of building the set. - return buildMangledSymbols(Name, ExportedSymbolsOnly); - } - - Error emitToBaseLayer(BaseLayerT &BaseLayer) { - // We don't need the mangled names set any more: Once we've emitted this - // to the base layer we'll just look for symbols there. - MangledSymbols.reset(); - return BaseLayer.addModule(std::move(K), std::move(M)); - } - - // If the mangled name of the given GlobalValue matches the given search - // name (and its visibility conforms to the ExportedSymbolsOnly flag) then - // return the symbol. Otherwise, add the mangled name to the Names map and - // return nullptr. - const GlobalValue* addGlobalValue(StringMap &Names, - const GlobalValue &GV, - const Mangler &Mang, StringRef SearchName, - bool ExportedSymbolsOnly) const { - // Modules don't "provide" decls or common symbols. - if (GV.isDeclaration() || GV.hasCommonLinkage()) - return nullptr; - - // Mangle the GV name. - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mang.getNameWithPrefix(MangledNameStream, &GV, false); - } - - // Check whether this is the name we were searching for, and if it is then - // bail out early. - if (MangledName == SearchName) - if (!ExportedSymbolsOnly || GV.hasDefaultVisibility()) - return &GV; - - // Otherwise add this to the map for later. - Names[MangledName] = &GV; - return nullptr; - } - - // Build the MangledSymbols map. Bails out early (with MangledSymbols left set - // to nullptr) if the given SearchName is found while building the map. - const GlobalValue* buildMangledSymbols(StringRef SearchName, - bool ExportedSymbolsOnly) const { - assert(!MangledSymbols && "Mangled symbols map already exists?"); - - auto Symbols = std::make_unique>(); - - Mangler Mang; - - for (const auto &GO : M->global_objects()) - if (auto GV = addGlobalValue(*Symbols, GO, Mang, SearchName, - ExportedSymbolsOnly)) - return GV; - - MangledSymbols = std::move(Symbols); - return nullptr; - } - - enum { NotEmitted, Emitting, Emitted } EmitState = NotEmitted; - VModuleKey K; - std::unique_ptr M; - mutable std::unique_ptr> MangledSymbols; - }; - - BaseLayerT &BaseLayer; - std::map> ModuleMap; - -public: - - /// Construct a lazy emitting layer. - LLVM_ATTRIBUTE_DEPRECATED( - LazyEmittingLayer(BaseLayerT &BaseLayer), - "ORCv1 layers (including LazyEmittingLayer) are deprecated. Please use " - "ORCv2, where lazy emission is the default"); - - /// Construct a lazy emitting layer. - LazyEmittingLayer(ORCv1DeprecationAcknowledgement, BaseLayerT &BaseLayer) - : BaseLayer(BaseLayer) {} - - /// Add the given module to the lazy emitting layer. - Error addModule(VModuleKey K, std::unique_ptr M) { - assert(!ModuleMap.count(K) && "VModuleKey K already in use"); - ModuleMap[K] = - std::make_unique(std::move(K), std::move(M)); - return Error::success(); - } - - /// Remove the module represented by the given handle. - /// - /// This method will free the memory associated with the given module, both - /// in this layer, and the base layer. - Error removeModule(VModuleKey K) { - auto I = ModuleMap.find(K); - assert(I != ModuleMap.end() && "VModuleKey K not valid here"); - auto EDM = std::move(I.second); - ModuleMap.erase(I); - return EDM->removeModuleFromBaseLayer(BaseLayer); - } - - /// Search for the given named symbol. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - // Look for the symbol among existing definitions. - if (auto Symbol = BaseLayer.findSymbol(Name, ExportedSymbolsOnly)) - return Symbol; - - // If not found then search the deferred modules. If any of these contain a - // definition of 'Name' then they will return a JITSymbol that will emit - // the corresponding module when the symbol address is requested. - for (auto &KV : ModuleMap) - if (auto Symbol = KV.second->find(Name, ExportedSymbolsOnly, BaseLayer)) - return Symbol; - - // If no definition found anywhere return a null symbol. - return nullptr; - } - - /// Get the address of the given symbol in the context of the of - /// compiled modules represented by the key K. - JITSymbol findSymbolIn(VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) { - assert(ModuleMap.count(K) && "VModuleKey K not valid here"); - return ModuleMap[K]->find(Name, ExportedSymbolsOnly, BaseLayer); - } - - /// Immediately emit and finalize the module represented by the given - /// key. - Error emitAndFinalize(VModuleKey K) { - assert(ModuleMap.count(K) && "VModuleKey K not valid here"); - return ModuleMap[K]->emitAndFinalize(BaseLayer); - } -}; - -template -LazyEmittingLayer::LazyEmittingLayer(BaseLayerT &BaseLayer) - : BaseLayer(BaseLayer) {} - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h b/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h index 9206e40fffb1c..e6a9d89452851 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LazyReexports.h @@ -144,12 +144,12 @@ class LazyReexportsMaterializationUnit : public MaterializationUnit { IndirectStubsManager &ISManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, - ImplSymbolMap *SrcJDLoc, VModuleKey K); + ImplSymbolMap *SrcJDLoc); StringRef getName() const override; private: - void materialize(MaterializationResponsibility R) override; + void materialize(std::unique_ptr R) override; void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); @@ -166,11 +166,10 @@ class LazyReexportsMaterializationUnit : public MaterializationUnit { inline std::unique_ptr lazyReexports(LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, JITDylib &SourceJD, - SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc = nullptr, - VModuleKey K = VModuleKey()) { + SymbolAliasMap CallableAliases, + ImplSymbolMap *SrcJDLoc = nullptr) { return std::make_unique( - LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc, - std::move(K)); + LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc); } } // End namespace orc diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h b/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h deleted file mode 100644 index b20202a49ef65..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/Legacy.h +++ /dev/null @@ -1,211 +0,0 @@ -//===--- Legacy.h -- Adapters for ExecutionEngine API interop ---*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Contains core ORC APIs. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_LEGACY_H -#define LLVM_EXECUTIONENGINE_ORC_LEGACY_H - -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/Core.h" - -namespace llvm { -namespace orc { - -/// SymbolResolver is a composable interface for looking up symbol flags -/// and addresses using the AsynchronousSymbolQuery type. It will -/// eventually replace the LegacyJITSymbolResolver interface as the -/// stardard ORC symbol resolver type. -/// -/// FIXME: SymbolResolvers should go away and be replaced with VSOs with -/// defenition generators. -class SymbolResolver { -public: - virtual ~SymbolResolver() = default; - - /// Returns the subset of the given symbols that the caller is responsible for - /// materializing. - virtual SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) = 0; - - /// For each symbol in Symbols that can be found, assigns that symbols - /// value in Query. Returns the set of symbols that could not be found. - virtual SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) = 0; - -private: - virtual void anchor(); -}; - -/// Implements SymbolResolver with a pair of supplied function objects -/// for convenience. See createSymbolResolver. -template -class LambdaSymbolResolver final : public SymbolResolver { -public: - template - LambdaSymbolResolver(GetResponsibilitySetFnRef &&GetResponsibilitySet, - LookupFnRef &&Lookup) - : GetResponsibilitySet( - std::forward(GetResponsibilitySet)), - Lookup(std::forward(Lookup)) {} - - SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final { - return GetResponsibilitySet(Symbols); - } - - SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) final { - return Lookup(std::move(Query), std::move(Symbols)); - } - -private: - GetResponsibilitySetFn GetResponsibilitySet; - LookupFn Lookup; -}; - -/// Creates a SymbolResolver implementation from the pair of supplied -/// function objects. -template -std::unique_ptr>, - std::remove_cv_t>>> -createSymbolResolver(GetResponsibilitySetFn &&GetResponsibilitySet, - LookupFn &&Lookup) { - using LambdaSymbolResolverImpl = LambdaSymbolResolver< - std::remove_cv_t>, - std::remove_cv_t>>; - return std::make_unique( - std::forward(GetResponsibilitySet), - std::forward(Lookup)); -} - -/// Legacy adapter. Remove once we kill off the old ORC layers. -class JITSymbolResolverAdapter : public JITSymbolResolver { -public: - JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R, - MaterializationResponsibility *MR); - Expected getResponsibilitySet(const LookupSet &Symbols) override; - void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override; - -private: - ExecutionSession &ES; - std::set ResolvedStrings; - SymbolResolver &R; - MaterializationResponsibility *MR; -}; - -/// Use the given legacy-style FindSymbol function (i.e. a function that takes -/// a const std::string& or StringRef and returns a JITSymbol) to get the -/// subset of symbols that the caller is responsible for materializing. If any -/// JITSymbol returned by FindSymbol is in an error state the function returns -/// immediately with that error. -/// -/// Useful for implementing getResponsibilitySet bodies that query legacy -/// resolvers. -template -Expected -getResponsibilitySetWithLegacyFn(const SymbolNameSet &Symbols, - FindSymbolFn FindSymbol) { - SymbolNameSet Result; - - for (auto &S : Symbols) { - if (JITSymbol Sym = FindSymbol(*S)) { - if (!Sym.getFlags().isStrong()) - Result.insert(S); - } else if (auto Err = Sym.takeError()) - return std::move(Err); - } - - return Result; -} - -/// Use the given legacy-style FindSymbol function (i.e. a function that -/// takes a const std::string& or StringRef and returns a JITSymbol) to -/// find the address and flags for each symbol in Symbols and store the -/// result in Query. If any JITSymbol returned by FindSymbol is in an -/// error then Query.notifyFailed(...) is called with that error and the -/// function returns immediately. On success, returns the set of symbols -/// not found. -/// -/// Useful for implementing lookup bodies that query legacy resolvers. -template -SymbolNameSet -lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query, - const SymbolNameSet &Symbols, FindSymbolFn FindSymbol) { - SymbolNameSet SymbolsNotFound; - bool NewSymbolsResolved = false; - - for (auto &S : Symbols) { - if (JITSymbol Sym = FindSymbol(*S)) { - if (auto Addr = Sym.getAddress()) { - Query.notifySymbolMetRequiredState( - S, JITEvaluatedSymbol(*Addr, Sym.getFlags())); - NewSymbolsResolved = true; - } else { - ES.legacyFailQuery(Query, Addr.takeError()); - return SymbolNameSet(); - } - } else if (auto Err = Sym.takeError()) { - ES.legacyFailQuery(Query, std::move(Err)); - return SymbolNameSet(); - } else - SymbolsNotFound.insert(S); - } - - if (NewSymbolsResolved && Query.isComplete()) - Query.handleComplete(); - - return SymbolsNotFound; -} - -/// An ORC SymbolResolver implementation that uses a legacy -/// findSymbol-like function to perform lookup; -template -class LegacyLookupFnResolver final : public SymbolResolver { -public: - using ErrorReporter = std::function; - - LegacyLookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup, - ErrorReporter ReportError) - : ES(ES), LegacyLookup(std::move(LegacyLookup)), - ReportError(std::move(ReportError)) {} - - SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final { - if (auto ResponsibilitySet = - getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup)) - return std::move(*ResponsibilitySet); - else { - ReportError(ResponsibilitySet.takeError()); - return SymbolNameSet(); - } - } - - SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) final { - return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup); - } - -private: - ExecutionSession &ES; - LegacyLookupFn LegacyLookup; - ErrorReporter ReportError; -}; - -template -std::shared_ptr> -createLegacyLookupResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup, - std::function ErrorReporter) { - return std::make_shared>( - ES, std::move(LegacyLookup), std::move(ErrorReporter)); -} - -} // End namespace orc -} // End namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_LEGACY_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h index 15fe079eccafd..90e1d4704f342 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h @@ -98,8 +98,9 @@ class MachOPlatform : public Platform { ExecutionSession &getExecutionSession() const { return ES; } Error setupJITDylib(JITDylib &JD) override; - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU) override; - Error notifyRemoving(JITDylib &JD, VModuleKey K) override; + Error notifyAdding(ResourceTracker &RT, + const MaterializationUnit &MU) override; + Error notifyRemoving(ResourceTracker &RT) override; Expected getInitializerSequence(JITDylib &JD); @@ -119,6 +120,19 @@ class MachOPlatform : public Platform { LocalDependenciesMap getSyntheticSymbolLocalDependencies( MaterializationResponsibility &MR) override; + // FIXME: We should be tentatively tracking scraped sections and discarding + // if the MR fails. + Error notifyFailed(MaterializationResponsibility &MR) override { + return Error::success(); + } + + Error notifyRemovingResources(ResourceKey K) override { + return Error::success(); + } + + void notifyTransferringResources(ResourceKey DstKey, + ResourceKey SrcKey) override {} + private: using InitSymbolDepMap = DenseMap; @@ -136,8 +150,6 @@ class MachOPlatform : public Platform { InitSymbolDepMap InitSymbolDeps; }; - static std::vector getDFSLinkOrder(JITDylib &JD); - void registerInitInfo(JITDylib &JD, JITTargetAddress ObjCImageInfoAddr, MachOJITDylibInitializers::SectionExtent ModInits, MachOJITDylibInitializers::SectionExtent ObjCSelRefs, diff --git a/llvm/include/llvm/ExecutionEngine/Orc/NullResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/NullResolver.h deleted file mode 100644 index ffa37a13d0649..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/NullResolver.h +++ /dev/null @@ -1,43 +0,0 @@ -//===------ NullResolver.h - Reject symbol lookup requests ------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Defines a RuntimeDyld::SymbolResolver subclass that rejects all symbol -// resolution requests, for clients that have no cross-object fixups. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H -#define LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H - -#include "llvm/ExecutionEngine/Orc/Legacy.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" - -namespace llvm { -namespace orc { - -class NullResolver : public SymbolResolver { -public: - SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final; - - SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) final; -}; - -/// SymbolResolver impliementation that rejects all resolution requests. -/// Useful for clients that have no cross-object fixups. -class NullLegacyResolver : public LegacyJITSymbolResolver { -public: - JITSymbol findSymbol(const std::string &Name) final; - - JITSymbol findSymbolInLogicalDylib(const std::string &Name) final; -}; - -} // End namespace orc. -} // End namespace llvm. - -#endif // LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index fbf9bde8a9d55..b73217f09b54b 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -51,7 +51,7 @@ class ObjectLinkingLayerJITLinkContext; /// Clients can use this class to add relocatable object files to an /// ExecutionSession, and it typically serves as the base layer (underneath /// a compiling layer like IRCompileLayer) for the rest of the JIT. -class ObjectLinkingLayer : public ObjectLayer { +class ObjectLinkingLayer : public ObjectLayer, private ResourceManager { friend class ObjectLinkingLayerJITLinkContext; public: @@ -72,10 +72,10 @@ class ObjectLinkingLayer : public ObjectLayer { virtual Error notifyEmitted(MaterializationResponsibility &MR) { return Error::success(); } - virtual Error notifyRemovingModule(VModuleKey K) { - return Error::success(); - } - virtual Error notifyRemovingAllModules() { return Error::success(); } + virtual Error notifyFailed(MaterializationResponsibility &MR) = 0; + virtual Error notifyRemovingResources(ResourceKey K) = 0; + virtual void notifyTransferringResources(ResourceKey DstKey, + ResourceKey SrcKey) = 0; /// Return any dependencies that synthetic symbols (e.g. init symbols) /// have on locally scoped jitlink::Symbols. This is used by the @@ -119,7 +119,7 @@ class ObjectLinkingLayer : public ObjectLayer { } /// Emit the object. - void emit(MaterializationResponsibility R, + void emit(std::unique_ptr R, std::unique_ptr O) override; /// Instructs this ObjectLinkingLayer instance to override the symbol flags @@ -161,8 +161,8 @@ class ObjectLinkingLayer : public ObjectLayer { void notifyLoaded(MaterializationResponsibility &MR); Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc); - Error removeModule(VModuleKey K); - Error removeAllModules(); + Error handleRemoveResources(ResourceKey K) override; + void handleTransferResources(ResourceKey DstKey, ResourceKey SrcKey) override; mutable std::mutex LayerMutex; jitlink::JITLinkMemoryManager &MemMgr; @@ -170,19 +170,22 @@ class ObjectLinkingLayer : public ObjectLayer { bool OverrideObjectFlags = false; bool AutoClaimObjectSymbols = false; ReturnObjectBufferFunction ReturnObjectBuffer; - DenseMap TrackedAllocs; - std::vector UntrackedAllocs; + DenseMap> Allocs; std::vector> Plugins; }; class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin { public: - EHFrameRegistrationPlugin(jitlink::EHFrameRegistrar &Registrar); - Error notifyEmitted(MaterializationResponsibility &MR) override; + EHFrameRegistrationPlugin( + ExecutionSession &ES, + std::unique_ptr Registrar); void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, jitlink::PassConfiguration &PassConfig) override; - Error notifyRemovingModule(VModuleKey K) override; - Error notifyRemovingAllModules() override; + Error notifyEmitted(MaterializationResponsibility &MR) override; + Error notifyFailed(MaterializationResponsibility &MR) override; + Error notifyRemovingResources(ResourceKey K) override; + void notifyTransferringResources(ResourceKey DstKey, + ResourceKey SrcKey) override; private: @@ -192,10 +195,10 @@ class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin { }; std::mutex EHFramePluginMutex; - jitlink::EHFrameRegistrar &Registrar; + ExecutionSession &ES; + std::unique_ptr Registrar; DenseMap InProcessLinks; - DenseMap TrackedEHFrameRanges; - std::vector UntrackedEHFrameRanges; + DenseMap> EHFrameRanges; }; } // end namespace orc diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h index bf989cc8677cf..d8395ab34e470 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h @@ -31,7 +31,7 @@ class ObjectTransformLayer : public ObjectLayer { ObjectTransformLayer(ExecutionSession &ES, ObjectLayer &BaseLayer, TransformFunction Transform = TransformFunction()); - void emit(MaterializationResponsibility R, + void emit(std::unique_ptr R, std::unique_ptr O) override; void setTransform(TransformFunction Transform) { @@ -43,88 +43,6 @@ class ObjectTransformLayer : public ObjectLayer { TransformFunction Transform; }; -/// Object mutating layer. -/// -/// This layer accepts sets of ObjectFiles (via addObject). It -/// immediately applies the user supplied functor to each object, then adds -/// the set of transformed objects to the layer below. -template -class LegacyObjectTransformLayer { -public: - /// Construct an ObjectTransformLayer with the given BaseLayer - LLVM_ATTRIBUTE_DEPRECATED( - LegacyObjectTransformLayer(BaseLayerT &BaseLayer, - TransformFtor Transform = TransformFtor()), - "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please " - "use " - "the ORCv2 ObjectTransformLayer instead"); - - /// Legacy layer constructor with deprecation acknowledgement. - LegacyObjectTransformLayer(ORCv1DeprecationAcknowledgement, - BaseLayerT &BaseLayer, - TransformFtor Transform = TransformFtor()) - : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} - - /// Apply the transform functor to each object in the object set, then - /// add the resulting set of objects to the base layer, along with the - /// memory manager and symbol resolver. - /// - /// @return A handle for the added objects. - template Error addObject(VModuleKey K, ObjectPtr Obj) { - return BaseLayer.addObject(std::move(K), Transform(std::move(Obj))); - } - - /// Remove the object set associated with the VModuleKey K. - Error removeObject(VModuleKey K) { return BaseLayer.removeObject(K); } - - /// Search for the given named symbol. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); - } - - /// Get the address of the given symbol in the context of the set of - /// objects represented by the VModuleKey K. This call is forwarded to - /// the base layer's implementation. - /// @param K The VModuleKey associated with the object set to search in. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it is found in the - /// given object set. - JITSymbol findSymbolIn(VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) { - return BaseLayer.findSymbolIn(K, Name, ExportedSymbolsOnly); - } - - /// Immediately emit and finalize the object set represented by the - /// given VModuleKey K. - Error emitAndFinalize(VModuleKey K) { return BaseLayer.emitAndFinalize(K); } - - /// Map section addresses for the objects associated with the - /// VModuleKey K. - void mapSectionAddress(VModuleKey K, const void *LocalAddress, - JITTargetAddress TargetAddr) { - BaseLayer.mapSectionAddress(K, LocalAddress, TargetAddr); - } - - /// Access the transform functor directly. - TransformFtor &getTransform() { return Transform; } - - /// Access the mumate functor directly. - const TransformFtor &getTransform() const { return Transform; } - -private: - BaseLayerT &BaseLayer; - TransformFtor Transform; -}; - -template -LegacyObjectTransformLayer:: - LegacyObjectTransformLayer(BaseLayerT &BaseLayer, TransformFtor Transform) - : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} - } // end namespace orc } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h index 9ada0871cf0cb..7dfbf32b1ffa5 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h @@ -20,7 +20,6 @@ #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/ExecutionEngine/Orc/Layer.h" -#include "llvm/ExecutionEngine/Orc/Legacy.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Error.h" @@ -36,16 +35,16 @@ namespace llvm { namespace orc { -class RTDyldObjectLinkingLayer : public ObjectLayer { +class RTDyldObjectLinkingLayer : public ObjectLayer, private ResourceManager { public: /// Functor for receiving object-loaded notifications. - using NotifyLoadedFunction = - std::function; + using NotifyLoadedFunction = std::function; /// Functor for receiving finalization notifications. - using NotifyEmittedFunction = - std::function)>; + using NotifyEmittedFunction = std::function)>; using GetMemoryManagerFunction = std::function()>; @@ -58,7 +57,7 @@ class RTDyldObjectLinkingLayer : public ObjectLayer { ~RTDyldObjectLinkingLayer(); /// Emit the object. - void emit(MaterializationResponsibility R, + void emit(std::unique_ptr R, std::unique_ptr O) override; /// Set the NotifyLoaded callback. @@ -123,16 +122,23 @@ class RTDyldObjectLinkingLayer : public ObjectLayer { void unregisterJITEventListener(JITEventListener &L); private: - Error onObjLoad(VModuleKey K, MaterializationResponsibility &R, + using MemoryManagerUP = std::unique_ptr; + + Error onObjLoad(MaterializationResponsibility &R, const object::ObjectFile &Obj, - RuntimeDyld::MemoryManager *MemMgr, - std::unique_ptr LoadedObjInfo, + RuntimeDyld::MemoryManager &MemMgr, + RuntimeDyld::LoadedObjectInfo &LoadedObjInfo, std::map Resolved, std::set &InternalSymbols); - void onObjEmit(VModuleKey K, MaterializationResponsibility &R, + void onObjEmit(MaterializationResponsibility &R, object::OwningBinary O, - RuntimeDyld::MemoryManager *MemMgr, Error Err); + std::unique_ptr MemMgr, + std::unique_ptr LoadedObjInfo, + Error Err); + + Error handleRemoveResources(ResourceKey K) override; + void handleTransferResources(ResourceKey DstKey, ResourceKey SrcKey) override; mutable std::mutex RTDyldLayerMutex; GetMemoryManagerFunction GetMemoryManager; @@ -141,361 +147,8 @@ class RTDyldObjectLinkingLayer : public ObjectLayer { bool ProcessAllSections = false; bool OverrideObjectFlags = false; bool AutoClaimObjectSymbols = false; - std::vector> MemMgrs; + DenseMap> MemMgrs; std::vector EventListeners; - DenseMap> - LoadedObjInfos; -}; - -class LegacyRTDyldObjectLinkingLayerBase { -public: - using ObjectPtr = std::unique_ptr; - -protected: - - /// Holds an object to be allocated/linked as a unit in the JIT. - /// - /// An instance of this class will be created for each object added - /// via JITObjectLayer::addObject. Deleting the instance (via - /// removeObject) frees its memory, removing all symbol definitions that - /// had been provided by this instance. Higher level layers are responsible - /// for taking any action required to handle the missing symbols. - class LinkedObject { - public: - LinkedObject() = default; - LinkedObject(const LinkedObject&) = delete; - void operator=(const LinkedObject&) = delete; - virtual ~LinkedObject() = default; - - virtual Error finalize() = 0; - - virtual JITSymbol::GetAddressFtor - getSymbolMaterializer(std::string Name) = 0; - - virtual void mapSectionAddress(const void *LocalAddress, - JITTargetAddress TargetAddr) const = 0; - - JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) { - auto SymEntry = SymbolTable.find(Name); - if (SymEntry == SymbolTable.end()) - return nullptr; - if (!SymEntry->second.getFlags().isExported() && ExportedSymbolsOnly) - return nullptr; - if (!Finalized) - return JITSymbol(getSymbolMaterializer(std::string(Name)), - SymEntry->second.getFlags()); - return JITSymbol(SymEntry->second); - } - - protected: - StringMap SymbolTable; - bool Finalized = false; - }; -}; - -/// Bare bones object linking layer. -/// -/// This class is intended to be used as the base layer for a JIT. It allows -/// object files to be loaded into memory, linked, and the addresses of their -/// symbols queried. All objects added to this layer can see each other's -/// symbols. -class LegacyRTDyldObjectLinkingLayer : public LegacyRTDyldObjectLinkingLayerBase { -public: - - using LegacyRTDyldObjectLinkingLayerBase::ObjectPtr; - - /// Functor for receiving object-loaded notifications. - using NotifyLoadedFtor = - std::function; - - /// Functor for receiving finalization notifications. - using NotifyFinalizedFtor = - std::function; - - /// Functor for receiving deallocation notifications. - using NotifyFreedFtor = std::function; - -private: - using OwnedObject = object::OwningBinary; - - template - class ConcreteLinkedObject : public LinkedObject { - public: - ConcreteLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K, - OwnedObject Obj, MemoryManagerPtrT MemMgr, - std::shared_ptr Resolver, - bool ProcessAllSections) - : K(std::move(K)), - Parent(Parent), - MemMgr(std::move(MemMgr)), - PFC(std::make_unique( - std::move(Obj), std::move(Resolver), - ProcessAllSections)) { - buildInitialSymbolTable(PFC->Obj); - } - - ~ConcreteLinkedObject() override { - if (this->Parent.NotifyFreed && ObjForNotify.getBinary()) - this->Parent.NotifyFreed(K, *ObjForNotify.getBinary()); - - MemMgr->deregisterEHFrames(); - } - - Error finalize() override { - assert(PFC && "mapSectionAddress called on finalized LinkedObject"); - - JITSymbolResolverAdapter ResolverAdapter(Parent.ES, *PFC->Resolver, - nullptr); - PFC->RTDyld = std::make_unique(*MemMgr, ResolverAdapter); - PFC->RTDyld->setProcessAllSections(PFC->ProcessAllSections); - - Finalized = true; - - std::unique_ptr Info = - PFC->RTDyld->loadObject(*PFC->Obj.getBinary()); - - // Copy the symbol table out of the RuntimeDyld instance. - { - auto SymTab = PFC->RTDyld->getSymbolTable(); - for (auto &KV : SymTab) - SymbolTable[KV.first] = KV.second; - } - - if (Parent.NotifyLoaded) - Parent.NotifyLoaded(K, *PFC->Obj.getBinary(), *Info); - - PFC->RTDyld->finalizeWithMemoryManagerLocking(); - - if (PFC->RTDyld->hasError()) - return make_error(PFC->RTDyld->getErrorString(), - inconvertibleErrorCode()); - - if (Parent.NotifyFinalized) - Parent.NotifyFinalized(K, *PFC->Obj.getBinary(), *Info); - - // Release resources. - if (this->Parent.NotifyFreed) - ObjForNotify = std::move(PFC->Obj); // needed for callback - PFC = nullptr; - return Error::success(); - } - - JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override { - return [this, Name]() -> Expected { - // The symbol may be materialized between the creation of this lambda - // and its execution, so we need to double check. - if (!this->Finalized) - if (auto Err = this->finalize()) - return std::move(Err); - return this->getSymbol(Name, false).getAddress(); - }; - } - - void mapSectionAddress(const void *LocalAddress, - JITTargetAddress TargetAddr) const override { - assert(PFC && "mapSectionAddress called on finalized LinkedObject"); - assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject"); - PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr); - } - - private: - void buildInitialSymbolTable(const OwnedObject &Obj) { - for (auto &Symbol : Obj.getBinary()->symbols()) { - if (Expected SymbolFlagsOrErr = Symbol.getFlags()) { - if (*SymbolFlagsOrErr & object::SymbolRef::SF_Undefined) - continue; - } else { - // FIXME: Raise an error for bad symbols. - consumeError(SymbolFlagsOrErr.takeError()); - continue; - } - - Expected SymbolName = Symbol.getName(); - // FIXME: Raise an error for bad symbols. - if (!SymbolName) { - consumeError(SymbolName.takeError()); - continue; - } - // FIXME: Raise an error for bad symbols. - auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol); - if (!Flags) { - consumeError(Flags.takeError()); - continue; - } - SymbolTable.insert( - std::make_pair(*SymbolName, JITEvaluatedSymbol(0, *Flags))); - } - } - - // Contains the information needed prior to finalization: the object files, - // memory manager, resolver, and flags needed for RuntimeDyld. - struct PreFinalizeContents { - PreFinalizeContents(OwnedObject Obj, - std::shared_ptr Resolver, - bool ProcessAllSections) - : Obj(std::move(Obj)), - Resolver(std::move(Resolver)), - ProcessAllSections(ProcessAllSections) {} - - OwnedObject Obj; - std::shared_ptr Resolver; - bool ProcessAllSections; - std::unique_ptr RTDyld; - }; - - VModuleKey K; - LegacyRTDyldObjectLinkingLayer &Parent; - MemoryManagerPtrT MemMgr; - OwnedObject ObjForNotify; - std::unique_ptr PFC; - }; - - template - std::unique_ptr> - createLinkedObject(LegacyRTDyldObjectLinkingLayer &Parent, VModuleKey K, - OwnedObject Obj, MemoryManagerPtrT MemMgr, - std::shared_ptr Resolver, - bool ProcessAllSections) { - using LOS = ConcreteLinkedObject; - return std::make_unique(Parent, std::move(K), std::move(Obj), - std::move(MemMgr), std::move(Resolver), - ProcessAllSections); - } - -public: - struct Resources { - std::shared_ptr MemMgr; - std::shared_ptr Resolver; - }; - - using ResourcesGetter = std::function; - - /// Construct an ObjectLinkingLayer with the given NotifyLoaded, - /// and NotifyFinalized functors. - LLVM_ATTRIBUTE_DEPRECATED( - LegacyRTDyldObjectLinkingLayer( - ExecutionSession &ES, ResourcesGetter GetResources, - NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), - NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(), - NotifyFreedFtor NotifyFreed = NotifyFreedFtor()), - "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please " - "use " - "ORCv2 (see docs/ORCv2.rst)"); - - // Legacy layer constructor with deprecation acknowledgement. - LegacyRTDyldObjectLinkingLayer( - ORCv1DeprecationAcknowledgement, ExecutionSession &ES, - ResourcesGetter GetResources, - NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), - NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor(), - NotifyFreedFtor NotifyFreed = NotifyFreedFtor()) - : ES(ES), GetResources(std::move(GetResources)), - NotifyLoaded(std::move(NotifyLoaded)), - NotifyFinalized(std::move(NotifyFinalized)), - NotifyFreed(std::move(NotifyFreed)), ProcessAllSections(false) {} - - /// Set the 'ProcessAllSections' flag. - /// - /// If set to true, all sections in each object file will be allocated using - /// the memory manager, rather than just the sections required for execution. - /// - /// This is kludgy, and may be removed in the future. - void setProcessAllSections(bool ProcessAllSections) { - this->ProcessAllSections = ProcessAllSections; - } - - /// Add an object to the JIT. - Error addObject(VModuleKey K, ObjectPtr ObjBuffer) { - - auto Obj = - object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - if (!Obj) - return Obj.takeError(); - - assert(!LinkedObjects.count(K) && "VModuleKey already in use"); - - auto R = GetResources(K); - - LinkedObjects[K] = createLinkedObject( - *this, K, OwnedObject(std::move(*Obj), std::move(ObjBuffer)), - std::move(R.MemMgr), std::move(R.Resolver), ProcessAllSections); - - return Error::success(); - } - - /// Remove the object associated with VModuleKey K. - /// - /// All memory allocated for the object will be freed, and the sections and - /// symbols it provided will no longer be available. No attempt is made to - /// re-emit the missing symbols, and any use of these symbols (directly or - /// indirectly) will result in undefined behavior. If dependence tracking is - /// required to detect or resolve such issues it should be added at a higher - /// layer. - Error removeObject(VModuleKey K) { - assert(LinkedObjects.count(K) && "VModuleKey not associated with object"); - // How do we invalidate the symbols in H? - LinkedObjects.erase(K); - return Error::success(); - } - - /// Search for the given named symbol. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it exists. - JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { - for (auto &KV : LinkedObjects) - if (auto Sym = KV.second->getSymbol(Name, ExportedSymbolsOnly)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - - return nullptr; - } - - /// Search for the given named symbol in the context of the loaded - /// object represented by the VModuleKey K. - /// @param K The VModuleKey for the object to search in. - /// @param Name The name of the symbol to search for. - /// @param ExportedSymbolsOnly If true, search only for exported symbols. - /// @return A handle for the given named symbol, if it is found in the - /// given object. - JITSymbol findSymbolIn(VModuleKey K, StringRef Name, - bool ExportedSymbolsOnly) { - assert(LinkedObjects.count(K) && "VModuleKey not associated with object"); - return LinkedObjects[K]->getSymbol(Name, ExportedSymbolsOnly); - } - - /// Map section addresses for the object associated with the - /// VModuleKey K. - void mapSectionAddress(VModuleKey K, const void *LocalAddress, - JITTargetAddress TargetAddr) { - assert(LinkedObjects.count(K) && "VModuleKey not associated with object"); - LinkedObjects[K]->mapSectionAddress(LocalAddress, TargetAddr); - } - - /// Immediately emit and finalize the object represented by the given - /// VModuleKey. - /// @param K VModuleKey for object to emit/finalize. - Error emitAndFinalize(VModuleKey K) { - assert(LinkedObjects.count(K) && "VModuleKey not associated with object"); - return LinkedObjects[K]->finalize(); - } - -private: - ExecutionSession &ES; - - ResourcesGetter GetResources; - NotifyLoadedFtor NotifyLoaded; - NotifyFinalizedFtor NotifyFinalized; - NotifyFreedFtor NotifyFreed; - - // NB! `LinkedObjects` needs to be destroyed before `NotifyFreed` because - // `~ConcreteLinkedObject` calls `NotifyFreed` - std::map> LinkedObjects; - bool ProcessAllSections = false; }; } // end namespace orc diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h deleted file mode 100644 index d7304cfcf9316..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/RemoteObjectLayer.h +++ /dev/null @@ -1,564 +0,0 @@ -//===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Forwards objects to a remote object layer via RPC. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H -#define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H - -#include "llvm/ExecutionEngine/Orc/Core.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" -#include "llvm/Object/ObjectFile.h" -#include - -namespace llvm { -namespace orc { - -/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer. -class RemoteObjectLayerAPI { -public: - - using ObjHandleT = remote::ResourceIdMgr::ResourceId; - -protected: - - using RemoteSymbolId = remote::ResourceIdMgr::ResourceId; - using RemoteSymbol = std::pair; - -public: - - using BadSymbolHandleError = remote::ResourceNotFound; - using BadObjectHandleError = remote::ResourceNotFound; - -protected: - - static const ObjHandleT InvalidObjectHandleId = 0; - static const RemoteSymbolId NullSymbolId = 0; - - class AddObject - : public rpc::Function(std::string)> { - public: - static const char *getName() { return "AddObject"; } - }; - - class RemoveObject - : public rpc::Function { - public: - static const char *getName() { return "RemoveObject"; } - }; - - class FindSymbol - : public rpc::Function(std::string, - bool)> { - public: - static const char *getName() { return "FindSymbol"; } - }; - - class FindSymbolIn - : public rpc::Function(ObjHandleT, std::string, - bool)> { - public: - static const char *getName() { return "FindSymbolIn"; } - }; - - class EmitAndFinalize - : public rpc::Function { - public: - static const char *getName() { return "EmitAndFinalize"; } - }; - - class Lookup - : public rpc::Function(ObjHandleT, std::string)> { - public: - static const char *getName() { return "Lookup"; } - }; - - class LookupInLogicalDylib - : public rpc::Function(ObjHandleT, std::string)> { - public: - static const char *getName() { return "LookupInLogicalDylib"; } - }; - - class ReleaseRemoteSymbol - : public rpc::Function { - public: - static const char *getName() { return "ReleaseRemoteSymbol"; } - }; - - class MaterializeRemoteSymbol - : public rpc::Function(RemoteSymbolId)> { - public: - static const char *getName() { return "MaterializeRemoteSymbol"; } - }; -}; - -/// Base class containing common utilities for RemoteObjectClientLayer and -/// RemoteObjectServerLayer. -template -class RemoteObjectLayer : public RemoteObjectLayerAPI { -public: - - RemoteObjectLayer(RPCEndpoint &Remote, - std::function ReportError) - : Remote(Remote), ReportError(std::move(ReportError)), - SymbolIdMgr(NullSymbolId + 1) { - using ThisT = RemoteObjectLayer; - Remote.template addHandler( - *this, &ThisT::handleReleaseRemoteSymbol); - Remote.template addHandler( - *this, &ThisT::handleMaterializeRemoteSymbol); - } - -protected: - - /// This class is used as the symbol materializer for JITSymbols returned by - /// RemoteObjectLayerClient/RemoteObjectLayerServer -- the materializer knows - /// how to call back to the other RPC endpoint to get the address when - /// requested. - class RemoteSymbolMaterializer { - public: - - /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer - /// with the given Id. - RemoteSymbolMaterializer(RemoteObjectLayer &C, - RemoteSymbolId Id) - : C(C), Id(Id) {} - - RemoteSymbolMaterializer(RemoteSymbolMaterializer &&Other) - : C(Other.C), Id(Other.Id) { - Other.Id = 0; - } - - RemoteSymbolMaterializer &operator=(RemoteSymbolMaterializer &&) = delete; - - /// Release the remote symbol. - ~RemoteSymbolMaterializer() { - if (Id) - C.releaseRemoteSymbol(Id); - } - - /// Materialize the symbol on the remote and get its address. - Expected materialize() { - auto Addr = C.materializeRemoteSymbol(Id); - Id = 0; - return Addr; - } - - private: - RemoteObjectLayer &C; - RemoteSymbolId Id; - }; - - /// Convenience function for getting a null remote symbol value. - RemoteSymbol nullRemoteSymbol() { - return RemoteSymbol(0, JITSymbolFlags()); - } - - /// Creates a StringError that contains a copy of Err's log message, then - /// sends that StringError to ReportError. - /// - /// This allows us to locally log error messages for errors that will actually - /// be delivered to the remote. - Error teeLog(Error Err) { - return handleErrors(std::move(Err), - [this](std::unique_ptr EIB) { - ReportError(make_error( - EIB->message(), - EIB->convertToErrorCode())); - return Error(std::move(EIB)); - }); - } - - Error badRemoteSymbolIdError(RemoteSymbolId Id) { - return make_error(Id, "Remote JIT Symbol"); - } - - Error badObjectHandleError(ObjHandleT H) { - return make_error( - H, "Bad object handle"); - } - - /// Create a RemoteSymbol wrapping the given JITSymbol. - Expected jitSymbolToRemote(JITSymbol Sym) { - if (Sym) { - auto Id = SymbolIdMgr.getNext(); - auto Flags = Sym.getFlags(); - assert(!InUseSymbols.count(Id) && "Symbol id already in use"); - InUseSymbols.insert(std::make_pair(Id, std::move(Sym))); - return RemoteSymbol(Id, Flags); - } else if (auto Err = Sym.takeError()) - return teeLog(std::move(Err)); - // else... - return nullRemoteSymbol(); - } - - /// Convert an Expected to a JITSymbol. - JITSymbol remoteToJITSymbol(Expected RemoteSymOrErr) { - if (RemoteSymOrErr) { - auto &RemoteSym = *RemoteSymOrErr; - if (RemoteSym == nullRemoteSymbol()) - return nullptr; - // else... - RemoteSymbolMaterializer RSM(*this, RemoteSym.first); - auto Sym = JITSymbol( - [RSM = std::move(RSM)]() mutable { return RSM.materialize(); }, - RemoteSym.second); - return Sym; - } else - return RemoteSymOrErr.takeError(); - } - - RPCEndpoint &Remote; - std::function ReportError; - -private: - - /// Notify the remote to release the given JITSymbol. - void releaseRemoteSymbol(RemoteSymbolId Id) { - if (auto Err = Remote.template callB(Id)) - ReportError(std::move(Err)); - } - - /// Notify the remote to materialize the JITSymbol with the given Id and - /// return its address. - Expected materializeRemoteSymbol(RemoteSymbolId Id) { - return Remote.template callB(Id); - } - - /// Release the JITSymbol with the given Id. - Error handleReleaseRemoteSymbol(RemoteSymbolId Id) { - auto SI = InUseSymbols.find(Id); - if (SI != InUseSymbols.end()) { - InUseSymbols.erase(SI); - return Error::success(); - } else - return teeLog(badRemoteSymbolIdError(Id)); - } - - /// Run the materializer for the JITSymbol with the given Id and return its - /// address. - Expected handleMaterializeRemoteSymbol(RemoteSymbolId Id) { - auto SI = InUseSymbols.find(Id); - if (SI != InUseSymbols.end()) { - auto AddrOrErr = SI->second.getAddress(); - InUseSymbols.erase(SI); - SymbolIdMgr.release(Id); - if (AddrOrErr) - return *AddrOrErr; - else - return teeLog(AddrOrErr.takeError()); - } else { - return teeLog(badRemoteSymbolIdError(Id)); - } - } - - remote::ResourceIdMgr SymbolIdMgr; - std::map InUseSymbols; -}; - -/// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC -/// connection. -/// -/// This class can be used as the base layer of a JIT stack on the client and -/// will forward operations to a corresponding RemoteObjectServerLayer on the -/// server (which can be composed on top of a "real" object layer like -/// RTDyldObjectLinkingLayer to actually carry out the operations). -/// -/// Sending relocatable objects to the server (rather than fully relocated -/// bits) allows JIT'd code to be cached on the server side and re-used in -/// subsequent JIT sessions. -template -class RemoteObjectClientLayer : public RemoteObjectLayer { -private: - - using AddObject = RemoteObjectLayerAPI::AddObject; - using RemoveObject = RemoteObjectLayerAPI::RemoveObject; - using FindSymbol = RemoteObjectLayerAPI::FindSymbol; - using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn; - using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize; - using Lookup = RemoteObjectLayerAPI::Lookup; - using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib; - - using RemoteObjectLayer::teeLog; - using RemoteObjectLayer::badObjectHandleError; - using RemoteObjectLayer::remoteToJITSymbol; - -public: - - using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT; - using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol; - - using ObjectPtr = std::unique_ptr; - - /// Create a RemoteObjectClientLayer that communicates with a - /// RemoteObjectServerLayer instance via the given RPCEndpoint. - /// - /// The ReportError functor can be used locally log errors that are intended - /// to be sent sent - LLVM_ATTRIBUTE_DEPRECATED( - RemoteObjectClientLayer(RPCEndpoint &Remote, - std::function ReportError), - "ORCv1 layers (including RemoteObjectClientLayer) are deprecated. Please " - "use " - "ORCv2 (see docs/ORCv2.rst)"); - - RemoteObjectClientLayer(ORCv1DeprecationAcknowledgement, RPCEndpoint &Remote, - std::function ReportError) - : RemoteObjectLayer(Remote, std::move(ReportError)) { - using ThisT = RemoteObjectClientLayer; - Remote.template addHandler(*this, &ThisT::lookup); - Remote.template addHandler( - *this, &ThisT::lookupInLogicalDylib); - } - - /// Add an object to the JIT. - /// - /// @return A handle that can be used to refer to the loaded object (for - /// symbol searching, finalization, freeing memory, etc.). - Expected - addObject(ObjectPtr ObjBuffer, - std::shared_ptr Resolver) { - if (auto HandleOrErr = - this->Remote.template callB(ObjBuffer->getBuffer())) { - auto &Handle = *HandleOrErr; - // FIXME: Return an error for this: - assert(!Resolvers.count(Handle) && "Handle already in use?"); - Resolvers[Handle] = std::move(Resolver); - return Handle; - } else - return HandleOrErr.takeError(); - } - - /// Remove the given object from the JIT. - Error removeObject(ObjHandleT H) { - return this->Remote.template callB(H); - } - - /// Search for the given named symbol. - JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { - return remoteToJITSymbol( - this->Remote.template callB(Name, - ExportedSymbolsOnly)); - } - - /// Search for the given named symbol within the given context. - JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) { - return remoteToJITSymbol( - this->Remote.template callB(H, Name, - ExportedSymbolsOnly)); - } - - /// Immediately emit and finalize the object with the given handle. - Error emitAndFinalize(ObjHandleT H) { - return this->Remote.template callB(H); - } - -private: - - Expected lookup(ObjHandleT H, const std::string &Name) { - auto RI = Resolvers.find(H); - if (RI != Resolvers.end()) { - return this->jitSymbolToRemote(RI->second->findSymbol(Name)); - } else - return teeLog(badObjectHandleError(H)); - } - - Expected lookupInLogicalDylib(ObjHandleT H, - const std::string &Name) { - auto RI = Resolvers.find(H); - if (RI != Resolvers.end()) - return this->jitSymbolToRemote( - RI->second->findSymbolInLogicalDylib(Name)); - else - return teeLog(badObjectHandleError(H)); - } - - std::map> - Resolvers; -}; - -/// RemoteObjectServerLayer acts as a server and handling RPC calls for the -/// object layer API from the given RPC connection. -/// -/// This class can be composed on top of a 'real' object layer (e.g. -/// RTDyldObjectLinkingLayer) to do the actual work of relocating objects -/// and making them executable. -template -class RemoteObjectServerLayer : public RemoteObjectLayer { -private: - - using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT; - using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol; - - using AddObject = RemoteObjectLayerAPI::AddObject; - using RemoveObject = RemoteObjectLayerAPI::RemoveObject; - using FindSymbol = RemoteObjectLayerAPI::FindSymbol; - using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn; - using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize; - using Lookup = RemoteObjectLayerAPI::Lookup; - using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib; - - using RemoteObjectLayer::teeLog; - using RemoteObjectLayer::badObjectHandleError; - using RemoteObjectLayer::remoteToJITSymbol; - -public: - - /// Create a RemoteObjectServerLayer with the given base layer (which must be - /// an object layer), RPC endpoint, and error reporter function. - LLVM_ATTRIBUTE_DEPRECATED( - RemoteObjectServerLayer(BaseLayerT &BaseLayer, RPCEndpoint &Remote, - std::function ReportError), - "ORCv1 layers (including RemoteObjectServerLayer) are deprecated. Please " - "use " - "ORCv2 (see docs/ORCv2.rst)"); - - RemoteObjectServerLayer(ORCv1DeprecationAcknowledgement, - BaseLayerT &BaseLayer, RPCEndpoint &Remote, - std::function ReportError) - : RemoteObjectLayer(Remote, std::move(ReportError)), - BaseLayer(BaseLayer), HandleIdMgr(1) { - using ThisT = RemoteObjectServerLayer; - - Remote.template addHandler(*this, &ThisT::addObject); - Remote.template addHandler(*this, &ThisT::removeObject); - Remote.template addHandler(*this, &ThisT::findSymbol); - Remote.template addHandler(*this, &ThisT::findSymbolIn); - Remote.template addHandler(*this, &ThisT::emitAndFinalize); - } - -private: - - class StringMemoryBuffer : public MemoryBuffer { - public: - StringMemoryBuffer(std::string Buffer) - : Buffer(std::move(Buffer)) { - init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(), - false); - } - - BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; } - private: - std::string Buffer; - }; - - JITSymbol lookup(ObjHandleT Id, const std::string &Name) { - return remoteToJITSymbol( - this->Remote.template callB(Id, Name)); - } - - JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) { - return remoteToJITSymbol( - this->Remote.template callB(Id, Name)); - } - - Expected addObject(std::string ObjBuffer) { - auto Buffer = std::make_unique(std::move(ObjBuffer)); - auto Id = HandleIdMgr.getNext(); - assert(!BaseLayerHandles.count(Id) && "Id already in use?"); - - auto Resolver = createLambdaResolver( - AcknowledgeORCv1Deprecation, - [this, Id](const std::string &Name) { return lookup(Id, Name); }, - [this, Id](const std::string &Name) { - return lookupInLogicalDylib(Id, Name); - }); - - if (auto HandleOrErr = - BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) { - BaseLayerHandles[Id] = std::move(*HandleOrErr); - return Id; - } else - return teeLog(HandleOrErr.takeError()); - } - - Error removeObject(ObjHandleT H) { - auto HI = BaseLayerHandles.find(H); - if (HI != BaseLayerHandles.end()) { - if (auto Err = BaseLayer.removeObject(HI->second)) - return teeLog(std::move(Err)); - return Error::success(); - } else - return teeLog(badObjectHandleError(H)); - } - - Expected findSymbol(const std::string &Name, - bool ExportedSymbolsOnly) { - if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly)) - return this->jitSymbolToRemote(std::move(Sym)); - else if (auto Err = Sym.takeError()) - return teeLog(std::move(Err)); - return this->nullRemoteSymbol(); - } - - Expected findSymbolIn(ObjHandleT H, const std::string &Name, - bool ExportedSymbolsOnly) { - auto HI = BaseLayerHandles.find(H); - if (HI != BaseLayerHandles.end()) { - if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly)) - return this->jitSymbolToRemote(std::move(Sym)); - else if (auto Err = Sym.takeError()) - return teeLog(std::move(Err)); - return this->nullRemoteSymbol(); - } else - return teeLog(badObjectHandleError(H)); - } - - Error emitAndFinalize(ObjHandleT H) { - auto HI = BaseLayerHandles.find(H); - if (HI != BaseLayerHandles.end()) { - if (auto Err = BaseLayer.emitAndFinalize(HI->second)) - return teeLog(std::move(Err)); - return Error::success(); - } else - return teeLog(badObjectHandleError(H)); - } - - BaseLayerT &BaseLayer; - remote::ResourceIdMgr HandleIdMgr; - std::map BaseLayerHandles; -}; - -template -RemoteObjectClientLayer::RemoteObjectClientLayer( - RPCEndpoint &Remote, std::function ReportError) - : RemoteObjectLayer(Remote, std::move(ReportError)) { - using ThisT = RemoteObjectClientLayer; - Remote.template addHandler(*this, &ThisT::lookup); - Remote.template addHandler( - *this, &ThisT::lookupInLogicalDylib); -} - -template -RemoteObjectServerLayer::RemoteObjectServerLayer( - BaseLayerT &BaseLayer, RPCEndpoint &Remote, - std::function ReportError) - : RemoteObjectLayer(Remote, std::move(ReportError)), - BaseLayer(BaseLayer), HandleIdMgr(1) { - using ThisT = RemoteObjectServerLayer; - - Remote.template addHandler(*this, &ThisT::addObject); - Remote.template addHandler(*this, &ThisT::removeObject); - Remote.template addHandler(*this, &ThisT::findSymbol); - Remote.template addHandler(*this, &ThisT::findSymbolIn); - Remote.template addHandler(*this, &ThisT::emitAndFinalize); -} - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h b/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h index 10f78c8bc6beb..a138f60a77564 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Speculation.h @@ -181,7 +181,8 @@ class IRSpeculationLayer : public IRLayer { : IRLayer(ES, BaseLayer.getManglingOptions()), NextLayer(BaseLayer), S(Spec), Mangle(Mangle), QueryAnalysis(Interpreter) {} - void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override; + void emit(std::unique_ptr R, + ThreadSafeModule TSM) override; private: TargetAndLikelies diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h index d35c8abc84a2e..3b5c4b9cf8cde 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h @@ -14,13 +14,16 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_TPCDYNAMICLIBRARYSEARCHGENERATOR_H #define LLVM_EXECUTIONENGINE_ORC_TPCDYNAMICLIBRARYSEARCHGENERATOR_H +#include "llvm/ADT/FunctionExtras.h" #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" namespace llvm { namespace orc { -class TPCDynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator { +class TPCDynamicLibrarySearchGenerator : public DefinitionGenerator { public: + using SymbolPredicate = unique_function; + /// Create a DynamicLibrarySearchGenerator that searches for symbols in the /// library with the given handle. /// @@ -28,29 +31,33 @@ class TPCDynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator { /// will be searched for. If the predicate is not given then all symbols will /// be searched for. TPCDynamicLibrarySearchGenerator(TargetProcessControl &TPC, - TargetProcessControl::DylibHandle H) - : TPC(TPC), H(H) {} + TargetProcessControl::DylibHandle H, + SymbolPredicate Allow = SymbolPredicate()) + : TPC(TPC), H(H), Allow(std::move(Allow)) {} /// Permanently loads the library at the given path and, on success, returns /// a DynamicLibrarySearchGenerator that will search it for symbol definitions /// in the library. On failure returns the reason the library failed to load. static Expected> - Load(TargetProcessControl &TPC, const char *LibraryPath); + Load(TargetProcessControl &TPC, const char *LibraryPath, + SymbolPredicate Allow = SymbolPredicate()); /// Creates a TPCDynamicLibrarySearchGenerator that searches for symbols in /// the target process. static Expected> - GetForTargetProcess(TargetProcessControl &TPC) { + GetForTargetProcess(TargetProcessControl &TPC, + SymbolPredicate Allow = SymbolPredicate()) { return Load(TPC, nullptr); } - Error tryToGenerate(LookupKind K, JITDylib &JD, + Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) override; private: TargetProcessControl &TPC; TargetProcessControl::DylibHandle H; + SymbolPredicate Allow; }; } // end namespace orc diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h index db9cd1b98cf9c..e7abd7fb90dfe 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h @@ -157,6 +157,19 @@ class TPCIndirectionUtils { std::vector> IndirectStubAllocs; }; +/// This will call writeResolver on the given TPCIndirectionUtils instance +/// to set up re-entry via a function that will directly return the trampoline +/// landing address. +/// +/// The TPCIndirectionUtils' LazyCallThroughManager must have been previously +/// created via TPCIndirectionUtils::createLazyCallThroughManager. +/// +/// The TPCIndirectionUtils' writeResolver method must not have been previously +/// called. +/// +/// This function is experimental and likely subject to revision. +Error setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils &TPCIU); + namespace detail { template @@ -206,4 +219,4 @@ TPCIndirectionUtils::CreateWithABI(TargetProcessControl &TPC) { } // end namespace orc } // end namespace llvm -#endif // LLVM_EXECUTIONENGINE_ORC_T_H +#endif // LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h index 159b6e8d56df3..d3349753284e2 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h @@ -149,8 +149,11 @@ class TargetProcessControl { virtual Expected loadDylib(const char *DylibPath) = 0; /// Search for symbols in the target process. + /// /// The result of the lookup is a 2-dimentional array of target addresses - /// that correspond to the lookup order. + /// that correspond to the lookup order. If a required symbol is not + /// found then this method will return an error. If a weakly referenced + /// symbol is not found then it be assigned a '0' value in the result. virtual Expected lookupSymbols(LookupRequest Request) = 0; protected: diff --git a/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h b/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h index 1b3ce1127e4a2..9b83092e653ff 100644 --- a/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -271,11 +271,11 @@ class RuntimeDyld { object::OwningBinary O, RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver, bool ProcessAllSections, - unique_function, + unique_function)> OnLoaded, - unique_function O, Error)> + unique_function O, + std::unique_ptr, Error)> OnEmitted); // RuntimeDyldImpl is the actual class. RuntimeDyld is just the public @@ -298,10 +298,11 @@ void jitLinkForORC( RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver, bool ProcessAllSections, unique_function, + RuntimeDyld::LoadedObjectInfo &, std::map)> OnLoaded, - unique_function, Error)> + unique_function, + std::unique_ptr, Error)> OnEmitted); } // end namespace llvm diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h index a03eac0ad40d6..7ccc679df4906 100644 --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -492,6 +492,20 @@ class Instruction : public User, /// merged DebugLoc. void applyMergedLocation(const DILocation *LocA, const DILocation *LocB); + /// Updates the debug location given that the instruction has been hoisted + /// from a block to a predecessor of that block. + /// Note: it is undefined behavior to call this on an instruction not + /// currently inserted into a function. + void updateLocationAfterHoist(); + + /// Drop the instruction's debug location. This does not guarantee removal + /// of the !dbg source location attachment, as it must set a line 0 location + /// with scope information attached on call instructions. To guarantee + /// removal of the !dbg attachment, use the \ref setDebugLoc() API. + /// Note: it is undefined behavior to call this on an instruction not + /// currently inserted into a function. + void dropLocation(); + private: /// Return true if we have an entry in the on-the-side metadata hash. bool hasMetadataHashEntry() const { diff --git a/llvm/include/llvm/IR/LegacyPassManagers.h b/llvm/include/llvm/IR/LegacyPassManagers.h index 6b1ddd4d79f8f..498e736a0100c 100644 --- a/llvm/include/llvm/IR/LegacyPassManagers.h +++ b/llvm/include/llvm/IR/LegacyPassManagers.h @@ -88,7 +88,6 @@ namespace llvm { template class ArrayRef; class Module; -class Pass; class StringRef; class Value; class Timer; diff --git a/llvm/tools/llvm-elfabi/ELFObjHandler.h b/llvm/include/llvm/InterfaceStub/ELFObjHandler.h similarity index 96% rename from llvm/tools/llvm-elfabi/ELFObjHandler.h rename to llvm/include/llvm/InterfaceStub/ELFObjHandler.h index 97f0d68f4d4fb..1ffd9a614eecd 100644 --- a/llvm/tools/llvm-elfabi/ELFObjHandler.h +++ b/llvm/include/llvm/InterfaceStub/ELFObjHandler.h @@ -13,9 +13,9 @@ #ifndef LLVM_TOOLS_ELFABI_ELFOBJHANDLER_H #define LLVM_TOOLS_ELFABI_ELFOBJHANDLER_H +#include "llvm/InterfaceStub/ELFStub.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" -#include "llvm/TextAPI/ELF/ELFStub.h" namespace llvm { diff --git a/llvm/include/llvm/TextAPI/ELF/ELFStub.h b/llvm/include/llvm/InterfaceStub/ELFStub.h similarity index 93% rename from llvm/include/llvm/TextAPI/ELF/ELFStub.h rename to llvm/include/llvm/InterfaceStub/ELFStub.h index 76b2af1216628..7832c1c7413b3 100644 --- a/llvm/include/llvm/TextAPI/ELF/ELFStub.h +++ b/llvm/include/llvm/InterfaceStub/ELFStub.h @@ -16,8 +16,8 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/VersionTuple.h" -#include #include +#include namespace llvm { namespace elfabi { @@ -42,15 +42,13 @@ struct ELFSymbol { bool Undefined; bool Weak; Optional Warning; - bool operator<(const ELFSymbol &RHS) const { - return Name < RHS.Name; - } + bool operator<(const ELFSymbol &RHS) const { return Name < RHS.Name; } }; // A cumulative representation of ELF stubs. // Both textual and binary stubs will read into and write from this object. class ELFStub { -// TODO: Add support for symbol versioning. + // TODO: Add support for symbol versioning. public: VersionTuple TbeVersion; Optional SoName; diff --git a/llvm/include/llvm/TextAPI/ELF/TBEHandler.h b/llvm/include/llvm/InterfaceStub/TBEHandler.h similarity index 100% rename from llvm/include/llvm/TextAPI/ELF/TBEHandler.h rename to llvm/include/llvm/InterfaceStub/TBEHandler.h index 76484410987fa..5c523eba037e7 100644 --- a/llvm/include/llvm/TextAPI/ELF/TBEHandler.h +++ b/llvm/include/llvm/InterfaceStub/TBEHandler.h @@ -15,8 +15,8 @@ #ifndef LLVM_TEXTAPI_ELF_TBEHANDLER_H #define LLVM_TEXTAPI_ELF_TBEHANDLER_H -#include "llvm/Support/VersionTuple.h" #include "llvm/Support/Error.h" +#include "llvm/Support/VersionTuple.h" #include namespace llvm { diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h index 8f78b99d37949..5d99c494b11eb 100644 --- a/llvm/include/llvm/MC/MCELFObjectWriter.h +++ b/llvm/include/llvm/MC/MCELFObjectWriter.h @@ -23,7 +23,6 @@ namespace llvm { class MCAssembler; class MCContext; class MCFixup; -class MCObjectWriter; class MCSymbol; class MCSymbolELF; class MCValue; diff --git a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h index 1d10c66b4201f..774569a090fd7 100644 --- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -24,7 +24,6 @@ namespace llvm { class MCInst; -class MCParsedAsmOperand; class MCStreamer; class MCSubtargetInfo; template class SmallVectorImpl; diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index bf0dffc9653cf..2f285bf54a6a9 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -55,7 +55,8 @@ enum class coveragemap_error { unsupported_version, truncated, malformed, - decompression_failed + decompression_failed, + invalid_or_missing_arch_specifier }; const std::error_category &coveragemap_category(); diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h index 562468333ef47..5e212092cb411 100644 --- a/llvm/include/llvm/ProfileData/SampleProf.h +++ b/llvm/include/llvm/ProfileData/SampleProf.h @@ -37,8 +37,6 @@ namespace llvm { -class raw_ostream; - const std::error_category &sampleprof_category(); enum class sampleprof_error { diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index 44e34a4a09b46..bdce13ebab666 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -20,6 +20,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" #include @@ -1685,6 +1686,12 @@ struct ScalarTraits { static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; +template <> struct ScalarTraits { + static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out); + static StringRef input(StringRef, void *, VersionTuple &); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + // Define non-member operator>> so that Input can stream in a document list. template inline std::enable_if_t::value, Input &> diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h index 60446bca53174..8e653b26e2997 100644 --- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h +++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h @@ -38,7 +38,6 @@ class ScalarEvolution; class SCEV; class SCEVExpander; class TargetLibraryInfo; -class TargetTransformInfo; class LPPassManager; class Instruction; struct RuntimeCheckingPtrGroup; diff --git a/llvm/include/llvm/Transforms/Utils/LoopVersioning.h b/llvm/include/llvm/Transforms/Utils/LoopVersioning.h index 1efdcc65b39a8..4c0998e463d42 100644 --- a/llvm/include/llvm/Transforms/Utils/LoopVersioning.h +++ b/llvm/include/llvm/Transforms/Utils/LoopVersioning.h @@ -24,7 +24,6 @@ namespace llvm { class Loop; class LoopAccessInfo; class LoopInfo; -class ScalarEvolution; struct RuntimeCheckingPtrGroup; typedef std::pair diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt index abe3ec59aec1a..35d204d7d63e2 100644 --- a/llvm/lib/CMakeLists.txt +++ b/llvm/lib/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(IR) add_subdirectory(FuzzMutate) +add_subdirectory(InterfaceStub) add_subdirectory(IRReader) add_subdirectory(CodeGen) add_subdirectory(BinaryFormat) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 2b56ed9a636a7..7ea414cae7a5b 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2857,7 +2857,7 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, if (const ConstantInt *CI = dyn_cast(CV)) { const uint64_t StoreSize = DL.getTypeStoreSize(CV->getType()); - if (StoreSize < 8) { + if (StoreSize <= 8) { if (AP.isVerbose()) AP.OutStreamer->GetCommentOS() << format("0x%" PRIx64 "\n", CI->getZExtValue()); diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index a7146515c4c96..1be0ca4412059 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -375,13 +375,15 @@ bool CallLowering::handleAssignments(CCState &CCInfo, << "Load/store a split arg to/from the stack not implemented yet"); return false; } - MVT VT = MVT::getVT(Args[i].Ty); - unsigned Size = VT == MVT::iPTR ? DL.getPointerSize() - : alignTo(VT.getSizeInBits(), 8) / 8; + + EVT LocVT = VA.getValVT(); + unsigned MemSize = LocVT == MVT::iPTR ? DL.getPointerSize() + : LocVT.getStoreSize(); + unsigned Offset = VA.getLocMemOffset(); MachinePointerInfo MPO; - Register StackAddr = Handler.getStackAddress(Size, Offset, MPO); - Handler.assignValueToAddress(Args[i], StackAddr, Size, MPO, VA); + Register StackAddr = Handler.getStackAddress(MemSize, Offset, MPO); + Handler.assignValueToAddress(Args[i], StackAddr, MemSize, MPO, VA); } else { // FIXME: Support byvals and other weirdness return false; diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index da519f99ad7e8..244e7a9583d61 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -2368,11 +2368,12 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { MI.RemoveOperand(1); Observer.changedInstr(MI); - MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt()); - auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS}); auto Zero = MIRBuilder.buildConstant(Ty, 0); + // Move insert point forward so we can use the Res register if needed. + MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt()); + // For *signed* multiply, overflow is detected by checking: // (hi != (lo >> bitwidth-1)) if (Opcode == TargetOpcode::G_SMULH) { diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 64af293caf9ea..8b3e6189a07f8 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5751,10 +5751,8 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG, // If we already have the use of the negated floating constant, it is free // to negate it even it has multiple uses. - if (!Op.hasOneUse() && CFP.use_empty()) { - RemoveDeadNode(CFP); + if (!Op.hasOneUse() && CFP.use_empty()) break; - } Cost = NegatibleCost::Neutral; return CFP; } diff --git a/llvm/lib/CodeGen/TailDuplicator.cpp b/llvm/lib/CodeGen/TailDuplicator.cpp index bd554189f12b5..f9773f74a7bdd 100644 --- a/llvm/lib/CodeGen/TailDuplicator.cpp +++ b/llvm/lib/CodeGen/TailDuplicator.cpp @@ -627,6 +627,14 @@ bool TailDuplicator::shouldTailDuplicate(bool IsSimple, if (PreRegAlloc && MI.isCall()) return false; + // TailDuplicator::appendCopies will erroneously place COPYs after + // INLINEASM_BR instructions after 4b0aa5724fea, which demonstrates the same + // bug that was fixed in f7a53d82c090. + // FIXME: Use findPHICopyInsertPoint() to find the correct insertion point + // for the COPY when replacing PHIs. + if (MI.getOpcode() == TargetOpcode::INLINEASM_BR) + return false; + if (MI.isBundle()) InstrCount += MI.getBundleSize(); else if (!MI.isPHI() && !MI.isMetaInstruction()) diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index 12b19e77a4223..2b12274281055 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -63,7 +63,7 @@ static CompileUnit *getUnitForOffset(const UnitListTy &Units, uint64_t Offset) { /// Resolve the DIE attribute reference that has been extracted in \p RefValue. /// The resulting DIE might be in another CompileUnit which is stored into \p /// ReferencedCU. \returns null if resolving fails for any reason. -DWARFDie DWARFLinker::resolveDIEReference(const DwarfFile &File, +DWARFDie DWARFLinker::resolveDIEReference(const DWARFFile &File, const UnitListTy &Units, const DWARFFormValue &RefValue, const DWARFDie &DIE, @@ -420,7 +420,7 @@ unsigned DWARFLinker::shouldKeepVariableDIE(AddressesMap &RelocMgr, /// \returns updated TraversalFlags. unsigned DWARFLinker::shouldKeepSubprogramDIE( AddressesMap &RelocMgr, RangesTy &Ranges, const DWARFDie &DIE, - const DwarfFile &File, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, + const DWARFFile &File, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); @@ -482,7 +482,7 @@ unsigned DWARFLinker::shouldKeepSubprogramDIE( /// Check if a DIE should be kept. /// \returns updated TraversalFlags. unsigned DWARFLinker::shouldKeepDIE(AddressesMap &RelocMgr, RangesTy &Ranges, - const DWARFDie &DIE, const DwarfFile &File, + const DWARFDie &DIE, const DWARFFile &File, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, unsigned Flags) { @@ -590,7 +590,7 @@ void DWARFLinker::lookForChildDIEsToKeep( /// kept. All DIEs referenced though attributes should be kept. void DWARFLinker::lookForRefDIEsToKeep( const DWARFDie &Die, CompileUnit &CU, unsigned Flags, - const UnitListTy &Units, const DwarfFile &File, + const UnitListTy &Units, const DWARFFile &File, SmallVectorImpl &Worklist) { bool UseOdr = (Flags & DWARFLinker::TF_DependencyWalk) ? (Flags & DWARFLinker::TF_ODR) @@ -700,7 +700,7 @@ void DWARFLinker::lookForParentDIEsToKeep( /// The return value indicates whether the DIE is incomplete. void DWARFLinker::lookForDIEsToKeep(AddressesMap &AddressesMap, RangesTy &Ranges, const UnitListTy &Units, - const DWARFDie &Die, const DwarfFile &File, + const DWARFDie &Die, const DWARFFile &File, CompileUnit &Cu, unsigned Flags) { // LIFO work list. SmallVector Worklist; @@ -838,7 +838,7 @@ unsigned DWARFLinker::DIECloner::cloneStringAttribute( unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute( DIE &Die, const DWARFDie &InputDIE, AttributeSpec AttrSpec, - unsigned AttrSize, const DWARFFormValue &Val, const DwarfFile &File, + unsigned AttrSize, const DWARFFormValue &Val, const DWARFFile &File, CompileUnit &Unit) { const DWARFUnit &U = Unit.getOrigUnit(); uint64_t Ref = *Val.getAsReference(); @@ -910,7 +910,7 @@ unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute( } void DWARFLinker::DIECloner::cloneExpression( - DataExtractor &Data, DWARFExpression Expression, const DwarfFile &File, + DataExtractor &Data, DWARFExpression Expression, const DWARFFile &File, CompileUnit &Unit, SmallVectorImpl &OutputBuffer) { using Encoding = DWARFExpression::Operation::Encoding; @@ -975,7 +975,7 @@ void DWARFLinker::DIECloner::cloneExpression( } unsigned DWARFLinker::DIECloner::cloneBlockAttribute( - DIE &Die, const DwarfFile &File, CompileUnit &Unit, AttributeSpec AttrSpec, + DIE &Die, const DWARFFile &File, CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, bool IsLittleEndian) { DIEValueList *Attr; DIEValue Value; @@ -1087,7 +1087,7 @@ unsigned DWARFLinker::DIECloner::cloneAddressAttribute( } unsigned DWARFLinker::DIECloner::cloneScalarAttribute( - DIE &Die, const DWARFDie &InputDIE, const DwarfFile &File, + DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File, CompileUnit &Unit, AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, AttributesInfo &Info) { uint64_t Value; @@ -1155,7 +1155,7 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute( /// value \p Val, and add it to \p Die. /// \returns the size of the cloned attribute. unsigned DWARFLinker::DIECloner::cloneAttribute( - DIE &Die, const DWARFDie &InputDIE, const DwarfFile &File, + DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File, CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val, const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info, bool IsLittleEndian) { @@ -1273,7 +1273,7 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, } DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, - const DwarfFile &File, CompileUnit &Unit, + const DWARFFile &File, CompileUnit &Unit, OffsetsStringPool &StringPool, int64_t PCOffset, uint32_t OutOffset, unsigned Flags, bool IsLittleEndian, @@ -1483,7 +1483,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, /// to point at the new entries. void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit, DWARFContext &OrigDwarf, - const DwarfFile &File) const { + const DWARFFile &File) const { DWARFDebugRangeList RangeList; const auto &FunctionRanges = Unit.getFunctionRanges(); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); @@ -1590,7 +1590,7 @@ static void patchStmtList(DIE &Die, DIEInteger Offset) { /// are present in the binary. void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf, - const DwarfFile &File) { + const DWARFFile &File) { DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE(); auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list)); if (!StmtList) @@ -1790,7 +1790,7 @@ void DWARFLinker::emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit) { /// This is actually pretty easy as the data of the CIEs and FDEs can /// be considered as black boxes and moved as is. The only thing to do /// is to patch the addresses in the headers. -void DWARFLinker::patchFrameInfoForObject(const DwarfFile &File, +void DWARFLinker::patchFrameInfoForObject(const DWARFFile &File, RangesTy &Ranges, DWARFContext &OrigDwarf, unsigned AddrSize) { @@ -1887,7 +1887,7 @@ void DWARFLinker::DIECloner::copyAbbrev( uint32_t DWARFLinker::DIECloner::hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, - const DwarfFile &File, + const DWARFFile &File, int ChildRecurseDepth) { const char *Name = nullptr; DWARFUnit *OrigUnit = &U.getOrigUnit(); @@ -1952,7 +1952,7 @@ static std::string remapPath(StringRef Path, } bool DWARFLinker::registerModuleReference( - DWARFDie CUDie, const DWARFUnit &Unit, const DwarfFile &File, + DWARFDie CUDie, const DWARFUnit &Unit, const DWARFFile &File, OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, uint64_t ModulesEndOffset, unsigned &UnitID, bool IsLittleEndian, unsigned Indent, bool Quiet) { @@ -2011,7 +2011,7 @@ bool DWARFLinker::registerModuleReference( Error DWARFLinker::loadClangModule( DWARFDie CUDie, StringRef Filename, StringRef ModuleName, uint64_t DwoId, - const DwarfFile &File, OffsetsStringPool &StringPool, + const DWARFFile &File, OffsetsStringPool &StringPool, UniquingStringPool &UniquingStringPool, DeclContextTree &ODRContexts, uint64_t ModulesEndOffset, unsigned &UnitID, bool IsLittleEndian, unsigned Indent, bool Quiet) { @@ -2096,7 +2096,7 @@ Error DWARFLinker::loadClangModule( } uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits( - DWARFContext &DwarfContext, const DwarfFile &File, + DWARFContext &DwarfContext, const DWARFFile &File, OffsetsStringPool &StringPool, bool IsLittleEndian) { uint64_t OutputDebugInfoSize = Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize(); @@ -2190,7 +2190,7 @@ void DWARFLinker::updateAccelKind(DWARFContext &Dwarf) { } } -bool DWARFLinker::emitPaperTrailWarnings(const DwarfFile &File, +bool DWARFLinker::emitPaperTrailWarnings(const DWARFFile &File, OffsetsStringPool &StringPool) { if (File.Warnings.empty()) @@ -2267,7 +2267,7 @@ void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) { "debug_aranges"); } -void DWARFLinker::addObjectFile(DwarfFile &File) { +void DWARFLinker::addObjectFile(DWARFFile &File) { ObjectContexts.emplace_back(LinkContext(File)); if (ObjectContexts.back().File.Dwarf) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 3a83317a73a3b..895dd7d2a575d 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -172,6 +172,15 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); } + if (Die.hasChildren()) { + if (Die.getFirstChild().isValid() && + Die.getFirstChild().getTag() == DW_TAG_null) { + warn() << dwarf::TagString(Die.getTag()) + << " has DW_CHILDREN_yes but DIE has no children: "; + Die.dump(OS); + } + } + NumUnitErrors += verifyDebugInfoCallSite(Die); } diff --git a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp index d8bd671c66619..c8bbf0bcdfda7 100644 --- a/llvm/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/llvm/lib/ExecutionEngine/ExecutionEngine.cpp @@ -53,11 +53,6 @@ ExecutionEngine *(*ExecutionEngine::MCJITCtor)( std::shared_ptr Resolver, std::unique_ptr TM) = nullptr; -ExecutionEngine *(*ExecutionEngine::OrcMCJITReplacementCtor)( - std::string *ErrorStr, std::shared_ptr MemMgr, - std::shared_ptr Resolver, - std::unique_ptr TM) = nullptr; - ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr M, std::string *ErrorStr) =nullptr; @@ -476,8 +471,7 @@ EngineBuilder::EngineBuilder() : EngineBuilder(nullptr) {} EngineBuilder::EngineBuilder(std::unique_ptr M) : M(std::move(M)), WhichEngine(EngineKind::Either), ErrorStr(nullptr), - OptLevel(CodeGenOpt::Default), MemMgr(nullptr), Resolver(nullptr), - UseOrcMCJITReplacement(false) { + OptLevel(CodeGenOpt::Default), MemMgr(nullptr), Resolver(nullptr) { // IR module verification is enabled by default in debug builds, and disabled // by default in release builds. #ifndef NDEBUG @@ -540,12 +534,7 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { } ExecutionEngine *EE = nullptr; - if (ExecutionEngine::OrcMCJITReplacementCtor && UseOrcMCJITReplacement) { - EE = ExecutionEngine::OrcMCJITReplacementCtor(ErrorStr, std::move(MemMgr), - std::move(Resolver), - std::move(TheTM)); - EE->addModule(std::move(M)); - } else if (ExecutionEngine::MCJITCtor) + if (ExecutionEngine::MCJITCtor) EE = ExecutionEngine::MCJITCtor(std::move(M), ErrorStr, std::move(MemMgr), std::move(Resolver), std::move(TheTM)); diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp index 54ba9ac39ea6a..9eda6fb9ea77b 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @@ -763,12 +763,19 @@ Error deregisterEHFrameSection(const void *EHFrameSectionAddr, EHFrameRegistrar::~EHFrameRegistrar() {} -InProcessEHFrameRegistrar &InProcessEHFrameRegistrar::getInstance() { - static InProcessEHFrameRegistrar Instance; - return Instance; +Error InProcessEHFrameRegistrar::registerEHFrames( + JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) { + return registerEHFrameSection( + jitTargetAddressToPointer(EHFrameSectionAddr), + EHFrameSectionSize); } -InProcessEHFrameRegistrar::InProcessEHFrameRegistrar() {} +Error InProcessEHFrameRegistrar::deregisterEHFrames( + JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) { + return deregisterEHFrameSection( + jitTargetAddressToPointer(EHFrameSectionAddr), + EHFrameSectionSize); +} LinkGraphPassFunction createEHFrameRecorderPass(const Triple &TT, diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp index 48bca4502920b..130d7e494c719 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp @@ -355,6 +355,9 @@ class ELFLinkGraphBuilder_x86_64 { if (SecRef.sh_type == ELF::SHT_SYMTAB) // TODO: Dynamic? SymTab = SecRef; + } else { + auto &Section = G->createSection(*Name, Prot); + G->createZeroFillBlock(Section, Size, Address, Alignment, 0); } } @@ -478,7 +481,8 @@ class ELFLinkGraphBuilder_x86_64 { return Name.takeError(); auto Section = G->findSectionByName(*Name); if (!Section) - return make_error("Could not find a section", + return make_error("Could not find a section " + + *Name, llvm::inconvertibleErrorCode()); // we only have one for now auto blocks = Section->blocks(); @@ -525,7 +529,8 @@ class ELFLinkGraphBuilder_x86_64 { auto JitSection = G->findSectionByName(*sectName); if (!JitSection) return make_error( - "Could not find a section", llvm::inconvertibleErrorCode()); + "Could not find the JitSection " + *sectName, + llvm::inconvertibleErrorCode()); auto bs = JitSection->blocks(); if (bs.empty()) return make_error( diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 5105ec4951484..71ec88639a5b7 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -93,6 +93,7 @@ const char *getScopeName(Scope S) { raw_ostream &operator<<(raw_ostream &OS, const Block &B) { return OS << formatv("{0:x16}", B.getAddress()) << " -- " << formatv("{0:x16}", B.getAddress() + B.getSize()) << ": " + << "size = " << formatv("{0:x}", B.getSize()) << ", " << (B.isZeroFill() ? "zero-fill" : "content") << ", align = " << B.getAlignment() << ", align-ofs = " << B.getAlignmentOffset() @@ -126,10 +127,10 @@ raw_ostream &operator<<(raw_ostream &OS, const Symbol &Sym) { break; } OS << (Sym.isLive() ? '+' : '-') - << ", size = " << formatv("{0:x8}", Sym.getSize()) + << ", size = " << formatv("{0:x}", Sym.getSize()) << ", addr = " << formatv("{0:x16}", Sym.getAddress()) << " (" << formatv("{0:x16}", Sym.getAddressable().getAddress()) << " + " - << formatv("{0:x8}", Sym.getOffset()); + << formatv("{0:x}", Sym.getOffset()); if (Sym.isDefined()) OS << " " << Sym.getBlock().getSection().getName(); OS << ")>"; @@ -139,8 +140,33 @@ raw_ostream &operator<<(raw_ostream &OS, const Symbol &Sym) { void printEdge(raw_ostream &OS, const Block &B, const Edge &E, StringRef EdgeKindName) { OS << "edge@" << formatv("{0:x16}", B.getAddress() + E.getOffset()) << ": " - << formatv("{0:x16}", B.getAddress()) << " + " << E.getOffset() << " -- " - << EdgeKindName << " -> " << E.getTarget() << " + " << E.getAddend(); + << formatv("{0:x16}", B.getAddress()) << " + " + << formatv("{0:x}", E.getOffset()) << " -- " << EdgeKindName << " -> "; + + auto &TargetSym = E.getTarget(); + if (TargetSym.hasName()) + OS << TargetSym.getName(); + else { + auto &TargetBlock = TargetSym.getBlock(); + auto &TargetSec = TargetBlock.getSection(); + JITTargetAddress SecAddress = ~JITTargetAddress(0); + for (auto *B : TargetSec.blocks()) + if (B->getAddress() < SecAddress) + SecAddress = B->getAddress(); + + JITTargetAddress SecDelta = TargetSym.getAddress() - SecAddress; + OS << formatv("{0:x16}", TargetSym.getAddress()) << " (section " + << TargetSec.getName(); + if (SecDelta) + OS << " + " << formatv("{0:x}", SecDelta); + OS << " / block " << formatv("{0:x16}", TargetBlock.getAddress()); + if (TargetSym.getOffset()) + OS << " + " << formatv("{0:x}", TargetSym.getOffset()); + OS << ")"; + } + + if (E.getAddend() != 0) + OS << " + " << E.getAddend(); } Section::~Section() { diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index 1876c3512d11a..6396fb5d11876 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -9,18 +9,14 @@ add_llvm_component_library(LLVMOrcJIT IRTransformLayer.cpp JITTargetMachineBuilder.cpp LazyReexports.cpp - Legacy.cpp Layer.cpp LLJIT.cpp MachOPlatform.cpp Mangling.cpp - NullResolver.cpp ObjectLinkingLayer.cpp ObjectTransformLayer.cpp OrcABISupport.cpp - OrcCBindings.cpp OrcV2CBindings.cpp - OrcMCJITReplacement.cpp RTDyldObjectLinkingLayer.cpp Speculation.cpp SpeculateAnalyses.cpp diff --git a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp index 9e38dc36faae7..68878f6729e98 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp @@ -73,22 +73,21 @@ class PartitioningIRMaterializationUnit : public IRMaterializationUnit { public: PartitioningIRMaterializationUnit(ExecutionSession &ES, const IRSymbolMapper::ManglingOptions &MO, - ThreadSafeModule TSM, VModuleKey K, + ThreadSafeModule TSM, CompileOnDemandLayer &Parent) - : IRMaterializationUnit(ES, MO, std::move(TSM), std::move(K)), - Parent(Parent) {} + : IRMaterializationUnit(ES, MO, std::move(TSM)), Parent(Parent) {} PartitioningIRMaterializationUnit( - ThreadSafeModule TSM, VModuleKey K, SymbolFlagsMap SymbolFlags, + ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol, SymbolNameToDefinitionMap SymbolToDefinition, CompileOnDemandLayer &Parent) - : IRMaterializationUnit(std::move(TSM), std::move(K), - std::move(SymbolFlags), std::move(InitSymbol), + : IRMaterializationUnit(std::move(TSM), std::move(SymbolFlags), + std::move(InitSymbol), std::move(SymbolToDefinition)), Parent(Parent) {} private: - void materialize(MaterializationResponsibility R) override { + void materialize(std::unique_ptr R) override { Parent.emitPartition(std::move(R), std::move(TSM), std::move(SymbolToDefinition)); } @@ -128,15 +127,15 @@ void CompileOnDemandLayer::setPartitionFunction(PartitionFunction Partition) { void CompileOnDemandLayer::setImplMap(ImplSymbolMap *Imp) { this->AliaseeImpls = Imp; } -void CompileOnDemandLayer::emit(MaterializationResponsibility R, - ThreadSafeModule TSM) { +void CompileOnDemandLayer::emit( + std::unique_ptr R, ThreadSafeModule TSM) { assert(TSM && "Null module"); auto &ES = getExecutionSession(); // Sort the callables and non-callables, build re-exports and lodge the // actual module with the implementation dylib. - auto &PDR = getPerDylibResources(R.getTargetJITDylib()); + auto &PDR = getPerDylibResources(R->getTargetJITDylib()); SymbolAliasMap NonCallables; SymbolAliasMap Callables; @@ -145,7 +144,7 @@ void CompileOnDemandLayer::emit(MaterializationResponsibility R, cleanUpModule(M); }); - for (auto &KV : R.getSymbols()) { + for (auto &KV : R->getSymbols()) { auto &Name = KV.first; auto &Flags = KV.second; if (Flags.isCallable()) @@ -158,19 +157,29 @@ void CompileOnDemandLayer::emit(MaterializationResponsibility R, // implementation dylib. if (auto Err = PDR.getImplDylib().define( std::make_unique( - ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), - *this))) { + ES, *getManglingOptions(), std::move(TSM), *this))) { ES.reportError(std::move(Err)); - R.failMaterialization(); + R->failMaterialization(); return; } if (!NonCallables.empty()) - R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables), - JITDylibLookupFlags::MatchAllSymbols)); - if (!Callables.empty()) - R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(), - std::move(Callables), AliaseeImpls)); + if (auto Err = + R->replace(reexports(PDR.getImplDylib(), std::move(NonCallables), + JITDylibLookupFlags::MatchAllSymbols))) { + getExecutionSession().reportError(std::move(Err)); + R->failMaterialization(); + return; + } + if (!Callables.empty()) { + if (auto Err = R->replace( + lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(), + std::move(Callables), AliaseeImpls))) { + getExecutionSession().reportError(std::move(Err)); + R->failMaterialization(); + return; + } + } } CompileOnDemandLayer::PerDylibResources & @@ -247,7 +256,7 @@ void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) { } void CompileOnDemandLayer::emitPartition( - MaterializationResponsibility R, ThreadSafeModule TSM, + std::unique_ptr R, ThreadSafeModule TSM, IRMaterializationUnit::SymbolNameToDefinitionMap Defs) { // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the @@ -257,8 +266,8 @@ void CompileOnDemandLayer::emitPartition( auto &ES = getExecutionSession(); GlobalValueSet RequestedGVs; - for (auto &Name : R.getRequestedSymbols()) { - if (Name == R.getInitializerSymbol()) + for (auto &Name : R->getRequestedSymbols()) { + if (Name == R->getInitializerSymbol()) TSM.withModuleDo([&](Module &M) { for (auto &GV : getStaticInitGVs(M)) RequestedGVs.insert(&GV); @@ -285,9 +294,14 @@ void CompileOnDemandLayer::emitPartition( // If the partition is empty, return the whole module to the symbol table. if (GVsToExtract->empty()) { - R.replace(std::make_unique( - std::move(TSM), R.getVModuleKey(), R.getSymbols(), - R.getInitializerSymbol(), std::move(Defs), *this)); + if (auto Err = + R->replace(std::make_unique( + std::move(TSM), R->getSymbols(), R->getInitializerSymbol(), + std::move(Defs), *this))) { + getExecutionSession().reportError(std::move(Err)); + R->failMaterialization(); + return; + } return; } @@ -308,7 +322,7 @@ void CompileOnDemandLayer::emitPartition( IRSymbolMapper::add(ES, *getManglingOptions(), PromotedGlobals, SymbolFlags); - if (auto Err = R.defineMaterializing(SymbolFlags)) + if (auto Err = R->defineMaterializing(SymbolFlags)) return std::move(Err); } @@ -348,12 +362,16 @@ void CompileOnDemandLayer::emitPartition( if (!ExtractedTSM) { ES.reportError(ExtractedTSM.takeError()); - R.failMaterialization(); + R->failMaterialization(); return; } - R.replace(std::make_unique( - ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), *this)); + if (auto Err = R->replace(std::make_unique( + ES, *getManglingOptions(), std::move(TSM), *this))) { + ES.reportError(std::move(Err)); + R->failMaterialization(); + return; + } BaseLayer.emit(std::move(R), std::move(*ExtractedTSM)); } diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index bad13cfebbc6b..726cf101cb324 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -12,6 +12,8 @@ #include "llvm/Config/llvm-config.h" #include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MSVCErrorWorkarounds.h" #include #if LLVM_ENABLE_THREADS @@ -23,6 +25,7 @@ namespace llvm { namespace orc { +char ResourceTrackerDefunct::ID = 0; char FailedToMaterialize::ID = 0; char SymbolsNotFound::ID = 0; char SymbolsCouldNotBeRemoved::ID = 0; @@ -34,6 +37,45 @@ RegisterDependenciesFunction NoDependenciesToRegister = void MaterializationUnit::anchor() {} +ResourceTracker::ResourceTracker(JITDylibSP JD) { + assert((reinterpret_cast(JD.get()) & 0x1) == 0 && + "JITDylib must be two byte aligned"); + JD->Retain(); + JDAndFlag.store(reinterpret_cast(JD.get())); +} + +ResourceTracker::~ResourceTracker() { + getJITDylib().getExecutionSession().destroyResourceTracker(*this); + getJITDylib().Release(); +} + +Error ResourceTracker::remove() { + return getJITDylib().getExecutionSession().removeResourceTracker(*this); +} + +void ResourceTracker::transferTo(ResourceTracker &DstRT) { + getJITDylib().getExecutionSession().transferResourceTracker(DstRT, *this); +} + +void ResourceTracker::makeDefunct() { + uintptr_t Val = JDAndFlag.load(); + Val |= 0x1U; + JDAndFlag.store(Val); +} + +ResourceManager::~ResourceManager() {} + +ResourceTrackerDefunct::ResourceTrackerDefunct(ResourceTrackerSP RT) + : RT(std::move(RT)) {} + +std::error_code ResourceTrackerDefunct::convertToErrorCode() const { + return orcError(OrcErrorCode::UnknownORCError); +} + +void ResourceTrackerDefunct::log(raw_ostream &OS) const { + OS << "Resource tracker " << (void *)RT.get() << " became defunct"; +} + FailedToMaterialize::FailedToMaterialize( std::shared_ptr Symbols) : Symbols(std::move(Symbols)) { @@ -137,8 +179,6 @@ void AsynchronousSymbolQuery::handleComplete() { TmpNotifyComplete(std::move(ResolvedSymbols)); } -bool AsynchronousSymbolQuery::canStillFail() { return !!NotifyComplete; } - void AsynchronousSymbolQuery::handleFailed(Error Err) { assert(QueryRegistrations.empty() && ResolvedSymbols.empty() && OutstandingSymbolsCount == 0 && @@ -181,156 +221,9 @@ void AsynchronousSymbolQuery::detach() { QueryRegistrations.clear(); } -MaterializationResponsibility::~MaterializationResponsibility() { - assert(SymbolFlags.empty() && - "All symbols should have been explicitly materialized or failed"); -} - -SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const { - return JD->getRequestedSymbols(SymbolFlags); -} - -Error MaterializationResponsibility::notifyResolved(const SymbolMap &Symbols) { - LLVM_DEBUG({ - dbgs() << "In " << JD->getName() << " resolving " << Symbols << "\n"; - }); -#ifndef NDEBUG - for (auto &KV : Symbols) { - auto WeakFlags = JITSymbolFlags::Weak | JITSymbolFlags::Common; - auto I = SymbolFlags.find(KV.first); - assert(I != SymbolFlags.end() && - "Resolving symbol outside this responsibility set"); - assert(!I->second.hasMaterializationSideEffectsOnly() && - "Can't resolve materialization-side-effects-only symbol"); - assert((KV.second.getFlags() & ~WeakFlags) == (I->second & ~WeakFlags) && - "Resolving symbol with incorrect flags"); - } -#endif - - return JD->resolve(Symbols); -} - -Error MaterializationResponsibility::notifyEmitted() { - - LLVM_DEBUG({ - dbgs() << "In " << JD->getName() << " emitting " << SymbolFlags << "\n"; - }); - - if (auto Err = JD->emit(SymbolFlags)) - return Err; - - SymbolFlags.clear(); - return Error::success(); -} - -Error MaterializationResponsibility::defineMaterializing( - SymbolFlagsMap NewSymbolFlags) { - - LLVM_DEBUG({ - dbgs() << "In " << JD->getName() << " defining materializing symbols " - << NewSymbolFlags << "\n"; - }); - if (auto AcceptedDefs = JD->defineMaterializing(std::move(NewSymbolFlags))) { - // Add all newly accepted symbols to this responsibility object. - for (auto &KV : *AcceptedDefs) - SymbolFlags.insert(KV); - return Error::success(); - } else - return AcceptedDefs.takeError(); -} - -void MaterializationResponsibility::failMaterialization() { - - LLVM_DEBUG({ - dbgs() << "In " << JD->getName() << " failing materialization for " - << SymbolFlags << "\n"; - }); - - JITDylib::FailedSymbolsWorklist Worklist; - - for (auto &KV : SymbolFlags) - Worklist.push_back(std::make_pair(JD.get(), KV.first)); - SymbolFlags.clear(); - - JD->notifyFailed(std::move(Worklist)); -} - -void MaterializationResponsibility::replace( - std::unique_ptr MU) { - - // If the replacement MU is empty then return. - if (MU->getSymbols().empty()) - return; - - for (auto &KV : MU->getSymbols()) { - assert(SymbolFlags.count(KV.first) && - "Replacing definition outside this responsibility set"); - SymbolFlags.erase(KV.first); - } - - if (MU->getInitializerSymbol() == InitSymbol) - InitSymbol = nullptr; - - LLVM_DEBUG(JD->getExecutionSession().runSessionLocked([&]() { - dbgs() << "In " << JD->getName() << " replacing symbols with " << *MU - << "\n"; - });); - - JD->replace(std::move(MU)); -} - -MaterializationResponsibility -MaterializationResponsibility::delegate(const SymbolNameSet &Symbols, - VModuleKey NewKey) { - - if (NewKey == VModuleKey()) - NewKey = K; - - SymbolStringPtr DelegatedInitSymbol; - SymbolFlagsMap DelegatedFlags; - - for (auto &Name : Symbols) { - auto I = SymbolFlags.find(Name); - assert(I != SymbolFlags.end() && - "Symbol is not tracked by this MaterializationResponsibility " - "instance"); - - DelegatedFlags[Name] = std::move(I->second); - if (Name == InitSymbol) - std::swap(InitSymbol, DelegatedInitSymbol); - - SymbolFlags.erase(I); - } - - return MaterializationResponsibility(JD, std::move(DelegatedFlags), - std::move(DelegatedInitSymbol), - std::move(NewKey)); -} - -void MaterializationResponsibility::addDependencies( - const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { - LLVM_DEBUG({ - dbgs() << "Adding dependencies for " << Name << ": " << Dependencies - << "\n"; - }); - assert(SymbolFlags.count(Name) && - "Symbol not covered by this MaterializationResponsibility instance"); - JD->addDependencies(Name, Dependencies); -} - -void MaterializationResponsibility::addDependenciesForAll( - const SymbolDependenceMap &Dependencies) { - LLVM_DEBUG({ - dbgs() << "Adding dependencies for all symbols in " << SymbolFlags << ": " - << Dependencies << "\n"; - }); - for (auto &KV : SymbolFlags) - JD->addDependencies(KV.first, Dependencies); -} - AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( - SymbolMap Symbols, VModuleKey K) - : MaterializationUnit(extractFlags(Symbols), nullptr, std::move(K)), + SymbolMap Symbols) + : MaterializationUnit(extractFlags(Symbols), nullptr), Symbols(std::move(Symbols)) {} StringRef AbsoluteSymbolsMaterializationUnit::getName() const { @@ -338,10 +231,10 @@ StringRef AbsoluteSymbolsMaterializationUnit::getName() const { } void AbsoluteSymbolsMaterializationUnit::materialize( - MaterializationResponsibility R) { + std::unique_ptr R) { // No dependencies, so these calls can't fail. - cantFail(R.notifyResolved(Symbols)); - cantFail(R.notifyEmitted()); + cantFail(R->notifyResolved(Symbols)); + cantFail(R->notifyEmitted()); } void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD, @@ -360,26 +253,25 @@ AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) { ReExportsMaterializationUnit::ReExportsMaterializationUnit( JITDylib *SourceJD, JITDylibLookupFlags SourceJDLookupFlags, - SymbolAliasMap Aliases, VModuleKey K) - : MaterializationUnit(extractFlags(Aliases), nullptr, std::move(K)), - SourceJD(SourceJD), SourceJDLookupFlags(SourceJDLookupFlags), - Aliases(std::move(Aliases)) {} + SymbolAliasMap Aliases) + : MaterializationUnit(extractFlags(Aliases), nullptr), SourceJD(SourceJD), + SourceJDLookupFlags(SourceJDLookupFlags), Aliases(std::move(Aliases)) {} StringRef ReExportsMaterializationUnit::getName() const { return ""; } void ReExportsMaterializationUnit::materialize( - MaterializationResponsibility R) { + std::unique_ptr R) { - auto &ES = R.getTargetJITDylib().getExecutionSession(); - JITDylib &TgtJD = R.getTargetJITDylib(); + auto &ES = R->getTargetJITDylib().getExecutionSession(); + JITDylib &TgtJD = R->getTargetJITDylib(); JITDylib &SrcJD = SourceJD ? *SourceJD : TgtJD; // Find the set of requested aliases and aliasees. Return any unrequested // aliases back to the JITDylib so as to not prematurely materialize any // aliasees. - auto RequestedSymbols = R.getRequestedSymbols(); + auto RequestedSymbols = R->getRequestedSymbols(); SymbolAliasMap RequestedAliases; for (auto &Name : RequestedSymbols) { @@ -398,19 +290,27 @@ void ReExportsMaterializationUnit::materialize( }); if (!Aliases.empty()) { - if (SourceJD) - R.replace(reexports(*SourceJD, std::move(Aliases), SourceJDLookupFlags)); - else - R.replace(symbolAliases(std::move(Aliases))); + auto Err = SourceJD ? R->replace(reexports(*SourceJD, std::move(Aliases), + SourceJDLookupFlags)) + : R->replace(symbolAliases(std::move(Aliases))); + + if (Err) { + // FIXME: Should this be reported / treated as failure to materialize? + // Or should this be treated as a sanctioned bailing-out? + ES.reportError(std::move(Err)); + R->failMaterialization(); + return; + } } // The OnResolveInfo struct will hold the aliases and responsibilty for each // query in the list. struct OnResolveInfo { - OnResolveInfo(MaterializationResponsibility R, SymbolAliasMap Aliases) + OnResolveInfo(std::unique_ptr R, + SymbolAliasMap Aliases) : R(std::move(R)), Aliases(std::move(Aliases)) {} - MaterializationResponsibility R; + std::unique_ptr R; SymbolAliasMap Aliases; }; @@ -450,8 +350,15 @@ void ReExportsMaterializationUnit::materialize( assert(!QuerySymbols.empty() && "Alias cycle detected!"); - auto QueryInfo = std::make_shared( - R.delegate(ResponsibilitySymbols), std::move(QueryAliases)); + auto NewR = R->delegate(ResponsibilitySymbols); + if (!NewR) { + ES.reportError(NewR.takeError()); + R->failMaterialization(); + return; + } + + auto QueryInfo = std::make_shared(std::move(*NewR), + std::move(QueryAliases)); QueryInfos.push_back( make_pair(std::move(QuerySymbols), std::move(QueryInfo))); } @@ -480,12 +387,12 @@ void ReExportsMaterializationUnit::materialize( for (auto &KV : QueryInfo->Aliases) if (SrcJDDeps.count(KV.second.Aliasee)) { PerAliasDeps = {KV.second.Aliasee}; - QueryInfo->R.addDependencies(KV.first, PerAliasDepsMap); + QueryInfo->R->addDependencies(KV.first, PerAliasDepsMap); } }; auto OnComplete = [QueryInfo](Expected Result) { - auto &ES = QueryInfo->R.getTargetJITDylib().getExecutionSession(); + auto &ES = QueryInfo->R->getTargetJITDylib().getExecutionSession(); if (Result) { SymbolMap ResolutionMap; for (auto &KV : QueryInfo->Aliases) { @@ -499,19 +406,19 @@ void ReExportsMaterializationUnit::materialize( ResolutionMap[KV.first] = JITEvaluatedSymbol( (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags); } - if (auto Err = QueryInfo->R.notifyResolved(ResolutionMap)) { + if (auto Err = QueryInfo->R->notifyResolved(ResolutionMap)) { ES.reportError(std::move(Err)); - QueryInfo->R.failMaterialization(); + QueryInfo->R->failMaterialization(); return; } - if (auto Err = QueryInfo->R.notifyEmitted()) { + if (auto Err = QueryInfo->R->notifyEmitted()) { ES.reportError(std::move(Err)); - QueryInfo->R.failMaterialization(); + QueryInfo->R->failMaterialization(); return; } } else { ES.reportError(Result.takeError()); - QueryInfo->R.failMaterialization(); + QueryInfo->R->failMaterialization(); } }; @@ -538,20 +445,16 @@ ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { return SymbolFlags; } -Expected -buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols) { +Expected buildSimpleReexportsAliasMap(JITDylib &SourceJD, + SymbolNameSet Symbols) { SymbolLookupSet LookupSet(Symbols); - auto Flags = SourceJD.lookupFlags( - LookupKind::Static, JITDylibLookupFlags::MatchAllSymbols, LookupSet); + auto Flags = SourceJD.getExecutionSession().lookupFlags( + LookupKind::Static, {{&SourceJD, JITDylibLookupFlags::MatchAllSymbols}}, + SymbolLookupSet(std::move(Symbols))); if (!Flags) return Flags.takeError(); - if (!LookupSet.empty()) { - LookupSet.sortByName(); - return make_error(LookupSet.getSymbolNames()); - } - SymbolAliasMap Result; for (auto &Name : Symbols) { assert(Flags->count(Name) && "Missing entry in flags map"); @@ -561,19 +464,100 @@ buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols) { return Result; } +class InProgressLookupState { +public: + InProgressLookupState(LookupKind K, JITDylibSearchOrder SearchOrder, + SymbolLookupSet LookupSet, SymbolState RequiredState) + : K(K), SearchOrder(std::move(SearchOrder)), + LookupSet(std::move(LookupSet)), RequiredState(RequiredState) { + DefGeneratorCandidates = this->LookupSet; + } + virtual ~InProgressLookupState() {} + virtual void complete(std::unique_ptr IPLS) = 0; + virtual void fail(Error Err) = 0; + + LookupKind K; + JITDylibSearchOrder SearchOrder; + SymbolLookupSet LookupSet; + SymbolState RequiredState; + + std::unique_lock GeneratorLock; + size_t CurSearchOrderIndex = 0; + bool NewJITDylib = true; + SymbolLookupSet DefGeneratorCandidates; + SymbolLookupSet DefGeneratorNonCandidates; + std::vector> CurDefGeneratorStack; +}; + +class InProgressLookupFlagsState : public InProgressLookupState { +public: + InProgressLookupFlagsState( + LookupKind K, JITDylibSearchOrder SearchOrder, SymbolLookupSet LookupSet, + unique_function)> OnComplete) + : InProgressLookupState(K, std::move(SearchOrder), std::move(LookupSet), + SymbolState::NeverSearched), + OnComplete(std::move(OnComplete)) {} + + void complete(std::unique_ptr IPLS) override { + GeneratorLock = {}; // Unlock and release. + auto &ES = SearchOrder.front().first->getExecutionSession(); + ES.OL_completeLookupFlags(std::move(IPLS), std::move(OnComplete)); + } + + void fail(Error Err) override { + GeneratorLock = {}; // Unlock and release. + OnComplete(std::move(Err)); + } + +private: + unique_function)> OnComplete; +}; + +class InProgressFullLookupState : public InProgressLookupState { +public: + InProgressFullLookupState(LookupKind K, JITDylibSearchOrder SearchOrder, + SymbolLookupSet LookupSet, + SymbolState RequiredState, + std::shared_ptr Q, + RegisterDependenciesFunction RegisterDependencies) + : InProgressLookupState(K, std::move(SearchOrder), std::move(LookupSet), + RequiredState), + Q(std::move(Q)), RegisterDependencies(std::move(RegisterDependencies)) { + } + + void complete(std::unique_ptr IPLS) override { + GeneratorLock = {}; // Unlock and release. + auto &ES = SearchOrder.front().first->getExecutionSession(); + ES.OL_completeLookup(std::move(IPLS), std::move(Q), + std::move(RegisterDependencies)); + } + + void fail(Error Err) override { + GeneratorLock = {}; + Q->detach(); + Q->handleFailed(std::move(Err)); + } + +private: + std::shared_ptr Q; + RegisterDependenciesFunction RegisterDependencies; +}; + ReexportsGenerator::ReexportsGenerator(JITDylib &SourceJD, JITDylibLookupFlags SourceJDLookupFlags, SymbolPredicate Allow) : SourceJD(SourceJD), SourceJDLookupFlags(SourceJDLookupFlags), Allow(std::move(Allow)) {} -Error ReexportsGenerator::tryToGenerate(LookupKind K, JITDylib &JD, +Error ReexportsGenerator::tryToGenerate(LookupState &LS, LookupKind K, + JITDylib &JD, JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &LookupSet) { assert(&JD != &SourceJD && "Cannot re-export from the same dylib"); // Use lookupFlags to find the subset of symbols that match our lookup. - auto Flags = SourceJD.lookupFlags(K, JDLookupFlags, LookupSet); + auto Flags = JD.getExecutionSession().lookupFlags( + K, {{&SourceJD, JDLookupFlags}}, LookupSet); if (!Flags) return Flags.takeError(); @@ -590,19 +574,60 @@ Error ReexportsGenerator::tryToGenerate(LookupKind K, JITDylib &JD, return JD.define(reexports(SourceJD, AliasMap, SourceJDLookupFlags)); } -JITDylib::DefinitionGenerator::~DefinitionGenerator() {} +LookupState::LookupState(std::unique_ptr IPLS) + : IPLS(std::move(IPLS)) {} -void JITDylib::removeGenerator(DefinitionGenerator &G) { +void LookupState::reset(InProgressLookupState *IPLS) { this->IPLS.reset(IPLS); } + +LookupState::~LookupState() {} + +void LookupState::continueLookup(Error Err) { + assert(IPLS && "Cannot call continueLookup on empty LookupState"); + auto &ES = IPLS->SearchOrder.begin()->first->getExecutionSession(); + ES.OL_applyQueryPhase1(std::move(IPLS), std::move(Err)); +} + +DefinitionGenerator::~DefinitionGenerator() {} + +Error JITDylib::clear() { + std::vector TrackersToRemove; ES.runSessionLocked([&]() { - auto I = std::find_if(DefGenerators.begin(), DefGenerators.end(), - [&](const std::unique_ptr &H) { - return H.get() == &G; - }); - assert(I != DefGenerators.end() && "Generator not found"); - DefGenerators.erase(I); + for (auto &KV : TrackerSymbols) + TrackersToRemove.push_back(KV.first); + TrackersToRemove.push_back(getDefaultResourceTracker()); + }); + + Error Err = Error::success(); + for (auto &RT : TrackersToRemove) + Err = joinErrors(std::move(Err), RT->remove()); + return Err; +} + +ResourceTrackerSP JITDylib::getDefaultResourceTracker() { + return ES.runSessionLocked([this] { + if (!DefaultTracker) + DefaultTracker = new ResourceTracker(this); + return DefaultTracker; + }); +} + +ResourceTrackerSP JITDylib::createResourceTracker() { + return ES.runSessionLocked([this] { + ResourceTrackerSP RT = new ResourceTracker(this); + return RT; }); } +void JITDylib::removeGenerator(DefinitionGenerator &G) { + std::lock_guard Lock(GeneratorsMutex); + auto I = std::find_if(DefGenerators.begin(), DefGenerators.end(), + [&](const std::shared_ptr &H) { + return H.get() == &G; + }); + assert(I != DefGenerators.end() && "Generator not found"); + DefGenerators.erase(I); +} + Expected JITDylib::defineMaterializing(SymbolFlagsMap SymbolFlags) { @@ -652,11 +677,18 @@ JITDylib::defineMaterializing(SymbolFlagsMap SymbolFlags) { }); } -void JITDylib::replace(std::unique_ptr MU) { +Error JITDylib::replace(MaterializationResponsibility &FromMR, + std::unique_ptr MU) { assert(MU != nullptr && "Can not replace with a null MaterializationUnit"); + std::unique_ptr MustRunMU; + std::unique_ptr MustRunMR; + + auto Err = + ES.runSessionLocked([&, this]() -> Error { + auto RT = getTracker(FromMR); - auto MustRunMU = - ES.runSessionLocked([&, this]() -> std::unique_ptr { + if (RT->isDefunct()) + return make_error(std::move(RT)); #ifndef NDEBUG for (auto &KV : MU->getSymbols()) { @@ -671,18 +703,27 @@ void JITDylib::replace(std::unique_ptr MU) { } #endif // NDEBUG + // If the tracker is defunct we need to bail out immediately. + // If any symbol has pending queries against it then we need to // materialize MU immediately. for (auto &KV : MU->getSymbols()) { auto MII = MaterializingInfos.find(KV.first); if (MII != MaterializingInfos.end()) { - if (MII->second.hasQueriesPending()) - return std::move(MU); + if (MII->second.hasQueriesPending()) { + MustRunMR = ES.createMaterializationResponsibility( + *RT, std::move(MU->SymbolFlags), std::move(MU->InitSymbol)); + MustRunMU = std::move(MU); + return Error::success(); + } } } // Otherwise, make MU responsible for all the symbols. - auto UMI = std::make_shared(std::move(MU)); + auto RTI = MRTrackers.find(&FromMR); + assert(RTI != MRTrackers.end() && "No tracker for FromMR"); + auto UMI = + std::make_shared(std::move(MU), RTI->second); for (auto &KV : UMI->MU->getSymbols()) { auto SymI = Symbols.find(KV.first); assert(SymI->second.getState() == SymbolState::Materializing && @@ -700,14 +741,36 @@ void JITDylib::replace(std::unique_ptr MU) { UMIEntry = UMI; } - return nullptr; + return Error::success(); }); + if (Err) + return Err; + if (MustRunMU) { - auto MR = - MustRunMU->createMaterializationResponsibility(shared_from_this()); - ES.dispatchMaterialization(std::move(MustRunMU), std::move(MR)); + assert(MustRunMR && "MustRunMU set implies MustRunMR set"); + ES.dispatchMaterialization(std::move(MustRunMU), std::move(MustRunMR)); + } else { + assert(!MustRunMR && "MustRunMU unset implies MustRunMR unset"); } + + return Error::success(); +} + +Expected> +JITDylib::delegate(MaterializationResponsibility &FromMR, + SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol) { + + return ES.runSessionLocked( + [&]() -> Expected> { + auto RT = getTracker(FromMR); + + if (RT->isDefunct()) + return make_error(std::move(RT)); + + return ES.createMaterializationResponsibility( + *RT, std::move(SymbolFlags), std::move(InitSymbol)); + }); } SymbolNameSet @@ -808,89 +871,93 @@ void JITDylib::addDependencies(const SymbolStringPtr &Name, Symbols[Name].setFlags(Symbols[Name].getFlags() | JITSymbolFlags::HasError); } -Error JITDylib::resolve(const SymbolMap &Resolved) { - SymbolNameSet SymbolsInErrorState; +Error JITDylib::resolve(MaterializationResponsibility &MR, + const SymbolMap &Resolved) { AsynchronousSymbolQuerySet CompletedQueries; - ES.runSessionLocked([&, this]() { - struct WorklistEntry { - SymbolTable::iterator SymI; - JITEvaluatedSymbol ResolvedSym; - }; - - std::vector Worklist; - Worklist.reserve(Resolved.size()); + if (auto Err = ES.runSessionLocked([&, this]() -> Error { + auto RTI = MRTrackers.find(&MR); + assert(RTI != MRTrackers.end() && "No resource tracker for MR?"); + if (RTI->second->isDefunct()) + return make_error(RTI->second); - // Build worklist and check for any symbols in the error state. - for (const auto &KV : Resolved) { + struct WorklistEntry { + SymbolTable::iterator SymI; + JITEvaluatedSymbol ResolvedSym; + }; - assert(!KV.second.getFlags().hasError() && - "Resolution result can not have error flag set"); + SymbolNameSet SymbolsInErrorState; + std::vector Worklist; + Worklist.reserve(Resolved.size()); - auto SymI = Symbols.find(KV.first); + // Build worklist and check for any symbols in the error state. + for (const auto &KV : Resolved) { - assert(SymI != Symbols.end() && "Symbol not found"); - assert(!SymI->second.hasMaterializerAttached() && - "Resolving symbol with materializer attached?"); - assert(SymI->second.getState() == SymbolState::Materializing && - "Symbol should be materializing"); - assert(SymI->second.getAddress() == 0 && - "Symbol has already been resolved"); + assert(!KV.second.getFlags().hasError() && + "Resolution result can not have error flag set"); - if (SymI->second.getFlags().hasError()) - SymbolsInErrorState.insert(KV.first); - else { - auto Flags = KV.second.getFlags(); - Flags &= ~(JITSymbolFlags::Weak | JITSymbolFlags::Common); - assert(Flags == (SymI->second.getFlags() & - ~(JITSymbolFlags::Weak | JITSymbolFlags::Common)) && - "Resolved flags should match the declared flags"); - - Worklist.push_back( - {SymI, JITEvaluatedSymbol(KV.second.getAddress(), Flags)}); - } - } + auto SymI = Symbols.find(KV.first); - // If any symbols were in the error state then bail out. - if (!SymbolsInErrorState.empty()) - return; + assert(SymI != Symbols.end() && "Symbol not found"); + assert(!SymI->second.hasMaterializerAttached() && + "Resolving symbol with materializer attached?"); + assert(SymI->second.getState() == SymbolState::Materializing && + "Symbol should be materializing"); + assert(SymI->second.getAddress() == 0 && + "Symbol has already been resolved"); + + if (SymI->second.getFlags().hasError()) + SymbolsInErrorState.insert(KV.first); + else { + auto Flags = KV.second.getFlags(); + Flags &= ~(JITSymbolFlags::Weak | JITSymbolFlags::Common); + assert(Flags == + (SymI->second.getFlags() & + ~(JITSymbolFlags::Weak | JITSymbolFlags::Common)) && + "Resolved flags should match the declared flags"); + + Worklist.push_back( + {SymI, JITEvaluatedSymbol(KV.second.getAddress(), Flags)}); + } + } - while (!Worklist.empty()) { - auto SymI = Worklist.back().SymI; - auto ResolvedSym = Worklist.back().ResolvedSym; - Worklist.pop_back(); + // If any symbols were in the error state then bail out. + if (!SymbolsInErrorState.empty()) { + auto FailedSymbolsDepMap = std::make_shared(); + (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState); + return make_error( + std::move(FailedSymbolsDepMap)); + } - auto &Name = SymI->first; + while (!Worklist.empty()) { + auto SymI = Worklist.back().SymI; + auto ResolvedSym = Worklist.back().ResolvedSym; + Worklist.pop_back(); - // Resolved symbols can not be weak: discard the weak flag. - JITSymbolFlags ResolvedFlags = ResolvedSym.getFlags(); - SymI->second.setAddress(ResolvedSym.getAddress()); - SymI->second.setFlags(ResolvedFlags); - SymI->second.setState(SymbolState::Resolved); + auto &Name = SymI->first; - auto MII = MaterializingInfos.find(Name); - if (MII == MaterializingInfos.end()) - continue; + // Resolved symbols can not be weak: discard the weak flag. + JITSymbolFlags ResolvedFlags = ResolvedSym.getFlags(); + SymI->second.setAddress(ResolvedSym.getAddress()); + SymI->second.setFlags(ResolvedFlags); + SymI->second.setState(SymbolState::Resolved); - auto &MI = MII->second; - for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) { - Q->notifySymbolMetRequiredState(Name, ResolvedSym); - Q->removeQueryDependence(*this, Name); - if (Q->isComplete()) - CompletedQueries.insert(std::move(Q)); - } - } - }); + auto MII = MaterializingInfos.find(Name); + if (MII == MaterializingInfos.end()) + continue; - assert((SymbolsInErrorState.empty() || CompletedQueries.empty()) && - "Can't fail symbols and completed queries at the same time"); + auto &MI = MII->second; + for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) { + Q->notifySymbolMetRequiredState(Name, ResolvedSym); + Q->removeQueryDependence(*this, Name); + if (Q->isComplete()) + CompletedQueries.insert(std::move(Q)); + } + } - // If we failed any symbols then return an error. - if (!SymbolsInErrorState.empty()) { - auto FailedSymbolsDepMap = std::make_shared(); - (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState); - return make_error(std::move(FailedSymbolsDepMap)); - } + return Error::success(); + })) + return Err; // Otherwise notify all the completed queries. for (auto &Q : CompletedQueries) { @@ -901,139 +968,145 @@ Error JITDylib::resolve(const SymbolMap &Resolved) { return Error::success(); } -Error JITDylib::emit(const SymbolFlagsMap &Emitted) { +Error JITDylib::emit(MaterializationResponsibility &MR, + const SymbolFlagsMap &Emitted) { AsynchronousSymbolQuerySet CompletedQueries; - SymbolNameSet SymbolsInErrorState; DenseMap ReadySymbols; - ES.runSessionLocked([&, this]() { - std::vector Worklist; + if (auto Err = ES.runSessionLocked([&, this]() -> Error { + auto RTI = MRTrackers.find(&MR); + assert(RTI != MRTrackers.end() && "No resource tracker for MR?"); + if (RTI->second->isDefunct()) + return make_error(RTI->second); - // Scan to build worklist, record any symbols in the erorr state. - for (const auto &KV : Emitted) { - auto &Name = KV.first; + SymbolNameSet SymbolsInErrorState; + std::vector Worklist; - auto SymI = Symbols.find(Name); - assert(SymI != Symbols.end() && "No symbol table entry for Name"); + // Scan to build worklist, record any symbols in the erorr state. + for (const auto &KV : Emitted) { + auto &Name = KV.first; - if (SymI->second.getFlags().hasError()) - SymbolsInErrorState.insert(Name); - else - Worklist.push_back(SymI); - } + auto SymI = Symbols.find(Name); + assert(SymI != Symbols.end() && "No symbol table entry for Name"); - // If any symbols were in the error state then bail out. - if (!SymbolsInErrorState.empty()) - return; + if (SymI->second.getFlags().hasError()) + SymbolsInErrorState.insert(Name); + else + Worklist.push_back(SymI); + } + + // If any symbols were in the error state then bail out. + if (!SymbolsInErrorState.empty()) { + auto FailedSymbolsDepMap = std::make_shared(); + (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState); + return make_error( + std::move(FailedSymbolsDepMap)); + } - // Otherwise update dependencies and move to the emitted state. - while (!Worklist.empty()) { - auto SymI = Worklist.back(); - Worklist.pop_back(); + // Otherwise update dependencies and move to the emitted state. + while (!Worklist.empty()) { + auto SymI = Worklist.back(); + Worklist.pop_back(); - auto &Name = SymI->first; - auto &SymEntry = SymI->second; + auto &Name = SymI->first; + auto &SymEntry = SymI->second; - // Move symbol to the emitted state. - assert(((SymEntry.getFlags().hasMaterializationSideEffectsOnly() && - SymEntry.getState() == SymbolState::Materializing) || - SymEntry.getState() == SymbolState::Resolved) && - "Emitting from state other than Resolved"); - SymEntry.setState(SymbolState::Emitted); + // Move symbol to the emitted state. + assert(((SymEntry.getFlags().hasMaterializationSideEffectsOnly() && + SymEntry.getState() == SymbolState::Materializing) || + SymEntry.getState() == SymbolState::Resolved) && + "Emitting from state other than Resolved"); + SymEntry.setState(SymbolState::Emitted); - auto MII = MaterializingInfos.find(Name); + auto MII = MaterializingInfos.find(Name); - // If this symbol has no MaterializingInfo then it's trivially ready. - // Update its state and continue. - if (MII == MaterializingInfos.end()) { - SymEntry.setState(SymbolState::Ready); - continue; - } + // If this symbol has no MaterializingInfo then it's trivially ready. + // Update its state and continue. + if (MII == MaterializingInfos.end()) { + SymEntry.setState(SymbolState::Ready); + continue; + } + + auto &MI = MII->second; + + // For each dependant, transfer this node's emitted dependencies to + // it. If the dependant node is ready (i.e. has no unemitted + // dependencies) then notify any pending queries. + for (auto &KV : MI.Dependants) { + auto &DependantJD = *KV.first; + auto &DependantJDReadySymbols = ReadySymbols[&DependantJD]; + for (auto &DependantName : KV.second) { + auto DependantMII = + DependantJD.MaterializingInfos.find(DependantName); + assert(DependantMII != DependantJD.MaterializingInfos.end() && + "Dependant should have MaterializingInfo"); + + auto &DependantMI = DependantMII->second; + + // Remove the dependant's dependency on this node. + assert(DependantMI.UnemittedDependencies.count(this) && + "Dependant does not have an unemitted dependencies record " + "for " + "this JITDylib"); + assert(DependantMI.UnemittedDependencies[this].count(Name) && + "Dependant does not count this symbol as a dependency?"); + + DependantMI.UnemittedDependencies[this].erase(Name); + if (DependantMI.UnemittedDependencies[this].empty()) + DependantMI.UnemittedDependencies.erase(this); + + // Transfer unemitted dependencies from this node to the + // dependant. + DependantJD.transferEmittedNodeDependencies(DependantMI, + DependantName, MI); + + auto DependantSymI = DependantJD.Symbols.find(DependantName); + assert(DependantSymI != DependantJD.Symbols.end() && + "Dependant has no entry in the Symbols table"); + auto &DependantSymEntry = DependantSymI->second; + + // If the dependant is emitted and this node was the last of its + // unemitted dependencies then the dependant node is now ready, so + // notify any pending queries on the dependant node. + if (DependantSymEntry.getState() == SymbolState::Emitted && + DependantMI.UnemittedDependencies.empty()) { + assert(DependantMI.Dependants.empty() && + "Dependants should be empty by now"); + + // Since this dependant is now ready, we erase its + // MaterializingInfo and update its materializing state. + DependantSymEntry.setState(SymbolState::Ready); + DependantJDReadySymbols.push_back(DependantName); + + for (auto &Q : + DependantMI.takeQueriesMeeting(SymbolState::Ready)) { + Q->notifySymbolMetRequiredState( + DependantName, DependantSymI->second.getSymbol()); + if (Q->isComplete()) + CompletedQueries.insert(Q); + Q->removeQueryDependence(DependantJD, DependantName); + } + } + } + } - auto &MI = MII->second; - - // For each dependant, transfer this node's emitted dependencies to - // it. If the dependant node is ready (i.e. has no unemitted - // dependencies) then notify any pending queries. - for (auto &KV : MI.Dependants) { - auto &DependantJD = *KV.first; - auto &DependantJDReadySymbols = ReadySymbols[&DependantJD]; - for (auto &DependantName : KV.second) { - auto DependantMII = - DependantJD.MaterializingInfos.find(DependantName); - assert(DependantMII != DependantJD.MaterializingInfos.end() && - "Dependant should have MaterializingInfo"); - - auto &DependantMI = DependantMII->second; - - // Remove the dependant's dependency on this node. - assert(DependantMI.UnemittedDependencies.count(this) && - "Dependant does not have an unemitted dependencies record for " - "this JITDylib"); - assert(DependantMI.UnemittedDependencies[this].count(Name) && - "Dependant does not count this symbol as a dependency?"); - - DependantMI.UnemittedDependencies[this].erase(Name); - if (DependantMI.UnemittedDependencies[this].empty()) - DependantMI.UnemittedDependencies.erase(this); - - // Transfer unemitted dependencies from this node to the dependant. - DependantJD.transferEmittedNodeDependencies(DependantMI, - DependantName, MI); - - auto DependantSymI = DependantJD.Symbols.find(DependantName); - assert(DependantSymI != DependantJD.Symbols.end() && - "Dependant has no entry in the Symbols table"); - auto &DependantSymEntry = DependantSymI->second; - - // If the dependant is emitted and this node was the last of its - // unemitted dependencies then the dependant node is now ready, so - // notify any pending queries on the dependant node. - if (DependantSymEntry.getState() == SymbolState::Emitted && - DependantMI.UnemittedDependencies.empty()) { - assert(DependantMI.Dependants.empty() && - "Dependants should be empty by now"); - - // Since this dependant is now ready, we erase its MaterializingInfo - // and update its materializing state. - DependantSymEntry.setState(SymbolState::Ready); - DependantJDReadySymbols.push_back(DependantName); - - for (auto &Q : DependantMI.takeQueriesMeeting(SymbolState::Ready)) { - Q->notifySymbolMetRequiredState( - DependantName, DependantSymI->second.getSymbol()); + auto &ThisJDReadySymbols = ReadySymbols[this]; + MI.Dependants.clear(); + if (MI.UnemittedDependencies.empty()) { + SymI->second.setState(SymbolState::Ready); + ThisJDReadySymbols.push_back(Name); + for (auto &Q : MI.takeQueriesMeeting(SymbolState::Ready)) { + Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol()); if (Q->isComplete()) CompletedQueries.insert(Q); - Q->removeQueryDependence(DependantJD, DependantName); + Q->removeQueryDependence(*this, Name); } } } - } - - auto &ThisJDReadySymbols = ReadySymbols[this]; - MI.Dependants.clear(); - if (MI.UnemittedDependencies.empty()) { - SymI->second.setState(SymbolState::Ready); - ThisJDReadySymbols.push_back(Name); - for (auto &Q : MI.takeQueriesMeeting(SymbolState::Ready)) { - Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol()); - if (Q->isComplete()) - CompletedQueries.insert(Q); - Q->removeQueryDependence(*this, Name); - } - } - } - }); - assert((SymbolsInErrorState.empty() || CompletedQueries.empty()) && - "Can't fail symbols and completed queries at the same time"); - - // If we failed any symbols then return an error. - if (!SymbolsInErrorState.empty()) { - auto FailedSymbolsDepMap = std::make_shared(); - (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState); - return make_error(std::move(FailedSymbolsDepMap)); - } + return Error::success(); + })) + return Err; // Otherwise notify all the completed queries. for (auto &Q : CompletedQueries) { @@ -1044,120 +1117,122 @@ Error JITDylib::emit(const SymbolFlagsMap &Emitted) { return Error::success(); } -void JITDylib::notifyFailed(FailedSymbolsWorklist Worklist) { - AsynchronousSymbolQuerySet FailedQueries; - auto FailedSymbolsMap = std::make_shared(); - - // Failing no symbols is a no-op. - if (Worklist.empty()) - return; - - auto &ES = Worklist.front().first->getExecutionSession(); - +void JITDylib::unlinkMaterializationResponsibility( + MaterializationResponsibility &MR) { ES.runSessionLocked([&]() { - while (!Worklist.empty()) { - assert(Worklist.back().first && "Failed JITDylib can not be null"); - auto &JD = *Worklist.back().first; - auto Name = std::move(Worklist.back().second); - Worklist.pop_back(); - - (*FailedSymbolsMap)[&JD].insert(Name); - - assert(JD.Symbols.count(Name) && "No symbol table entry for Name"); - auto &Sym = JD.Symbols[Name]; - - // Move the symbol into the error state. - // Note that this may be redundant: The symbol might already have been - // moved to this state in response to the failure of a dependence. - Sym.setFlags(Sym.getFlags() | JITSymbolFlags::HasError); - - // FIXME: Come up with a sane mapping of state to - // presence-of-MaterializingInfo so that we can assert presence / absence - // here, rather than testing it. - auto MII = JD.MaterializingInfos.find(Name); + auto I = MRTrackers.find(&MR); + assert(I != MRTrackers.end() && "MaterializationResponsibility not linked"); + MRTrackers.erase(I); + }); +} - if (MII == JD.MaterializingInfos.end()) - continue; +std::pair> +JITDylib::failSymbols(FailedSymbolsWorklist Worklist) { + AsynchronousSymbolQuerySet FailedQueries; + auto FailedSymbolsMap = std::make_shared(); - auto &MI = MII->second; - - // Move all dependants to the error state and disconnect from them. - for (auto &KV : MI.Dependants) { - auto &DependantJD = *KV.first; - for (auto &DependantName : KV.second) { - assert(DependantJD.Symbols.count(DependantName) && - "No symbol table entry for DependantName"); - auto &DependantSym = DependantJD.Symbols[DependantName]; - DependantSym.setFlags(DependantSym.getFlags() | - JITSymbolFlags::HasError); - - assert(DependantJD.MaterializingInfos.count(DependantName) && - "No MaterializingInfo for dependant"); - auto &DependantMI = DependantJD.MaterializingInfos[DependantName]; - - auto UnemittedDepI = DependantMI.UnemittedDependencies.find(&JD); - assert(UnemittedDepI != DependantMI.UnemittedDependencies.end() && - "No UnemittedDependencies entry for this JITDylib"); - assert(UnemittedDepI->second.count(Name) && - "No UnemittedDependencies entry for this symbol"); - UnemittedDepI->second.erase(Name); - if (UnemittedDepI->second.empty()) - DependantMI.UnemittedDependencies.erase(UnemittedDepI); - - // If this symbol is already in the emitted state then we need to - // take responsibility for failing its queries, so add it to the - // worklist. - if (DependantSym.getState() == SymbolState::Emitted) { - assert(DependantMI.Dependants.empty() && - "Emitted symbol should not have dependants"); - Worklist.push_back(std::make_pair(&DependantJD, DependantName)); - } - } - } - MI.Dependants.clear(); - - // Disconnect from all unemitted depenencies. - for (auto &KV : MI.UnemittedDependencies) { - auto &UnemittedDepJD = *KV.first; - for (auto &UnemittedDepName : KV.second) { - auto UnemittedDepMII = - UnemittedDepJD.MaterializingInfos.find(UnemittedDepName); - assert(UnemittedDepMII != UnemittedDepJD.MaterializingInfos.end() && - "Missing MII for unemitted dependency"); - assert(UnemittedDepMII->second.Dependants.count(&JD) && - "JD not listed as a dependant of unemitted dependency"); - assert(UnemittedDepMII->second.Dependants[&JD].count(Name) && - "Name is not listed as a dependant of unemitted dependency"); - UnemittedDepMII->second.Dependants[&JD].erase(Name); - if (UnemittedDepMII->second.Dependants[&JD].empty()) - UnemittedDepMII->second.Dependants.erase(&JD); + while (!Worklist.empty()) { + assert(Worklist.back().first && "Failed JITDylib can not be null"); + auto &JD = *Worklist.back().first; + auto Name = std::move(Worklist.back().second); + Worklist.pop_back(); + + (*FailedSymbolsMap)[&JD].insert(Name); + + assert(JD.Symbols.count(Name) && "No symbol table entry for Name"); + auto &Sym = JD.Symbols[Name]; + + // Move the symbol into the error state. + // Note that this may be redundant: The symbol might already have been + // moved to this state in response to the failure of a dependence. + Sym.setFlags(Sym.getFlags() | JITSymbolFlags::HasError); + + // FIXME: Come up with a sane mapping of state to + // presence-of-MaterializingInfo so that we can assert presence / absence + // here, rather than testing it. + auto MII = JD.MaterializingInfos.find(Name); + + if (MII == JD.MaterializingInfos.end()) + continue; + + auto &MI = MII->second; + + // Move all dependants to the error state and disconnect from them. + for (auto &KV : MI.Dependants) { + auto &DependantJD = *KV.first; + for (auto &DependantName : KV.second) { + assert(DependantJD.Symbols.count(DependantName) && + "No symbol table entry for DependantName"); + auto &DependantSym = DependantJD.Symbols[DependantName]; + DependantSym.setFlags(DependantSym.getFlags() | + JITSymbolFlags::HasError); + + assert(DependantJD.MaterializingInfos.count(DependantName) && + "No MaterializingInfo for dependant"); + auto &DependantMI = DependantJD.MaterializingInfos[DependantName]; + + auto UnemittedDepI = DependantMI.UnemittedDependencies.find(&JD); + assert(UnemittedDepI != DependantMI.UnemittedDependencies.end() && + "No UnemittedDependencies entry for this JITDylib"); + assert(UnemittedDepI->second.count(Name) && + "No UnemittedDependencies entry for this symbol"); + UnemittedDepI->second.erase(Name); + if (UnemittedDepI->second.empty()) + DependantMI.UnemittedDependencies.erase(UnemittedDepI); + + // If this symbol is already in the emitted state then we need to + // take responsibility for failing its queries, so add it to the + // worklist. + if (DependantSym.getState() == SymbolState::Emitted) { + assert(DependantMI.Dependants.empty() && + "Emitted symbol should not have dependants"); + Worklist.push_back(std::make_pair(&DependantJD, DependantName)); } } - MI.UnemittedDependencies.clear(); - - // Collect queries to be failed for this MII. - AsynchronousSymbolQueryList ToDetach; - for (auto &Q : MII->second.pendingQueries()) { - // Add the query to the list to be failed and detach it. - FailedQueries.insert(Q); - ToDetach.push_back(Q); + } + MI.Dependants.clear(); + + // Disconnect from all unemitted depenencies. + for (auto &KV : MI.UnemittedDependencies) { + auto &UnemittedDepJD = *KV.first; + for (auto &UnemittedDepName : KV.second) { + auto UnemittedDepMII = + UnemittedDepJD.MaterializingInfos.find(UnemittedDepName); + assert(UnemittedDepMII != UnemittedDepJD.MaterializingInfos.end() && + "Missing MII for unemitted dependency"); + assert(UnemittedDepMII->second.Dependants.count(&JD) && + "JD not listed as a dependant of unemitted dependency"); + assert(UnemittedDepMII->second.Dependants[&JD].count(Name) && + "Name is not listed as a dependant of unemitted dependency"); + UnemittedDepMII->second.Dependants[&JD].erase(Name); + if (UnemittedDepMII->second.Dependants[&JD].empty()) + UnemittedDepMII->second.Dependants.erase(&JD); } - for (auto &Q : ToDetach) - Q->detach(); - - assert(MI.Dependants.empty() && - "Can not delete MaterializingInfo with dependants still attached"); - assert(MI.UnemittedDependencies.empty() && - "Can not delete MaterializingInfo with unemitted dependencies " - "still attached"); - assert(!MI.hasQueriesPending() && - "Can not delete MaterializingInfo with queries pending"); - JD.MaterializingInfos.erase(MII); } - }); + MI.UnemittedDependencies.clear(); + + // Collect queries to be failed for this MII. + AsynchronousSymbolQueryList ToDetach; + for (auto &Q : MII->second.pendingQueries()) { + // Add the query to the list to be failed and detach it. + FailedQueries.insert(Q); + ToDetach.push_back(Q); + } + for (auto &Q : ToDetach) + Q->detach(); - for (auto &Q : FailedQueries) - Q->handleFailed(make_error(FailedSymbolsMap)); + assert(MI.Dependants.empty() && + "Can not delete MaterializingInfo with dependants still attached"); + assert(MI.UnemittedDependencies.empty() && + "Can not delete MaterializingInfo with unemitted dependencies " + "still attached"); + assert(!MI.hasQueriesPending() && + "Can not delete MaterializingInfo with queries pending"); + JD.MaterializingInfos.erase(MII); + } + + return std::make_pair(std::move(FailedQueries), std::move(FailedSymbolsMap)); } void JITDylib::setLinkOrder(JITDylibSearchOrder NewLinkOrder, @@ -1257,295 +1332,22 @@ Error JITDylib::remove(const SymbolNameSet &Names) { }); } -Expected -JITDylib::lookupFlags(LookupKind K, JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet LookupSet) { - return ES.runSessionLocked([&, this]() -> Expected { - SymbolFlagsMap Result; - lookupFlagsImpl(Result, K, JDLookupFlags, LookupSet); - - // Run any definition generators. - for (auto &DG : DefGenerators) { - - // Bail out early if we found everything. - if (LookupSet.empty()) - break; +void JITDylib::dump(raw_ostream &OS) { + ES.runSessionLocked([&, this]() { + OS << "JITDylib \"" << JITDylibName << "\" (ES: " + << format("0x%016" PRIx64, reinterpret_cast(&ES)) << "):\n" + << "Link order: " << LinkOrder << "\n" + << "Symbol table:\n"; - // Run this generator. - if (auto Err = DG->tryToGenerate(K, *this, JDLookupFlags, LookupSet)) - return std::move(Err); + for (auto &KV : Symbols) { + OS << " \"" << *KV.first << "\": "; + if (auto Addr = KV.second.getAddress()) + OS << format("0x%016" PRIx64, Addr) << ", " << KV.second.getFlags() + << " "; + else + OS << " "; - // Re-try the search. - lookupFlagsImpl(Result, K, JDLookupFlags, LookupSet); - } - - return Result; - }); -} - -void JITDylib::lookupFlagsImpl(SymbolFlagsMap &Result, LookupKind K, - JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet &LookupSet) { - - LookupSet.forEachWithRemoval( - [&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) -> bool { - auto I = Symbols.find(Name); - if (I == Symbols.end()) - return false; - assert(!Result.count(Name) && "Symbol already present in Flags map"); - Result[Name] = I->second.getFlags(); - return true; - }); -} - -Error JITDylib::lodgeQuery(MaterializationUnitList &MUs, - std::shared_ptr &Q, - LookupKind K, JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet &Unresolved) { - assert(Q && "Query can not be null"); - - if (auto Err = lodgeQueryImpl(MUs, Q, K, JDLookupFlags, Unresolved)) - return Err; - - // Run any definition generators. - for (auto &DG : DefGenerators) { - - // Bail out early if we have resolved everything. - if (Unresolved.empty()) - break; - - // Run the generator. - if (auto Err = DG->tryToGenerate(K, *this, JDLookupFlags, Unresolved)) - return Err; - - // Lodge query. This can not fail as any new definitions were added - // by the generator under the session locked. Since they can't have - // started materializing yet they can not have failed. - cantFail(lodgeQueryImpl(MUs, Q, K, JDLookupFlags, Unresolved)); - } - - return Error::success(); -} - -Error JITDylib::lodgeQueryImpl(MaterializationUnitList &MUs, - std::shared_ptr &Q, - LookupKind K, JITDylibLookupFlags JDLookupFlags, - SymbolLookupSet &Unresolved) { - - return Unresolved.forEachWithRemoval( - [&](const SymbolStringPtr &Name, - SymbolLookupFlags SymLookupFlags) -> Expected { - // Search for name in symbols. If not found then continue without - // removal. - auto SymI = Symbols.find(Name); - if (SymI == Symbols.end()) - return false; - - // If we match against a materialization-side-effects only symbol then - // make sure it is weakly-referenced. Otherwise bail out with an error. - if (SymI->second.getFlags().hasMaterializationSideEffectsOnly() && - SymLookupFlags != SymbolLookupFlags::WeaklyReferencedSymbol) - return make_error(SymbolNameVector({Name})); - - // If this is a non exported symbol and we're matching exported symbols - // only then skip this symbol without removal. - if (!SymI->second.getFlags().isExported() && - JDLookupFlags == JITDylibLookupFlags::MatchExportedSymbolsOnly) - return false; - - // If we matched against this symbol but it is in the error state then - // bail out and treat it as a failure to materialize. - if (SymI->second.getFlags().hasError()) { - auto FailedSymbolsMap = std::make_shared(); - (*FailedSymbolsMap)[this] = {Name}; - return make_error(std::move(FailedSymbolsMap)); - } - - // If this symbol already meets the required state for then notify the - // query, then remove the symbol and continue. - if (SymI->second.getState() >= Q->getRequiredState()) { - Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol()); - return true; - } - - // Otherwise this symbol does not yet meet the required state. Check - // whether it has a materializer attached, and if so prepare to run it. - if (SymI->second.hasMaterializerAttached()) { - assert(SymI->second.getAddress() == 0 && - "Symbol not resolved but already has address?"); - auto UMII = UnmaterializedInfos.find(Name); - assert(UMII != UnmaterializedInfos.end() && - "Lazy symbol should have UnmaterializedInfo"); - auto MU = std::move(UMII->second->MU); - assert(MU != nullptr && "Materializer should not be null"); - - // Move all symbols associated with this MaterializationUnit into - // materializing state. - for (auto &KV : MU->getSymbols()) { - auto SymK = Symbols.find(KV.first); - SymK->second.setMaterializerAttached(false); - SymK->second.setState(SymbolState::Materializing); - UnmaterializedInfos.erase(KV.first); - } - - // Add MU to the list of MaterializationUnits to be materialized. - MUs.push_back(std::move(MU)); - } - - // Add the query to the PendingQueries list and continue, deleting the - // element. - assert(SymI->second.getState() != SymbolState::NeverSearched && - SymI->second.getState() != SymbolState::Ready && - "By this line the symbol should be materializing"); - auto &MI = MaterializingInfos[Name]; - MI.addQuery(Q); - Q->addQueryDependence(*this, Name); - return true; - }); -} - -Expected -JITDylib::legacyLookup(std::shared_ptr Q, - SymbolNameSet Names) { - assert(Q && "Query can not be null"); - - ES.runOutstandingMUs(); - - bool QueryComplete = false; - std::vector> MUs; - - SymbolLookupSet Unresolved(Names); - auto Err = ES.runSessionLocked([&, this]() -> Error { - QueryComplete = lookupImpl(Q, MUs, Unresolved); - - // Run any definition generators. - for (auto &DG : DefGenerators) { - - // Bail out early if we have resolved everything. - if (Unresolved.empty()) - break; - - assert(!QueryComplete && "query complete but unresolved symbols remain?"); - if (auto Err = DG->tryToGenerate(LookupKind::Static, *this, - JITDylibLookupFlags::MatchAllSymbols, - Unresolved)) - return Err; - - if (!Unresolved.empty()) - QueryComplete = lookupImpl(Q, MUs, Unresolved); - } - return Error::success(); - }); - - if (Err) - return std::move(Err); - - assert((MUs.empty() || !QueryComplete) && - "If action flags are set, there should be no work to do (so no MUs)"); - - if (QueryComplete) - Q->handleComplete(); - - // FIXME: Swap back to the old code below once RuntimeDyld works with - // callbacks from asynchronous queries. - // Add MUs to the OutstandingMUs list. - { - std::lock_guard Lock(ES.OutstandingMUsMutex); - auto ThisJD = shared_from_this(); - for (auto &MU : MUs) { - auto MR = MU->createMaterializationResponsibility(ThisJD); - ES.OutstandingMUs.push_back(make_pair(std::move(MU), std::move(MR))); - } - } - ES.runOutstandingMUs(); - - // Dispatch any required MaterializationUnits for materialization. - // for (auto &MU : MUs) - // ES.dispatchMaterialization(*this, std::move(MU)); - - SymbolNameSet RemainingSymbols; - for (auto &KV : Unresolved) - RemainingSymbols.insert(KV.first); - - return RemainingSymbols; -} - -bool JITDylib::lookupImpl( - std::shared_ptr &Q, - std::vector> &MUs, - SymbolLookupSet &Unresolved) { - bool QueryComplete = false; - - std::vector ToRemove; - Unresolved.forEachWithRemoval( - [&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) -> bool { - // Search for the name in Symbols. Skip without removing if not found. - auto SymI = Symbols.find(Name); - if (SymI == Symbols.end()) - return false; - - // If the symbol is already in the required state then notify the query - // and remove. - if (SymI->second.getState() >= Q->getRequiredState()) { - Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol()); - if (Q->isComplete()) - QueryComplete = true; - return true; - } - - // If the symbol is lazy, get the MaterialiaztionUnit for it. - if (SymI->second.hasMaterializerAttached()) { - assert(SymI->second.getAddress() == 0 && - "Lazy symbol should not have a resolved address"); - auto UMII = UnmaterializedInfos.find(Name); - assert(UMII != UnmaterializedInfos.end() && - "Lazy symbol should have UnmaterializedInfo"); - auto MU = std::move(UMII->second->MU); - assert(MU != nullptr && "Materializer should not be null"); - - // Kick all symbols associated with this MaterializationUnit into - // materializing state. - for (auto &KV : MU->getSymbols()) { - auto SymK = Symbols.find(KV.first); - assert(SymK != Symbols.end() && "Missing symbol table entry"); - SymK->second.setState(SymbolState::Materializing); - SymK->second.setMaterializerAttached(false); - UnmaterializedInfos.erase(KV.first); - } - - // Add MU to the list of MaterializationUnits to be materialized. - MUs.push_back(std::move(MU)); - } - - // Add the query to the PendingQueries list. - assert(SymI->second.getState() != SymbolState::NeverSearched && - SymI->second.getState() != SymbolState::Ready && - "By this line the symbol should be materializing"); - auto &MI = MaterializingInfos[Name]; - MI.addQuery(Q); - Q->addQueryDependence(*this, Name); - return true; - }); - - return QueryComplete; -} - -void JITDylib::dump(raw_ostream &OS) { - ES.runSessionLocked([&, this]() { - OS << "JITDylib \"" << JITDylibName << "\" (ES: " - << format("0x%016" PRIx64, reinterpret_cast(&ES)) << "):\n" - << "Link order: " << LinkOrder << "\n" - << "Symbol table:\n"; - - for (auto &KV : Symbols) { - OS << " \"" << *KV.first << "\": "; - if (auto Addr = KV.second.getAddress()) - OS << format("0x%016" PRIx64, Addr) << ", " << KV.second.getFlags() - << " "; - else - OS << " "; - - OS << KV.second.getFlags() << " " << KV.second.getState(); + OS << KV.second.getFlags() << " " << KV.second.getState(); if (KV.second.hasMaterializerAttached()) { OS << " (Materializer "; @@ -1618,6 +1420,137 @@ JITDylib::JITDylib(ExecutionSession &ES, std::string Name) LinkOrder.push_back({this, JITDylibLookupFlags::MatchAllSymbols}); } +ResourceTrackerSP JITDylib::getTracker(MaterializationResponsibility &MR) { + auto I = MRTrackers.find(&MR); + assert(I != MRTrackers.end() && "MR is not linked"); + assert(I->second && "Linked tracker is null"); + return I->second; +} + +std::pair> +JITDylib::removeTracker(ResourceTracker &RT) { + // Note: Should be called under the session lock. + + SymbolNameVector SymbolsToRemove; + std::vector> SymbolsToFail; + + if (&RT == DefaultTracker.get()) { + SymbolNameSet TrackedSymbols; + for (auto &KV : TrackerSymbols) + for (auto &Sym : KV.second) + TrackedSymbols.insert(Sym); + + for (auto &KV : Symbols) { + auto &Sym = KV.first; + if (!TrackedSymbols.count(Sym)) + SymbolsToRemove.push_back(Sym); + } + + DefaultTracker.reset(); + } else { + /// Check for a non-default tracker. + auto I = TrackerSymbols.find(&RT); + if (I != TrackerSymbols.end()) { + SymbolsToRemove = std::move(I->second); + TrackerSymbols.erase(I); + } + // ... if not found this tracker was already defunct. Nothing to do. + } + + for (auto &Sym : SymbolsToRemove) { + assert(Symbols.count(Sym) && "Symbol not in symbol table"); + + // If there is a MaterializingInfo then collect any queries to fail. + auto MII = MaterializingInfos.find(Sym); + if (MII != MaterializingInfos.end()) + SymbolsToFail.push_back({this, Sym}); + } + + AsynchronousSymbolQuerySet QueriesToFail; + auto Result = failSymbols(std::move(SymbolsToFail)); + + // Removed symbols should be taken out of the table altogether. + for (auto &Sym : SymbolsToRemove) { + auto I = Symbols.find(Sym); + assert(I != Symbols.end() && "Symbol not present in table"); + + // Remove Materializer if present. + if (I->second.hasMaterializerAttached()) { + // FIXME: Should this discard the symbols? + UnmaterializedInfos.erase(Sym); + } else { + assert(!UnmaterializedInfos.count(Sym) && + "Symbol has materializer attached"); + } + + Symbols.erase(I); + } + + return Result; +} + +void JITDylib::transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT) { + assert(&DstRT != &SrcRT && "No-op transfers shouldn't call transferTracker"); + assert(&DstRT.getJITDylib() == this && "DstRT is not for this JITDylib"); + assert(&SrcRT.getJITDylib() == this && "SrcRT is not for this JITDylib"); + + // Update trackers for any not-yet materialized units. + for (auto &KV : UnmaterializedInfos) { + if (KV.second->RT == &SrcRT) + KV.second->RT = &DstRT; + } + + // Update trackers for any active materialization responsibilities. + for (auto &KV : MRTrackers) { + if (KV.second == &SrcRT) + KV.second = &DstRT; + } + + // If we're transfering to the default tracker we just need to delete the + // tracked symbols for the source tracker. + if (&DstRT == DefaultTracker.get()) { + TrackerSymbols.erase(&SrcRT); + return; + } + + // If we're transferring from the default tracker we need to find all + // currently untracked symbols. + if (&SrcRT == DefaultTracker.get()) { + assert(!TrackerSymbols.count(&SrcRT) && + "Default tracker should not appear in TrackerSymbols"); + + SymbolNameVector SymbolsToTrack; + + SymbolNameSet CurrentlyTrackedSymbols; + for (auto &KV : TrackerSymbols) + for (auto &Sym : KV.second) + CurrentlyTrackedSymbols.insert(Sym); + + for (auto &KV : Symbols) { + auto &Sym = KV.first; + if (!CurrentlyTrackedSymbols.count(Sym)) + SymbolsToTrack.push_back(Sym); + } + + TrackerSymbols[&DstRT] = std::move(SymbolsToTrack); + return; + } + + auto &DstTrackedSymbols = TrackerSymbols[&DstRT]; + + // Finally if neither SrtRT or DstRT are the default tracker then + // just append DstRT's tracked symbols to SrtRT's. + auto SI = TrackerSymbols.find(&SrcRT); + if (SI == TrackerSymbols.end()) + return; + + DstTrackedSymbols.reserve(DstTrackedSymbols.size() + SI->second.size()); + for (auto &Sym : SI->second) + DstTrackedSymbols.push_back(std::move(Sym)); + TrackerSymbols.erase(SI); +} + Error JITDylib::defineImpl(MaterializationUnit &MU) { LLVM_DEBUG({ dbgs() << " " << MU.getSymbols() << "\n"; }); @@ -1685,6 +1618,22 @@ Error JITDylib::defineImpl(MaterializationUnit &MU) { return Error::success(); } +void JITDylib::installMaterializationUnit( + std::unique_ptr MU, ResourceTracker &RT) { + + /// defineImpl succeeded. + if (&RT != DefaultTracker.get()) { + auto &TS = TrackerSymbols[&RT]; + TS.reserve(TS.size() + MU->getSymbols().size()); + for (auto &KV : MU->getSymbols()) + TS.push_back(KV.first); + } + + auto UMI = std::make_shared(std::move(MU), &RT); + for (auto &KV : UMI->MU->getSymbols()) + UnmaterializedInfos[KV.first] = UMI; +} + void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q, const SymbolNameSet &QuerySymbols) { for (auto &QuerySymbol : QuerySymbols) { @@ -1773,7 +1722,39 @@ Expected> Platform::lookupInitSymbols( } ExecutionSession::ExecutionSession(std::shared_ptr SSP) - : SSP(SSP ? std::move(SSP) : std::make_shared()) { + : SSP(SSP ? std::move(SSP) : std::make_shared()) {} + +Error ExecutionSession::endSession() { + LLVM_DEBUG(dbgs() << "Ending ExecutionSession " << this << "\n"); + + std::vector JITDylibsToClose = runSessionLocked([&] { + SessionOpen = false; + return std::move(JDs); + }); + + // TODO: notifiy platform? run static deinits? + + Error Err = Error::success(); + for (auto &JD : JITDylibsToClose) + Err = joinErrors(std::move(Err), JD->clear()); + return Err; +} + +void ExecutionSession::registerResourceManager(ResourceManager &RM) { + runSessionLocked([&] { ResourceManagers.push_back(&RM); }); +} + +void ExecutionSession::deregisterResourceManager(ResourceManager &RM) { + runSessionLocked([&] { + assert(!ResourceManagers.empty() && "No managers registered"); + if (ResourceManagers.back() == &RM) + ResourceManagers.pop_back(); + else { + auto I = llvm::find(ResourceManagers, &RM); + assert(I != ResourceManagers.end() && "RM not registered"); + ResourceManagers.erase(I); + } + }); } JITDylib *ExecutionSession::getJITDylibByName(StringRef Name) { @@ -1788,8 +1769,7 @@ JITDylib *ExecutionSession::getJITDylibByName(StringRef Name) { JITDylib &ExecutionSession::createBareJITDylib(std::string Name) { assert(!getJITDylibByName(Name) && "JITDylib with that name already exists"); return runSessionLocked([&, this]() -> JITDylib & { - JDs.push_back( - std::shared_ptr(new JITDylib(*this, std::move(Name)))); + JDs.push_back(new JITDylib(*this, std::move(Name))); return *JDs.back(); }); } @@ -1802,29 +1782,121 @@ Expected ExecutionSession::createJITDylib(std::string Name) { return JD; } -void ExecutionSession::legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err) { - assert(!!Err && "Error should be in failure state"); +std::vector JITDylib::getDFSLinkOrder(ArrayRef JDs) { + if (JDs.empty()) + return {}; - bool SendErrorToQuery; - runSessionLocked([&]() { - Q.detach(); - SendErrorToQuery = Q.canStillFail(); + auto &ES = JDs.front()->getExecutionSession(); + return ES.runSessionLocked([&]() { + DenseSet Visited; + std::vector Result; + + for (auto &JD : JDs) { + + if (Visited.count(JD.get())) + continue; + + SmallVector WorkStack; + WorkStack.push_back(JD); + Visited.insert(JD.get()); + + while (!WorkStack.empty()) { + Result.push_back(std::move(WorkStack.back())); + WorkStack.pop_back(); + + for (auto &KV : llvm::reverse(Result.back()->LinkOrder)) { + auto &JD = *KV.first; + if (Visited.count(&JD)) + continue; + Visited.insert(&JD); + WorkStack.push_back(&JD); + } + } + } + return Result; }); +} - if (SendErrorToQuery) - Q.handleFailed(std::move(Err)); - else - reportError(std::move(Err)); +std::vector +JITDylib::getReverseDFSLinkOrder(ArrayRef JDs) { + auto Tmp = getDFSLinkOrder(JDs); + std::reverse(Tmp.begin(), Tmp.end()); + return Tmp; +} + +std::vector JITDylib::getDFSLinkOrder() { + return getDFSLinkOrder({this}); +} + +std::vector JITDylib::getReverseDFSLinkOrder() { + return getReverseDFSLinkOrder({this}); +} + +void ExecutionSession::lookupFlags( + LookupKind K, JITDylibSearchOrder SearchOrder, SymbolLookupSet LookupSet, + unique_function)> OnComplete) { + + OL_applyQueryPhase1(std::make_unique( + K, std::move(SearchOrder), std::move(LookupSet), + std::move(OnComplete)), + Error::success()); +} + +Expected +ExecutionSession::lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder, + SymbolLookupSet LookupSet) { + + std::promise> ResultP; + OL_applyQueryPhase1(std::make_unique( + K, std::move(SearchOrder), std::move(LookupSet), + [&ResultP](Expected Result) { + ResultP.set_value(std::move(Result)); + }), + Error::success()); + + auto ResultF = ResultP.get_future(); + return ResultF.get(); } -Expected ExecutionSession::legacyLookup( - LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names, - SymbolState RequiredState, +void ExecutionSession::lookup( + LookupKind K, const JITDylibSearchOrder &SearchOrder, + SymbolLookupSet Symbols, SymbolState RequiredState, + SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies) { + + LLVM_DEBUG({ + runSessionLocked([&]() { + dbgs() << "Looking up " << Symbols << " in " << SearchOrder + << " (required state: " << RequiredState << ")\n"; + }); + }); + + // lookup can be re-entered recursively if running on a single thread. Run any + // outstanding MUs in case this query depends on them, otherwise this lookup + // will starve waiting for a result from an MU that is stuck in the queue. + dispatchOutstandingMUs(); + + auto Unresolved = std::move(Symbols); + auto Q = std::make_shared(Unresolved, RequiredState, + std::move(NotifyComplete)); + + auto IPLS = std::make_unique( + K, SearchOrder, std::move(Unresolved), RequiredState, std::move(Q), + std::move(RegisterDependencies)); + + OL_applyQueryPhase1(std::move(IPLS), Error::success()); +} + +Expected +ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder, + const SymbolLookupSet &Symbols, LookupKind K, + SymbolState RequiredState, + RegisterDependenciesFunction RegisterDependencies) { #if LLVM_ENABLE_THREADS // In the threaded case we use promises to return the results. std::promise PromisedResult; Error ResolutionError = Error::success(); + auto NotifyComplete = [&](Expected R) { if (R) PromisedResult.set_value(std::move(*R)); @@ -1834,6 +1906,7 @@ Expected ExecutionSession::legacyLookup( PromisedResult.set_value(SymbolMap()); } }; + #else SymbolMap Result; Error ResolutionError = Error::success(); @@ -1847,33 +1920,17 @@ Expected ExecutionSession::legacyLookup( }; #endif - auto Query = std::make_shared( - SymbolLookupSet(Names), RequiredState, std::move(NotifyComplete)); - // FIXME: This should be run session locked along with the registration code - // and error reporting below. - SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names)); - - // If the query was lodged successfully then register the dependencies, - // otherwise fail it with an error. - if (UnresolvedSymbols.empty()) - RegisterDependencies(Query->QueryRegistrations); - else { - bool DeliverError = runSessionLocked([&]() { - Query->detach(); - return Query->canStillFail(); - }); - auto Err = make_error(std::move(UnresolvedSymbols)); - if (DeliverError) - Query->handleFailed(std::move(Err)); - else - reportError(std::move(Err)); - } + // Perform the asynchronous lookup. + lookup(K, SearchOrder, Symbols, RequiredState, NotifyComplete, + RegisterDependencies); #if LLVM_ENABLE_THREADS auto ResultFuture = PromisedResult.get_future(); auto Result = ResultFuture.get(); + if (ResolutionError) return std::move(ResolutionError); + return std::move(Result); #else @@ -1884,219 +1941,829 @@ Expected ExecutionSession::legacyLookup( #endif } -void ExecutionSession::lookup( - LookupKind K, const JITDylibSearchOrder &SearchOrder, - SymbolLookupSet Symbols, SymbolState RequiredState, - SymbolsResolvedCallback NotifyComplete, - RegisterDependenciesFunction RegisterDependencies) { +Expected +ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder, + SymbolStringPtr Name, SymbolState RequiredState) { + SymbolLookupSet Names({Name}); - LLVM_DEBUG({ - runSessionLocked([&]() { - dbgs() << "Looking up " << Symbols << " in " << SearchOrder - << " (required state: " << RequiredState << ")\n"; - }); - }); + if (auto ResultMap = lookup(SearchOrder, std::move(Names), LookupKind::Static, + RequiredState, NoDependenciesToRegister)) { + assert(ResultMap->size() == 1 && "Unexpected number of results"); + assert(ResultMap->count(Name) && "Missing result for symbol"); + return std::move(ResultMap->begin()->second); + } else + return ResultMap.takeError(); +} - // lookup can be re-entered recursively if running on a single thread. Run any - // outstanding MUs in case this query depends on them, otherwise this lookup - // will starve waiting for a result from an MU that is stuck in the queue. - runOutstandingMUs(); +Expected +ExecutionSession::lookup(ArrayRef SearchOrder, SymbolStringPtr Name, + SymbolState RequiredState) { + return lookup(makeJITDylibSearchOrder(SearchOrder), Name, RequiredState); +} + +Expected +ExecutionSession::lookup(ArrayRef SearchOrder, StringRef Name, + SymbolState RequiredState) { + return lookup(SearchOrder, intern(Name), RequiredState); +} + +void ExecutionSession::dump(raw_ostream &OS) { + runSessionLocked([this, &OS]() { + for (auto &JD : JDs) + JD->dump(OS); + }); +} + +void ExecutionSession::dispatchOutstandingMUs() { + LLVM_DEBUG(dbgs() << "Dispatching MaterializationUnits...\n"); + while (1) { + Optional, + std::unique_ptr>> + JMU; + + { + std::lock_guard Lock(OutstandingMUsMutex); + if (!OutstandingMUs.empty()) { + JMU.emplace(std::move(OutstandingMUs.back())); + OutstandingMUs.pop_back(); + } + } + + if (!JMU) + break; + + assert(JMU->first && "No MU?"); + LLVM_DEBUG(dbgs() << " Dispatching \"" << JMU->first->getName() << "\"\n"); + dispatchMaterialization(std::move(JMU->first), std::move(JMU->second)); + } + LLVM_DEBUG(dbgs() << "Done dispatching MaterializationUnits.\n"); +} + +Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) { + LLVM_DEBUG({ + dbgs() << "In " << RT.getJITDylib().getName() << " removing tracker " + << formatv("{0:x}", RT.getKeyUnsafe()) << "\n"; + }); + std::vector CurrentResourceManagers; + + JITDylib::AsynchronousSymbolQuerySet QueriesToFail; + std::shared_ptr FailedSymbols; + + runSessionLocked([&] { + CurrentResourceManagers = ResourceManagers; + RT.makeDefunct(); + std::tie(QueriesToFail, FailedSymbols) = RT.getJITDylib().removeTracker(RT); + }); + + Error Err = Error::success(); + + for (auto *L : reverse(CurrentResourceManagers)) + Err = + joinErrors(std::move(Err), L->handleRemoveResources(RT.getKeyUnsafe())); + + for (auto &Q : QueriesToFail) + Q->handleFailed(make_error(FailedSymbols)); + + return Err; +} + +void ExecutionSession::transferResourceTracker(ResourceTracker &DstRT, + ResourceTracker &SrcRT) { + LLVM_DEBUG({ + dbgs() << "In " << SrcRT.getJITDylib().getName() + << " transfering resources from tracker " + << formatv("{0:x}", SrcRT.getKeyUnsafe()) << " to tracker " + << formatv("{0:x}", DstRT.getKeyUnsafe()) << "\n"; + }); + + // No-op transfers are allowed and do not invalidate the source. + if (&DstRT == &SrcRT) + return; + + assert(&DstRT.getJITDylib() == &SrcRT.getJITDylib() && + "Can't transfer resources between JITDylibs"); + runSessionLocked([&]() { + SrcRT.makeDefunct(); + auto &JD = DstRT.getJITDylib(); + JD.transferTracker(DstRT, SrcRT); + for (auto *L : reverse(ResourceManagers)) + L->handleTransferResources(DstRT.getKeyUnsafe(), SrcRT.getKeyUnsafe()); + }); +} + +void ExecutionSession::destroyResourceTracker(ResourceTracker &RT) { + runSessionLocked([&]() { + LLVM_DEBUG({ + dbgs() << "In " << RT.getJITDylib().getName() << " destroying tracker " + << formatv("{0:x}", RT.getKeyUnsafe()) << "\n"; + }); + if (!RT.isDefunct()) + transferResourceTracker(*RT.getJITDylib().getDefaultResourceTracker(), + RT); + }); +} + +Error ExecutionSession::IL_updateCandidatesFor( + JITDylib &JD, JITDylibLookupFlags JDLookupFlags, + SymbolLookupSet &Candidates, SymbolLookupSet *NonCandidates) { + return Candidates.forEachWithRemoval( + [&](const SymbolStringPtr &Name, + SymbolLookupFlags SymLookupFlags) -> Expected { + /// Search for the symbol. If not found then continue without + /// removal. + auto SymI = JD.Symbols.find(Name); + if (SymI == JD.Symbols.end()) + return false; + + // If this is a non-exported symbol and we're matching exported + // symbols only then remove this symbol from the candidates list. + // + // If we're tracking non-candidates then add this to the non-candidate + // list. + if (!SymI->second.getFlags().isExported() && + JDLookupFlags == JITDylibLookupFlags::MatchExportedSymbolsOnly) { + if (NonCandidates) + NonCandidates->add(Name, SymLookupFlags); + return true; + } + + // If we match against a materialization-side-effects only symbol + // then make sure it is weakly-referenced. Otherwise bail out with + // an error. + // FIXME: Use a "materialization-side-effects-only symbols must be + // weakly referenced" specific error here to reduce confusion. + if (SymI->second.getFlags().hasMaterializationSideEffectsOnly() && + SymLookupFlags != SymbolLookupFlags::WeaklyReferencedSymbol) + return make_error(SymbolNameVector({Name})); + + // If we matched against this symbol but it is in the error state + // then bail out and treat it as a failure to materialize. + if (SymI->second.getFlags().hasError()) { + auto FailedSymbolsMap = std::make_shared(); + (*FailedSymbolsMap)[&JD] = {Name}; + return make_error(std::move(FailedSymbolsMap)); + } + + // Otherwise this is a match. Remove it from the candidate set. + return true; + }); +} + +void ExecutionSession::OL_applyQueryPhase1( + std::unique_ptr IPLS, Error Err) { + + LLVM_DEBUG({ + dbgs() << "Entering OL_applyQueryPhase1:\n" + << " Lookup kind: " << IPLS->K << "\n" + << " Search order: " << IPLS->SearchOrder + << ", Current index = " << IPLS->CurSearchOrderIndex + << (IPLS->NewJITDylib ? " (entering new JITDylib)" : "") << "\n" + << " Lookup set: " << IPLS->LookupSet << "\n" + << " Definition generator candidates: " + << IPLS->DefGeneratorCandidates << "\n" + << " Definition generator non-candidates: " + << IPLS->DefGeneratorNonCandidates << "\n"; + }); + + // FIXME: We should attach the query as we go: This provides a result in a + // single pass in the common case where all symbols have already reached the + // required state. The query could be detached again in the 'fail' method on + // IPLS. Phase 2 would be reduced to collecting and dispatching the MUs. + + while (IPLS->CurSearchOrderIndex != IPLS->SearchOrder.size()) { + + // If we've been handed an error or received one back from a generator then + // fail the query. We don't need to unlink: At this stage the query hasn't + // actually been lodged. + if (Err) + return IPLS->fail(std::move(Err)); + + // Get the next JITDylib and lookup flags. + auto &KV = IPLS->SearchOrder[IPLS->CurSearchOrderIndex]; + auto &JD = *KV.first; + auto JDLookupFlags = KV.second; + + LLVM_DEBUG({ + dbgs() << "Visiting \"" << JD.getName() << "\" (" << JDLookupFlags + << ") with lookup set " << IPLS->LookupSet << ":\n"; + }); + + // If we've just reached a new JITDylib then perform some setup. + if (IPLS->NewJITDylib) { + + // Acquire the generator lock for this JITDylib. + IPLS->GeneratorLock = std::unique_lock(JD.GeneratorsMutex); + + // Add any non-candidates from the last JITDylib (if any) back on to the + // list of definition candidates for this JITDylib, reset definition + // non-candiates to the empty set. + SymbolLookupSet Tmp; + std::swap(IPLS->DefGeneratorNonCandidates, Tmp); + IPLS->DefGeneratorCandidates.append(std::move(Tmp)); + + LLVM_DEBUG({ + dbgs() << " First time visiting " << JD.getName() + << ", resetting candidate sets and building generator stack\n"; + }); + + // Build the definition generator stack for this JITDylib. + for (auto &DG : reverse(JD.DefGenerators)) + IPLS->CurDefGeneratorStack.push_back(DG); + + // Flag that we've done our initialization. + IPLS->NewJITDylib = false; + } + + // Remove any generation candidates that are already defined (and match) in + // this JITDylib. + runSessionLocked([&] { + // Update the list of candidates (and non-candidates) for definition + // generation. + LLVM_DEBUG(dbgs() << " Updating candidate set...\n"); + Err = IL_updateCandidatesFor( + JD, JDLookupFlags, IPLS->DefGeneratorCandidates, + JD.DefGenerators.empty() ? nullptr + : &IPLS->DefGeneratorNonCandidates); + LLVM_DEBUG({ + dbgs() << " Remaining candidates = " << IPLS->DefGeneratorCandidates + << "\n"; + }); + }); + + // If we encountered an error while filtering generation candidates then + // bail out. + if (Err) + return IPLS->fail(std::move(Err)); + + /// Apply any definition generators on the stack. + LLVM_DEBUG({ + if (IPLS->CurDefGeneratorStack.empty()) + LLVM_DEBUG(dbgs() << " No generators to run for this JITDylib.\n"); + else if (IPLS->DefGeneratorCandidates.empty()) + LLVM_DEBUG(dbgs() << " No candidates to generate.\n"); + else + dbgs() << " Running " << IPLS->CurDefGeneratorStack.size() + << " remaining generators for " + << IPLS->DefGeneratorCandidates.size() << " candidates\n"; + }); + while (!IPLS->CurDefGeneratorStack.empty() && + !IPLS->DefGeneratorCandidates.empty()) { + auto DG = IPLS->CurDefGeneratorStack.back().lock(); + IPLS->CurDefGeneratorStack.pop_back(); + + if (!DG) + return IPLS->fail(make_error( + "DefinitionGenerator removed while lookup in progress", + inconvertibleErrorCode())); + + auto K = IPLS->K; + auto &LookupSet = IPLS->DefGeneratorCandidates; + + // Run the generator. If the generator takes ownership of QA then this + // will break the loop. + { + LLVM_DEBUG(dbgs() << " Attempting to generate " << LookupSet << "\n"); + LookupState LS(std::move(IPLS)); + Err = DG->tryToGenerate(LS, K, JD, JDLookupFlags, LookupSet); + IPLS = std::move(LS.IPLS); + } + + // If there was an error then fail the query. + if (Err) { + LLVM_DEBUG({ + dbgs() << " Error attempting to generate " << LookupSet << "\n"; + }); + assert(IPLS && "LS cannot be retained if error is returned"); + return IPLS->fail(std::move(Err)); + } + + // Otherwise if QA was captured then break the loop. + if (!IPLS) { + LLVM_DEBUG( + { dbgs() << " LookupState captured. Exiting phase1 for now.\n"; }); + return; + } + + // Otherwise if we're continuing around the loop then update candidates + // for the next round. + runSessionLocked([&] { + LLVM_DEBUG(dbgs() << " Updating candidate set post-generation\n"); + Err = IL_updateCandidatesFor( + JD, JDLookupFlags, IPLS->DefGeneratorCandidates, + JD.DefGenerators.empty() ? nullptr + : &IPLS->DefGeneratorNonCandidates); + }); + + // If updating candidates failed then fail the query. + if (Err) { + LLVM_DEBUG(dbgs() << " Error encountered while updating candidates\n"); + return IPLS->fail(std::move(Err)); + } + } + + // If we get here then we've moved on to the next JITDylib. + LLVM_DEBUG(dbgs() << "Phase 1 moving to next JITDylib.\n"); + ++IPLS->CurSearchOrderIndex; + IPLS->NewJITDylib = true; + } + + // Remove any weakly referenced candidates that could not be found/generated. + IPLS->DefGeneratorCandidates.remove_if( + [](const SymbolStringPtr &Name, SymbolLookupFlags SymLookupFlags) { + return SymLookupFlags == SymbolLookupFlags::WeaklyReferencedSymbol; + }); + + // If we get here then we've finished searching all JITDylibs. + // If we matched all symbols then move to phase 2, otherwise fail the query + // with a SymbolsNotFound error. + if (IPLS->DefGeneratorCandidates.empty()) { + LLVM_DEBUG(dbgs() << "Phase 1 succeeded.\n"); + IPLS->complete(std::move(IPLS)); + } else { + LLVM_DEBUG(dbgs() << "Phase 1 failed with unresolved symbols.\n"); + IPLS->fail(make_error( + IPLS->DefGeneratorCandidates.getSymbolNames())); + } +} + +void ExecutionSession::OL_completeLookup( + std::unique_ptr IPLS, + std::shared_ptr Q, + RegisterDependenciesFunction RegisterDependencies) { + + LLVM_DEBUG({ + dbgs() << "Entering OL_completeLookup:\n" + << " Lookup kind: " << IPLS->K << "\n" + << " Search order: " << IPLS->SearchOrder + << ", Current index = " << IPLS->CurSearchOrderIndex + << (IPLS->NewJITDylib ? " (entering new JITDylib)" : "") << "\n" + << " Lookup set: " << IPLS->LookupSet << "\n" + << " Definition generator candidates: " + << IPLS->DefGeneratorCandidates << "\n" + << " Definition generator non-candidates: " + << IPLS->DefGeneratorNonCandidates << "\n"; + }); - auto Unresolved = std::move(Symbols); - std::map CollectedMUsMap; - auto Q = std::make_shared(Unresolved, RequiredState, - std::move(NotifyComplete)); bool QueryComplete = false; + DenseMap CollectedUMIs; auto LodgingErr = runSessionLocked([&]() -> Error { - auto LodgeQuery = [&]() -> Error { - for (auto &KV : SearchOrder) { - assert(KV.first && "JITDylibList entries must not be null"); - assert(!CollectedMUsMap.count(KV.first) && - "JITDylibList should not contain duplicate entries"); + for (auto &KV : IPLS->SearchOrder) { + auto &JD = *KV.first; + auto JDLookupFlags = KV.second; + LLVM_DEBUG({ + dbgs() << "Visiting \"" << JD.getName() << "\" (" << JDLookupFlags + << ") with lookup set " << IPLS->LookupSet << ":\n"; + }); - auto &JD = *KV.first; - auto JDLookupFlags = KV.second; - if (auto Err = JD.lodgeQuery(CollectedMUsMap[&JD], Q, K, JDLookupFlags, - Unresolved)) - return Err; - } + auto Err = IPLS->LookupSet.forEachWithRemoval( + [&](const SymbolStringPtr &Name, + SymbolLookupFlags SymLookupFlags) -> Expected { + LLVM_DEBUG({ + dbgs() << " Attempting to match \"" << Name << "\" (" + << SymLookupFlags << ")... "; + }); + + /// Search for the symbol. If not found then continue without + /// removal. + auto SymI = JD.Symbols.find(Name); + if (SymI == JD.Symbols.end()) { + LLVM_DEBUG(dbgs() << "skipping: not present\n"); + return false; + } + + // If this is a non-exported symbol and we're matching exported + // symbols only then skip this symbol without removal. + if (!SymI->second.getFlags().isExported() && + JDLookupFlags == + JITDylibLookupFlags::MatchExportedSymbolsOnly) { + LLVM_DEBUG(dbgs() << "skipping: not exported\n"); + return false; + } + + // If we match against a materialization-side-effects only symbol + // then make sure it is weakly-referenced. Otherwise bail out with + // an error. + // FIXME: Use a "materialization-side-effects-only symbols must be + // weakly referenced" specific error here to reduce confusion. + if (SymI->second.getFlags().hasMaterializationSideEffectsOnly() && + SymLookupFlags != SymbolLookupFlags::WeaklyReferencedSymbol) { + LLVM_DEBUG({ + dbgs() << "error: " + "required, but symbol is has-side-effects-only\n"; + }); + return make_error(SymbolNameVector({Name})); + } + + // If we matched against this symbol but it is in the error state + // then bail out and treat it as a failure to materialize. + if (SymI->second.getFlags().hasError()) { + LLVM_DEBUG(dbgs() << "error: symbol is in error state\n"); + auto FailedSymbolsMap = std::make_shared(); + (*FailedSymbolsMap)[&JD] = {Name}; + return make_error( + std::move(FailedSymbolsMap)); + } + + // Otherwise this is a match. - // Strip any weakly referenced symbols that were not found. - Unresolved.forEachWithRemoval( - [&](const SymbolStringPtr &Name, SymbolLookupFlags Flags) { - if (Flags == SymbolLookupFlags::WeaklyReferencedSymbol) { - Q->dropSymbol(Name); + // If this symbol is already in the requried state then notify the + // query, remove the symbol and continue. + if (SymI->second.getState() >= Q->getRequiredState()) { + LLVM_DEBUG(dbgs() + << "matched, symbol already in required state\n"); + Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol()); return true; } - return false; - }); - if (!Unresolved.empty()) - return make_error(Unresolved.getSymbolNames()); + // Otherwise this symbol does not yet meet the required state. Check + // whether it has a materializer attached, and if so prepare to run + // it. + if (SymI->second.hasMaterializerAttached()) { + assert(SymI->second.getAddress() == 0 && + "Symbol not resolved but already has address?"); + auto UMII = JD.UnmaterializedInfos.find(Name); + assert(UMII != JD.UnmaterializedInfos.end() && + "Lazy symbol should have UnmaterializedInfo"); + + auto UMI = UMII->second; + assert(UMI->MU && "Materializer should not be null"); + assert(UMI->RT && "Tracker should not be null"); + LLVM_DEBUG({ + dbgs() << "matched, preparing to dispatch MU@" << UMI->MU.get() + << " (" << UMI->MU->getName() << ")\n"; + }); + + // Move all symbols associated with this MaterializationUnit into + // materializing state. + for (auto &KV : UMI->MU->getSymbols()) { + auto SymK = JD.Symbols.find(KV.first); + assert(SymK != JD.Symbols.end() && + "No entry for symbol covered by MaterializationUnit"); + SymK->second.setMaterializerAttached(false); + SymK->second.setState(SymbolState::Materializing); + JD.UnmaterializedInfos.erase(KV.first); + } + + // Add MU to the list of MaterializationUnits to be materialized. + CollectedUMIs[&JD].push_back(std::move(UMI)); + } else + LLVM_DEBUG(dbgs() << "matched, registering query"); + + // Add the query to the PendingQueries list and continue, deleting + // the element from the lookup set. + assert(SymI->second.getState() != SymbolState::NeverSearched && + SymI->second.getState() != SymbolState::Ready && + "By this line the symbol should be materializing"); + auto &MI = JD.MaterializingInfos[Name]; + MI.addQuery(Q); + Q->addQueryDependence(JD, Name); + + return true; + }); - return Error::success(); - }; + // Handle failure. + if (Err) { - if (auto Err = LodgeQuery()) { - // Query failed. + LLVM_DEBUG({ + dbgs() << "Lookup failed. Detaching query and replacing MUs.\n"; + }); - // Disconnect the query from its dependencies. - Q->detach(); + // Detach the query. + Q->detach(); - // Replace the MUs. - for (auto &KV : CollectedMUsMap) - for (auto &MU : KV.second) - KV.first->replace(std::move(MU)); + // Replace the MUs. + for (auto &KV : CollectedUMIs) { + auto &JD = *KV.first; + for (auto &UMI : KV.second) + for (auto &KV2 : UMI->MU->getSymbols()) { + assert(!JD.UnmaterializedInfos.count(KV2.first) && + "Unexpected materializer in map"); + auto SymI = JD.Symbols.find(KV2.first); + assert(SymI != JD.Symbols.end() && "Missing symbol entry"); + assert(SymI->second.getState() == SymbolState::Materializing && + "Can not replace symbol that is not materializing"); + assert(!SymI->second.hasMaterializerAttached() && + "MaterializerAttached flag should not be set"); + SymI->second.setMaterializerAttached(true); + JD.UnmaterializedInfos[KV2.first] = UMI; + } + } - return Err; + return Err; + } } - // Query lodged successfully. + LLVM_DEBUG(dbgs() << "Stripping unmatched weakly-refererced symbols\n"); + IPLS->LookupSet.forEachWithRemoval( + [&](const SymbolStringPtr &Name, SymbolLookupFlags SymLookupFlags) { + if (SymLookupFlags == SymbolLookupFlags::WeaklyReferencedSymbol) { + Q->dropSymbol(Name); + return true; + } else + return false; + }); + + if (!IPLS->LookupSet.empty()) { + LLVM_DEBUG(dbgs() << "Failing due to unresolved symbols\n"); + return make_error(IPLS->LookupSet.getSymbolNames()); + } - // Record whether this query is fully ready / resolved. We will use - // this to call handleFullyResolved/handleFullyReady outside the session - // lock. + // Record whether the query completed. QueryComplete = Q->isComplete(); - // Call the register dependencies function. - if (RegisterDependencies && !Q->QueryRegistrations.empty()) + LLVM_DEBUG({ + dbgs() << "Query successfully " + << (QueryComplete ? "completed" : "lodged") << "\n"; + }); + + // Move the collected MUs to the OutstandingMUs list. + if (!CollectedUMIs.empty()) { + std::lock_guard Lock(OutstandingMUsMutex); + + LLVM_DEBUG(dbgs() << "Adding MUs to dispatch:\n"); + for (auto &KV : CollectedUMIs) { + auto &JD = *KV.first; + LLVM_DEBUG({ + dbgs() << " For " << JD.getName() << ": Adding " << KV.second.size() + << " MUs.\n"; + }); + for (auto &UMI : KV.second) { + std::unique_ptr MR( + new MaterializationResponsibility( + &JD, std::move(UMI->MU->SymbolFlags), + std::move(UMI->MU->InitSymbol))); + JD.MRTrackers[MR.get()] = UMI->RT; + OutstandingMUs.push_back( + std::make_pair(std::move(UMI->MU), std::move(MR))); + } + } + } else + LLVM_DEBUG(dbgs() << "No MUs to dispatch.\n"); + + if (RegisterDependencies && !Q->QueryRegistrations.empty()) { + LLVM_DEBUG(dbgs() << "Registering dependencies\n"); RegisterDependencies(Q->QueryRegistrations); + } else + LLVM_DEBUG(dbgs() << "No dependencies to register\n"); return Error::success(); }); if (LodgingErr) { + LLVM_DEBUG(dbgs() << "Failing query\n"); + Q->detach(); Q->handleFailed(std::move(LodgingErr)); return; } - if (QueryComplete) + if (QueryComplete) { + LLVM_DEBUG(dbgs() << "Completing query\n"); Q->handleComplete(); + } - // Move the MUs to the OutstandingMUs list, then materialize. - { - std::lock_guard Lock(OutstandingMUsMutex); + dispatchOutstandingMUs(); +} + +void ExecutionSession::OL_completeLookupFlags( + std::unique_ptr IPLS, + unique_function)> OnComplete) { + + auto Result = runSessionLocked([&]() -> Expected { + LLVM_DEBUG({ + dbgs() << "Entering OL_completeLookupFlags:\n" + << " Lookup kind: " << IPLS->K << "\n" + << " Search order: " << IPLS->SearchOrder + << ", Current index = " << IPLS->CurSearchOrderIndex + << (IPLS->NewJITDylib ? " (entering new JITDylib)" : "") << "\n" + << " Lookup set: " << IPLS->LookupSet << "\n" + << " Definition generator candidates: " + << IPLS->DefGeneratorCandidates << "\n" + << " Definition generator non-candidates: " + << IPLS->DefGeneratorNonCandidates << "\n"; + }); - for (auto &KV : CollectedMUsMap) { - auto JD = KV.first->shared_from_this(); - for (auto &MU : KV.second) { - auto MR = MU->createMaterializationResponsibility(JD); - OutstandingMUs.push_back(std::make_pair(std::move(MU), std::move(MR))); - } - } - } + SymbolFlagsMap Result; - runOutstandingMUs(); -} + // Attempt to find flags for each symbol. + for (auto &KV : IPLS->SearchOrder) { + auto &JD = *KV.first; + auto JDLookupFlags = KV.second; + LLVM_DEBUG({ + dbgs() << "Visiting \"" << JD.getName() << "\" (" << JDLookupFlags + << ") with lookup set " << IPLS->LookupSet << ":\n"; + }); -Expected -ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder, - const SymbolLookupSet &Symbols, LookupKind K, - SymbolState RequiredState, - RegisterDependenciesFunction RegisterDependencies) { -#if LLVM_ENABLE_THREADS - // In the threaded case we use promises to return the results. - std::promise PromisedResult; - Error ResolutionError = Error::success(); + IPLS->LookupSet.forEachWithRemoval([&](const SymbolStringPtr &Name, + SymbolLookupFlags SymLookupFlags) { + LLVM_DEBUG({ + dbgs() << " Attempting to match \"" << Name << "\" (" + << SymLookupFlags << ")... "; + }); + + // Search for the symbol. If not found then continue without removing + // from the lookup set. + auto SymI = JD.Symbols.find(Name); + if (SymI == JD.Symbols.end()) { + LLVM_DEBUG(dbgs() << "skipping: not present\n"); + return false; + } - auto NotifyComplete = [&](Expected R) { - if (R) - PromisedResult.set_value(std::move(*R)); - else { - ErrorAsOutParameter _(&ResolutionError); - ResolutionError = R.takeError(); - PromisedResult.set_value(SymbolMap()); + // If this is a non-exported symbol then it doesn't match. Skip it. + if (!SymI->second.getFlags().isExported() && + JDLookupFlags == JITDylibLookupFlags::MatchExportedSymbolsOnly) { + LLVM_DEBUG(dbgs() << "skipping: not exported\n"); + return false; + } + + LLVM_DEBUG({ + dbgs() << "matched, \"" << Name << "\" -> " << SymI->second.getFlags() + << "\n"; + }); + Result[Name] = SymI->second.getFlags(); + return true; + }); } - }; -#else - SymbolMap Result; - Error ResolutionError = Error::success(); + // Remove any weakly referenced symbols that haven't been resolved. + IPLS->LookupSet.remove_if( + [](const SymbolStringPtr &Name, SymbolLookupFlags SymLookupFlags) { + return SymLookupFlags == SymbolLookupFlags::WeaklyReferencedSymbol; + }); - auto NotifyComplete = [&](Expected R) { - ErrorAsOutParameter _(&ResolutionError); - if (R) - Result = std::move(*R); - else - ResolutionError = R.takeError(); - }; -#endif + if (!IPLS->LookupSet.empty()) { + LLVM_DEBUG(dbgs() << "Failing due to unresolved symbols\n"); + return make_error(IPLS->LookupSet.getSymbolNames()); + } - // Perform the asynchronous lookup. - lookup(K, SearchOrder, Symbols, RequiredState, NotifyComplete, - RegisterDependencies); + LLVM_DEBUG(dbgs() << "Succeded, result = " << Result << "\n"); + return Result; + }); -#if LLVM_ENABLE_THREADS - auto ResultFuture = PromisedResult.get_future(); - auto Result = ResultFuture.get(); + // Run the callback on the result. + LLVM_DEBUG(dbgs() << "Sending result to handler.\n"); + OnComplete(std::move(Result)); +} - if (ResolutionError) - return std::move(ResolutionError); +void ExecutionSession::OL_destroyMaterializationResponsibility( + MaterializationResponsibility &MR) { - return std::move(Result); + assert(MR.SymbolFlags.empty() && + "All symbols should have been explicitly materialized or failed"); + MR.JD->unlinkMaterializationResponsibility(MR); +} -#else - if (ResolutionError) - return std::move(ResolutionError); +SymbolNameSet ExecutionSession::OL_getRequestedSymbols( + const MaterializationResponsibility &MR) { + return MR.JD->getRequestedSymbols(MR.SymbolFlags); +} - return Result; +Error ExecutionSession::OL_notifyResolved(MaterializationResponsibility &MR, + const SymbolMap &Symbols) { + LLVM_DEBUG({ + dbgs() << "In " << MR.JD->getName() << " resolving " << Symbols << "\n"; + }); +#ifndef NDEBUG + for (auto &KV : Symbols) { + auto WeakFlags = JITSymbolFlags::Weak | JITSymbolFlags::Common; + auto I = MR.SymbolFlags.find(KV.first); + assert(I != MR.SymbolFlags.end() && + "Resolving symbol outside this responsibility set"); + assert(!I->second.hasMaterializationSideEffectsOnly() && + "Can't resolve materialization-side-effects-only symbol"); + assert((KV.second.getFlags() & ~WeakFlags) == (I->second & ~WeakFlags) && + "Resolving symbol with incorrect flags"); + } #endif + + return MR.JD->resolve(MR, Symbols); } -Expected -ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder, - SymbolStringPtr Name, SymbolState RequiredState) { - SymbolLookupSet Names({Name}); +Error ExecutionSession::OL_notifyEmitted(MaterializationResponsibility &MR) { + LLVM_DEBUG({ + dbgs() << "In " << MR.JD->getName() << " emitting " << MR.SymbolFlags << "\n"; + }); - if (auto ResultMap = lookup(SearchOrder, std::move(Names), LookupKind::Static, - RequiredState, NoDependenciesToRegister)) { - assert(ResultMap->size() == 1 && "Unexpected number of results"); - assert(ResultMap->count(Name) && "Missing result for symbol"); - return std::move(ResultMap->begin()->second); - } else - return ResultMap.takeError(); -} + if (auto Err = MR.JD->emit(MR, MR.SymbolFlags)) + return Err; -Expected -ExecutionSession::lookup(ArrayRef SearchOrder, SymbolStringPtr Name, - SymbolState RequiredState) { - return lookup(makeJITDylibSearchOrder(SearchOrder), Name, RequiredState); + MR.SymbolFlags.clear(); + return Error::success(); } -Expected -ExecutionSession::lookup(ArrayRef SearchOrder, StringRef Name, - SymbolState RequiredState) { - return lookup(SearchOrder, intern(Name), RequiredState); +Error ExecutionSession::OL_defineMaterializing( + MaterializationResponsibility &MR, SymbolFlagsMap NewSymbolFlags) { + + LLVM_DEBUG({ + dbgs() << "In " << MR.JD->getName() << " defining materializing symbols " + << NewSymbolFlags << "\n"; + }); + if (auto AcceptedDefs = MR.JD->defineMaterializing(std::move(NewSymbolFlags))) { + // Add all newly accepted symbols to this responsibility object. + for (auto &KV : *AcceptedDefs) + MR.SymbolFlags.insert(KV); + return Error::success(); + } else + return AcceptedDefs.takeError(); } -void ExecutionSession::dump(raw_ostream &OS) { - runSessionLocked([this, &OS]() { - for (auto &JD : JDs) - JD->dump(OS); +void ExecutionSession::OL_notifyFailed(MaterializationResponsibility &MR) { + + LLVM_DEBUG({ + dbgs() << "In " << MR.JD->getName() << " failing materialization for " + << MR.SymbolFlags << "\n"; }); + + JITDylib::FailedSymbolsWorklist Worklist; + + for (auto &KV : MR.SymbolFlags) + Worklist.push_back(std::make_pair(MR.JD.get(), KV.first)); + MR.SymbolFlags.clear(); + + if (Worklist.empty()) + return; + + JITDylib::AsynchronousSymbolQuerySet FailedQueries; + std::shared_ptr FailedSymbols; + + runSessionLocked([&]() { + auto RTI = MR.JD->MRTrackers.find(&MR); + assert(RTI != MR.JD->MRTrackers.end() && "No tracker for this"); + if (RTI->second->isDefunct()) + return; + + std::tie(FailedQueries, FailedSymbols) = + JITDylib::failSymbols(std::move(Worklist)); + }); + + for (auto &Q : FailedQueries) + Q->handleFailed(make_error(FailedSymbols)); } -void ExecutionSession::runOutstandingMUs() { - while (1) { - Optional, - MaterializationResponsibility>> - JMU; +Error ExecutionSession::OL_replace(MaterializationResponsibility &MR, + std::unique_ptr MU) { + for (auto &KV : MU->getSymbols()) { + assert(MR.SymbolFlags.count(KV.first) && + "Replacing definition outside this responsibility set"); + MR.SymbolFlags.erase(KV.first); + } - { - std::lock_guard Lock(OutstandingMUsMutex); - if (!OutstandingMUs.empty()) { - JMU.emplace(std::move(OutstandingMUs.back())); - OutstandingMUs.pop_back(); - } - } + if (MU->getInitializerSymbol() == MR.InitSymbol) + MR.InitSymbol = nullptr; - if (!JMU) - break; + LLVM_DEBUG(MR.JD->getExecutionSession().runSessionLocked([&]() { + dbgs() << "In " << MR.JD->getName() << " replacing symbols with " << *MU + << "\n"; + });); - assert(JMU->first && "No MU?"); - dispatchMaterialization(std::move(JMU->first), std::move(JMU->second)); + return MR.JD->replace(MR, std::move(MU)); +} + +Expected> +ExecutionSession::OL_delegate(MaterializationResponsibility &MR, + const SymbolNameSet &Symbols) { + + SymbolStringPtr DelegatedInitSymbol; + SymbolFlagsMap DelegatedFlags; + + for (auto &Name : Symbols) { + auto I = MR.SymbolFlags.find(Name); + assert(I != MR.SymbolFlags.end() && + "Symbol is not tracked by this MaterializationResponsibility " + "instance"); + + DelegatedFlags[Name] = std::move(I->second); + if (Name == MR.InitSymbol) + std::swap(MR.InitSymbol, DelegatedInitSymbol); + + MR.SymbolFlags.erase(I); } + + return MR.JD->delegate(MR, std::move(DelegatedFlags), + std::move(DelegatedInitSymbol)); +} + +void ExecutionSession::OL_addDependencies( + MaterializationResponsibility &MR, const SymbolStringPtr &Name, + const SymbolDependenceMap &Dependencies) { + LLVM_DEBUG({ + dbgs() << "Adding dependencies for " << Name << ": " << Dependencies + << "\n"; + }); + assert(MR.SymbolFlags.count(Name) && + "Symbol not covered by this MaterializationResponsibility instance"); + MR.JD->addDependencies(Name, Dependencies); +} + +void ExecutionSession::OL_addDependenciesForAll( + MaterializationResponsibility &MR, + const SymbolDependenceMap &Dependencies) { + LLVM_DEBUG({ + dbgs() << "Adding dependencies for all symbols in " << MR.SymbolFlags << ": " + << Dependencies << "\n"; + }); + for (auto &KV : MR.SymbolFlags) + MR.JD->addDependencies(KV.first, Dependencies); } #ifndef NDEBUG diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp index 278f492f0ebe7..5f9faf693c82c 100644 --- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -261,8 +261,8 @@ DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix, } Error DynamicLibrarySearchGenerator::tryToGenerate( - LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, - const SymbolLookupSet &Symbols) { + LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { orc::SymbolMap NewSymbols; bool HasGlobalPrefix = (GlobalPrefix != '\0'); @@ -365,8 +365,8 @@ StaticLibraryDefinitionGenerator::Create( } Error StaticLibraryDefinitionGenerator::tryToGenerate( - LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, - const SymbolLookupSet &Symbols) { + LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { // Don't materialize symbols from static archives unless this is a static // lookup. @@ -397,8 +397,7 @@ Error StaticLibraryDefinitionGenerator::tryToGenerate( MemoryBufferRef ChildBufferRef(ChildBufferInfo.first, ChildBufferInfo.second); - if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false), - VModuleKey())) + if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false))) return Err; } diff --git a/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp b/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp index 023940dc82982..aadc437c80c49 100644 --- a/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp @@ -25,7 +25,7 @@ void IRCompileLayer::setNotifyCompiled(NotifyCompiledFunction NotifyCompiled) { this->NotifyCompiled = std::move(NotifyCompiled); } -void IRCompileLayer::emit(MaterializationResponsibility R, +void IRCompileLayer::emit(std::unique_ptr R, ThreadSafeModule TSM) { assert(TSM && "Module must not be null"); @@ -33,13 +33,13 @@ void IRCompileLayer::emit(MaterializationResponsibility R, { std::lock_guard Lock(IRLayerMutex); if (NotifyCompiled) - NotifyCompiled(R.getVModuleKey(), std::move(TSM)); + NotifyCompiled(*R, std::move(TSM)); else TSM = ThreadSafeModule(); } BaseLayer.emit(std::move(R), std::move(*Obj)); } else { - R.failMaterialization(); + R->failMaterialization(); getExecutionSession().reportError(Obj.takeError()); } } diff --git a/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp b/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp index 511248f83b259..d5b11349277c1 100644 --- a/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IRTransformLayer.cpp @@ -17,14 +17,14 @@ IRTransformLayer::IRTransformLayer(ExecutionSession &ES, IRLayer &BaseLayer, : IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer), Transform(std::move(Transform)) {} -void IRTransformLayer::emit(MaterializationResponsibility R, +void IRTransformLayer::emit(std::unique_ptr R, ThreadSafeModule TSM) { assert(TSM && "Module must not be null"); - if (auto TransformedTSM = Transform(std::move(TSM), R)) + if (auto TransformedTSM = Transform(std::move(TSM), *R)) BaseLayer.emit(std::move(R), std::move(*TransformedTSM)); else { - R.failMaterialization(); + R->failMaterialization(); getExecutionSession().reportError(TransformedTSM.takeError()); } } diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp index 4f7f6089e68db..373f67dabe706 100644 --- a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -25,20 +25,20 @@ class CompileCallbackMaterializationUnit : public orc::MaterializationUnit { using CompileFunction = JITCompileCallbackManager::CompileFunction; CompileCallbackMaterializationUnit(SymbolStringPtr Name, - CompileFunction Compile, VModuleKey K) + CompileFunction Compile) : MaterializationUnit(SymbolFlagsMap({{Name, JITSymbolFlags::Exported}}), - nullptr, std::move(K)), + nullptr), Name(std::move(Name)), Compile(std::move(Compile)) {} StringRef getName() const override { return ""; } private: - void materialize(MaterializationResponsibility R) override { + void materialize(std::unique_ptr R) override { SymbolMap Result; Result[Name] = JITEvaluatedSymbol(Compile(), JITSymbolFlags::Exported); // No dependencies, so these calls cannot fail. - cantFail(R.notifyResolved(Result)); - cantFail(R.notifyEmitted()); + cantFail(R->notifyResolved(Result)); + cantFail(R->notifyEmitted()); } void discard(const JITDylib &JD, const SymbolStringPtr &Name) override { @@ -65,10 +65,9 @@ JITCompileCallbackManager::getCompileCallback(CompileFunction Compile) { std::lock_guard Lock(CCMgrMutex); AddrToSymbol[*TrampolineAddr] = CallbackName; - cantFail(CallbacksJD.define( - std::make_unique( - std::move(CallbackName), std::move(Compile), - ES.allocateVModule()))); + cantFail( + CallbacksJD.define(std::make_unique( + std::move(CallbackName), std::move(Compile)))); return *TrampolineAddr; } else return TrampolineAddr.takeError(); diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 531a71d50b9ec..13d447563d379 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -88,8 +88,9 @@ class GenericLLVMIRPlatform : public Platform { public: GenericLLVMIRPlatform(GenericLLVMIRPlatformSupport &S) : S(S) {} Error setupJITDylib(JITDylib &JD) override; - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU) override; - Error notifyRemoving(JITDylib &JD, VModuleKey K) override { + Error notifyAdding(ResourceTracker &RT, + const MaterializationUnit &MU) override; + Error notifyRemoving(ResourceTracker &RT) override { // Noop -- Nothing to do (yet). return Error::success(); } @@ -187,7 +188,8 @@ class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport { return J.addIRModule(JD, ThreadSafeModule(std::move(M), std::move(Ctx))); } - Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU) { + Error notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) { + auto &JD = RT.getJITDylib(); if (auto &InitSym = MU.getInitializerSymbol()) InitSymbols[&JD].add(InitSym, SymbolLookupFlags::WeaklyReferencedSymbol); else { @@ -261,23 +263,23 @@ class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport { return std::move(Err); DenseMap LookupSymbols; - std::vector DFSLinkOrder; + std::vector DFSLinkOrder; getExecutionSession().runSessionLocked([&]() { - DFSLinkOrder = getDFSLinkOrder(JD); - - for (auto *NextJD : DFSLinkOrder) { - auto IFItr = InitFunctions.find(NextJD); - if (IFItr != InitFunctions.end()) { - LookupSymbols[NextJD] = std::move(IFItr->second); - InitFunctions.erase(IFItr); - } + DFSLinkOrder = JD.getDFSLinkOrder(); + + for (auto &NextJD : DFSLinkOrder) { + auto IFItr = InitFunctions.find(NextJD.get()); + if (IFItr != InitFunctions.end()) { + LookupSymbols[NextJD.get()] = std::move(IFItr->second); + InitFunctions.erase(IFItr); } - }); + } + }); LLVM_DEBUG({ dbgs() << "JITDylib init order is [ "; - for (auto *JD : llvm::reverse(DFSLinkOrder)) + for (auto &JD : llvm::reverse(DFSLinkOrder)) dbgs() << "\"" << JD->getName() << "\" "; dbgs() << "]\n"; dbgs() << "Looking up init functions:\n"; @@ -311,26 +313,26 @@ class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport { auto LLJITRunAtExits = J.mangleAndIntern("__lljit_run_atexits"); DenseMap LookupSymbols; - std::vector DFSLinkOrder; + std::vector DFSLinkOrder; ES.runSessionLocked([&]() { - DFSLinkOrder = getDFSLinkOrder(JD); - - for (auto *NextJD : DFSLinkOrder) { - auto &JDLookupSymbols = LookupSymbols[NextJD]; - auto DIFItr = DeInitFunctions.find(NextJD); - if (DIFItr != DeInitFunctions.end()) { - LookupSymbols[NextJD] = std::move(DIFItr->second); - DeInitFunctions.erase(DIFItr); - } - JDLookupSymbols.add(LLJITRunAtExits, + DFSLinkOrder = JD.getDFSLinkOrder(); + + for (auto &NextJD : DFSLinkOrder) { + auto &JDLookupSymbols = LookupSymbols[NextJD.get()]; + auto DIFItr = DeInitFunctions.find(NextJD.get()); + if (DIFItr != DeInitFunctions.end()) { + LookupSymbols[NextJD.get()] = std::move(DIFItr->second); + DeInitFunctions.erase(DIFItr); + } + JDLookupSymbols.add(LLJITRunAtExits, SymbolLookupFlags::WeaklyReferencedSymbol); } }); LLVM_DEBUG({ dbgs() << "JITDylib deinit order is [ "; - for (auto *JD : DFSLinkOrder) + for (auto &JD : DFSLinkOrder) dbgs() << "\"" << JD->getName() << "\" "; dbgs() << "]\n"; dbgs() << "Looking up deinit functions:\n"; @@ -344,8 +346,8 @@ class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport { return LookupResult.takeError(); std::vector DeInitializers; - for (auto *NextJD : DFSLinkOrder) { - auto DeInitsItr = LookupResult->find(NextJD); + for (auto &NextJD : DFSLinkOrder) { + auto DeInitsItr = LookupResult->find(NextJD.get()); assert(DeInitsItr != LookupResult->end() && "Every JD should have at least __lljit_run_atexits"); @@ -361,46 +363,23 @@ class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport { return DeInitializers; } - // Returns a DFS traversal order of the JITDylibs reachable (via - // links-against edges) from JD, starting with JD itself. - static std::vector getDFSLinkOrder(JITDylib &JD) { - std::vector DFSLinkOrder; - std::vector WorkStack({&JD}); - DenseSet Visited; - - while (!WorkStack.empty()) { - auto &NextJD = *WorkStack.back(); - WorkStack.pop_back(); - if (Visited.count(&NextJD)) - continue; - Visited.insert(&NextJD); - DFSLinkOrder.push_back(&NextJD); - NextJD.withLinkOrderDo([&](const JITDylibSearchOrder &LinkOrder) { - for (auto &KV : LinkOrder) - WorkStack.push_back(KV.first); - }); - } - - return DFSLinkOrder; - } - /// Issue lookups for all init symbols required to initialize JD (and any /// JITDylibs that it depends on). Error issueInitLookups(JITDylib &JD) { DenseMap RequiredInitSymbols; - std::vector DFSLinkOrder; + std::vector DFSLinkOrder; getExecutionSession().runSessionLocked([&]() { - DFSLinkOrder = getDFSLinkOrder(JD); - - for (auto *NextJD : DFSLinkOrder) { - auto ISItr = InitSymbols.find(NextJD); - if (ISItr != InitSymbols.end()) { - RequiredInitSymbols[NextJD] = std::move(ISItr->second); - InitSymbols.erase(ISItr); - } + DFSLinkOrder = JD.getDFSLinkOrder(); + + for (auto &NextJD : DFSLinkOrder) { + auto ISItr = InitSymbols.find(NextJD.get()); + if (ISItr != InitSymbols.end()) { + RequiredInitSymbols[NextJD.get()] = std::move(ISItr->second); + InitSymbols.erase(ISItr); } - }); + } + }); return Platform::lookupInitSymbols(getExecutionSession(), RequiredInitSymbols) @@ -469,9 +448,9 @@ Error GenericLLVMIRPlatform::setupJITDylib(JITDylib &JD) { return S.setupJITDylib(JD); } -Error GenericLLVMIRPlatform::notifyAdding(JITDylib &JD, +Error GenericLLVMIRPlatform::notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) { - return S.notifyAdding(JD, MU); + return S.notifyAdding(RT, MU); } Expected @@ -984,7 +963,7 @@ Error LLJITBuilderState::prepareForConstruction() { ObjLinkingLayer = std::make_unique( ES, std::make_unique()); ObjLinkingLayer->addPlugin(std::make_unique( - jitlink::InProcessEHFrameRegistrar::getInstance())); + ES, std::make_unique())); return std::move(ObjLinkingLayer); }; } @@ -996,23 +975,33 @@ Error LLJITBuilderState::prepareForConstruction() { LLJIT::~LLJIT() { if (CompileThreads) CompileThreads->wait(); + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); } -Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) { +Error LLJIT::addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM) { assert(TSM && "Can not add null module"); if (auto Err = TSM.withModuleDo([&](Module &M) { return applyDataLayout(M); })) return Err; - return InitHelperTransformLayer->add(JD, std::move(TSM), - ES->allocateVModule()); + return InitHelperTransformLayer->add(std::move(RT), std::move(TSM)); } -Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr Obj) { +Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) { + return addIRModule(JD.getDefaultResourceTracker(), std::move(TSM)); +} + +Error LLJIT::addObjectFile(ResourceTrackerSP RT, + std::unique_ptr Obj) { assert(Obj && "Can not add null object"); - return ObjTransformLayer.add(JD, std::move(Obj), ES->allocateVModule()); + return ObjTransformLayer.add(std::move(RT), std::move(Obj)); +} + +Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr Obj) { + return addObjectFile(JD.getDefaultResourceTracker(), std::move(Obj)); } Expected LLJIT::lookupLinkerMangled(JITDylib &JD, @@ -1108,15 +1097,17 @@ LLJIT::LLJIT(LLJITBuilderState &S, Error &Err) std::make_unique(hardware_concurrency(S.NumCompileThreads)); ES->setDispatchMaterialization( [this](std::unique_ptr MU, - MaterializationResponsibility MR) { - // FIXME: Switch to move capture once ThreadPool uses unique_function. - auto SharedMU = std::shared_ptr(std::move(MU)); - auto SharedMR = - std::make_shared(std::move(MR)); - auto Work = [SharedMU, SharedMR]() mutable { - SharedMU->materialize(std::move(*SharedMR)); - }; - CompileThreads->async(std::move(Work)); + std::unique_ptr MR) { + // FIXME: We should be able to use move-capture here, but ThreadPool's + // AsyncTaskTys are std::functions rather than unique_functions + // (because MSVC's std::packaged_tasks don't support move-only types). + // Fix this when all the above gets sorted out. + CompileThreads->async( + [UnownedMU = MU.release(), UnownedMR = MR.release()]() mutable { + std::unique_ptr MU(UnownedMU); + std::unique_ptr MR(UnownedMR); + MU->materialize(std::move(MR)); + }); }); } @@ -1178,7 +1169,7 @@ Error LLLazyJIT::addLazyIRModule(JITDylib &JD, ThreadSafeModule TSM) { [&](Module &M) -> Error { return applyDataLayout(M); })) return Err; - return CODLayer->add(JD, std::move(TSM), ES->allocateVModule()); + return CODLayer->add(JD, std::move(TSM)); } LLLazyJIT::LLLazyJIT(LLLazyJITBuilderState &S, Error &Err) : LLJIT(S, Err) { diff --git a/llvm/lib/ExecutionEngine/Orc/Layer.cpp b/llvm/lib/ExecutionEngine/Orc/Layer.cpp index 0a5d5577e99e8..5e27e343d23b4 100644 --- a/llvm/lib/ExecutionEngine/Orc/Layer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Layer.cpp @@ -22,16 +22,18 @@ namespace orc { IRLayer::~IRLayer() {} -Error IRLayer::add(JITDylib &JD, ThreadSafeModule TSM, VModuleKey K) { +Error IRLayer::add(ResourceTrackerSP RT, ThreadSafeModule TSM) { + assert(RT && "RT can not be null"); + auto &JD = RT->getJITDylib(); return JD.define(std::make_unique( - *this, *getManglingOptions(), std::move(TSM), std::move(K))); + *this, *getManglingOptions(), std::move(TSM)), + std::move(RT)); } IRMaterializationUnit::IRMaterializationUnit( ExecutionSession &ES, const IRSymbolMapper::ManglingOptions &MO, - ThreadSafeModule TSM, VModuleKey K) - : MaterializationUnit(SymbolFlagsMap(), nullptr, std::move(K)), - TSM(std::move(TSM)) { + ThreadSafeModule TSM) + : MaterializationUnit(SymbolFlagsMap(), nullptr), TSM(std::move(TSM)) { assert(this->TSM && "Module must not be null"); @@ -96,10 +98,9 @@ IRMaterializationUnit::IRMaterializationUnit( } IRMaterializationUnit::IRMaterializationUnit( - ThreadSafeModule TSM, VModuleKey K, SymbolFlagsMap SymbolFlags, + ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol, SymbolNameToDefinitionMap SymbolToDefinition) - : MaterializationUnit(std::move(SymbolFlags), std::move(InitSymbol), - std::move(K)), + : MaterializationUnit(std::move(SymbolFlags), std::move(InitSymbol)), TSM(std::move(TSM)), SymbolToDefinition(std::move(SymbolToDefinition)) {} StringRef IRMaterializationUnit::getName() const { @@ -126,14 +127,12 @@ void IRMaterializationUnit::discard(const JITDylib &JD, } BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit( - IRLayer &L, const IRSymbolMapper::ManglingOptions &MO, ThreadSafeModule TSM, - VModuleKey K) - : IRMaterializationUnit(L.getExecutionSession(), MO, std::move(TSM), - std::move(K)), - L(L), K(std::move(K)) {} + IRLayer &L, const IRSymbolMapper::ManglingOptions &MO, ThreadSafeModule TSM) + : IRMaterializationUnit(L.getExecutionSession(), MO, std::move(TSM)), L(L) { +} void BasicIRLayerMaterializationUnit::materialize( - MaterializationResponsibility R) { + std::unique_ptr R) { // Throw away the SymbolToDefinition map: it's not usable after we hand // off the module. @@ -144,8 +143,8 @@ void BasicIRLayerMaterializationUnit::materialize( TSM = cloneToNewContext(TSM); #ifndef NDEBUG - auto &ES = R.getTargetJITDylib().getExecutionSession(); - auto &N = R.getTargetJITDylib().getName(); + auto &ES = R->getTargetJITDylib().getExecutionSession(); + auto &N = R->getTargetJITDylib().getName(); #endif // NDEBUG LLVM_DEBUG(ES.runSessionLocked( @@ -160,17 +159,17 @@ ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {} ObjectLayer::~ObjectLayer() {} -Error ObjectLayer::add(JITDylib &JD, std::unique_ptr O, - VModuleKey K) { - auto ObjMU = BasicObjectLayerMaterializationUnit::Create(*this, std::move(K), - std::move(O)); +Error ObjectLayer::add(ResourceTrackerSP RT, std::unique_ptr O) { + assert(RT && "RT can not be null"); + auto ObjMU = BasicObjectLayerMaterializationUnit::Create(*this, std::move(O)); if (!ObjMU) return ObjMU.takeError(); - return JD.define(std::move(*ObjMU)); + auto &JD = RT->getJITDylib(); + return JD.define(std::move(*ObjMU), std::move(RT)); } Expected> -BasicObjectLayerMaterializationUnit::Create(ObjectLayer &L, VModuleKey K, +BasicObjectLayerMaterializationUnit::Create(ObjectLayer &L, std::unique_ptr O) { auto ObjSymInfo = getObjectSymbolInfo(L.getExecutionSession(), O->getMemBufferRef()); @@ -183,15 +182,14 @@ BasicObjectLayerMaterializationUnit::Create(ObjectLayer &L, VModuleKey K, return std::unique_ptr( new BasicObjectLayerMaterializationUnit( - L, K, std::move(O), std::move(SymbolFlags), std::move(InitSymbol))); + L, std::move(O), std::move(SymbolFlags), std::move(InitSymbol))); } BasicObjectLayerMaterializationUnit::BasicObjectLayerMaterializationUnit( - ObjectLayer &L, VModuleKey K, std::unique_ptr O, - SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol) - : MaterializationUnit(std::move(SymbolFlags), std::move(InitSymbol), - std::move(K)), - L(L), O(std::move(O)) {} + ObjectLayer &L, std::unique_ptr O, SymbolFlagsMap SymbolFlags, + SymbolStringPtr InitSymbol) + : MaterializationUnit(std::move(SymbolFlags), std::move(InitSymbol)), L(L), + O(std::move(O)) {} StringRef BasicObjectLayerMaterializationUnit::getName() const { if (O) @@ -200,7 +198,7 @@ StringRef BasicObjectLayerMaterializationUnit::getName() const { } void BasicObjectLayerMaterializationUnit::materialize( - MaterializationResponsibility R) { + std::unique_ptr R) { L.emit(std::move(R), std::move(O)); } diff --git a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp index 5e604130d6eab..e1f494415e86b 100644 --- a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -143,9 +143,8 @@ createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, - JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc, - VModuleKey K) - : MaterializationUnit(extractFlags(CallableAliases), nullptr, std::move(K)), + JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc) + : MaterializationUnit(extractFlags(CallableAliases), nullptr), LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD), CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {} @@ -154,8 +153,8 @@ StringRef LazyReexportsMaterializationUnit::getName() const { } void LazyReexportsMaterializationUnit::materialize( - MaterializationResponsibility R) { - auto RequestedSymbols = R.getRequestedSymbols(); + std::unique_ptr R) { + auto RequestedSymbols = R->getRequestedSymbols(); SymbolAliasMap RequestedAliases; for (auto &RequestedSymbol : RequestedSymbols) { @@ -166,8 +165,13 @@ void LazyReexportsMaterializationUnit::materialize( } if (!CallableAliases.empty()) - R.replace(lazyReexports(LCTManager, ISManager, SourceJD, - std::move(CallableAliases), AliaseeTable)); + if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD, + std::move(CallableAliases), + AliaseeTable))) { + R->getExecutionSession().reportError(std::move(Err)); + R->failMaterialization(); + return; + } IndirectStubsManager::StubInitsMap StubInits; for (auto &Alias : RequestedAliases) { @@ -182,7 +186,7 @@ void LazyReexportsMaterializationUnit::materialize( if (!CallThroughTrampoline) { SourceJD.getExecutionSession().reportError( CallThroughTrampoline.takeError()); - R.failMaterialization(); + R->failMaterialization(); return; } @@ -195,7 +199,7 @@ void LazyReexportsMaterializationUnit::materialize( if (auto Err = ISManager.createStubs(StubInits)) { SourceJD.getExecutionSession().reportError(std::move(Err)); - R.failMaterialization(); + R->failMaterialization(); return; } @@ -204,8 +208,8 @@ void LazyReexportsMaterializationUnit::materialize( Stubs[Alias.first] = ISManager.findStub(*Alias.first, false); // No registered dependencies, so these calls cannot fail. - cantFail(R.notifyResolved(Stubs)); - cantFail(R.notifyEmitted()); + cantFail(R->notifyResolved(Stubs)); + cantFail(R->notifyEmitted()); } void LazyReexportsMaterializationUnit::discard(const JITDylib &JD, diff --git a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp deleted file mode 100644 index 67b804c37287d..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===------- Legacy.cpp - Adapters for ExecutionEngine API interop --------===// -// -// 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/ExecutionEngine/Orc/Legacy.h" - -namespace llvm { -namespace orc { - -void SymbolResolver::anchor() {} - -JITSymbolResolverAdapter::JITSymbolResolverAdapter( - ExecutionSession &ES, SymbolResolver &R, MaterializationResponsibility *MR) - : ES(ES), R(R), MR(MR) {} - -void JITSymbolResolverAdapter::lookup(const LookupSet &Symbols, - OnResolvedFunction OnResolved) { - SymbolNameSet InternedSymbols; - for (auto &S : Symbols) - InternedSymbols.insert(ES.intern(S)); - - auto OnResolvedWithUnwrap = [OnResolved = std::move(OnResolved)]( - Expected InternedResult) mutable { - if (!InternedResult) { - OnResolved(InternedResult.takeError()); - return; - } - - LookupResult Result; - for (auto &KV : *InternedResult) - Result[*KV.first] = std::move(KV.second); - OnResolved(Result); - }; - - auto Q = std::make_shared( - SymbolLookupSet(InternedSymbols), SymbolState::Resolved, - std::move(OnResolvedWithUnwrap)); - - auto Unresolved = R.lookup(Q, InternedSymbols); - if (Unresolved.empty()) { - if (MR) - MR->addDependenciesForAll(Q->QueryRegistrations); - } else - ES.legacyFailQuery(*Q, make_error(std::move(Unresolved))); -} - -Expected -JITSymbolResolverAdapter::getResponsibilitySet(const LookupSet &Symbols) { - SymbolNameSet InternedSymbols; - for (auto &S : Symbols) - InternedSymbols.insert(ES.intern(S)); - - auto InternedResult = R.getResponsibilitySet(InternedSymbols); - LookupSet Result; - for (auto &S : InternedResult) { - ResolvedStrings.insert(S); - Result.insert(*S); - } - - return Result; -} - -} // End namespace orc. -} // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index 15c3aa79a2a84..17b9465a0541b 100644 --- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -159,7 +159,9 @@ Error MachOPlatform::setupJITDylib(JITDylib &JD) { return ObjLinkingLayer.add(JD, std::move(ObjBuffer)); } -Error MachOPlatform::notifyAdding(JITDylib &JD, const MaterializationUnit &MU) { +Error MachOPlatform::notifyAdding(ResourceTracker &RT, + const MaterializationUnit &MU) { + auto &JD = RT.getJITDylib(); const auto &InitSym = MU.getInitializerSymbol(); if (!InitSym) return Error::success(); @@ -173,7 +175,7 @@ Error MachOPlatform::notifyAdding(JITDylib &JD, const MaterializationUnit &MU) { return Error::success(); } -Error MachOPlatform::notifyRemoving(JITDylib &JD, VModuleKey K) { +Error MachOPlatform::notifyRemoving(ResourceTracker &RT) { llvm_unreachable("Not supported yet"); } @@ -185,19 +187,19 @@ MachOPlatform::getInitializerSequence(JITDylib &JD) { << JD.getName() << "\n"; }); - std::vector DFSLinkOrder; + std::vector DFSLinkOrder; while (true) { DenseMap NewInitSymbols; ES.runSessionLocked([&]() { - DFSLinkOrder = getDFSLinkOrder(JD); + DFSLinkOrder = JD.getDFSLinkOrder(); - for (auto *InitJD : DFSLinkOrder) { - auto RISItr = RegisteredInitSymbols.find(InitJD); + for (auto &InitJD : DFSLinkOrder) { + auto RISItr = RegisteredInitSymbols.find(InitJD.get()); if (RISItr != RegisteredInitSymbols.end()) { - NewInitSymbols[InitJD] = std::move(RISItr->second); + NewInitSymbols[InitJD.get()] = std::move(RISItr->second); RegisteredInitSymbols.erase(RISItr); } } @@ -229,14 +231,14 @@ MachOPlatform::getInitializerSequence(JITDylib &JD) { InitializerSequence FullInitSeq; { std::lock_guard Lock(InitSeqsMutex); - for (auto *InitJD : reverse(DFSLinkOrder)) { + for (auto &InitJD : reverse(DFSLinkOrder)) { LLVM_DEBUG({ dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName() << "\" to sequence\n"; }); - auto ISItr = InitSeqs.find(InitJD); + auto ISItr = InitSeqs.find(InitJD.get()); if (ISItr != InitSeqs.end()) { - FullInitSeq.emplace_back(InitJD, std::move(ISItr->second)); + FullInitSeq.emplace_back(InitJD.get(), std::move(ISItr->second)); InitSeqs.erase(ISItr); } } @@ -247,39 +249,19 @@ MachOPlatform::getInitializerSequence(JITDylib &JD) { Expected MachOPlatform::getDeinitializerSequence(JITDylib &JD) { - std::vector DFSLinkOrder = getDFSLinkOrder(JD); + std::vector DFSLinkOrder = JD.getDFSLinkOrder(); DeinitializerSequence FullDeinitSeq; { std::lock_guard Lock(InitSeqsMutex); - for (auto *DeinitJD : DFSLinkOrder) { - FullDeinitSeq.emplace_back(DeinitJD, MachOJITDylibDeinitializers()); + for (auto &DeinitJD : DFSLinkOrder) { + FullDeinitSeq.emplace_back(DeinitJD.get(), MachOJITDylibDeinitializers()); } } return FullDeinitSeq; } -std::vector MachOPlatform::getDFSLinkOrder(JITDylib &JD) { - std::vector Result, WorkStack({&JD}); - DenseSet Visited; - - while (!WorkStack.empty()) { - auto *NextJD = WorkStack.back(); - WorkStack.pop_back(); - if (Visited.count(NextJD)) - continue; - Visited.insert(NextJD); - Result.push_back(NextJD); - NextJD->withLinkOrderDo([&](const JITDylibSearchOrder &LO) { - for (auto &KV : LO) - WorkStack.push_back(KV.first); - }); - } - - return Result; -} - void MachOPlatform::registerInitInfo( JITDylib &JD, JITTargetAddress ObjCImageInfoAddr, MachOJITDylibInitializers::SectionExtent ModInits, @@ -319,13 +301,16 @@ void MachOPlatform::InitScraperPlugin::modifyPassConfig( MaterializationResponsibility &MR, const Triple &TT, jitlink::PassConfiguration &Config) { + if (!MR.getInitializerSymbol()) + return; + Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error { JITLinkSymbolVector InitSectionSymbols; preserveInitSectionIfPresent(InitSectionSymbols, G, "__mod_init_func"); preserveInitSectionIfPresent(InitSectionSymbols, G, "__objc_selrefs"); preserveInitSectionIfPresent(InitSectionSymbols, G, "__objc_classlist"); - if (!InitSymbolDeps.empty()) { + if (!InitSectionSymbols.empty()) { std::lock_guard Lock(InitScraperMutex); InitSymbolDeps[&MR] = std::move(InitSectionSymbols); } @@ -343,10 +328,8 @@ void MachOPlatform::InitScraperPlugin::modifyPassConfig( JITTargetAddress ObjCImageInfoAddr = 0; if (auto *ObjCImageInfoSec = G.findSectionByName("__objc_image_info")) { - if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) { + if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) ObjCImageInfoAddr = Addr; - dbgs() << "Recorded __objc_imageinfo @ " << formatv("{0:x16}", Addr); - } } // Record __mod_init_func. diff --git a/llvm/lib/ExecutionEngine/Orc/NullResolver.cpp b/llvm/lib/ExecutionEngine/Orc/NullResolver.cpp deleted file mode 100644 index 5b4345b870bb8..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/NullResolver.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===---------- NullResolver.cpp - Reject symbol lookup requests ----------===// -// -// 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/ExecutionEngine/Orc/NullResolver.h" - -#include "llvm/Support/ErrorHandling.h" - -namespace llvm { -namespace orc { - -SymbolNameSet NullResolver::getResponsibilitySet(const SymbolNameSet &Symbols) { - return Symbols; -} - -SymbolNameSet -NullResolver::lookup(std::shared_ptr Query, - SymbolNameSet Symbols) { - assert(Symbols.empty() && "Null resolver: Symbols must be empty"); - return Symbols; -} - -JITSymbol NullLegacyResolver::findSymbol(const std::string &Name) { - llvm_unreachable("Unexpected cross-object symbol reference"); -} - -JITSymbol -NullLegacyResolver::findSymbolInLogicalDylib(const std::string &Name) { - llvm_unreachable("Unexpected cross-object symbol reference"); -} - -} // End namespace orc. -} // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 5b828ed84462a..5dd32fbc224e6 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -24,9 +24,10 @@ namespace orc { class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { public: - ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer, - MaterializationResponsibility MR, - std::unique_ptr ObjBuffer) + ObjectLinkingLayerJITLinkContext( + ObjectLinkingLayer &Layer, + std::unique_ptr MR, + std::unique_ptr ObjBuffer) : Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {} ~ObjectLinkingLayerJITLinkContext() { @@ -43,15 +44,17 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { } void notifyFailed(Error Err) override { + for (auto &P : Layer.Plugins) + Err = joinErrors(std::move(Err), P->notifyFailed(*MR)); Layer.getExecutionSession().reportError(std::move(Err)); - MR.failMaterialization(); + MR->failMaterialization(); } void lookup(const LookupMap &Symbols, std::unique_ptr LC) override { JITDylibSearchOrder LinkOrder; - MR.getTargetJITDylib().withLinkOrderDo( + MR->getTargetJITDylib().withLinkOrderDo( [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; }); auto &ES = Layer.getExecutionSession(); @@ -71,9 +74,8 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { } // OnResolve -- De-intern the symbols and pass the result to the linker. - auto OnResolve = [this, LookupContinuation = std::move(LC)]( - Expected Result) mutable { - auto Main = Layer.getExecutionSession().intern("_main"); + auto OnResolve = [LookupContinuation = + std::move(LC)](Expected Result) mutable { if (!Result) LookupContinuation->run(Result.takeError()); else { @@ -86,8 +88,8 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { for (auto &KV : InternalNamedSymbolDeps) { SymbolDependenceMap InternalDeps; - InternalDeps[&MR.getTargetJITDylib()] = std::move(KV.second); - MR.addDependencies(KV.first, InternalDeps); + InternalDeps[&MR->getTargetJITDylib()] = std::move(KV.second); + MR->addDependencies(KV.first, InternalDeps); } ES.lookup(LookupKind::Static, LinkOrder, std::move(LookupSet), @@ -116,7 +118,7 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { InternedResult[InternedName] = JITEvaluatedSymbol(Sym->getAddress(), Flags); - if (AutoClaim && !MR.getSymbols().count(InternedName)) { + if (AutoClaim && !MR->getSymbols().count(InternedName)) { assert(!ExtraSymbolsToClaim.count(InternedName) && "Duplicate symbol to claim?"); ExtraSymbolsToClaim[InternedName] = Flags; @@ -134,7 +136,7 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { Flags |= JITSymbolFlags::Weak; InternedResult[InternedName] = JITEvaluatedSymbol(Sym->getAddress(), Flags); - if (AutoClaim && !MR.getSymbols().count(InternedName)) { + if (AutoClaim && !MR->getSymbols().count(InternedName)) { assert(!ExtraSymbolsToClaim.count(InternedName) && "Duplicate symbol to claim?"); ExtraSymbolsToClaim[InternedName] = Flags; @@ -142,19 +144,19 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { } if (!ExtraSymbolsToClaim.empty()) - if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim)) + if (auto Err = MR->defineMaterializing(ExtraSymbolsToClaim)) return Err; { - // Check that InternedResult matches up with MR.getSymbols(). + // Check that InternedResult matches up with MR->getSymbols(). // This guards against faulty transformations / compilers / object caches. // First check that there aren't any missing symbols. size_t NumMaterializationSideEffectsOnlySymbols = 0; SymbolNameVector ExtraSymbols; SymbolNameVector MissingSymbols; - for (auto &KV : MR.getSymbols()) { + for (auto &KV : MR->getSymbols()) { // If this is a materialization-side-effects only symbol then bump // the counter and make sure it's *not* defined, otherwise make @@ -176,9 +178,9 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { // If there are more definitions than expected, add them to the // ExtraSymbols vector. if (InternedResult.size() > - MR.getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) { + MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) { for (auto &KV : InternedResult) - if (!MR.getSymbols().count(KV.first)) + if (!MR->getSymbols().count(KV.first)) ExtraSymbols.push_back(KV.first); } @@ -188,23 +190,23 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { std::move(ExtraSymbols)); } - if (auto Err = MR.notifyResolved(InternedResult)) + if (auto Err = MR->notifyResolved(InternedResult)) return Err; - Layer.notifyLoaded(MR); + Layer.notifyLoaded(*MR); return Error::success(); } void notifyFinalized( std::unique_ptr A) override { - if (auto Err = Layer.notifyEmitted(MR, std::move(A))) { + if (auto Err = Layer.notifyEmitted(*MR, std::move(A))) { Layer.getExecutionSession().reportError(std::move(Err)); - MR.failMaterialization(); + MR->failMaterialization(); return; } - if (auto Err = MR.notifyEmitted()) { + if (auto Err = MR->notifyEmitted()) { Layer.getExecutionSession().reportError(std::move(Err)); - MR.failMaterialization(); + MR->failMaterialization(); } } @@ -218,7 +220,7 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { Config.PrePrunePasses.push_back( [this](LinkGraph &G) { return externalizeWeakAndCommonSymbols(G); }); - Layer.modifyPassConfig(MR, TT, Config); + Layer.modifyPassConfig(*MR, TT, Config); Config.PostPrunePasses.push_back( [this](LinkGraph &G) { return computeNamedSymbolDependencies(G); }); @@ -238,13 +240,13 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { auto &ES = Layer.getExecutionSession(); for (auto *Sym : G.defined_symbols()) if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) { - if (!MR.getSymbols().count(ES.intern(Sym->getName()))) + if (!MR->getSymbols().count(ES.intern(Sym->getName()))) G.makeExternal(*Sym); } for (auto *Sym : G.absolute_symbols()) if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) { - if (!MR.getSymbols().count(ES.intern(Sym->getName()))) + if (!MR->getSymbols().count(ES.intern(Sym->getName()))) G.makeExternal(*Sym); } @@ -254,13 +256,13 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { Error markResponsibilitySymbolsLive(LinkGraph &G) const { auto &ES = Layer.getExecutionSession(); for (auto *Sym : G.defined_symbols()) - if (Sym->hasName() && MR.getSymbols().count(ES.intern(Sym->getName()))) + if (Sym->hasName() && MR->getSymbols().count(ES.intern(Sym->getName()))) Sym->setLive(true); return Error::success(); } Error computeNamedSymbolDependencies(LinkGraph &G) { - auto &ES = MR.getTargetJITDylib().getExecutionSession(); + auto &ES = MR->getTargetJITDylib().getExecutionSession(); auto LocalDeps = computeLocalDeps(G); // Compute dependencies for symbols defined in the JITLink graph. @@ -307,7 +309,7 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { } for (auto &P : Layer.Plugins) { - auto SyntheticLocalDeps = P->getSyntheticSymbolLocalDependencies(MR); + auto SyntheticLocalDeps = P->getSyntheticSymbolLocalDependencies(*MR); if (SyntheticLocalDeps.empty()) continue; @@ -427,12 +429,12 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { SymbolDeps.erase(&SourceJD); } - MR.addDependencies(Name, SymbolDeps); + MR->addDependencies(Name, SymbolDeps); } } ObjectLinkingLayer &Layer; - MaterializationResponsibility MR; + std::unique_ptr MR; std::unique_ptr ObjBuffer; DenseMap ExternalNamedSymbolDeps; DenseMap InternalNamedSymbolDeps; @@ -442,18 +444,22 @@ ObjectLinkingLayer::Plugin::~Plugin() {} ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, JITLinkMemoryManager &MemMgr) - : ObjectLayer(ES), MemMgr(MemMgr) {} + : ObjectLayer(ES), MemMgr(MemMgr) { + ES.registerResourceManager(*this); +} ObjectLinkingLayer::ObjectLinkingLayer( ExecutionSession &ES, std::unique_ptr MemMgr) - : ObjectLayer(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) {} + : ObjectLayer(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) { + ES.registerResourceManager(*this); +} ObjectLinkingLayer::~ObjectLinkingLayer() { - if (auto Err = removeAllModules()) - getExecutionSession().reportError(std::move(Err)); + assert(Allocs.empty() && "Layer destroyed with resources still attached"); + getExecutionSession().deregisterResourceManager(*this); } -void ObjectLinkingLayer::emit(MaterializationResponsibility R, +void ObjectLinkingLayer::emit(std::unique_ptr R, std::unique_ptr O) { assert(O && "Object must not be null"); jitLink(std::make_unique( @@ -481,63 +487,56 @@ Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR, if (Err) return Err; - { - std::lock_guard Lock(LayerMutex); - UntrackedAllocs.push_back(std::move(Alloc)); - } - - return Error::success(); + return MR.withResourceKeyDo( + [&](ResourceKey K) { Allocs[K].push_back(std::move(Alloc)); }); } -Error ObjectLinkingLayer::removeModule(VModuleKey K) { +Error ObjectLinkingLayer::handleRemoveResources(ResourceKey K) { + Error Err = Error::success(); for (auto &P : Plugins) - Err = joinErrors(std::move(Err), P->notifyRemovingModule(K)); - - AllocPtr Alloc; + Err = joinErrors(std::move(Err), P->notifyRemovingResources(K)); + + std::vector AllocsToRemove; + getExecutionSession().runSessionLocked([&] { + auto I = Allocs.find(K); + if (I != Allocs.end()) { + std::swap(AllocsToRemove, I->second); + Allocs.erase(I); + } + }); - { - std::lock_guard Lock(LayerMutex); - auto AllocItr = TrackedAllocs.find(K); - Alloc = std::move(AllocItr->second); - TrackedAllocs.erase(AllocItr); + while (!AllocsToRemove.empty()) { + Err = joinErrors(std::move(Err), AllocsToRemove.back()->deallocate()); + AllocsToRemove.pop_back(); } - assert(Alloc && "No allocation for key K"); - - return joinErrors(std::move(Err), Alloc->deallocate()); + return Err; } -Error ObjectLinkingLayer::removeAllModules() { - - Error Err = Error::success(); - - for (auto &P : Plugins) - Err = joinErrors(std::move(Err), P->notifyRemovingAllModules()); - - std::vector Allocs; - { - std::lock_guard Lock(LayerMutex); - Allocs = std::move(UntrackedAllocs); - - for (auto &KV : TrackedAllocs) - Allocs.push_back(std::move(KV.second)); - - TrackedAllocs.clear(); +void ObjectLinkingLayer::handleTransferResources(ResourceKey DstKey, + ResourceKey SrcKey) { + auto I = Allocs.find(SrcKey); + if (I != Allocs.end()) { + auto &SrcAllocs = I->second; + auto &DstAllocs = Allocs[DstKey]; + DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size()); + for (auto &Alloc : SrcAllocs) + DstAllocs.push_back(std::move(Alloc)); + + // Erase SrcKey entry using value rather than iterator I: I may have been + // invalidated when we looked up DstKey. + Allocs.erase(SrcKey); } - while (!Allocs.empty()) { - Err = joinErrors(std::move(Err), Allocs.back()->deallocate()); - Allocs.pop_back(); - } - - return Err; + for (auto &P : Plugins) + P->notifyTransferringResources(DstKey, SrcKey); } EHFrameRegistrationPlugin::EHFrameRegistrationPlugin( - EHFrameRegistrar &Registrar) - : Registrar(Registrar) {} + ExecutionSession &ES, std::unique_ptr Registrar) + : ES(ES), Registrar(std::move(Registrar)) {} void EHFrameRegistrationPlugin::modifyPassConfig( MaterializationResponsibility &MR, const Triple &TT, @@ -556,65 +555,70 @@ void EHFrameRegistrationPlugin::modifyPassConfig( Error EHFrameRegistrationPlugin::notifyEmitted( MaterializationResponsibility &MR) { - std::lock_guard Lock(EHFramePluginMutex); - - auto EHFrameRangeItr = InProcessLinks.find(&MR); - if (EHFrameRangeItr == InProcessLinks.end()) - return Error::success(); - - auto EHFrameRange = EHFrameRangeItr->second; - assert(EHFrameRange.Addr && - "eh-frame addr to register can not be null"); - - InProcessLinks.erase(EHFrameRangeItr); - if (auto Key = MR.getVModuleKey()) - TrackedEHFrameRanges[Key] = EHFrameRange; - else - UntrackedEHFrameRanges.push_back(EHFrameRange); - return Registrar.registerEHFrames(EHFrameRange.Addr, EHFrameRange.Size); -} - -Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) { - std::lock_guard Lock(EHFramePluginMutex); + EHFrameRange EmittedRange; + { + std::lock_guard Lock(EHFramePluginMutex); - auto EHFrameRangeItr = TrackedEHFrameRanges.find(K); - if (EHFrameRangeItr == TrackedEHFrameRanges.end()) - return Error::success(); + auto EHFrameRangeItr = InProcessLinks.find(&MR); + if (EHFrameRangeItr == InProcessLinks.end()) + return Error::success(); - auto EHFrameRange = EHFrameRangeItr->second; - assert(EHFrameRange.Addr && "Tracked eh-frame range must not be null"); + EmittedRange = EHFrameRangeItr->second; + assert(EmittedRange.Addr && "eh-frame addr to register can not be null"); + InProcessLinks.erase(EHFrameRangeItr); + } - TrackedEHFrameRanges.erase(EHFrameRangeItr); + if (auto Err = MR.withResourceKeyDo( + [&](ResourceKey K) { EHFrameRanges[K].push_back(EmittedRange); })) + return Err; - return Registrar.deregisterEHFrames(EHFrameRange.Addr, EHFrameRange.Size); + return Registrar->registerEHFrames(EmittedRange.Addr, EmittedRange.Size); } -Error EHFrameRegistrationPlugin::notifyRemovingAllModules() { +Error EHFrameRegistrationPlugin::notifyFailed( + MaterializationResponsibility &MR) { std::lock_guard Lock(EHFramePluginMutex); + InProcessLinks.erase(&MR); + return Error::success(); +} - std::vector EHFrameRanges = - std::move(UntrackedEHFrameRanges); - EHFrameRanges.reserve(EHFrameRanges.size() + TrackedEHFrameRanges.size()); - - for (auto &KV : TrackedEHFrameRanges) - EHFrameRanges.push_back(KV.second); +Error EHFrameRegistrationPlugin::notifyRemovingResources(ResourceKey K) { + std::vector RangesToRemove; - TrackedEHFrameRanges.clear(); + ES.runSessionLocked([&] { + auto I = EHFrameRanges.find(K); + if (I != EHFrameRanges.end()) { + RangesToRemove = std::move(I->second); + EHFrameRanges.erase(I); + } + }); Error Err = Error::success(); - - while (!EHFrameRanges.empty()) { - auto EHFrameRange = EHFrameRanges.back(); - assert(EHFrameRange.Addr && "Untracked eh-frame range must not be null"); - EHFrameRanges.pop_back(); - Err = joinErrors(std::move(Err), - Registrar.deregisterEHFrames(EHFrameRange.Addr, - EHFrameRange.Size)); + while (!RangesToRemove.empty()) { + auto RangeToRemove = RangesToRemove.back(); + RangesToRemove.pop_back(); + assert(RangeToRemove.Addr && "Untracked eh-frame range must not be null"); + Err = joinErrors( + std::move(Err), + Registrar->deregisterEHFrames(RangeToRemove.Addr, RangeToRemove.Size)); } return Err; } +void EHFrameRegistrationPlugin::notifyTransferringResources( + ResourceKey DstKey, ResourceKey SrcKey) { + auto SI = EHFrameRanges.find(SrcKey); + if (SI != EHFrameRanges.end()) { + auto &SrcRanges = SI->second; + auto &DstRanges = EHFrameRanges[DstKey]; + DstRanges.reserve(DstRanges.size() + SrcRanges.size()); + for (auto &SrcRange : SrcRanges) + DstRanges.push_back(std::move(SrcRange)); + EHFrameRanges.erase(SI); + } +} + } // End namespace orc. } // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp index d18eb38a41423..a57662e10a794 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectTransformLayer.cpp @@ -17,8 +17,9 @@ ObjectTransformLayer::ObjectTransformLayer(ExecutionSession &ES, TransformFunction Transform) : ObjectLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {} -void ObjectTransformLayer::emit(MaterializationResponsibility R, - std::unique_ptr O) { +void ObjectTransformLayer::emit( + std::unique_ptr R, + std::unique_ptr O) { assert(O && "Module must not be null"); // If there is a transform set then apply it. @@ -26,7 +27,7 @@ void ObjectTransformLayer::emit(MaterializationResponsibility R, if (auto TransformedObj = Transform(std::move(O))) O = std::move(*TransformedObj); else { - R.failMaterialization(); + R->failMaterialization(); getExecutionSession().reportError(TransformedObj.takeError()); return; } diff --git a/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp deleted file mode 100644 index 28c8479abba44..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp +++ /dev/null @@ -1,158 +0,0 @@ -//===----------- OrcCBindings.cpp - C bindings for the Orc APIs -----------===// -// -// 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 "OrcCBindingsStack.h" -#include "llvm-c/OrcBindings.h" -#include "llvm/ExecutionEngine/JITEventListener.h" - -using namespace llvm; - -LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM) { - TargetMachine *TM2(unwrap(TM)); - - Triple T(TM2->getTargetTriple()); - - auto IndirectStubsMgrBuilder = - orc::createLocalIndirectStubsManagerBuilder(T); - - OrcCBindingsStack *JITStack = - new OrcCBindingsStack(*TM2, std::move(IndirectStubsMgrBuilder)); - - return wrap(JITStack); -} - -const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack) { - OrcCBindingsStack &J = *unwrap(JITStack); - return J.getErrorMessage().c_str(); -} - -void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledName, - const char *SymbolName) { - OrcCBindingsStack &J = *unwrap(JITStack); - std::string Mangled = J.mangle(SymbolName); - *MangledName = new char[Mangled.size() + 1]; - strcpy(*MangledName, Mangled.c_str()); -} - -void LLVMOrcDisposeMangledSymbol(char *MangledName) { delete[] MangledName; } - -LLVMErrorRef LLVMOrcCreateLazyCompileCallback( - LLVMOrcJITStackRef JITStack, LLVMOrcTargetAddress *RetAddr, - LLVMOrcLazyCompileCallbackFn Callback, void *CallbackCtx) { - OrcCBindingsStack &J = *unwrap(JITStack); - if (auto Addr = J.createLazyCompileCallback(Callback, CallbackCtx)) { - *RetAddr = *Addr; - return LLVMErrorSuccess; - } else - return wrap(Addr.takeError()); -} - -LLVMErrorRef LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, - const char *StubName, - LLVMOrcTargetAddress InitAddr) { - OrcCBindingsStack &J = *unwrap(JITStack); - return wrap(J.createIndirectStub(StubName, InitAddr)); -} - -LLVMErrorRef LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, - const char *StubName, - LLVMOrcTargetAddress NewAddr) { - OrcCBindingsStack &J = *unwrap(JITStack); - return wrap(J.setIndirectStubPointer(StubName, NewAddr)); -} - -LLVMErrorRef LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle *RetHandle, - LLVMModuleRef Mod, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx) { - OrcCBindingsStack &J = *unwrap(JITStack); - std::unique_ptr M(unwrap(Mod)); - if (auto Handle = - J.addIRModuleEager(std::move(M), SymbolResolver, SymbolResolverCtx)) { - *RetHandle = *Handle; - return LLVMErrorSuccess; - } else - return wrap(Handle.takeError()); -} - -LLVMErrorRef LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle *RetHandle, - LLVMModuleRef Mod, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx) { - OrcCBindingsStack &J = *unwrap(JITStack); - std::unique_ptr M(unwrap(Mod)); - if (auto Handle = - J.addIRModuleLazy(std::move(M), SymbolResolver, SymbolResolverCtx)) { - *RetHandle = *Handle; - return LLVMErrorSuccess; - } else - return wrap(Handle.takeError()); -} - -LLVMErrorRef LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle *RetHandle, - LLVMMemoryBufferRef Obj, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx) { - OrcCBindingsStack &J = *unwrap(JITStack); - std::unique_ptr O(unwrap(Obj)); - if (auto Handle = - J.addObject(std::move(O), SymbolResolver, SymbolResolverCtx)) { - *RetHandle = *Handle; - return LLVMErrorSuccess; - } else - return wrap(Handle.takeError()); -} - -LLVMErrorRef LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, - LLVMOrcModuleHandle H) { - OrcCBindingsStack &J = *unwrap(JITStack); - return wrap(J.removeModule(H)); -} - -LLVMErrorRef LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack, - LLVMOrcTargetAddress *RetAddr, - const char *SymbolName) { - OrcCBindingsStack &J = *unwrap(JITStack); - if (auto Addr = J.findSymbolAddress(SymbolName, true)) { - *RetAddr = *Addr; - return LLVMErrorSuccess; - } else - return wrap(Addr.takeError()); -} - -LLVMErrorRef LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack, - LLVMOrcTargetAddress *RetAddr, - LLVMOrcModuleHandle H, - const char *SymbolName) { - OrcCBindingsStack &J = *unwrap(JITStack); - if (auto Addr = J.findSymbolAddressIn(H, SymbolName, true)) { - *RetAddr = *Addr; - return LLVMErrorSuccess; - } else - return wrap(Addr.takeError()); -} - -LLVMErrorRef LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack) { - auto *J = unwrap(JITStack); - auto Err = J->shutdown(); - delete J; - return wrap(std::move(Err)); -} - -void LLVMOrcRegisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L) -{ - unwrap(JITStack)->RegisterJITEventListener(unwrap(L)); -} - -void LLVMOrcUnregisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L) -{ - unwrap(JITStack)->UnregisterJITEventListener(unwrap(L)); -} diff --git a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h deleted file mode 100644 index 87bb4398765de..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h +++ /dev/null @@ -1,534 +0,0 @@ -//===- OrcCBindingsStack.h - Orc JIT stack for C bindings -----*- C++ -*---===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H -#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H - -#include "llvm-c/OrcBindings.h" -#include "llvm-c/TargetMachine.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/CBindingWrapping.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace llvm { - -class OrcCBindingsStack; - -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcCBindingsStack, LLVMOrcJITStackRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) - -namespace detail { - -// FIXME: Kill this off once the Layer concept becomes an interface. -class GenericLayer { -public: - virtual ~GenericLayer() = default; - - virtual JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) = 0; - virtual Error removeModule(orc::VModuleKey K) = 0; - }; - - template class GenericLayerImpl : public GenericLayer { - public: - GenericLayerImpl(LayerT &Layer) : Layer(Layer) {} - - JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) override { - return Layer.findSymbolIn(K, Name, ExportedSymbolsOnly); - } - - Error removeModule(orc::VModuleKey K) override { - return Layer.removeModule(K); - } - - private: - LayerT &Layer; - }; - - template <> - class GenericLayerImpl : public GenericLayer { - private: - using LayerT = orc::LegacyRTDyldObjectLinkingLayer; - public: - GenericLayerImpl(LayerT &Layer) : Layer(Layer) {} - - JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) override { - return Layer.findSymbolIn(K, Name, ExportedSymbolsOnly); - } - - Error removeModule(orc::VModuleKey K) override { - return Layer.removeObject(K); - } - - private: - LayerT &Layer; - }; - - template - std::unique_ptr> createGenericLayer(LayerT &Layer) { - return std::make_unique>(Layer); - } - -} // end namespace detail - -class OrcCBindingsStack { -public: - - using CompileCallbackMgr = orc::JITCompileCallbackManager; - using ObjLayerT = orc::LegacyRTDyldObjectLinkingLayer; - using CompileLayerT = orc::LegacyIRCompileLayer; - using CODLayerT = - orc::LegacyCompileOnDemandLayer; - - using CallbackManagerBuilder = - std::function()>; - - using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT; - -private: - - using OwningObject = object::OwningBinary; - - class CBindingsResolver : public orc::SymbolResolver { - public: - CBindingsResolver(OrcCBindingsStack &Stack, - LLVMOrcSymbolResolverFn ExternalResolver, - void *ExternalResolverCtx) - : Stack(Stack), ExternalResolver(std::move(ExternalResolver)), - ExternalResolverCtx(std::move(ExternalResolverCtx)) {} - - orc::SymbolNameSet - getResponsibilitySet(const orc::SymbolNameSet &Symbols) override { - orc::SymbolNameSet Result; - - for (auto &S : Symbols) { - if (auto Sym = findSymbol(std::string(*S))) { - if (!Sym.getFlags().isStrong()) - Result.insert(S); - } else if (auto Err = Sym.takeError()) { - Stack.reportError(std::move(Err)); - return orc::SymbolNameSet(); - } - } - - return Result; - } - - orc::SymbolNameSet - lookup(std::shared_ptr Query, - orc::SymbolNameSet Symbols) override { - orc::SymbolNameSet UnresolvedSymbols; - - for (auto &S : Symbols) { - if (auto Sym = findSymbol(std::string(*S))) { - if (auto Addr = Sym.getAddress()) { - Query->notifySymbolMetRequiredState( - S, JITEvaluatedSymbol(*Addr, Sym.getFlags())); - } else { - Stack.ES.legacyFailQuery(*Query, Addr.takeError()); - return orc::SymbolNameSet(); - } - } else if (auto Err = Sym.takeError()) { - Stack.ES.legacyFailQuery(*Query, std::move(Err)); - return orc::SymbolNameSet(); - } else - UnresolvedSymbols.insert(S); - } - - if (Query->isComplete()) - Query->handleComplete(); - - return UnresolvedSymbols; - } - - private: - JITSymbol findSymbol(const std::string &Name) { - // Search order: - // 1. JIT'd symbols. - // 2. Runtime overrides. - // 3. External resolver (if present). - - if (Stack.CODLayer) { - if (auto Sym = Stack.CODLayer->findSymbol(Name, true)) - return Sym; - else if (auto Err = Sym.takeError()) - return Sym.takeError(); - } else { - if (auto Sym = Stack.CompileLayer.findSymbol(Name, true)) - return Sym; - else if (auto Err = Sym.takeError()) - return Sym.takeError(); - } - - if (auto Sym = Stack.CXXRuntimeOverrides.searchOverrides(Name)) - return Sym; - - if (ExternalResolver) - return JITSymbol(ExternalResolver(Name.c_str(), ExternalResolverCtx), - JITSymbolFlags::Exported); - - return JITSymbol(nullptr); - } - - OrcCBindingsStack &Stack; - LLVMOrcSymbolResolverFn ExternalResolver; - void *ExternalResolverCtx = nullptr; - }; - -public: - OrcCBindingsStack(TargetMachine &TM, - IndirectStubsManagerBuilder IndirectStubsMgrBuilder) - : CCMgr(createCompileCallbackManager(TM, ES)), DL(TM.createDataLayout()), - IndirectStubsMgr(IndirectStubsMgrBuilder()), - ObjectLayer( - AcknowledgeORCv1Deprecation, ES, - [this](orc::VModuleKey K) { - auto ResolverI = Resolvers.find(K); - assert(ResolverI != Resolvers.end() && - "No resolver for module K"); - auto Resolver = std::move(ResolverI->second); - Resolvers.erase(ResolverI); - return ObjLayerT::Resources{ - std::make_shared(), Resolver}; - }, - nullptr, - [this](orc::VModuleKey K, const object::ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) { - this->notifyFinalized(K, Obj, LoadedObjInfo); - }, - [this](orc::VModuleKey K, const object::ObjectFile &Obj) { - this->notifyFreed(K, Obj); - }), - CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer, - orc::SimpleCompiler(TM)), - CODLayer(createCODLayer(ES, CompileLayer, CCMgr.get(), - std::move(IndirectStubsMgrBuilder), Resolvers)), - CXXRuntimeOverrides( - AcknowledgeORCv1Deprecation, - [this](const std::string &S) { return mangle(S); }) {} - - Error shutdown() { - // Run any destructors registered with __cxa_atexit. - CXXRuntimeOverrides.runDestructors(); - // Run any IR destructors. - for (auto &DtorRunner : IRStaticDestructorRunners) - if (auto Err = DtorRunner.runViaLayer(*this)) - return Err; - return Error::success(); - } - - std::string mangle(StringRef Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; - } - - template - static PtrTy fromTargetAddress(JITTargetAddress Addr) { - return reinterpret_cast(static_cast(Addr)); - } - - Expected - createLazyCompileCallback(LLVMOrcLazyCompileCallbackFn Callback, - void *CallbackCtx) { - auto WrappedCallback = [=]() -> JITTargetAddress { - return Callback(wrap(this), CallbackCtx); - }; - - return CCMgr->getCompileCallback(std::move(WrappedCallback)); - } - - Error createIndirectStub(StringRef StubName, JITTargetAddress Addr) { - return IndirectStubsMgr->createStub(StubName, Addr, - JITSymbolFlags::Exported); - } - - Error setIndirectStubPointer(StringRef Name, JITTargetAddress Addr) { - return IndirectStubsMgr->updatePointer(Name, Addr); - } - - template - Expected - addIRModule(LayerT &Layer, std::unique_ptr M, - std::unique_ptr MemMgr, - LLVMOrcSymbolResolverFn ExternalResolver, - void *ExternalResolverCtx) { - - // Attach a data-layout if one isn't already present. - if (M->getDataLayout().isDefault()) - M->setDataLayout(DL); - - // Record the static constructors and destructors. We have to do this before - // we hand over ownership of the module to the JIT. - std::vector CtorNames, DtorNames; - for (auto Ctor : orc::getConstructors(*M)) - CtorNames.push_back(mangle(Ctor.Func->getName())); - for (auto Dtor : orc::getDestructors(*M)) - DtorNames.push_back(mangle(Dtor.Func->getName())); - - // Add the module to the JIT. - auto K = ES.allocateVModule(); - Resolvers[K] = std::make_shared(*this, ExternalResolver, - ExternalResolverCtx); - if (auto Err = Layer.addModule(K, std::move(M))) - return std::move(Err); - - KeyLayers[K] = detail::createGenericLayer(Layer); - - // Run the static constructors, and save the static destructor runner for - // execution when the JIT is torn down. - orc::LegacyCtorDtorRunner CtorRunner( - AcknowledgeORCv1Deprecation, std::move(CtorNames), K); - if (auto Err = CtorRunner.runViaLayer(*this)) - return std::move(Err); - - IRStaticDestructorRunners.emplace_back(AcknowledgeORCv1Deprecation, - std::move(DtorNames), K); - - return K; - } - - Expected - addIRModuleEager(std::unique_ptr M, - LLVMOrcSymbolResolverFn ExternalResolver, - void *ExternalResolverCtx) { - return addIRModule(CompileLayer, std::move(M), - std::make_unique(), - std::move(ExternalResolver), ExternalResolverCtx); - } - - Expected - addIRModuleLazy(std::unique_ptr M, - LLVMOrcSymbolResolverFn ExternalResolver, - void *ExternalResolverCtx) { - if (!CODLayer) - return make_error("Can not add lazy module: No compile " - "callback manager available", - inconvertibleErrorCode()); - - return addIRModule(*CODLayer, std::move(M), - std::make_unique(), - std::move(ExternalResolver), ExternalResolverCtx); - } - - Error removeModule(orc::VModuleKey K) { - // FIXME: Should error release the module key? - if (auto Err = KeyLayers[K]->removeModule(K)) - return Err; - ES.releaseVModule(K); - KeyLayers.erase(K); - return Error::success(); - } - - Expected addObject(std::unique_ptr ObjBuffer, - LLVMOrcSymbolResolverFn ExternalResolver, - void *ExternalResolverCtx) { - if (auto Obj = object::ObjectFile::createObjectFile( - ObjBuffer->getMemBufferRef())) { - - auto K = ES.allocateVModule(); - Resolvers[K] = std::make_shared( - *this, ExternalResolver, ExternalResolverCtx); - - if (auto Err = ObjectLayer.addObject(K, std::move(ObjBuffer))) - return std::move(Err); - - KeyLayers[K] = detail::createGenericLayer(ObjectLayer); - - return K; - } else - return Obj.takeError(); - } - - JITSymbol findSymbol(const std::string &Name, - bool ExportedSymbolsOnly) { - if (auto Sym = IndirectStubsMgr->findStub(Name, ExportedSymbolsOnly)) - return Sym; - if (CODLayer) - return CODLayer->findSymbol(mangle(Name), ExportedSymbolsOnly); - return CompileLayer.findSymbol(mangle(Name), ExportedSymbolsOnly); - } - - JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name, - bool ExportedSymbolsOnly) { - assert(KeyLayers.count(K) && "looking up symbol in unknown module"); - return KeyLayers[K]->findSymbolIn(K, mangle(Name), ExportedSymbolsOnly); - } - - Expected findSymbolAddress(const std::string &Name, - bool ExportedSymbolsOnly) { - if (auto Sym = findSymbol(Name, ExportedSymbolsOnly)) { - // Successful lookup, non-null symbol: - if (auto AddrOrErr = Sym.getAddress()) - return *AddrOrErr; - else - return AddrOrErr.takeError(); - } else if (auto Err = Sym.takeError()) { - // Lookup failure - report error. - return std::move(Err); - } - - // No symbol not found. Return 0. - return 0; - } - - Expected findSymbolAddressIn(orc::VModuleKey K, - const std::string &Name, - bool ExportedSymbolsOnly) { - if (auto Sym = findSymbolIn(K, Name, ExportedSymbolsOnly)) { - // Successful lookup, non-null symbol: - if (auto AddrOrErr = Sym.getAddress()) - return *AddrOrErr; - else - return AddrOrErr.takeError(); - } else if (auto Err = Sym.takeError()) { - // Lookup failure - report error. - return std::move(Err); - } - - // Symbol not found. Return 0. - return 0; - } - - const std::string &getErrorMessage() const { return ErrMsg; } - - void RegisterJITEventListener(JITEventListener *L) { - if (!L) - return; - EventListeners.push_back(L); - } - - void UnregisterJITEventListener(JITEventListener *L) { - if (!L) - return; - - auto I = find(reverse(EventListeners), L); - if (I != EventListeners.rend()) { - std::swap(*I, EventListeners.back()); - EventListeners.pop_back(); - } - } - -private: - using ResolverMap = - std::map>; - - static std::unique_ptr - createCompileCallbackManager(TargetMachine &TM, orc::ExecutionSession &ES) { - auto CCMgr = createLocalCompileCallbackManager(TM.getTargetTriple(), ES, 0); - if (!CCMgr) { - // FIXME: It would be good if we could report this somewhere, but we do - // have an instance yet. - logAllUnhandledErrors(CCMgr.takeError(), errs(), "ORC error: "); - return nullptr; - } - return std::move(*CCMgr); - } - - static std::unique_ptr - createCODLayer(orc::ExecutionSession &ES, CompileLayerT &CompileLayer, - CompileCallbackMgr *CCMgr, - IndirectStubsManagerBuilder IndirectStubsMgrBuilder, - ResolverMap &Resolvers) { - // If there is no compile callback manager available we can not create a - // compile on demand layer. - if (!CCMgr) - return nullptr; - - return std::make_unique( - AcknowledgeORCv1Deprecation, ES, CompileLayer, - [&Resolvers](orc::VModuleKey K) { - auto ResolverI = Resolvers.find(K); - assert(ResolverI != Resolvers.end() && "No resolver for module K"); - return ResolverI->second; - }, - [&Resolvers](orc::VModuleKey K, - std::shared_ptr Resolver) { - assert(!Resolvers.count(K) && "Resolver already present"); - Resolvers[K] = std::move(Resolver); - }, - [](Function &F) { return std::set({&F}); }, *CCMgr, - std::move(IndirectStubsMgrBuilder), false); - } - - void reportError(Error Err) { - // FIXME: Report errors on the execution session. - logAllUnhandledErrors(std::move(Err), errs(), "ORC error: "); - }; - - void notifyFinalized(orc::VModuleKey K, - const object::ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) { - uint64_t Key = static_cast( - reinterpret_cast(Obj.getData().data())); - for (auto &Listener : EventListeners) - Listener->notifyObjectLoaded(Key, Obj, LoadedObjInfo); - } - - void notifyFreed(orc::VModuleKey K, const object::ObjectFile &Obj) { - uint64_t Key = static_cast( - reinterpret_cast(Obj.getData().data())); - for (auto &Listener : EventListeners) - Listener->notifyFreeingObject(Key); - } - - orc::ExecutionSession ES; - std::unique_ptr CCMgr; - - std::vector EventListeners; - - DataLayout DL; - SectionMemoryManager CCMgrMemMgr; - - std::unique_ptr IndirectStubsMgr; - - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; - std::unique_ptr CODLayer; - - std::map> KeyLayers; - - orc::LegacyLocalCXXRuntimeOverrides CXXRuntimeOverrides; - std::vector> IRStaticDestructorRunners; - std::string ErrMsg; - - ResolverMap Resolvers; -}; - -} // end namespace llvm - -#endif // LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H diff --git a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp deleted file mode 100644 index 772a9c2c4ab2f..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp +++ /dev/null @@ -1,138 +0,0 @@ -//===-------- OrcMCJITReplacement.cpp - Orc-based MCJIT replacement -------===// -// -// 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 "OrcMCJITReplacement.h" -#include "llvm/ExecutionEngine/GenericValue.h" - -namespace { - -static struct RegisterJIT { - RegisterJIT() { llvm::orc::OrcMCJITReplacement::Register(); } -} JITRegistrator; - -} - -extern "C" void LLVMLinkInOrcMCJITReplacement() {} - -namespace llvm { -namespace orc { - -GenericValue -OrcMCJITReplacement::runFunction(Function *F, - ArrayRef ArgValues) { - assert(F && "Function *F was null at entry to run()"); - - void *FPtr = getPointerToFunction(F); - assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); - FunctionType *FTy = F->getFunctionType(); - Type *RetTy = FTy->getReturnType(); - - assert((FTy->getNumParams() == ArgValues.size() || - (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && - "Wrong number of arguments passed into function!"); - assert(FTy->getNumParams() == ArgValues.size() && - "This doesn't support passing arguments through varargs (yet)!"); - - // Handle some common cases first. These cases correspond to common `main' - // prototypes. - if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { - switch (ArgValues.size()) { - case 3: - if (FTy->getParamType(0)->isIntegerTy(32) && - FTy->getParamType(1)->isPointerTy() && - FTy->getParamType(2)->isPointerTy()) { - int (*PF)(int, char **, const char **) = - (int (*)(int, char **, const char **))(intptr_t)FPtr; - - // Call the function. - GenericValue rv; - rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), - (char **)GVTOP(ArgValues[1]), - (const char **)GVTOP(ArgValues[2]))); - return rv; - } - break; - case 2: - if (FTy->getParamType(0)->isIntegerTy(32) && - FTy->getParamType(1)->isPointerTy()) { - int (*PF)(int, char **) = (int (*)(int, char **))(intptr_t)FPtr; - - // Call the function. - GenericValue rv; - rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), - (char **)GVTOP(ArgValues[1]))); - return rv; - } - break; - case 1: - if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy(32)) { - GenericValue rv; - int (*PF)(int) = (int (*)(int))(intptr_t)FPtr; - rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); - return rv; - } - break; - } - } - - // Handle cases where no arguments are passed first. - if (ArgValues.empty()) { - GenericValue rv; - switch (RetTy->getTypeID()) { - default: - llvm_unreachable("Unknown return type for function call!"); - case Type::IntegerTyID: { - unsigned BitWidth = cast(RetTy)->getBitWidth(); - if (BitWidth == 1) - rv.IntVal = APInt(BitWidth, ((bool (*)())(intptr_t)FPtr)()); - else if (BitWidth <= 8) - rv.IntVal = APInt(BitWidth, ((char (*)())(intptr_t)FPtr)()); - else if (BitWidth <= 16) - rv.IntVal = APInt(BitWidth, ((short (*)())(intptr_t)FPtr)()); - else if (BitWidth <= 32) - rv.IntVal = APInt(BitWidth, ((int (*)())(intptr_t)FPtr)()); - else if (BitWidth <= 64) - rv.IntVal = APInt(BitWidth, ((int64_t (*)())(intptr_t)FPtr)()); - else - llvm_unreachable("Integer types > 64 bits not supported"); - return rv; - } - case Type::VoidTyID: - rv.IntVal = APInt(32, ((int (*)())(intptr_t)FPtr)()); - return rv; - case Type::FloatTyID: - rv.FloatVal = ((float (*)())(intptr_t)FPtr)(); - return rv; - case Type::DoubleTyID: - rv.DoubleVal = ((double (*)())(intptr_t)FPtr)(); - return rv; - case Type::X86_FP80TyID: - case Type::FP128TyID: - case Type::PPC_FP128TyID: - llvm_unreachable("long double not supported yet"); - case Type::PointerTyID: - return PTOGV(((void *(*)())(intptr_t)FPtr)()); - } - } - - llvm_unreachable("Full-featured argument passing not supported yet!"); -} - -void OrcMCJITReplacement::runStaticConstructorsDestructors(bool isDtors) { - auto &CtorDtorsMap = isDtors ? UnexecutedDestructors : UnexecutedConstructors; - - for (auto &KV : CtorDtorsMap) - cantFail(LegacyCtorDtorRunner( - AcknowledgeORCv1Deprecation, std::move(KV.second), KV.first) - .runViaLayer(LazyEmitLayer)); - - CtorDtorsMap.clear(); -} - -} // End namespace orc. -} // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h deleted file mode 100644 index 139572bd69779..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h +++ /dev/null @@ -1,502 +0,0 @@ -//===- OrcMCJITReplacement.h - Orc based MCJIT replacement ------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Orc based MCJIT replacement. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCMCJITREPLACEMENT_H -#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCMCJITREPLACEMENT_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace llvm { - -class ObjectCache; - -namespace orc { - -class OrcMCJITReplacement : public ExecutionEngine { - - // OrcMCJITReplacement needs to do a little extra book-keeping to ensure that - // Orc's automatic finalization doesn't kick in earlier than MCJIT clients are - // expecting - see finalizeMemory. - class MCJITReplacementMemMgr : public MCJITMemoryManager { - public: - MCJITReplacementMemMgr(OrcMCJITReplacement &M, - std::shared_ptr ClientMM) - : M(M), ClientMM(std::move(ClientMM)) {} - - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, - StringRef SectionName) override { - uint8_t *Addr = - ClientMM->allocateCodeSection(Size, Alignment, SectionID, - SectionName); - M.SectionsAllocatedSinceLastLoad.insert(Addr); - return Addr; - } - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName, - bool IsReadOnly) override { - uint8_t *Addr = ClientMM->allocateDataSection(Size, Alignment, SectionID, - SectionName, IsReadOnly); - M.SectionsAllocatedSinceLastLoad.insert(Addr); - return Addr; - } - - void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, - uintptr_t RODataSize, uint32_t RODataAlign, - uintptr_t RWDataSize, - uint32_t RWDataAlign) override { - return ClientMM->reserveAllocationSpace(CodeSize, CodeAlign, - RODataSize, RODataAlign, - RWDataSize, RWDataAlign); - } - - bool needsToReserveAllocationSpace() override { - return ClientMM->needsToReserveAllocationSpace(); - } - - void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, - size_t Size) override { - return ClientMM->registerEHFrames(Addr, LoadAddr, Size); - } - - void deregisterEHFrames() override { - return ClientMM->deregisterEHFrames(); - } - - void notifyObjectLoaded(RuntimeDyld &RTDyld, - const object::ObjectFile &O) override { - return ClientMM->notifyObjectLoaded(RTDyld, O); - } - - void notifyObjectLoaded(ExecutionEngine *EE, - const object::ObjectFile &O) override { - return ClientMM->notifyObjectLoaded(EE, O); - } - - bool finalizeMemory(std::string *ErrMsg = nullptr) override { - // Each set of objects loaded will be finalized exactly once, but since - // symbol lookup during relocation may recursively trigger the - // loading/relocation of other modules, and since we're forwarding all - // finalizeMemory calls to a single underlying memory manager, we need to - // defer forwarding the call on until all necessary objects have been - // loaded. Otherwise, during the relocation of a leaf object, we will end - // up finalizing memory, causing a crash further up the stack when we - // attempt to apply relocations to finalized memory. - // To avoid finalizing too early, look at how many objects have been - // loaded but not yet finalized. This is a bit of a hack that relies on - // the fact that we're lazily emitting object files: The only way you can - // get more than one set of objects loaded but not yet finalized is if - // they were loaded during relocation of another set. - if (M.UnfinalizedSections.size() == 1) - return ClientMM->finalizeMemory(ErrMsg); - return false; - } - - private: - OrcMCJITReplacement &M; - std::shared_ptr ClientMM; - }; - - class LinkingORCResolver : public orc::SymbolResolver { - public: - LinkingORCResolver(OrcMCJITReplacement &M) : M(M) {} - - SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) override { - SymbolNameSet Result; - - for (auto &S : Symbols) { - if (auto Sym = M.findMangledSymbol(*S)) { - if (!Sym.getFlags().isStrong()) - Result.insert(S); - } else if (auto Err = Sym.takeError()) { - M.reportError(std::move(Err)); - return SymbolNameSet(); - } else { - if (auto Sym2 = - M.ClientResolver->findSymbolInLogicalDylib(std::string(*S))) { - if (!Sym2.getFlags().isStrong()) - Result.insert(S); - } else if (auto Err = Sym2.takeError()) { - M.reportError(std::move(Err)); - return SymbolNameSet(); - } else - Result.insert(S); - } - } - - return Result; - } - - SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) override { - SymbolNameSet UnresolvedSymbols; - bool NewSymbolsResolved = false; - - for (auto &S : Symbols) { - if (auto Sym = M.findMangledSymbol(*S)) { - if (auto Addr = Sym.getAddress()) { - Query->notifySymbolMetRequiredState( - S, JITEvaluatedSymbol(*Addr, Sym.getFlags())); - NewSymbolsResolved = true; - } else { - M.ES.legacyFailQuery(*Query, Addr.takeError()); - return SymbolNameSet(); - } - } else if (auto Err = Sym.takeError()) { - M.ES.legacyFailQuery(*Query, std::move(Err)); - return SymbolNameSet(); - } else { - if (auto Sym2 = M.ClientResolver->findSymbol(std::string(*S))) { - if (auto Addr = Sym2.getAddress()) { - Query->notifySymbolMetRequiredState( - S, JITEvaluatedSymbol(*Addr, Sym2.getFlags())); - NewSymbolsResolved = true; - } else { - M.ES.legacyFailQuery(*Query, Addr.takeError()); - return SymbolNameSet(); - } - } else if (auto Err = Sym2.takeError()) { - M.ES.legacyFailQuery(*Query, std::move(Err)); - return SymbolNameSet(); - } else - UnresolvedSymbols.insert(S); - } - } - - if (NewSymbolsResolved && Query->isComplete()) - Query->handleComplete(); - - return UnresolvedSymbols; - } - - private: - OrcMCJITReplacement &M; - }; - -private: - static ExecutionEngine * - createOrcMCJITReplacement(std::string *ErrorMsg, - std::shared_ptr MemMgr, - std::shared_ptr Resolver, - std::unique_ptr TM) { - return new OrcMCJITReplacement(std::move(MemMgr), std::move(Resolver), - std::move(TM)); - } - - void reportError(Error Err) { - logAllUnhandledErrors(std::move(Err), errs(), "MCJIT error: "); - } - -public: - OrcMCJITReplacement(std::shared_ptr MemMgr, - std::shared_ptr ClientResolver, - std::unique_ptr TM) - : ExecutionEngine(TM->createDataLayout()), TM(std::move(TM)), - MemMgr( - std::make_shared(*this, std::move(MemMgr))), - Resolver(std::make_shared(*this)), - ClientResolver(std::move(ClientResolver)), NotifyObjectLoaded(*this), - NotifyFinalized(*this), - ObjectLayer( - AcknowledgeORCv1Deprecation, ES, - [this](VModuleKey K) { - return ObjectLayerT::Resources{this->MemMgr, this->Resolver}; - }, - NotifyObjectLoaded, NotifyFinalized), - CompileLayer(AcknowledgeORCv1Deprecation, ObjectLayer, - SimpleCompiler(*this->TM), - [this](VModuleKey K, std::unique_ptr M) { - Modules.push_back(std::move(M)); - }), - LazyEmitLayer(AcknowledgeORCv1Deprecation, CompileLayer) {} - - static void Register() { - OrcMCJITReplacementCtor = createOrcMCJITReplacement; - } - - void addModule(std::unique_ptr M) override { - // If this module doesn't have a DataLayout attached then attach the - // default. - if (M->getDataLayout().isDefault()) { - M->setDataLayout(getDataLayout()); - } else { - assert(M->getDataLayout() == getDataLayout() && "DataLayout Mismatch"); - } - - // Rename, bump linkage and record static constructors and destructors. - // We have to do this before we hand over ownership of the module to the - // JIT. - std::vector CtorNames, DtorNames; - { - unsigned CtorId = 0, DtorId = 0; - for (auto Ctor : orc::getConstructors(*M)) { - std::string NewCtorName = ("__ORCstatic_ctor." + Twine(CtorId++)).str(); - Ctor.Func->setName(NewCtorName); - Ctor.Func->setLinkage(GlobalValue::ExternalLinkage); - Ctor.Func->setVisibility(GlobalValue::HiddenVisibility); - CtorNames.push_back(mangle(NewCtorName)); - } - for (auto Dtor : orc::getDestructors(*M)) { - std::string NewDtorName = ("__ORCstatic_dtor." + Twine(DtorId++)).str(); - dbgs() << "Found dtor: " << NewDtorName << "\n"; - Dtor.Func->setName(NewDtorName); - Dtor.Func->setLinkage(GlobalValue::ExternalLinkage); - Dtor.Func->setVisibility(GlobalValue::HiddenVisibility); - DtorNames.push_back(mangle(NewDtorName)); - } - } - - auto K = ES.allocateVModule(); - - UnexecutedConstructors[K] = std::move(CtorNames); - UnexecutedDestructors[K] = std::move(DtorNames); - - cantFail(LazyEmitLayer.addModule(K, std::move(M))); - } - - void addObjectFile(std::unique_ptr O) override { - cantFail(ObjectLayer.addObject( - ES.allocateVModule(), MemoryBuffer::getMemBufferCopy(O->getData()))); - } - - void addObjectFile(object::OwningBinary O) override { - std::unique_ptr Obj; - std::unique_ptr ObjBuffer; - std::tie(Obj, ObjBuffer) = O.takeBinary(); - cantFail(ObjectLayer.addObject(ES.allocateVModule(), std::move(ObjBuffer))); - } - - void addArchive(object::OwningBinary A) override { - Archives.push_back(std::move(A)); - } - - bool removeModule(Module *M) override { - auto I = Modules.begin(); - for (auto E = Modules.end(); I != E; ++I) - if (I->get() == M) - break; - if (I == Modules.end()) - return false; - Modules.erase(I); - return true; - } - - uint64_t getSymbolAddress(StringRef Name) { - return cantFail(findSymbol(Name).getAddress()); - } - - JITSymbol findSymbol(StringRef Name) { - return findMangledSymbol(mangle(Name)); - } - - void finalizeObject() override { - // This is deprecated - Aim to remove in ExecutionEngine. - // REMOVE IF POSSIBLE - Doesn't make sense for New JIT. - } - - void mapSectionAddress(const void *LocalAddress, - uint64_t TargetAddress) override { - for (auto &P : UnfinalizedSections) - if (P.second.count(LocalAddress)) - ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress); - } - - uint64_t getGlobalValueAddress(const std::string &Name) override { - return getSymbolAddress(Name); - } - - uint64_t getFunctionAddress(const std::string &Name) override { - return getSymbolAddress(Name); - } - - void *getPointerToFunction(Function *F) override { - uint64_t FAddr = getSymbolAddress(F->getName()); - return reinterpret_cast(static_cast(FAddr)); - } - - void *getPointerToNamedFunction(StringRef Name, - bool AbortOnFailure = true) override { - uint64_t Addr = getSymbolAddress(Name); - if (!Addr && AbortOnFailure) - llvm_unreachable("Missing symbol!"); - return reinterpret_cast(static_cast(Addr)); - } - - GenericValue runFunction(Function *F, - ArrayRef ArgValues) override; - - void setObjectCache(ObjectCache *NewCache) override { - CompileLayer.getCompiler().setObjectCache(NewCache); - } - - void setProcessAllSections(bool ProcessAllSections) override { - ObjectLayer.setProcessAllSections(ProcessAllSections); - } - - void runStaticConstructorsDestructors(bool isDtors) override; - -private: - JITSymbol findMangledSymbol(StringRef Name) { - if (auto Sym = LazyEmitLayer.findSymbol(std::string(Name), false)) - return Sym; - if (auto Sym = ClientResolver->findSymbol(std::string(Name))) - return Sym; - if (auto Sym = scanArchives(Name)) - return Sym; - - return nullptr; - } - - JITSymbol scanArchives(StringRef Name) { - for (object::OwningBinary &OB : Archives) { - object::Archive *A = OB.getBinary(); - // Look for our symbols in each Archive - auto OptionalChildOrErr = A->findSym(Name); - if (!OptionalChildOrErr) - report_fatal_error(OptionalChildOrErr.takeError()); - auto &OptionalChild = *OptionalChildOrErr; - if (OptionalChild) { - // FIXME: Support nested archives? - Expected> ChildBinOrErr = - OptionalChild->getAsBinary(); - if (!ChildBinOrErr) { - // TODO: Actually report errors helpfully. - consumeError(ChildBinOrErr.takeError()); - continue; - } - std::unique_ptr &ChildBin = ChildBinOrErr.get(); - if (ChildBin->isObject()) { - cantFail(ObjectLayer.addObject( - ES.allocateVModule(), - MemoryBuffer::getMemBufferCopy(ChildBin->getData()))); - if (auto Sym = ObjectLayer.findSymbol(Name, true)) - return Sym; - } - } - } - return nullptr; - } - - class NotifyObjectLoadedT { - public: - using LoadedObjInfoListT = - std::vector>; - - NotifyObjectLoadedT(OrcMCJITReplacement &M) : M(M) {} - - void operator()(VModuleKey K, const object::ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &Info) const { - M.UnfinalizedSections[K] = std::move(M.SectionsAllocatedSinceLastLoad); - M.SectionsAllocatedSinceLastLoad = SectionAddrSet(); - M.MemMgr->notifyObjectLoaded(&M, Obj); - } - private: - OrcMCJITReplacement &M; - }; - - class NotifyFinalizedT { - public: - NotifyFinalizedT(OrcMCJITReplacement &M) : M(M) {} - - void operator()(VModuleKey K, const object::ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &Info) { - M.UnfinalizedSections.erase(K); - } - - private: - OrcMCJITReplacement &M; - }; - - std::string mangle(StringRef Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mang.getNameWithPrefix(MangledNameStream, Name, getDataLayout()); - } - return MangledName; - } - - using ObjectLayerT = LegacyRTDyldObjectLinkingLayer; - using CompileLayerT = LegacyIRCompileLayer; - using LazyEmitLayerT = LazyEmittingLayer; - - ExecutionSession ES; - - std::unique_ptr TM; - std::shared_ptr MemMgr; - std::shared_ptr Resolver; - std::shared_ptr ClientResolver; - Mangler Mang; - - // IMPORTANT: ShouldDelete *must* come before LocalModules: The shared_ptr - // delete blocks in LocalModules refer to the ShouldDelete map, so - // LocalModules needs to be destructed before ShouldDelete. - std::map ShouldDelete; - - NotifyObjectLoadedT NotifyObjectLoaded; - NotifyFinalizedT NotifyFinalized; - - ObjectLayerT ObjectLayer; - CompileLayerT CompileLayer; - LazyEmitLayerT LazyEmitLayer; - - std::map> UnexecutedConstructors; - std::map> UnexecutedDestructors; - - // We need to store ObjLayerT::ObjSetHandles for each of the object sets - // that have been emitted but not yet finalized so that we can forward the - // mapSectionAddress calls appropriately. - using SectionAddrSet = std::set; - SectionAddrSet SectionsAllocatedSinceLastLoad; - std::map UnfinalizedSections; - - std::vector> Archives; -}; - -} // end namespace orc - -} // end namespace llvm - -#endif // LLVM_LIB_EXECUTIONENGINE_ORC_MCJITREPLACEMENT_H diff --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp index 5933c2e666d1c..dfdd2c6c669f9 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp @@ -6,11 +6,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm-c/LLJIT.h" #include "llvm-c/Orc.h" +#include "llvm-c/OrcEE.h" #include "llvm-c/TargetMachine.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" using namespace llvm; using namespace llvm::orc; @@ -18,6 +22,8 @@ using namespace llvm::orc; namespace llvm { namespace orc { +class InProgressLookupState; + class OrcV2CAPIHelper { public: using PoolEntry = SymbolStringPtr::PoolEntry; @@ -29,58 +35,278 @@ class OrcV2CAPIHelper { return Result; } + static SymbolStringPtr retainSymbolStringPtr(PoolEntryPtr P) { + return SymbolStringPtr(P); + } + static PoolEntryPtr getRawPoolEntryPtr(const SymbolStringPtr &S) { return S.S; } + static void retainPoolEntry(PoolEntryPtr P) { + SymbolStringPtr S(P); + S.S = nullptr; + } + static void releasePoolEntry(PoolEntryPtr P) { SymbolStringPtr S; S.S = P; } + + static InProgressLookupState *extractLookupState(LookupState &LS) { + return LS.IPLS.release(); + } + + static void resetLookupState(LookupState &LS, InProgressLookupState *IPLS) { + return LS.reset(IPLS); + } }; -} // end namespace orc -} // end namespace llvm +} // namespace orc +} // namespace llvm DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionSession, LLVMOrcExecutionSessionRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SymbolStringPool, LLVMOrcSymbolStringPoolRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcV2CAPIHelper::PoolEntry, LLVMOrcSymbolStringPoolEntryRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(MaterializationUnit, + LLVMOrcMaterializationUnitRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITDylib, LLVMOrcJITDylibRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITDylib::DefinitionGenerator, - LLVMOrcJITDylibDefinitionGeneratorRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ResourceTracker, LLVMOrcResourceTrackerRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DefinitionGenerator, + LLVMOrcDefinitionGeneratorRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(InProgressLookupState, LLVMOrcLookupStateRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeContext, LLVMOrcThreadSafeContextRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITTargetMachineBuilder, LLVMOrcJITTargetMachineBuilderRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) +namespace llvm { +namespace orc { + +class CAPIDefinitionGenerator final : public DefinitionGenerator { +public: + CAPIDefinitionGenerator( + void *Ctx, + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate) + : Ctx(Ctx), TryToGenerate(TryToGenerate) {} + + Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, + const SymbolLookupSet &LookupSet) override { + + // Take the lookup state. + LLVMOrcLookupStateRef LSR = ::wrap(OrcV2CAPIHelper::extractLookupState(LS)); + + // Translate the lookup kind. + LLVMOrcLookupKind CLookupKind; + switch (K) { + case LookupKind::Static: + CLookupKind = LLVMOrcLookupKindStatic; + break; + case LookupKind::DLSym: + CLookupKind = LLVMOrcLookupKindDLSym; + break; + } + + // Translate the JITDylibSearchFlags. + LLVMOrcJITDylibLookupFlags CJDLookupFlags; + switch (JDLookupFlags) { + case JITDylibLookupFlags::MatchExportedSymbolsOnly: + CJDLookupFlags = LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly; + break; + case JITDylibLookupFlags::MatchAllSymbols: + CJDLookupFlags = LLVMOrcJITDylibLookupFlagsMatchAllSymbols; + break; + } + + // Translate the lookup set. + std::vector CLookupSet; + CLookupSet.reserve(LookupSet.size()); + for (auto &KV : LookupSet) { + LLVMOrcSymbolLookupFlags SLF; + LLVMOrcSymbolStringPoolEntryRef Name = + ::wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(KV.first)); + switch (KV.second) { + case SymbolLookupFlags::RequiredSymbol: + SLF = LLVMOrcSymbolLookupFlagsRequiredSymbol; + break; + case SymbolLookupFlags::WeaklyReferencedSymbol: + SLF = LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol; + break; + } + CLookupSet.push_back({Name, SLF}); + } + + // Run the C TryToGenerate function. + auto Err = unwrap(TryToGenerate(::wrap(this), Ctx, &LSR, CLookupKind, + ::wrap(&JD), CJDLookupFlags, + CLookupSet.data(), CLookupSet.size())); + + // Restore the lookup state. + OrcV2CAPIHelper::resetLookupState(LS, ::unwrap(LSR)); + + return Err; + } + +private: + void *Ctx; + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate; +}; + +} // end namespace orc +} // end namespace llvm + +void LLVMOrcExecutionSessionSetErrorReporter( + LLVMOrcExecutionSessionRef ES, LLVMOrcErrorReporterFunction ReportError, + void *Ctx) { + unwrap(ES)->setErrorReporter( + [=](Error Err) { ReportError(Ctx, wrap(std::move(Err))); }); +} + +LLVMOrcSymbolStringPoolRef +LLVMOrcExecutionSessionGetSymbolStringPool(LLVMOrcExecutionSessionRef ES) { + return wrap(unwrap(ES)->getSymbolStringPool().get()); +} + +void LLVMOrcSymbolStringPoolClearDeadEntries(LLVMOrcSymbolStringPoolRef SSP) { + unwrap(SSP)->clearDeadEntries(); +} + LLVMOrcSymbolStringPoolEntryRef LLVMOrcExecutionSessionIntern(LLVMOrcExecutionSessionRef ES, const char *Name) { return wrap( OrcV2CAPIHelper::releaseSymbolStringPtr(unwrap(ES)->intern(Name))); } +void LLVMOrcRetainSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S) { + OrcV2CAPIHelper::retainPoolEntry(unwrap(S)); +} + void LLVMOrcReleaseSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S) { OrcV2CAPIHelper::releasePoolEntry(unwrap(S)); } -void LLVMOrcDisposeJITDylibDefinitionGenerator( - LLVMOrcJITDylibDefinitionGeneratorRef DG) { - delete unwrap(DG); +const char *LLVMOrcSymbolStringPoolEntryStr(LLVMOrcSymbolStringPoolEntryRef S) { + return unwrap(S)->getKey().data(); +} + +LLVMOrcResourceTrackerRef +LLVMOrcJITDylibCreateResourceTracker(LLVMOrcJITDylibRef JD) { + auto RT = unwrap(JD)->createResourceTracker(); + // Retain the pointer for the C API client. + RT->Retain(); + return wrap(RT.get()); +} + +LLVMOrcResourceTrackerRef +LLVMOrcJITDylibGetDefaultResourceTracker(LLVMOrcJITDylibRef JD) { + auto RT = unwrap(JD)->getDefaultResourceTracker(); + // Retain the pointer for the C API client. + return wrap(RT.get()); +} + +void LLVMOrcReleaseResourceTracker(LLVMOrcResourceTrackerRef RT) { + ResourceTrackerSP TmpRT(unwrap(RT)); + TmpRT->Release(); +} + +void LLVMOrcResourceTrackerTransferTo(LLVMOrcResourceTrackerRef SrcRT, + LLVMOrcResourceTrackerRef DstRT) { + ResourceTrackerSP TmpRT(unwrap(SrcRT)); + TmpRT->transferTo(*unwrap(DstRT)); +} + +LLVMErrorRef LLVMOrcResourceTrackerRemove(LLVMOrcResourceTrackerRef RT) { + ResourceTrackerSP TmpRT(unwrap(RT)); + return wrap(TmpRT->remove()); +} + +void LLVMOrcDisposeDefinitionGenerator(LLVMOrcDefinitionGeneratorRef DG) { + std::unique_ptr TmpDG(unwrap(DG)); +} + +void LLVMOrcDisposeMaterializationUnit(LLVMOrcMaterializationUnitRef MU) { + std::unique_ptr TmpMU(unwrap(MU)); +} + +LLVMOrcMaterializationUnitRef +LLVMOrcAbsoluteSymbols(LLVMOrcCSymbolMapPairs Syms, size_t NumPairs) { + SymbolMap SM; + for (size_t I = 0; I != NumPairs; ++I) { + JITSymbolFlags Flags; + + if (Syms[I].Sym.Flags.GenericFlags & LLVMJITSymbolGenericFlagsExported) + Flags |= JITSymbolFlags::Exported; + if (Syms[I].Sym.Flags.GenericFlags & LLVMJITSymbolGenericFlagsWeak) + Flags |= JITSymbolFlags::Weak; + + Flags.getTargetFlags() = Syms[I].Sym.Flags.TargetFlags; + + SM[OrcV2CAPIHelper::retainSymbolStringPtr(unwrap(Syms[I].Name))] = + JITEvaluatedSymbol(Syms[I].Sym.Address, Flags); + } + + return wrap(absoluteSymbols(std::move(SM)).release()); +} + +LLVMOrcJITDylibRef +LLVMOrcExecutionSessionCreateBareJITDylib(LLVMOrcExecutionSessionRef ES, + const char *Name) { + return wrap(&unwrap(ES)->createBareJITDylib(Name)); +} + +LLVMErrorRef +LLVMOrcExecutionSessionCreateJITDylib(LLVMOrcExecutionSessionRef ES, + LLVMOrcJITDylibRef *Result, + const char *Name) { + auto JD = unwrap(ES)->createJITDylib(Name); + if (!JD) + return wrap(JD.takeError()); + *Result = wrap(&*JD); + return LLVMErrorSuccess; +} + +LLVMOrcJITDylibRef +LLVMOrcExecutionSessionGetJITDylibByName(LLVMOrcExecutionSessionRef ES, + const char *Name) { + return wrap(unwrap(ES)->getJITDylibByName(Name)); +} + +LLVMErrorRef LLVMOrcJITDylibDefine(LLVMOrcJITDylibRef JD, + LLVMOrcMaterializationUnitRef MU) { + std::unique_ptr TmpMU(unwrap(MU)); + + if (auto Err = unwrap(JD)->define(TmpMU)) { + TmpMU.release(); + return wrap(std::move(Err)); + } + return LLVMErrorSuccess; +} + +LLVMErrorRef LLVMOrcJITDylibClear(LLVMOrcJITDylibRef JD) { + return wrap(unwrap(JD)->clear()); } void LLVMOrcJITDylibAddGenerator(LLVMOrcJITDylibRef JD, - LLVMOrcJITDylibDefinitionGeneratorRef DG) { - unwrap(JD)->addGenerator( - std::unique_ptr(unwrap(DG))); + LLVMOrcDefinitionGeneratorRef DG) { + unwrap(JD)->addGenerator(std::unique_ptr(unwrap(DG))); +} + +LLVMOrcDefinitionGeneratorRef LLVMOrcCreateCustomCAPIDefinitionGenerator( + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction F, void *Ctx) { + auto DG = std::make_unique(Ctx, F); + return wrap(DG.release()); } LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( - LLVMOrcJITDylibDefinitionGeneratorRef *Result, char GlobalPrefix, + LLVMOrcDefinitionGeneratorRef *Result, char GlobalPrefix, LLVMOrcSymbolPredicate Filter, void *FilterCtx) { assert(Result && "Result can not be null"); assert((Filter || !FilterCtx) && @@ -89,7 +315,7 @@ LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( DynamicLibrarySearchGenerator::SymbolPredicate Pred; if (Filter) Pred = [=](const SymbolStringPtr &Name) -> bool { - return Filter(wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(Name)), FilterCtx); + return Filter(FilterCtx, wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(Name))); }; auto ProcessSymsGenerator = @@ -143,7 +369,7 @@ LLVMErrorRef LLVMOrcJITTargetMachineBuilderDetectHost( } LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM) { +LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM) { auto *TemplateTM = unwrap(TM); auto JTMB = @@ -167,6 +393,10 @@ void LLVMOrcDisposeJITTargetMachineBuilder( delete unwrap(JTMB); } +void lLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer) { + delete unwrap(ObjLayer); +} + LLVMOrcLLJITBuilderRef LLVMOrcCreateLLJITBuilder(void) { return wrap(new LLJITBuilder()); } @@ -180,6 +410,17 @@ void LLVMOrcLLJITBuilderSetJITTargetMachineBuilder( unwrap(Builder)->setJITTargetMachineBuilder(*unwrap(JTMB)); } +void LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator( + LLVMOrcLLJITBuilderRef Builder, + LLVMOrcLLJITBuilderObjectLinkingLayerCreatorFunction F, void *Ctx) { + unwrap(Builder)->setObjectLinkingLayerCreator( + [=](ExecutionSession &ES, const Triple &TT) { + auto TTStr = TT.str(); + return std::unique_ptr( + unwrap(F(Ctx, wrap(&ES), TTStr.c_str()))); + }); +} + LLVMErrorRef LLVMOrcCreateLLJIT(LLVMOrcLLJITRef *Result, LLVMOrcLLJITBuilderRef Builder) { assert(Result && "Result can not be null"); @@ -232,10 +473,27 @@ LLVMErrorRef LLVMOrcLLJITAddObjectFile(LLVMOrcLLJITRef J, LLVMOrcJITDylibRef JD, *unwrap(JD), std::unique_ptr(unwrap(ObjBuffer)))); } +LLVMErrorRef LLVMOrcLLJITAddObjectFileWithRT(LLVMOrcLLJITRef J, + LLVMOrcResourceTrackerRef RT, + LLVMMemoryBufferRef ObjBuffer) { + return wrap(unwrap(J)->addObjectFile( + ResourceTrackerSP(unwrap(RT)), + std::unique_ptr(unwrap(ObjBuffer)))); +} + LLVMErrorRef LLVMOrcLLJITAddLLVMIRModule(LLVMOrcLLJITRef J, LLVMOrcJITDylibRef JD, LLVMOrcThreadSafeModuleRef TSM) { - return wrap(unwrap(J)->addIRModule(*unwrap(JD), std::move(*unwrap(TSM)))); + std::unique_ptr TmpTSM(unwrap(TSM)); + return wrap(unwrap(J)->addIRModule(*unwrap(JD), std::move(*TmpTSM))); +} + +LLVMErrorRef LLVMOrcLLJITAddLLVMIRModuleWithRT(LLVMOrcLLJITRef J, + LLVMOrcResourceTrackerRef RT, + LLVMOrcThreadSafeModuleRef TSM) { + std::unique_ptr TmpTSM(unwrap(TSM)); + return wrap(unwrap(J)->addIRModule(ResourceTrackerSP(unwrap(RT)), + std::move(*TmpTSM))); } LLVMErrorRef LLVMOrcLLJITLookup(LLVMOrcLLJITRef J, @@ -252,3 +510,20 @@ LLVMErrorRef LLVMOrcLLJITLookup(LLVMOrcLLJITRef J, *Result = Sym->getAddress(); return LLVMErrorSuccess; } + +LLVMOrcObjectLayerRef +LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager( + LLVMOrcExecutionSessionRef ES) { + assert(ES && "ES must not be null"); + return wrap(new RTDyldObjectLinkingLayer( + *unwrap(ES), [] { return std::make_unique(); })); +} + +void LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener( + LLVMOrcObjectLayerRef RTDyldObjLinkingLayer, + LLVMJITEventListenerRef Listener) { + assert(RTDyldObjLinkingLayer && "RTDyldObjLinkingLayer must not be null"); + assert(Listener && "Listener must not be null"); + reinterpret_cast(unwrap(RTDyldObjLinkingLayer)) + ->registerJITEventListener(*unwrap(Listener)); +} diff --git a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp index 7888c2fcbdbd9..a6cccb90936cd 100644 --- a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp @@ -77,35 +77,26 @@ namespace orc { RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer( ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager) - : ObjectLayer(ES), GetMemoryManager(GetMemoryManager) {} + : ObjectLayer(ES), GetMemoryManager(GetMemoryManager) { + ES.registerResourceManager(*this); +} RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() { - std::lock_guard Lock(RTDyldLayerMutex); - for (auto &MemMgr : MemMgrs) { - for (auto *L : EventListeners) - L->notifyFreeingObject( - static_cast(reinterpret_cast(MemMgr.get()))); - MemMgr->deregisterEHFrames(); - } + assert(MemMgrs.empty() && "Layer destroyed with resources still attached"); } -void RTDyldObjectLinkingLayer::emit(MaterializationResponsibility R, - std::unique_ptr O) { +void RTDyldObjectLinkingLayer::emit( + std::unique_ptr R, + std::unique_ptr O) { assert(O && "Object must not be null"); - // This method launches an asynchronous link step that will fulfill our - // materialization responsibility. We need to switch R to be heap - // allocated before that happens so it can live as long as the asynchronous - // link needs it to (i.e. it must be able to outlive this method). - auto SharedR = std::make_shared(std::move(R)); - auto &ES = getExecutionSession(); auto Obj = object::ObjectFile::createObjectFile(*O); if (!Obj) { getExecutionSession().reportError(Obj.takeError()); - SharedR->failMaterialization(); + R->failMaterialization(); return; } @@ -121,7 +112,7 @@ void RTDyldObjectLinkingLayer::emit(MaterializationResponsibility R, continue; } else { ES.reportError(SymType.takeError()); - R.failMaterialization(); + R->failMaterialization(); return; } @@ -129,7 +120,7 @@ void RTDyldObjectLinkingLayer::emit(MaterializationResponsibility R, if (!SymFlagsOrErr) { // TODO: Test this error. ES.reportError(SymFlagsOrErr.takeError()); - R.failMaterialization(); + R->failMaterialization(); return; } @@ -139,39 +130,38 @@ void RTDyldObjectLinkingLayer::emit(MaterializationResponsibility R, InternalSymbols->insert(*SymName); else { ES.reportError(SymName.takeError()); - R.failMaterialization(); + R->failMaterialization(); return; } } } } - auto K = R.getVModuleKey(); - RuntimeDyld::MemoryManager *MemMgr = nullptr; + auto MemMgr = GetMemoryManager(); + auto &MemMgrRef = *MemMgr; - // Create a record a memory manager for this object. - { - auto Tmp = GetMemoryManager(); - std::lock_guard Lock(RTDyldLayerMutex); - MemMgrs.push_back(std::move(Tmp)); - MemMgr = MemMgrs.back().get(); - } + // Switch to shared ownership of MR so that it can be captured by both + // lambdas below. + std::shared_ptr SharedR(std::move(R)); JITDylibSearchOrderResolver Resolver(*SharedR); jitLinkForORC( object::OwningBinary(std::move(*Obj), std::move(O)), - *MemMgr, Resolver, ProcessAllSections, - [this, K, SharedR, MemMgr, InternalSymbols]( + MemMgrRef, Resolver, ProcessAllSections, + [this, SharedR, &MemMgrRef, InternalSymbols]( const object::ObjectFile &Obj, - std::unique_ptr LoadedObjInfo, + RuntimeDyld::LoadedObjectInfo &LoadedObjInfo, std::map ResolvedSymbols) { - return onObjLoad(K, *SharedR, Obj, MemMgr, std::move(LoadedObjInfo), + return onObjLoad(*SharedR, Obj, MemMgrRef, LoadedObjInfo, ResolvedSymbols, *InternalSymbols); }, - [this, K, SharedR, MemMgr](object::OwningBinary Obj, - Error Err) mutable { - onObjEmit(K, *SharedR, std::move(Obj), MemMgr, std::move(Err)); + [this, SharedR, MemMgr = std::move(MemMgr)]( + object::OwningBinary Obj, + std::unique_ptr LoadedObjInfo, + Error Err) mutable { + onObjEmit(*SharedR, std::move(Obj), std::move(MemMgr), + std::move(LoadedObjInfo), std::move(Err)); }); } @@ -191,9 +181,9 @@ void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener &L) { } Error RTDyldObjectLinkingLayer::onObjLoad( - VModuleKey K, MaterializationResponsibility &R, - const object::ObjectFile &Obj, RuntimeDyld::MemoryManager *MemMgr, - std::unique_ptr LoadedObjInfo, + MaterializationResponsibility &R, const object::ObjectFile &Obj, + RuntimeDyld::MemoryManager &MemMgr, + RuntimeDyld::LoadedObjectInfo &LoadedObjInfo, std::map Resolved, std::set &InternalSymbols) { SymbolFlagsMap ExtraSymbolsToClaim; @@ -274,19 +264,16 @@ Error RTDyldObjectLinkingLayer::onObjLoad( } if (NotifyLoaded) - NotifyLoaded(K, Obj, *LoadedObjInfo); - - std::lock_guard Lock(RTDyldLayerMutex); - assert(!LoadedObjInfos.count(MemMgr) && "Duplicate loaded info for MemMgr"); - LoadedObjInfos[MemMgr] = std::move(LoadedObjInfo); + NotifyLoaded(R, Obj, LoadedObjInfo); return Error::success(); } void RTDyldObjectLinkingLayer::onObjEmit( - VModuleKey K, MaterializationResponsibility &R, + MaterializationResponsibility &R, object::OwningBinary O, - RuntimeDyld::MemoryManager *MemMgr, Error Err) { + std::unique_ptr MemMgr, + std::unique_ptr LoadedObjInfo, Error Err) { if (Err) { getExecutionSession().reportError(std::move(Err)); R.failMaterialization(); @@ -306,27 +293,60 @@ void RTDyldObjectLinkingLayer::onObjEmit( // Run EventListener notifyLoaded callbacks. { std::lock_guard Lock(RTDyldLayerMutex); - auto LOIItr = LoadedObjInfos.find(MemMgr); - assert(LOIItr != LoadedObjInfos.end() && "LoadedObjInfo missing"); for (auto *L : EventListeners) - L->notifyObjectLoaded( - static_cast(reinterpret_cast(MemMgr)), *Obj, - *LOIItr->second); - LoadedObjInfos.erase(MemMgr); + L->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr.get()), *Obj, + *LoadedObjInfo); } if (NotifyEmitted) - NotifyEmitted(K, std::move(ObjBuffer)); + NotifyEmitted(R, std::move(ObjBuffer)); + + if (auto Err = R.withResourceKeyDo( + [&](ResourceKey K) { MemMgrs[K].push_back(std::move(MemMgr)); })) { + getExecutionSession().reportError(std::move(Err)); + R.failMaterialization(); + } } -LegacyRTDyldObjectLinkingLayer::LegacyRTDyldObjectLinkingLayer( - ExecutionSession &ES, ResourcesGetter GetResources, - NotifyLoadedFtor NotifyLoaded, NotifyFinalizedFtor NotifyFinalized, - NotifyFreedFtor NotifyFreed) - : ES(ES), GetResources(std::move(GetResources)), - NotifyLoaded(std::move(NotifyLoaded)), - NotifyFinalized(std::move(NotifyFinalized)), - NotifyFreed(std::move(NotifyFreed)), ProcessAllSections(false) {} +Error RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K) { + + std::vector MemMgrsToRemove; + + getExecutionSession().runSessionLocked([&] { + auto I = MemMgrs.find(K); + if (I != MemMgrs.end()) { + std::swap(MemMgrsToRemove, I->second); + MemMgrs.erase(I); + } + }); + + { + std::lock_guard Lock(RTDyldLayerMutex); + for (auto &MemMgr : MemMgrsToRemove) { + for (auto *L : EventListeners) + L->notifyFreeingObject(pointerToJITTargetAddress(MemMgr.get())); + MemMgr->deregisterEHFrames(); + } + } + + return Error::success(); +} + +void RTDyldObjectLinkingLayer::handleTransferResources(ResourceKey DstKey, + ResourceKey SrcKey) { + auto I = MemMgrs.find(SrcKey); + if (I != MemMgrs.end()) { + auto &SrcMemMgrs = I->second; + auto &DstMemMgrs = MemMgrs[DstKey]; + DstMemMgrs.reserve(DstMemMgrs.size() + SrcMemMgrs.size()); + for (auto &MemMgr : SrcMemMgrs) + DstMemMgrs.push_back(std::move(MemMgr)); + + // Erase SrcKey entry using value rather than iterator I: I may have been + // invalidated when we looked up DstKey. + MemMgrs.erase(SrcKey); + } +} } // End namespace orc. } // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/Speculation.cpp b/llvm/lib/ExecutionEngine/Orc/Speculation.cpp index 3dd536d8253e3..0b4755fe23cfc 100644 --- a/llvm/lib/ExecutionEngine/Orc/Speculation.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Speculation.cpp @@ -55,7 +55,7 @@ Error Speculator::addSpeculationRuntime(JITDylib &JD, // If two modules, share the same LLVMContext, different threads must // not access them concurrently without locking the associated LLVMContext // this implementation follows this contract. -void IRSpeculationLayer::emit(MaterializationResponsibility R, +void IRSpeculationLayer::emit(std::unique_ptr R, ThreadSafeModule TSM) { assert(TSM && "Speculation Layer received Null Module ?"); @@ -127,7 +127,7 @@ void IRSpeculationLayer::emit(MaterializationResponsibility R, assert(Mutator.GetInsertBlock()->getParent() == &Fn && "IR builder association mismatch?"); S.registerSymbols(internToJITSymbols(IRNames.getValue()), - &R.getTargetJITDylib()); + &R->getTargetJITDylib()); } } } diff --git a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp index 18de5b616eec8..ab58641b34789 100644 --- a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp @@ -13,37 +13,55 @@ namespace orc { Expected> TPCDynamicLibrarySearchGenerator::Load(TargetProcessControl &TPC, - const char *LibraryPath) { + const char *LibraryPath, + SymbolPredicate Allow) { auto Handle = TPC.loadDylib(LibraryPath); if (!Handle) return Handle.takeError(); - return std::make_unique(TPC, *Handle); + return std::make_unique(TPC, *Handle, + std::move(Allow)); } Error TPCDynamicLibrarySearchGenerator::tryToGenerate( - LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, - const SymbolLookupSet &Symbols) { + LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { if (Symbols.empty()) return Error::success(); + SymbolLookupSet LookupSymbols; + + for (auto &KV : Symbols) { + // Skip symbols that don't match the filter. + if (Allow && !Allow(KV.first)) + continue; + LookupSymbols.add(KV.first, SymbolLookupFlags::WeaklyReferencedSymbol); + } + SymbolMap NewSymbols; - TargetProcessControl::LookupRequestElement Request(H, Symbols); + TargetProcessControl::LookupRequestElement Request(H, LookupSymbols); auto Result = TPC.lookupSymbols(Request); if (!Result) return Result.takeError(); assert(Result->size() == 1 && "Results for more than one library returned"); - assert(Result->front().size() == Symbols.size() && + assert(Result->front().size() == LookupSymbols.size() && "Result has incorrect number of elements"); + SymbolNameVector MissingSymbols; auto ResultI = Result->front().begin(); - for (auto &KV : Symbols) - NewSymbols[KV.first] = - JITEvaluatedSymbol(*ResultI++, JITSymbolFlags::Exported); + for (auto &KV : LookupSymbols) + if (*ResultI) + NewSymbols[KV.first] = + JITEvaluatedSymbol(*ResultI++, JITSymbolFlags::Exported); + + // If there were no resolved symbols bail out. + if (NewSymbols.empty()) + return Error::success(); + // Define resolved symbols. return JD.define(absoluteSymbols(std::move(NewSymbols))); } diff --git a/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp index 85dc4bec9a122..de13f064189ab 100644 --- a/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp @@ -11,6 +11,8 @@ #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h" #include "llvm/Support/MathExtras.h" +#include + using namespace llvm; using namespace llvm::orc; @@ -398,5 +400,24 @@ TPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) { return std::move(Result); } +static JITTargetAddress reentry(JITTargetAddress LCTMAddr, + JITTargetAddress TrampolineAddr) { + auto &LCTM = *jitTargetAddressToPointer(LCTMAddr); + std::promise LandingAddrP; + auto LandingAddrF = LandingAddrP.get_future(); + LCTM.resolveTrampolineLandingAddress( + TrampolineAddr, + [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); }); + return LandingAddrF.get(); +} + +Error setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils &TPCIU) { + auto &LCTM = TPCIU.getLazyCallThroughManager(); + return TPCIU + .writeResolverBlock(pointerToJITTargetAddress(&reentry), + pointerToJITTargetAddress(&LCTM)) + .takeError(); +} + } // end namespace orc } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp index 59c9ce2393c92..1e7736d1f40db 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp @@ -78,14 +78,14 @@ SelfTargetProcessControl::lookupSymbols(LookupRequest Request) { auto &Sym = KV.first; std::string Tmp((*Sym).data() + !!GlobalManglingPrefix, (*Sym).size() - !!GlobalManglingPrefix); - if (void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str())) - R.back().push_back(pointerToJITTargetAddress(Addr)); - else if (KV.second == SymbolLookupFlags::RequiredSymbol) { + void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str()); + if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) { // FIXME: Collect all failing symbols before erroring out. SymbolNameVector MissingSymbols; MissingSymbols.push_back(Sym); return make_error(std::move(MissingSymbols)); } + R.back().push_back(pointerToJITTargetAddress(Addr)); } } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 7e9b0690cceab..7b2d05163127c 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -1200,16 +1200,19 @@ Error RuntimeDyldImpl::resolveExternalSymbols() { void RuntimeDyldImpl::finalizeAsync( std::unique_ptr This, - unique_function, Error)> + unique_function, + std::unique_ptr, Error)> OnEmitted, - object::OwningBinary O) { + object::OwningBinary O, + std::unique_ptr Info) { auto SharedThis = std::shared_ptr(std::move(This)); auto PostResolveContinuation = - [SharedThis, OnEmitted = std::move(OnEmitted), O = std::move(O)]( + [SharedThis, OnEmitted = std::move(OnEmitted), O = std::move(O), + Info = std::move(Info)]( Expected Result) mutable { if (!Result) { - OnEmitted(std::move(O), Result.takeError()); + OnEmitted(std::move(O), std::move(Info), Result.takeError()); return; } @@ -1223,11 +1226,11 @@ void RuntimeDyldImpl::finalizeAsync( SharedThis->registerEHFrames(); std::string ErrMsg; if (SharedThis->MemMgr.finalizeMemory(&ErrMsg)) - OnEmitted(std::move(O), + OnEmitted(std::move(O), std::move(Info), make_error(std::move(ErrMsg), inconvertibleErrorCode())); else - OnEmitted(std::move(O), Error::success()); + OnEmitted(std::move(O), std::move(Info), Error::success()); }; JITSymbolResolver::LookupSet Symbols; @@ -1418,12 +1421,12 @@ void jitLinkForORC( object::OwningBinary O, RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver, bool ProcessAllSections, - unique_function< - Error(const object::ObjectFile &Obj, - std::unique_ptr LoadedObj, - std::map)> + unique_function)> OnLoaded, - unique_function, Error)> + unique_function, + std::unique_ptr, Error)> OnEmitted) { RuntimeDyld RTDyld(MemMgr, Resolver); @@ -1432,17 +1435,17 @@ void jitLinkForORC( auto Info = RTDyld.loadObject(*O.getBinary()); if (RTDyld.hasError()) { - OnEmitted(std::move(O), make_error(RTDyld.getErrorString(), - inconvertibleErrorCode())); + OnEmitted(std::move(O), std::move(Info), + make_error(RTDyld.getErrorString(), + inconvertibleErrorCode())); return; } - if (auto Err = - OnLoaded(*O.getBinary(), std::move(Info), RTDyld.getSymbolTable())) - OnEmitted(std::move(O), std::move(Err)); + if (auto Err = OnLoaded(*O.getBinary(), *Info, RTDyld.getSymbolTable())) + OnEmitted(std::move(O), std::move(Info), std::move(Err)); RuntimeDyldImpl::finalizeAsync(std::move(RTDyld.Dyld), std::move(OnEmitted), - std::move(O)); + std::move(O), std::move(Info)); } } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index a9346536fd095..d34fae9aaf0c8 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -535,9 +535,12 @@ class RuntimeDyldImpl { static void finalizeAsync( std::unique_ptr This, - unique_function, Error)> + unique_function, + std::unique_ptr, + Error)> OnEmitted, - object::OwningBinary O); + object::OwningBinary O, + std::unique_ptr Info); void reassignSectionAddress(unsigned SectionID, uint64_t Addr); diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h index ebe3ca33d3089..9df3e2e3c3bf1 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h @@ -113,11 +113,10 @@ class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF { // The MemoryManager can make sure this is always true by forcing the // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection. const uint64_t ImageBase = getImageBase(); - if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) { - llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an" - << "ordered section layout.\n"; - write32BitOffset(Target, 0, 0); - } else { + if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) + report_fatal_error("IMAGE_REL_AMD64_ADDR32NB relocation requires an " + "ordered section layout"); + else { write32BitOffset(Target, RE.Addend, Value - ImageBase); } break; diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 6f3bbc80d4fd5..c1f7329034e09 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -3952,6 +3952,19 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr, singleThread ? SyncScope::SingleThread : SyncScope::System)); } +unsigned LLVMGetNumMaskElements(LLVMValueRef SVInst) { + Value *P = unwrap(SVInst); + ShuffleVectorInst *I = cast(P); + return I->getShuffleMask().size(); +} + +int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) { + Value *P = unwrap(SVInst); + ShuffleVectorInst *I = cast(P); + return I->getMaskValue(Elt); +} + +int LLVMGetUndefMaskElem(void) { return UndefMaskElem; } LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { Value *P = unwrap(AtomicInst); diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index a6ee5cbb0b3c3..fd3016710298a 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -696,6 +696,38 @@ void Instruction::applyMergedLocation(const DILocation *LocA, setDebugLoc(DILocation::getMergedLocation(LocA, LocB)); } +void Instruction::updateLocationAfterHoist() { dropLocation(); } + +void Instruction::dropLocation() { + const DebugLoc &DL = getDebugLoc(); + if (!DL) + return; + + // If this isn't a call, drop the location to allow a location from a + // preceding instruction to propagate. + if (!isa(this)) { + setDebugLoc(DebugLoc()); + return; + } + + // Set a line 0 location for calls to preserve scope information in case + // inlining occurs. + const DISubprogram *SP = getFunction()->getSubprogram(); + if (SP) + // If a function scope is available, set it on the line 0 location. When + // hoisting a call to a predecessor block, using the function scope avoids + // making it look like the callee was reached earlier than it should be. + setDebugLoc(DebugLoc::get(0, 0, SP)); + else + // The parent function has no scope. Go ahead and drop the location. If + // the parent function is inlined, and the callee has a subprogram, the + // inliner will attach a location to the call. + // + // One alternative is to set a line 0 location with the existing scope and + // inlinedAt info. The location might be sensitive to when inlining occurs. + setDebugLoc(DebugLoc()); +} + //===----------------------------------------------------------------------===// // LLVM C API implementations. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index f81e947dc94c2..2e9c2e4af90df 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2404,6 +2404,10 @@ void Verifier::visitFunction(const Function &F) { "function must have a single !dbg attachment", &F, I.second); AssertDI(isa(I.second), "function !dbg attachment must be a subprogram", &F, I.second); + AssertDI(cast(I.second)->isDistinct(), + "function definition may only have a distinct !dbg attachment", + &F); + auto *SP = cast(I.second); const Function *&AttachedTo = DISubprogramAttachments[SP]; AssertDI(!AttachedTo || AttachedTo == &F, diff --git a/llvm/lib/InterfaceStub/CMakeLists.txt b/llvm/lib/InterfaceStub/CMakeLists.txt new file mode 100644 index 0000000000000..af702e58479a7 --- /dev/null +++ b/llvm/lib/InterfaceStub/CMakeLists.txt @@ -0,0 +1,5 @@ +add_llvm_component_library(LLVMInterfaceStub + ELFObjHandler.cpp + ELFStub.cpp + TBEHandler.cpp +) diff --git a/llvm/tools/llvm-elfabi/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp similarity index 91% rename from llvm/tools/llvm-elfabi/ELFObjHandler.cpp rename to llvm/lib/InterfaceStub/ELFObjHandler.cpp index 124fffbb9cf6a..82e7a3c8b1baa 100644 --- a/llvm/tools/llvm-elfabi/ELFObjHandler.cpp +++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp @@ -6,14 +6,14 @@ // //===-----------------------------------------------------------------------===/ -#include "ELFObjHandler.h" +#include "llvm/InterfaceStub/ELFObjHandler.h" +#include "llvm/InterfaceStub/ELFStub.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/TextAPI/ELF/ELFStub.h" using llvm::MemoryBufferRef; using llvm::object::ELFObjectFile; @@ -128,19 +128,17 @@ static Error populateDynamic(DynamicEntries &Dyn, "Couldn't locate dynamic symbol table (no DT_SYMTAB entry)"); } if (Dyn.SONameOffset.hasValue() && *Dyn.SONameOffset >= Dyn.StrSize) { - return createStringError( - object_error::parse_failed, - "DT_SONAME string offset (0x%016" PRIx64 - ") outside of dynamic string table", - *Dyn.SONameOffset); + return createStringError(object_error::parse_failed, + "DT_SONAME string offset (0x%016" PRIx64 + ") outside of dynamic string table", + *Dyn.SONameOffset); } for (uint64_t Offset : Dyn.NeededLibNames) { if (Offset >= Dyn.StrSize) { - return createStringError( - object_error::parse_failed, - "DT_NEEDED string offset (0x%016" PRIx64 - ") outside of dynamic string table", - Offset); + return createStringError(object_error::parse_failed, + "DT_NEEDED string offset (0x%016" PRIx64 + ") outside of dynamic string table", + Offset); } } @@ -212,16 +210,16 @@ static Expected getNumSyms(DynamicEntries &Dyn, static ELFSymbolType convertInfoToType(uint8_t Info) { Info = Info & 0xf; switch (Info) { - case ELF::STT_NOTYPE: - return ELFSymbolType::NoType; - case ELF::STT_OBJECT: - return ELFSymbolType::Object; - case ELF::STT_FUNC: - return ELFSymbolType::Func; - case ELF::STT_TLS: - return ELFSymbolType::TLS; - default: - return ELFSymbolType::Unknown; + case ELF::STT_NOTYPE: + return ELFSymbolType::NoType; + case ELF::STT_OBJECT: + return ELFSymbolType::Object; + case ELF::STT_FUNC: + return ELFSymbolType::Func; + case ELF::STT_TLS: + return ELFSymbolType::TLS; + default: + return ELFSymbolType::Unknown; } } @@ -259,8 +257,8 @@ static ELFSymbol createELFSym(StringRef SymName, /// @param DynStr StringRef to the dynamic string table. template static Error populateSymbols(ELFStub &TargetStub, - const typename ELFT::SymRange DynSym, - StringRef DynStr) { + const typename ELFT::SymRange DynSym, + StringRef DynStr) { // Skips the first symbol since it's the NULL symbol. for (auto RawSym : DynSym.drop_front(1)) { // If a symbol does not have global or weak binding, ignore it. @@ -311,7 +309,7 @@ buildStub(const ELFObjectFile &ElfObj) { if (Error Err = populateDynamic(DynEnt, *DynTable)) return std::move(Err); - // Get pointer to in-memory location of .dynstr section. + // Get pointer to in-memory location of .dynstr section. Expected DynStrPtr = ElfFile->toMappedAddr(DynEnt.StrTabAddr); if (!DynStrPtr) @@ -355,9 +353,8 @@ buildStub(const ELFObjectFile &ElfObj) { if (!DynSymPtr) return appendToError(DynSymPtr.takeError(), "when locating .dynsym section contents"); - Elf_Sym_Range DynSyms = - ArrayRef(reinterpret_cast(*DynSymPtr), - *SymCount); + Elf_Sym_Range DynSyms = ArrayRef( + reinterpret_cast(*DynSymPtr), *SymCount); Error SymReadError = populateSymbols(*DestStub, DynSyms, DynStr); if (SymReadError) return appendToError(std::move(SymReadError), diff --git a/llvm/lib/TextAPI/ELF/ELFStub.cpp b/llvm/lib/InterfaceStub/ELFStub.cpp similarity index 95% rename from llvm/lib/TextAPI/ELF/ELFStub.cpp rename to llvm/lib/InterfaceStub/ELFStub.cpp index f8463497093b1..3c637695d8e71 100644 --- a/llvm/lib/TextAPI/ELF/ELFStub.cpp +++ b/llvm/lib/InterfaceStub/ELFStub.cpp @@ -6,7 +6,7 @@ // //===-----------------------------------------------------------------------===/ -#include "llvm/TextAPI/ELF/ELFStub.h" +#include "llvm/InterfaceStub/ELFStub.h" using namespace llvm; using namespace llvm::elfabi; diff --git a/llvm/lib/InterfaceStub/LLVMBuild.txt b/llvm/lib/InterfaceStub/LLVMBuild.txt new file mode 100644 index 0000000000000..e69544d4f5f67 --- /dev/null +++ b/llvm/lib/InterfaceStub/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./lib/InterfaceStub/LLVMBuild.txt ------------------------*- Conf -*--===; +; +; 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 +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = InterfaceStub +parent = Libraries +required_libraries = Object Support diff --git a/llvm/lib/TextAPI/ELF/TBEHandler.cpp b/llvm/lib/InterfaceStub/TBEHandler.cpp similarity index 85% rename from llvm/lib/TextAPI/ELF/TBEHandler.cpp rename to llvm/lib/InterfaceStub/TBEHandler.cpp index cb597d8896e81..ee95d21ee6618 100644 --- a/llvm/lib/TextAPI/ELF/TBEHandler.cpp +++ b/llvm/lib/InterfaceStub/TBEHandler.cpp @@ -6,12 +6,12 @@ // //===-----------------------------------------------------------------------===/ -#include "llvm/TextAPI/ELF/TBEHandler.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/InterfaceStub/TBEHandler.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/InterfaceStub/ELFStub.h" #include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" -#include "llvm/TextAPI/ELF/ELFStub.h" using namespace llvm; using namespace llvm::elfabi; @@ -69,28 +69,6 @@ template <> struct ScalarTraits { static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; -/// YAML traits for TbeVersion. -template <> struct ScalarTraits { - static void output(const VersionTuple &Value, void *, - llvm::raw_ostream &Out) { - Out << Value.getAsString(); - } - - static StringRef input(StringRef Scalar, void *, VersionTuple &Value) { - if (Value.tryParse(Scalar)) - return StringRef("Can't parse version: invalid version format."); - - if (Value > TBEVersionCurrent) - return StringRef("Unsupported TBE version."); - - // Returning empty StringRef indicates successful parse. - return StringRef(); - } - - // Don't place quotation marks around version value. - static QuotingType mustQuote(StringRef) { return QuotingType::None; } -}; - /// YAML traits for ELFSymbol. template <> struct MappingTraits { static void mapping(IO &IO, ELFSymbol &Symbol) { @@ -149,6 +127,11 @@ Expected> elfabi::readTBEFromBuffer(StringRef Buf) { if (std::error_code Err = YamlIn.error()) return createStringError(Err, "YAML failed reading as TBE"); + if (Stub->TbeVersion > elfabi::TBEVersionCurrent) + return make_error( + "TBE version " + Stub->TbeVersion.getAsString() + " is unsupported.", + std::make_error_code(std::errc::invalid_argument)); + return std::move(Stub); } diff --git a/llvm/lib/LLVMBuild.txt b/llvm/lib/LLVMBuild.txt index 824abd36fc998..a81c6a1fe3fa4 100644 --- a/llvm/lib/LLVMBuild.txt +++ b/llvm/lib/LLVMBuild.txt @@ -30,6 +30,7 @@ subdirectories = FuzzMutate LineEditor Linker + InterfaceStub IR IRReader LTO diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 70f00d333db17..30cead95cbee6 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -807,6 +807,8 @@ static std::string getCoverageMapErrString(coveragemap_error Err) { return "Malformed coverage data"; case coveragemap_error::decompression_failed: return "Failed to decompress coverage data (zlib)"; + case coveragemap_error::invalid_or_missing_arch_specifier: + return "`-arch` specifier is invalid or missing for universal binary"; } llvm_unreachable("A value of coveragemap_error has no message."); } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index b75738bc360ce..4936638c61cc9 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -950,6 +950,19 @@ loadBinaryFormat(std::unique_ptr Bin, StringRef Arch) { BytesInAddress, Endian); } +/// Determine whether \p Arch is invalid or empty, given \p Bin. +static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) { + // If we have a universal binary and Arch doesn't identify any of its slices, + // it's user error. + if (auto *Universal = dyn_cast(Bin)) { + for (auto &ObjForArch : Universal->objects()) + if (Arch == ObjForArch.getArchFlagName()) + return false; + return true; + } + return false; +} + Expected>> BinaryCoverageReader::create( MemoryBufferRef ObjectBuffer, StringRef Arch, @@ -970,6 +983,10 @@ BinaryCoverageReader::create( return BinOrErr.takeError(); std::unique_ptr Bin = std::move(BinOrErr.get()); + if (isArchSpecifierInvalidOrMissing(Bin.get(), Arch)) + return make_error( + coveragemap_error::invalid_or_missing_arch_specifier); + // MachO universal binaries which contain archives need to be treated as // archives, not as regular binaries. if (auto *Universal = dyn_cast(Bin.get())) { diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 569cac790af99..362595d8f8b1c 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -2242,6 +2242,21 @@ IEEEFloat::opStatus IEEEFloat::convert(const fltSemantics &toSemantics, if (!X86SpecialNan && semantics == &semX87DoubleExtended) APInt::tcSetBit(significandParts(), semantics->precision - 1); + // If we are truncating NaN, it is possible that we shifted out all of the + // set bits in a signalling NaN payload. But NaN must remain NaN, so some + // bit in the significand must be set (otherwise it is Inf). + // This can only happen with sNaN. Set the 1st bit after the quiet bit, + // so that we still have an sNaN. + // FIXME: Set quiet and return opInvalidOp (on convert of any sNaN). + // But this requires fixing LLVM to parse 32-bit hex FP or ignoring + // conversions while parsing IR. + if (APInt::tcIsZero(significandParts(), newPartCount)) { + assert(shift < 0 && "Should not lose NaN payload on extend"); + assert(semantics->precision >= 3 && "Unexpectedly narrow significand"); + assert(*losesInfo && "Missing payload should have set lost info"); + APInt::tcSetBit(significandParts(), semantics->precision - 3); + } + // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) // does not give you back the same bits. This is dubious, and we // don't currently do it. You're really supposed to get diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp index 9ac7c65e19f73..10c5d3eef1ae5 100644 --- a/llvm/lib/Support/YAMLTraits.cpp +++ b/llvm/lib/Support/YAMLTraits.cpp @@ -1087,3 +1087,15 @@ StringRef ScalarTraits::input(StringRef Scalar, void *, Hex64 &Val) { Val = Num; return StringRef(); } + +void ScalarTraits::output(const VersionTuple &Val, void *, + llvm::raw_ostream &Out) { + Out << Val.getAsString(); +} + +StringRef ScalarTraits::input(StringRef Scalar, void *, + VersionTuple &Val) { + if (Val.tryParse(Scalar)) + return "invalid version format"; + return StringRef(); +} diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp index 11a8d5def4296..4832ae8f415f2 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -84,11 +84,16 @@ struct IncomingArgHandler : public CallLowering::ValueHandler { } } - void assignValueToAddress(Register ValVReg, Register Addr, uint64_t Size, + void assignValueToAddress(Register ValVReg, Register Addr, uint64_t MemSize, MachinePointerInfo &MPO, CCValAssign &VA) override { MachineFunction &MF = MIRBuilder.getMF(); + + // The reported memory location may be wider than the value. + const LLT RegTy = MRI.getType(ValVReg); + MemSize = std::min(static_cast(RegTy.getSizeInBytes()), MemSize); + auto MMO = MF.getMachineMemOperand( - MPO, MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant, Size, + MPO, MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant, MemSize, inferAlignFromPtrInfo(MF, MPO)); MIRBuilder.buildLoad(ValVReg, Addr, *MMO); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp index 05a4e3462a263..949dcea3aa188 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp @@ -129,13 +129,17 @@ struct IncomingArgHandler : public CallLowering::ValueHandler { } } - void assignValueToAddress(Register ValVReg, Register Addr, uint64_t Size, + void assignValueToAddress(Register ValVReg, Register Addr, uint64_t MemSize, MachinePointerInfo &MPO, CCValAssign &VA) override { MachineFunction &MF = MIRBuilder.getMF(); + // The reported memory location may be wider than the value. + const LLT RegTy = MRI.getType(ValVReg); + MemSize = std::min(static_cast(RegTy.getSizeInBytes()), MemSize); + // FIXME: Get alignment auto MMO = MF.getMachineMemOperand( - MPO, MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant, Size, + MPO, MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant, MemSize, inferAlignFromPtrInfo(MF, MPO)); MIRBuilder.buildLoad(ValVReg, Addr, *MMO); } diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt index 36528f0995d8e..b63bc64b31f14 100644 --- a/llvm/lib/TextAPI/CMakeLists.txt +++ b/llvm/lib/TextAPI/CMakeLists.txt @@ -1,6 +1,4 @@ add_llvm_component_library(LLVMTextAPI - ELF/ELFStub.cpp - ELF/TBEHandler.cpp MachO/Architecture.cpp MachO/ArchitectureSet.cpp MachO/InterfaceFile.cpp diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 17a5ec3f87fa3..e444af31de057 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2526,10 +2526,10 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { // If we are removing an alloca with a dbg.declare, insert dbg.value calls // before each store. - TinyPtrVector DIIs; + SmallVector DVIs; std::unique_ptr DIB; if (isa(MI)) { - DIIs = FindDbgAddrUses(&MI); + findDbgUsers(DVIs, &MI); DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); } @@ -2563,8 +2563,9 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { ConstantInt::get(Type::getInt1Ty(C->getContext()), C->isFalseWhenEqual())); } else if (auto *SI = dyn_cast(I)) { - for (auto *DII : DIIs) - ConvertDebugDeclareToDebugValue(DII, SI, *DIB); + for (auto *DVI : DVIs) + if (DVI->isAddressOfVariable()) + ConvertDebugDeclareToDebugValue(DVI, SI, *DIB); } else { // Casts, GEP, or anything else: we're about to delete this instruction, // so it can not have any valid uses. @@ -2581,8 +2582,31 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { None, "", II->getParent()); } - for (auto *DII : DIIs) - eraseInstFromFunction(*DII); + // Remove debug intrinsics which describe the value contained within the + // alloca. In addition to removing dbg.{declare,addr} which simply point to + // the alloca, remove dbg.value(, ..., DW_OP_deref)'s as well, e.g.: + // + // ``` + // define void @foo(i32 %0) { + // %a = alloca i32 ; Deleted. + // store i32 %0, i32* %a + // dbg.value(i32 %0, "arg0") ; Not deleted. + // dbg.value(i32* %a, "arg0", DW_OP_deref) ; Deleted. + // call void @trivially_inlinable_no_op(i32* %a) + // ret void + // } + // ``` + // + // This may not be required if we stop describing the contents of allocas + // using dbg.value(, ..., DW_OP_deref), but we currently do this in + // the LowerDbgDeclare utility. + // + // If there is a dead store to `%a` in @trivially_inlinable_no_op, the + // "arg0" dbg.value may be stale after the call. However, failing to remove + // the DW_OP_deref dbg.value causes large gaps in location coverage. + for (auto *DVI : DVIs) + if (DVI->isAddressOfVariable() || DVI->getExpression()->startsWithDeref()) + DVI->eraseFromParent(); return eraseInstFromFunction(MI); } diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp index b16f8591b5a46..3953ac52ba277 100644 --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -46,7 +46,6 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" @@ -1251,8 +1250,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, // Instructions that have been inserted in predecessor(s) to materialize // the load address do not retain their original debug locations. Doing // so could lead to confusing (but correct) source attributions. - if (const DebugLoc &DL = I->getDebugLoc()) - I->setDebugLoc(DebugLoc::get(0, 0, DL.getScope(), DL.getInlinedAt())); + I->updateLocationAfterHoist(); // FIXME: We really _ought_ to insert these value numbers into their // parent's availability map. However, in doing so, we risk getting into diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 1a22edaf87266..1adf3c4236aa2 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -1658,10 +1658,7 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop, // Move the new node to the destination block, before its terminator. moveInstructionBefore(I, *Dest->getTerminator(), *SafetyInfo, MSSAU, SE); - // Apply line 0 debug locations when we are moving instructions to different - // basic blocks because we want to avoid jumpy line tables. - if (const DebugLoc &DL = I.getDebugLoc()) - I.setDebugLoc(DebugLoc::get(0, 0, DL.getScope(), DL.getInlinedAt())); + I.updateLocationAfterHoist(); if (isa(I)) ++NumMovedLoads; diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt index d56f7af583eda..c58b864376a7d 100644 --- a/llvm/runtimes/CMakeLists.txt +++ b/llvm/runtimes/CMakeLists.txt @@ -105,10 +105,6 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) # Avoid checking whether the compiler is working. set(LLVM_COMPILER_CHECKED ON) - # Enable warnings, otherwise -w gets added to the cflags by HandleLLVMOptions - # resulting in unjustified successes by check_cxx_compiler_flag. - set(LLVM_ENABLE_WARNINGS ON) - # Handle common options used by all runtimes. include(AddLLVM) include(HandleLLVMOptions) diff --git a/llvm/test/Assembler/disubprogram.ll b/llvm/test/Assembler/disubprogram.ll index 10bd5520d84dc..6feb27ce48012 100644 --- a/llvm/test/Assembler/disubprogram.ll +++ b/llvm/test/Assembler/disubprogram.ll @@ -25,8 +25,8 @@ define void @_Z3foov() !dbg !9 { isOptimized: true, flags: "-O2", splitDebugFilename: "abc.debug", emissionKind: 2) -; CHECK: !9 = !DISubprogram(scope: null, spFlags: 0) -!9 = !DISubprogram(isDefinition: false) +; CHECK: !9 = distinct !DISubprogram(scope: null, spFlags: 0) +!9 = distinct !DISubprogram(isDefinition: false) ; CHECK: !10 = distinct !DISubprogram(name: "foo", linkageName: "_Zfoov", scope: !1, file: !2, line: 7, type: !3, scopeLine: 8, containingType: !4, virtualIndex: 10, thisAdjustment: 3, flags: DIFlagPrototyped | DIFlagNoReturn, spFlags: DISPFlagPureVirtual | DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !8, templateParams: !5, declaration: !9, retainedNodes: !6) !10 = distinct !DISubprogram(name: "foo", linkageName: "_Zfoov", scope: !1, diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll index 510798592b9d3..5494170f3cd65 100644 --- a/llvm/test/Bindings/llvm-c/echo.ll +++ b/llvm/test/Bindings/llvm-c/echo.ll @@ -156,6 +156,24 @@ define void @memops(i8* %ptr) { ret void } +define i32 @vectorops(i32, i32) { + %a = insertelement <4 x i32> undef, i32 %0, i32 0 + %b = insertelement <4 x i32> %a, i32 %1, i32 2 + %c = shufflevector <4 x i32> %b, <4 x i32> undef, <4 x i32> zeroinitializer + %d = shufflevector <4 x i32> %c, <4 x i32> %b, <4 x i32> + %e = add <4 x i32> %d, %a + %f = mul <4 x i32> %e, %b + %g = xor <4 x i32> %f, %d + %h = or <4 x i32> %f, %e + %i = lshr <4 x i32> %h, + %j = shl <4 x i32> %i, + %k = shufflevector <4 x i32> %j, <4 x i32> %i, <4 x i32> + %m = shufflevector <4 x i32> %k, <4 x i32> undef, <1 x i32> + %n = shufflevector <4 x i32> %j, <4 x i32> undef, <8 x i32> + %p = extractelement <8 x i32> %n, i32 5 + ret i32 %p +} + declare void @personalityFn() define void @exn() personality void ()* @personalityFn { diff --git a/llvm/test/Bitcode/DISubprogram-v4.ll b/llvm/test/Bitcode/DISubprogram-v4.ll index ce5521002cafb..9e5caecd7361a 100644 --- a/llvm/test/Bitcode/DISubprogram-v4.ll +++ b/llvm/test/Bitcode/DISubprogram-v4.ll @@ -24,8 +24,8 @@ define void @_Z3foov() !dbg !9 { !8 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", file: !2, isOptimized: true, flags: "-O2") -; CHECK: !9 = !DISubprogram(scope: null, spFlags: 0) -!9 = !DISubprogram(isDefinition: false) +; CHECK: !9 = distinct !DISubprogram(scope: null, spFlags: 0) +!9 = distinct !DISubprogram(isDefinition: false) ; CHECK: !10 = distinct !DISubprogram({{.*}}, spFlags: DISPFlagPureVirtual | DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, !10 = distinct !DISubprogram(name: "foo", linkageName: "_Zfoov", scope: !1, diff --git a/llvm/test/Bitcode/DISubprogram-v4.ll.bc b/llvm/test/Bitcode/DISubprogram-v4.ll.bc index 392df4aae74d3..41bbcf874ac14 100644 Binary files a/llvm/test/Bitcode/DISubprogram-v4.ll.bc and b/llvm/test/Bitcode/DISubprogram-v4.ll.bc differ diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-evt-bug47619.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-evt-bug47619.ll new file mode 100644 index 0000000000000..ca36e5da5e5fb --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-evt-bug47619.ll @@ -0,0 +1,26 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -global-isel -mtriple=aarch64-unknown-unknown -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s + +; Make sure the i3 %arg8 value is correctly handled. This was trying +; to use MVT for EVT values passed on the stack and asserting before +; b98f902f1877c3d679f77645a267edc89ffcd5d6 +define i3 @bug47619(i64 %arg, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %arg5, i64 %arg6, i64 %arg7, i3 %arg8) { + ; CHECK-LABEL: name: bug47619 + ; CHECK: bb.1.bb: + ; CHECK: liveins: $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK: [[COPY3:%[0-9]+]]:_(s64) = COPY $x3 + ; CHECK: [[COPY4:%[0-9]+]]:_(s64) = COPY $x4 + ; CHECK: [[COPY5:%[0-9]+]]:_(s64) = COPY $x5 + ; CHECK: [[COPY6:%[0-9]+]]:_(s64) = COPY $x6 + ; CHECK: [[COPY7:%[0-9]+]]:_(s64) = COPY $x7 + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0 + ; CHECK: [[LOAD:%[0-9]+]]:_(s3) = G_LOAD [[FRAME_INDEX]](p0) :: (invariant load 1 from %fixed-stack.0, align 16) + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD]](s3) + ; CHECK: $w0 = COPY [[ANYEXT]](s32) + ; CHECK: RET_ReallyLR implicit $w0 +bb: + ret i3 %arg8 +} diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir index 3260eb6ca6fd2..187ddebd9804b 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir @@ -28,8 +28,8 @@ body: | ; CHECK-LABEL: name: test_smul_overflow ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 - ; CHECK: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]] ; CHECK: [[SMULH:%[0-9]+]]:_(s64) = G_SMULH [[COPY]], [[COPY1]] + ; CHECK: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]] ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 63 ; CHECK: [[ASHR:%[0-9]+]]:_(s64) = G_ASHR [[MUL]], [[C]] ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[SMULH]](s64), [[ASHR]] @@ -51,9 +51,9 @@ body: | ; CHECK-LABEL: name: test_umul_overflow ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 - ; CHECK: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]] ; CHECK: [[UMULH:%[0-9]+]]:_(s64) = G_UMULH [[COPY]], [[COPY1]] ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0 + ; CHECK: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]] ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[UMULH]](s64), [[C]] ; CHECK: $x0 = COPY [[MUL]](s64) ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[ICMP]](s32) @@ -66,3 +66,67 @@ body: | $w0 = COPY %4(s32) ... +--- +name: test_umulo_overflow_no_invalid_mir +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x0' } + - { reg: '$x1' } + - { reg: '$x2' } +frameInfo: + maxAlignment: 16 +stack: + - { id: 0, size: 8, alignment: 8 } + - { id: 1, size: 8, alignment: 8 } + - { id: 2, size: 16, alignment: 16 } + - { id: 3, size: 16, alignment: 8 } +machineFunctionInfo: {} +body: | + bb.1: + liveins: $x0, $x1, $x2 + ; Check that the overflow result doesn't generate incorrect MIR by using a G_CONSTANT 0 + ; before it's been defined. + ; CHECK-LABEL: name: test_umulo_overflow_no_invalid_mir + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1 + ; CHECK: [[FRAME_INDEX2:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.3 + ; CHECK: G_STORE [[COPY2]](s64), [[FRAME_INDEX]](p0) :: (store 8) + ; CHECK: G_STORE [[COPY1]](s64), [[FRAME_INDEX1]](p0) :: (store 8) + ; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX]](p0) :: (dereferenceable load 8) + ; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX1]](p0) :: (dereferenceable load 8) + ; CHECK: [[UMULH:%[0-9]+]]:_(s64) = G_UMULH [[LOAD]], [[LOAD1]] + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0 + ; CHECK: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[LOAD]], [[LOAD1]] + ; CHECK: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[UMULH]](s64), [[C]] + ; CHECK: G_STORE [[C]](s64), [[FRAME_INDEX2]](p0) :: (store 8, align 1) + ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1 + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[ICMP]](s32) + ; CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[ANYEXT]], [[C1]] + ; CHECK: $x0 = COPY [[MUL]](s64) + ; CHECK: $x1 = COPY [[AND]](s64) + ; CHECK: RET_ReallyLR implicit $x0 + %0:_(p0) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %25:_(s32) = G_CONSTANT i32 0 + %3:_(p0) = G_FRAME_INDEX %stack.0 + %4:_(p0) = G_FRAME_INDEX %stack.1 + %6:_(p0) = G_FRAME_INDEX %stack.3 + G_STORE %2(s64), %3(p0) :: (store 8) + G_STORE %1(s64), %4(p0) :: (store 8) + %7:_(s64) = G_LOAD %3(p0) :: (dereferenceable load 8) + %8:_(s64) = G_LOAD %4(p0) :: (dereferenceable load 8) + %9:_(s64), %10:_(s1) = G_UMULO %7, %8 + %31:_(s64) = G_CONSTANT i64 0 + G_STORE %31(s64), %6(p0) :: (store 8, align 1) + %16:_(s64) = G_ZEXT %10(s1) + $x0 = COPY %9(s64) + $x1 = COPY %16(s64) + RET_ReallyLR implicit $x0 + +... diff --git a/llvm/test/CodeGen/Mips/GlobalISel/legalizer/mul.mir b/llvm/test/CodeGen/Mips/GlobalISel/legalizer/mul.mir index c92a55d0af322..b146aa5ff13d5 100644 --- a/llvm/test/CodeGen/Mips/GlobalISel/legalizer/mul.mir +++ b/llvm/test/CodeGen/Mips/GlobalISel/legalizer/mul.mir @@ -439,9 +439,9 @@ body: | ; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1 ; MIPS32: [[COPY2:%[0-9]+]]:_(p0) = COPY $a2 ; MIPS32: [[COPY3:%[0-9]+]]:_(p0) = COPY $a3 - ; MIPS32: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY]], [[COPY1]] ; MIPS32: [[UMULH:%[0-9]+]]:_(s32) = G_UMULH [[COPY]], [[COPY1]] ; MIPS32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; MIPS32: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY]], [[COPY1]] ; MIPS32: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[UMULH]](s32), [[C]] ; MIPS32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; MIPS32: [[COPY4:%[0-9]+]]:_(s32) = COPY [[ICMP]](s32) diff --git a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/mul.ll b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/mul.ll index 659eadf181c02..f7250ccde898f 100644 --- a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/mul.ll +++ b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/mul.ll @@ -180,13 +180,13 @@ declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) define void @umul_with_overflow(i32 %lhs, i32 %rhs, i32* %pmul, i1* %pcarry_flag) { ; MIPS32-LABEL: umul_with_overflow: ; MIPS32: # %bb.0: -; MIPS32-NEXT: mul $1, $4, $5 ; MIPS32-NEXT: multu $4, $5 -; MIPS32-NEXT: mfhi $2 -; MIPS32-NEXT: sltu $2, $zero, $2 -; MIPS32-NEXT: andi $2, $2, 1 -; MIPS32-NEXT: sb $2, 0($7) -; MIPS32-NEXT: sw $1, 0($6) +; MIPS32-NEXT: mfhi $1 +; MIPS32-NEXT: mul $2, $4, $5 +; MIPS32-NEXT: sltu $1, $zero, $1 +; MIPS32-NEXT: andi $1, $1, 1 +; MIPS32-NEXT: sb $1, 0($7) +; MIPS32-NEXT: sw $2, 0($6) ; MIPS32-NEXT: jr $ra ; MIPS32-NEXT: nop %res = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %lhs, i32 %rhs) diff --git a/llvm/test/CodeGen/Mips/emit-big-cst.ll b/llvm/test/CodeGen/Mips/emit-big-cst.ll index 67c2f107db19a..679824ef047b6 100644 --- a/llvm/test/CodeGen/Mips/emit-big-cst.ll +++ b/llvm/test/CodeGen/Mips/emit-big-cst.ll @@ -16,6 +16,14 @@ ; LE-NEXT: .space 5 ; LE-NEXT: .size bigCst, 16 +; BE-LABEL: notSoBigCst: +; BE-NEXT: .8byte 72057594037927935 +; BE-NEXT: .size notSoBigCst, 8 + +; LE-LABEL: notSoBigCst: +; LE-NEXT: .8byte 72057594037927935 +; LE-NEXT: .size notSoBigCst, 8 + ; BE-LABEL: smallCst: ; BE-NEXT: .2byte 4386 ; BE-NEXT: .byte 51 @@ -38,4 +46,14 @@ define void @accessBig(i64* %storage) { ret void } +@notSoBigCst = internal constant i57 72057594037927935 + +define void @accessNotSoBig(i64* %storage) { + %addr = bitcast i64* %storage to i57* + %bigLoadedCst = load volatile i57, i57* @notSoBigCst + %tmp = add i57 %bigLoadedCst, 1 + store i57 %tmp, i57* %addr + ret void +} + @smallCst = internal constant i24 1122867 diff --git a/llvm/test/CodeGen/X86/pr47517.ll b/llvm/test/CodeGen/X86/pr47517.ll index 5672fbc69a41d..afc27b49ab2a4 100644 --- a/llvm/test/CodeGen/X86/pr47517.ll +++ b/llvm/test/CodeGen/X86/pr47517.ll @@ -26,3 +26,16 @@ entry: %fmul6 = fmul fast float %fmul3, %fadd4 ret float %fmul6 } + +; To ensure negated result will not be removed when NegX=NegY and +; NegX is needed +define float @test2(float %x, float %y) { + %add = fadd fast float %x, 750.0 + %sub = fsub fast float %x, %add + %mul = fmul fast float %sub, %sub + %mul2 = fmul fast float %mul, %sub + %add2 = fadd fast float %mul2, 1.0 + %add3 = fadd fast float %mul2, %add2 + %mul3 = fmul fast float %y, %add3 + ret float %mul3 +} diff --git a/llvm/test/CodeGen/X86/tail-dup-asm-goto.ll b/llvm/test/CodeGen/X86/tail-dup-asm-goto.ll new file mode 100644 index 0000000000000..77aa3adf0fc69 --- /dev/null +++ b/llvm/test/CodeGen/X86/tail-dup-asm-goto.ll @@ -0,0 +1,61 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -mtriple=x86_64-linux -stop-after=early-tailduplication < %s | FileCheck %s + +; Ensure that we don't duplicate a block with an "INLINEASM_BR" instruction +; during code gen. +declare void @foo() + +define i8* @test1(i8** %arg1, i8* %arg2) { + ; CHECK-LABEL: name: test1 + ; CHECK: bb.0.bb: + ; CHECK: successors: %bb.1(0x50000000), %bb.2(0x30000000) + ; CHECK: liveins: $rdi, $rsi + ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi + ; CHECK: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 0, $noreg :: (load 8 from %ir.arg1) + ; CHECK: [[SUB64rr:%[0-9]+]]:gr64 = SUB64rr [[MOV64rm]], [[COPY]], implicit-def $eflags + ; CHECK: JCC_1 %bb.2, 4, implicit $eflags + ; CHECK: JMP_1 %bb.1 + ; CHECK: bb.1.bb100: + ; CHECK: successors: %bb.3(0x80000000) + ; CHECK: MOV64mi32 [[COPY1]], 1, $noreg, 0, $noreg, 0 :: (store 8 into %ir.arg1) + ; CHECK: JMP_1 %bb.3 + ; CHECK: bb.2.bb106: + ; CHECK: successors: %bb.3(0x80000000) + ; CHECK: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp + ; CHECK: CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp + ; CHECK: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp + ; CHECK: bb.3.bb110: + ; CHECK: successors: %bb.5(0x80000000), %bb.4(0x00000000) + ; CHECK: [[PHI:%[0-9]+]]:gr64 = PHI [[COPY]], %bb.2, [[MOV64rm]], %bb.1 + ; CHECK: INLINEASM_BR &"#$0 $1 $2", 9 /* sideeffect mayload attdialect */, 13 /* imm */, 42, 13 /* imm */, 0, 13 /* imm */, blockaddress(@test1, %ir-block.bb17.i.i.i), 12 /* clobber */, implicit-def early-clobber $df, 12 /* clobber */, implicit-def early-clobber $fpsw, 12 /* clobber */, implicit-def early-clobber $eflags + ; CHECK: JMP_1 %bb.5 + ; CHECK: bb.4.bb17.i.i.i (address-taken): + ; CHECK: successors: %bb.5(0x80000000) + ; CHECK: bb.5.kmem_cache_has_cpu_partial.exit: + ; CHECK: $rax = COPY [[PHI]] + ; CHECK: RET 0, $rax +bb: + %i28.i = load i8*, i8** %arg1, align 8 + %if = icmp ne i8* %i28.i, %arg2 + br i1 %if, label %bb100, label %bb106 + +bb100: ; preds = %bb + store i8* null, i8** %arg1, align 8 + br label %bb110 + +bb106: ; preds = %bb + call void @foo() + br label %bb110 + +bb110: ; preds = %bb106, %bb100 + %i10.1 = phi i8* [ %arg2, %bb106 ], [ %i28.i, %bb100 ] + callbr void asm sideeffect "#$0 $1 $2", "i,i,X,~{dirflag},~{fpsr},~{flags}"(i32 42, i1 false, i8* blockaddress(@test1, %bb17.i.i.i)) + to label %kmem_cache_has_cpu_partial.exit [label %bb17.i.i.i] + +bb17.i.i.i: ; preds = %bb110 + br label %kmem_cache_has_cpu_partial.exit + +kmem_cache_has_cpu_partial.exit: ; preds = %bb110 + ret i8* %i10.1 +} diff --git a/llvm/test/DebugInfo/Generic/2009-11-03-InsertExtractValue.ll b/llvm/test/DebugInfo/Generic/2009-11-03-InsertExtractValue.ll index 57ee7ebbb2cb3..81bb5f2457ed9 100644 --- a/llvm/test/DebugInfo/Generic/2009-11-03-InsertExtractValue.ll +++ b/llvm/test/DebugInfo/Generic/2009-11-03-InsertExtractValue.ll @@ -3,7 +3,7 @@ !llvm.module.flags = !{!6} !llvm.dbg.cu = !{!5} -!0 = !DISubprogram(name: "bar", linkageName: "_ZN3foo3barEv", line: 3, isLocal: false, isDefinition: false, virtualIndex: 6, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: false, scopeLine: 3, file: !4, scope: !1, type: !2) +!0 = distinct !DISubprogram(name: "bar", linkageName: "_ZN3foo3barEv", line: 3, isLocal: false, isDefinition: false, virtualIndex: 6, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: false, scopeLine: 3, file: !4, scope: !1, type: !2) !1 = !DIFile(filename: "/foo", directory: "bar.cpp") !2 = !DISubroutineType(types: !3) !3 = !{null} diff --git a/llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll b/llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll index 0a13e9604f0c8..37c642170aa39 100644 --- a/llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll +++ b/llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll @@ -18,9 +18,8 @@ ; We make sure that the instruction that is hoisted into the preheader ; does not have a debug location. ; CHECK: for.body.lr.ph: -; CHECK: getelementptr{{.*}}%p.addr, i64 4{{.*}} !dbg [[zero:![0-9]+]] +; CHECK: getelementptr{{.*}}%p.addr, i64 4{{$}} ; CHECK: for.body: -; CHECK: [[zero]] = !DILocation(line: 0 ; ; ModuleID = 't.ll' source_filename = "test.c" diff --git a/llvm/test/DebugInfo/X86/skeleton-unit-verify.s b/llvm/test/DebugInfo/X86/skeleton-unit-verify.s index d990d918cef6f..95fbd113942a4 100644 --- a/llvm/test/DebugInfo/X86/skeleton-unit-verify.s +++ b/llvm/test/DebugInfo/X86/skeleton-unit-verify.s @@ -3,6 +3,8 @@ # CHECK: Verifying .debug_abbrev... # CHECK-NEXT: Verifying .debug_info Unit Header Chain... +# CHECK-NEXT: warning: DW_TAG_skeleton_unit has DW_CHILDREN_yes but DIE has no children +# CHECK-NEXT: DW_TAG_skeleton_unit # CHECK-NEXT: error: Skeleton compilation unit has children. # CHECK-NEXT: Verifying .debug_info references... # CHECK-NEXT: Verifying .debug_types Unit Header Chain... @@ -30,7 +32,7 @@ .byte 8 # Address Size (in bytes) .long .debug_abbrev # Offset Into Abbrev. Section .quad -6573227469967412476 - .byte 1 # Abbrev [1] + .byte 1 # Abbrev [1] .byte 0 .Lcu_end0: .long .Lcu_end1-.Lcu_start1 # Length of Unit diff --git a/llvm/test/Examples/OrcV2Examples/Inputs/bar-mod.ll b/llvm/test/Examples/OrcV2Examples/Inputs/bar-mod.ll new file mode 100644 index 0000000000000..aad22f8ce783b --- /dev/null +++ b/llvm/test/Examples/OrcV2Examples/Inputs/bar-mod.ll @@ -0,0 +1,7 @@ +define i32 @bar() { + ret i32 0 +} + +^0 = module: (path: "bar-mod.o", hash: (3482110761, 1514484043, 2322286514, 2767576375, 2807967785)) +^1 = gv: (name: "bar", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0)))) ; guid = 16434608426314478903 +^2 = blockcount: 0 diff --git a/llvm/test/Examples/OrcV2Examples/Inputs/foo-mod.ll b/llvm/test/Examples/OrcV2Examples/Inputs/foo-mod.ll new file mode 100644 index 0000000000000..e08e1ddb897d4 --- /dev/null +++ b/llvm/test/Examples/OrcV2Examples/Inputs/foo-mod.ll @@ -0,0 +1,7 @@ +define i32 @foo() { + ret i32 0 +} + +^0 = module: (path: "foo-mod.o", hash: (3133549885, 2087596051, 4175159200, 756405190, 968713858)) +^1 = gv: (name: "foo", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0)))) ; guid = 6699318081062747564 +^2 = blockcount: 0 diff --git a/llvm/test/Examples/OrcV2Examples/Inputs/main-mod.ll b/llvm/test/Examples/OrcV2Examples/Inputs/main-mod.ll new file mode 100644 index 0000000000000..d3b39061b56d2 --- /dev/null +++ b/llvm/test/Examples/OrcV2Examples/Inputs/main-mod.ll @@ -0,0 +1,27 @@ +define i32 @main(i32 %argc, i8** %argv) { +entry: + %and = and i32 %argc, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + %call = tail call i32 @foo() #2 + br label %return + +if.end: ; preds = %entry + %call1 = tail call i32 @bar() #2 + br label %return + +return: ; preds = %if.end, %if.then + %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] + ret i32 %retval.0 +} + +declare i32 @foo() +declare i32 @bar() + +^0 = module: (path: "main-mod.o", hash: (1466373418, 2110622332, 1230295500, 3229354382, 2004933020)) +^1 = gv: (name: "foo") ; guid = 6699318081062747564 +^2 = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 22, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0), calls: ((callee: ^1), (callee: ^3))))) ; guid = 15822663052811949562 +^3 = gv: (name: "bar") ; guid = 16434608426314478903 +^4 = blockcount: 0 diff --git a/llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test b/llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test new file mode 100644 index 0000000000000..f82ac41bce38d --- /dev/null +++ b/llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test @@ -0,0 +1,12 @@ +# RUN: opt -module-summary %p/Inputs/main-mod.ll -o main-mod.bc +# RUN: opt -module-summary %p/Inputs/foo-mod.ll -o foo-mod.bc +# RUN: opt -module-summary %p/Inputs/bar-mod.ll -o bar-mod.bc + +# RUN: llvm-lto -thinlto -o main-foo-bar main-mod.bc foo-mod.bc bar-mod.bc + +# RUN: LLJITWithThinLTOSummaries main-foo-bar.thinlto.bc 2>&1 | FileCheck %s + +# CHECK: About to load module: main-mod.bc +# CHECK: About to load module: foo-mod.bc +# CHECK: About to load module: bar-mod.bc +# CHECK: 'main' finished with exit code: 0 diff --git a/llvm/test/Examples/lit.local.cfg b/llvm/test/Examples/lit.local.cfg index 72f5c0fff056d..a9f3860333603 100644 --- a/llvm/test/Examples/lit.local.cfg +++ b/llvm/test/Examples/lit.local.cfg @@ -1,2 +1,5 @@ if not config.build_examples or sys.platform in ['win32']: - config.unsupported = True \ No newline at end of file + config.unsupported = True + +# Test discovery should ignore subdirectories that contain test inputs. +config.excludes = ['Inputs'] diff --git a/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s b/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s index 0eee9a449cea9..efd438f3d2a89 100644 --- a/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s @@ -34,6 +34,17 @@ named_data: .long 42 .size named_data, 4 +# Test BSS / zero-fill section handling. +# llvm-jitlink: *{4}bss_variable = 0 + + .type bss_variable,@object + .bss + .globl bss_variable + .p2align 2 +bss_variable: + .long 0 + .size bss_variable, 4 + .ident "clang version 10.0.0-4ubuntu1 " .section ".note.GNU-stack","",@progbits .addrsig diff --git a/llvm/test/ExecutionEngine/OrcMCJIT/2002-12-16-ArgTest.ll b/llvm/test/ExecutionEngine/OrcMCJIT/2002-12-16-ArgTest.ll deleted file mode 100644 index 825892e9fbdd0..0000000000000 --- a/llvm/test/ExecutionEngine/OrcMCJIT/2002-12-16-ArgTest.ll +++ /dev/null @@ -1,37 +0,0 @@ -; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null - -@.LC0 = internal global [10 x i8] c"argc: %d\0A\00" ; <[10 x i8]*> [#uses=1] - -declare i32 @puts(i8*) - -define void @getoptions(i32* %argc) { -bb0: - ret void -} - -declare i32 @printf(i8*, ...) - -define i32 @main(i32 %argc, i8** %argv) { -bb0: - call i32 (i8*, ...) @printf( i8* getelementptr ([10 x i8], [10 x i8]* @.LC0, i64 0, i64 0), i32 %argc ) ; :0 [#uses=0] - %cast224 = bitcast i8** %argv to i8* ; [#uses=1] - %local = alloca i8* ; [#uses=3] - store i8* %cast224, i8** %local - %cond226 = icmp sle i32 %argc, 0 ; [#uses=1] - br i1 %cond226, label %bb3, label %bb2 -bb2: ; preds = %bb2, %bb0 - %cann-indvar = phi i32 [ 0, %bb0 ], [ %add1-indvar, %bb2 ] ; [#uses=2] - %add1-indvar = add i32 %cann-indvar, 1 ; [#uses=2] - %cann-indvar-idxcast = sext i32 %cann-indvar to i64 ; [#uses=1] - %CT = bitcast i8** %local to i8*** ; [#uses=1] - %reg115 = load i8**, i8*** %CT ; [#uses=1] - %cast235 = getelementptr i8*, i8** %reg115, i64 %cann-indvar-idxcast ; [#uses=1] - %reg117 = load i8*, i8** %cast235 ; [#uses=1] - %reg236 = call i32 @puts( i8* %reg117 ) ; [#uses=0] - %cond239 = icmp slt i32 %add1-indvar, %argc ; [#uses=1] - br i1 %cond239, label %bb2, label %bb3 -bb3: ; preds = %bb2, %bb0 - %cast243 = bitcast i8** %local to i32* ; [#uses=1] - call void @getoptions( i32* %cast243 ) - ret i32 0 -} diff --git a/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-ArgumentBug.ll b/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-ArgumentBug.ll deleted file mode 100644 index 2061329f25211..0000000000000 --- a/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-ArgumentBug.ll +++ /dev/null @@ -1,13 +0,0 @@ -; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null - -define i32 @foo(i32 %X, i32 %Y, double %A) { - %cond212 = fcmp une double %A, 1.000000e+00 ; [#uses=1] - %cast110 = zext i1 %cond212 to i32 ; [#uses=1] - ret i32 %cast110 -} - -define i32 @main() { - %reg212 = call i32 @foo( i32 0, i32 1, double 1.000000e+00 ) ; [#uses=1] - ret i32 %reg212 -} - diff --git a/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-LoopTest.ll b/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-LoopTest.ll deleted file mode 100644 index a298172e6780a..0000000000000 --- a/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-LoopTest.ll +++ /dev/null @@ -1,20 +0,0 @@ -; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null - -define i32 @main() { - call i32 @mylog( i32 4 ) ; :1 [#uses=0] - ret i32 0 -} - -define internal i32 @mylog(i32 %num) { -bb0: - br label %bb2 -bb2: ; preds = %bb2, %bb0 - %reg112 = phi i32 [ 10, %bb2 ], [ 1, %bb0 ] ; [#uses=1] - %cann-indvar = phi i32 [ %cann-indvar, %bb2 ], [ 0, %bb0 ] ; [#uses=1] - %reg114 = add i32 %reg112, 1 ; [#uses=2] - %cond222 = icmp slt i32 %reg114, %num ; [#uses=1] - br i1 %cond222, label %bb2, label %bb3 -bb3: ; preds = %bb2 - ret i32 %reg114 -} - diff --git a/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-PhiTest.ll b/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-PhiTest.ll deleted file mode 100644 index a24e188438fb5..0000000000000 --- a/llvm/test/ExecutionEngine/OrcMCJIT/2003-01-04-PhiTest.ll +++ /dev/null @@ -1,12 +0,0 @@ -; RUN: %lli -jit-kind=orc-mcjit %s > /dev/null - -define i32 @main() { -;