Skip to content

[stdlib/msvc] Runtime with MSVC library #1918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/Runtime/HeapObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ struct TwoWordPair {
// in registers, so cram the result into an unsigned long long.
// Use an enum class with implicit conversions so we don't dirty C callers
// too much.
#if __arm__ || __i386__ || defined(__CYGWIN__)
#if defined(__CYGWIN__)
#if __arm__ || __i386__ || defined(__CYGWIN__) || defined(_MSC_VER)
#if defined(__CYGWIN__) || defined(_MSC_VER)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file LGTM.

enum class Return : unsigned __int128 {};
#else
enum class Return : unsigned long long {};
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Runtime/MutexWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ struct ReadWriteLockPlatformHelper {
};
}

#endif
#endif
47 changes: 41 additions & 6 deletions stdlib/public/runtime/Errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,31 @@
//
//===----------------------------------------------------------------------===//

#if defined(__CYGWIN__) || defined(__ANDROID__) || defined(_MSC_VER)
# define SWIFT_SUPPORTS_BACKTRACE_REPORTING 0
#else
# define SWIFT_SUPPORTS_BACKTRACE_REPORTING 1
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_MSC_VER)
#include <io.h>
#else
#include <unistd.h>
#endif
#include <stdarg.h>
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Basic/Demangle.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"

#if !defined(_MSC_VER)
#include <cxxabi.h>

#if !defined(__CYGWIN__) && !defined(__ANDROID__)
#endif
#if SWIFT_SUPPORTS_BACKTRACE_REPORTING

