Merge pull request #75594 from benlangmuir/script-load-foundation-early

[immediate] Load Foundation early enough for bridging
This commit is contained in:
Ben Langmuir
2024-08-02 00:36:14 -07:00
committed by GitHub
5 changed files with 65 additions and 0 deletions

View File

@@ -115,6 +115,8 @@ ERROR(error_immediate_mode_missing_library,none,
(unsigned, StringRef)) (unsigned, StringRef))
ERROR(error_immediate_mode_primary_file,none, ERROR(error_immediate_mode_primary_file,none,
"immediate mode is incompatible with -primary-file", ()) "immediate mode is incompatible with -primary-file", ())
WARNING(warning_immediate_mode_cannot_load_foundation,none,
"immediate mode failed to load Foundation: %0", (StringRef))
ERROR(error_missing_frontend_action,none, ERROR(error_missing_frontend_action,none,
"no frontend action was selected", ()) "no frontend action was selected", ())
ERROR(error_invalid_source_location_str,none, ERROR(error_invalid_source_location_str,none,

View File

@@ -24,6 +24,7 @@
namespace swift { namespace swift {
class CompilerInstance; class CompilerInstance;
class DiagnosticEngine;
class IRGenOptions; class IRGenOptions;
class SILOptions; class SILOptions;
class SILModule; class SILModule;
@@ -44,6 +45,9 @@ namespace swift {
int RunImmediatelyFromAST(CompilerInstance &CI); int RunImmediatelyFromAST(CompilerInstance &CI);
/// On platforms that support ObjC bridging from the Foundation framework,
/// ensure that Foundation is loaded early enough. Otherwise does nothing.
void loadFoundationIfNeeded(DiagnosticEngine &Diags);
} // end namespace swift } // end namespace swift
#endif // SWIFT_IMMEDIATE_IMMEDIATE_H #endif // SWIFT_IMMEDIATE_IMMEDIATE_H

View File

@@ -1955,6 +1955,13 @@ int swift::performFrontend(ArrayRef<const char *> Args,
return finishDiagProcessing(1, /*verifierEnabled*/ false); return finishDiagProcessing(1, /*verifierEnabled*/ false);
} }
// Scripts that use the Foundation framework need it loaded early for bridging
// to work correctly on Darwin platforms. On other platforms this is a no-op.
if (Invocation.getFrontendOptions().RequestedAction ==
FrontendOptions::ActionType::Immediate) {
loadFoundationIfNeeded(Instance->getDiags());
}
// Don't ask clients to report bugs when running a script in immediate mode. // Don't ask clients to report bugs when running a script in immediate mode.
// When a script asserts the compiler reports the error with the same // When a script asserts the compiler reports the error with the same
// stacktrace as a compiler crash. From here we can't tell which is which, // stacktrace as a compiler crash. From here we can't tell which is which,

View File

@@ -432,3 +432,30 @@ int swift::RunImmediatelyFromAST(CompilerInstance &CI) {
return *Result; return *Result;
} }
void swift::loadFoundationIfNeeded(DiagnosticEngine &Diags) {
#if defined(__APPLE__)
const char *FoundationPath =
"/System/Library/Frameworks/Foundation.framework/Foundation";
void *handle = dlopen(FoundationPath, RTLD_NOLOAD);
if (handle) {
// Foundation is already loaded. Use dlclose to release the ref-count that
// was incremented by dlopen and return.
dlclose(handle);
return;
} else {
// Foundation is not yet loaded. Load it now and leak the handle.
// FIXME: it is fragile to load here, as there is no guarantee the swift
// runtime has not initialized already. As the compiler adds more swift code
// we may need to move this or find another solution.
handle = dlopen(FoundationPath, RTLD_LAZY | RTLD_GLOBAL);
if (!handle)
Diags.diagnose(SourceLoc(),
diag::warning_immediate_mode_cannot_load_foundation,
dlerror());
}
#else
// Nothing to do.
#endif
}

View File

@@ -0,0 +1,25 @@
// Check that we can access localizedDescription, which crashes in the runtime
// if Foundation is loaded after the runtime is already initialized on Darwin.
// REQUIRES: executable_test
// REQUIRES: objc_interop
// REQUIRES: OS=macosx
// FIXME: There's a separate bridging error with the just-built stdlib on CI
// nodes.
// REQUIRES: use_os_stdlib
// RUN: %target-jit-run %s
// RUN: DYLD_INSERT_LIBRARIES=/System/Library/Frameworks/Foundation.framework/Foundation %target-jit-run %s
import Foundation
print("Insert Libraries: \(ProcessInfo.processInfo.environment["DYLD_INSERT_LIBRARIES"] ?? "<nil>")")
enum SomeError: LocalizedError {
case fail
}
let err = SomeError.fail
let path = (#file as NSString).lastPathComponent
let desc = err.localizedDescription