// execinfo.h is not available on Android. Checks in this file ensure that
// fatalError behaves as expected, but without stack traces.
Expand All @@ -50,7 +60,7 @@ enum: uint32_t {

using namespace swift;

#if !defined(__CYGWIN__) && !defined(__ANDROID__)
#if SWIFT_SUPPORTS_BACKTRACE_REPORTING
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is much cleaner now!


static bool getSymbolNameAddr(llvm::StringRef libraryName, Dl_info dlinfo,
std::string &symbolName, uintptr_t &addrOut) {
Expand Down Expand Up @@ -187,11 +197,16 @@ reportOnCrash(uint32_t flags, const char *message)
static void
reportNow(uint32_t flags, const char *message)
{
#if defined(_MSC_VER)
#define STDERR_FILENO 2
_write(STDERR_FILENO, message, strlen(message));
#else
write(STDERR_FILENO, message, strlen(message));
#endif
#ifdef __APPLE__
asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", message);
#endif
#if !defined(__CYGWIN__) && !defined(__ANDROID__)
#if SWIFT_SUPPORTS_BACKTRACE_REPORTING
if (flags & FatalErrorFlags::ReportBacktrace) {
fputs("Current stack trace:\n", stderr);
constexpr unsigned maxSupportedStackDepth = 128;
Expand All @@ -213,6 +228,26 @@ void swift::swift_reportError(uint32_t flags,
reportOnCrash(flags, message);
}

static int swift_vasprintf(char **strp, const char *fmt, va_list ap) {
#if defined(_MSC_VER)
int len = _vscprintf(fmt, ap);
if (len < 0)
return -1;
char *buffer = reinterpret_cast<char *>(malloc(len + 1));
if (!buffer)
return -1;
int result = vsprintf(*strp, fmt, ap);
if (result < 0) {
free(buffer);
return -1;
}
*strp = buffer;
return result;
#else
return vasprintf(strp, fmt, ap);
#endif
}

// Report a fatal error to system console, stderr, and crash logs, then abort.
LLVM_ATTRIBUTE_NORETURN
void
Expand All @@ -222,7 +257,7 @@ swift::fatalError(uint32_t flags, const char *format, ...)
va_start(args, format);

char *log;
vasprintf(&log, format, args);
swift_vasprintf(&log, format, args);

swift_reportError(flags, log);
abort();
Expand Down
3 changes: 0 additions & 3 deletions stdlib/public/runtime/HeapObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
#include <cstring>
#include <cstdio>
#include <cstdlib>
#if !defined(_MSC_VER)
#include <unistd.h>
#endif
#include "../SwiftShims/RuntimeShims.h"
#if SWIFT_OBJC_INTEROP
# include <objc/NSObject.h>
Expand Down
70 changes: 55 additions & 15 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@
#include <condition_variable>
#include <new>
#include <cctype>
#if defined(_MSC_VER)
// Avoid defining macro max(), min() which conflict with std::max(), std::min()
#define NOMINMAX
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#endif
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h"
#include "ErrorObject.h"
Expand All @@ -56,19 +62,56 @@
using namespace swift;
using namespace metadataimpl;

void *MetadataAllocator::alloc(size_t size) {
static uintptr_t swift_pageSize() {
#if defined(__APPLE__)
const uintptr_t PageSizeMask = vm_page_mask;
return vm_page_size;
#elif defined(_MSC_VER)
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
return SystemInfo.dwPageSize;
#else
return sysconf(_SC_PAGESIZE);
#endif
}

// allocate memory up to a nearby page boundary
static void *swift_allocateMetadataRoundingToPage(size_t size) {
const uintptr_t PageSizeMask = SWIFT_LAZY_CONSTANT(swift_pageSize()) - 1;
size = (size + PageSizeMask) & ~PageSizeMask;
#if defined(_MSC_VER)
auto mem = VirtualAlloc(
nullptr, size, MEM_TOP_DOWN | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
#else
static const uintptr_t PageSizeMask = sysconf(_SC_PAGESIZE) - 1;
auto mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
VM_TAG_FOR_SWIFT_METADATA, 0);
if (mem == MAP_FAILED)
mem = nullptr;
#endif
return mem;
}

// free memory allocated by swift_allocateMetadataRoundingToPage()
static void swift_freeMetadata(void *addr, size_t size) {
#if defined(_MSC_VER)
// On success, VirtualFree() returns nonzero, on failure 0
int result = VirtualFree(addr, 0, MEM_RELEASE);
if (result == 0)
fatalError(/* flags = */ 0, "swift_freePage: VirtualFree() failed");
#else
// On success, munmap() returns 0, on failure -1
int result = munmap(addr, size);
if (result != 0)
fatalError(/* flags = */ 0, "swift_freePage: munmap() failed");
#endif
}

void *MetadataAllocator::alloc(size_t size) {
const uintptr_t PageSize = SWIFT_LAZY_CONSTANT(swift_pageSize());
// If the requested size is a page or larger, map page(s) for it
// specifically.
if (LLVM_UNLIKELY(size > PageSizeMask)) {
auto mem = mmap(nullptr, (size + PageSizeMask) & ~PageSizeMask,
PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE,
VM_TAG_FOR_SWIFT_METADATA, 0);
if (mem == MAP_FAILED)
if (LLVM_UNLIKELY(size >= PageSize)) {
void *mem = swift_allocateMetadataRoundingToPage(size);
if (!mem)
crash("unable to allocate memory for metadata cache");
return mem;
}
Expand All @@ -80,16 +123,13 @@ void *MetadataAllocator::alloc(size_t size) {

// If we wrap over the end of the page, allocate a new page.
void *allocation = nullptr;
const uintptr_t PageSizeMask = PageSize - 1;
if (LLVM_UNLIKELY(((uintptr_t)next & ~PageSizeMask)
!= (((uintptr_t)end & ~PageSizeMask)))) {
// Allocate a new page if we haven't already.
allocation = mmap(nullptr, PageSizeMask + 1,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE,
VM_TAG_FOR_SWIFT_METADATA,
/*offset*/ 0);
allocation = swift_allocateMetadataRoundingToPage(PageSize);

if (allocation == MAP_FAILED)
if (!allocation)
crash("unable to allocate memory for metadata cache");

next = (char*) allocation;
Expand All @@ -107,7 +147,7 @@ void *MetadataAllocator::alloc(size_t size) {
// This potentially causes us to perform multiple mmaps under contention,
// but it keeps the fast path pristine.
if (allocation) {
munmap(allocation, PageSizeMask + 1);
swift_freeMetadata(allocation, PageSize);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ using namespace Demangle;
#define SWIFT_TYPE_METADATA_SECTION "__swift2_types"
#elif defined(__ELF__)
#define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start"
#elif defined(__CYGWIN__)
#elif defined(__CYGWIN__) || defined(_MSC_VER)
#define SWIFT_TYPE_METADATA_SECTION ".sw2tymd"
#endif

Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/runtime/Once.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ void swift::swift_once(swift_once_t *predicate, void (*fn)(void *)) {
// process (the token is a word that is atomically incremented from 0 to
// 1 to 2 during initialization) to work. We should implement our own version
// that we can rely on to continue to work that way.
// The MSVC port also relies on this, because the std::call_once on MSVC
// follows the compatible init process.
// For more information, see rdar://problem/18499385
std::call_once(*predicate, [fn]() { fn(nullptr); });
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file LGTM.

Expand Down
4 changes: 3 additions & 1 deletion stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ namespace swift {
dest = newValue;
}

#if defined(__CYGWIN__)
#if defined(__CYGWIN__) || defined(_MSC_VER)
struct dl_phdr_info {
void *dlpi_addr;
const char *dlpi_name;
Expand All @@ -183,6 +183,8 @@ namespace swift {
void *data);
uint8_t *_swift_getSectionDataPE(void *handle, const char *sectionName,
unsigned long *sectionSize);
#endif
#if defined(__CYGWIN__)
void _swift_once_f(uintptr_t *predicate, void *context,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the ABI of std::once_flag on MSVC happens to match what we expect? If so, please extend the comment in stdlib/public/runtime/Once.cpp to mention that MSVC port also relies on this, not just libstdc++-based ports.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file LGTM otherwise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sizeof(swift_once_t) <= sizeof(void*) was passed. But I couldn't conform that std::call_once() follows compatible init process (0 to 1 to 2). Could you let me know the counter part source which determines the compatibility.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the code after if (Builtin.ID == BuiltinValueKind::Once) in lib/IRGen/GenBuiltin.cpp.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler assumes that swift_once_t is zero-initialized, and nonzero after initialization finishes. It doesn't care what exact nonzero values it becomes once initialization begins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The definition of std::once_flag on MSVC is

struct once_flag
    {   // opaque data structure for call_once()
    constexpr once_flag() noexcept
        : _Opaque(0)
        {   // default construct
        }
     .....
    void *_Opaque;
    };

.
I verified that the variable of the type std::once_flag is initialized to zero and the variable is changed to 2 after I call std::call_once with it. Does this behavior match what we expect?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this matches our expectations.

void (*function)(void *));
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file LGTM.

Expand Down
24 changes: 20 additions & 4 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
#include <link.h>
#endif

#if defined(_MSC_VER)
#include <windows.h>
#else
#include <dlfcn.h>
#endif

using namespace swift;

Expand Down Expand Up @@ -144,7 +148,7 @@ const {
#define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto"
#elif defined(__ELF__)
#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start"
#elif defined(__CYGWIN__)
#elif defined(__CYGWIN__) || defined(_MSC_VER)
#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".sw2prtc"
#endif

Expand Down Expand Up @@ -396,17 +400,25 @@ void swift::_swift_initializeCallbacksToInspectDylib(
// rdar://problem/19045112
dl_iterate_phdr(_addImageProtocolConformances, &inspectArgs);
}
#elif defined(__CYGWIN__)
#elif defined(__CYGWIN__) || defined(_MSC_VER)
static int _addImageProtocolConformances(struct dl_phdr_info *info,
size_t size, void *data) {
InspectArgs *inspectArgs = (InspectArgs *)data;
// inspectArgs contains addImage*Block function and the section name
#if defined(_MSC_VER)
HMODULE handle;

if (!info->dlpi_name || info->dlpi_name[0] == '\0')
handle = GetModuleHandle(nullptr);
else
handle = GetModuleHandle(info->dlpi_name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can Cygwin use GetModuleHandle too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Cygwin can use both functions. I didn't merge because Cygwin prefers POSIX version.

#else
void *handle;
if (!info->dlpi_name || info->dlpi_name[0] == '\0') {
if (!info->dlpi_name || info->dlpi_name[0] == '\0')
handle = dlopen(nullptr, RTLD_LAZY);
} else
else
handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD);
#endif

unsigned long conformancesSize;
const uint8_t *conformances =
Expand All @@ -416,7 +428,11 @@ static int _addImageProtocolConformances(struct dl_phdr_info *info,
if (conformances)
inspectArgs->fnAddImageBlock(conformances, conformancesSize);

#if defined(_MSC_VER)
FreeLibrary(handle);
#else
dlclose(handle);
#endif
return 0;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file LGTM.

Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/runtime/SwiftObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
#include "../SwiftShims/RuntimeShims.h"
#include "Private.h"
#include "swift/Runtime/Debug.h"
#if SWIFT_OBJC_INTEROP
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unordered_map>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to this file LGTM.

Expand Down
Loading