Skip to content

[RemoteMirror] Update interop to handle 4.2 libraries. #20363

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 3 commits into from
Nov 26, 2018
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
2 changes: 1 addition & 1 deletion include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ extern "C" {

/// Get the metadata version supported by the Remote Mirror library.
SWIFT_REMOTE_MIRROR_LINKAGE
uint16_t swift_reflection_getSupportedMetadataVersion();
uint16_t swift_reflection_getSupportedMetadataVersion(void);

/// \returns An opaque reflection context.
SWIFT_REMOTE_MIRROR_LINKAGE
Expand Down
99 changes: 55 additions & 44 deletions include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "SwiftRemoteMirrorLegacyInteropTypes.h"
#include "SwiftRemoteMirror.h"

#include <string.h>
#include <dlfcn.h>
#include <mach-o/getsect.h>

Expand All @@ -37,14 +38,19 @@
static inline SwiftReflectionInteropContextRef
swift_reflection_interop_createReflectionContext(
void *ReaderContext,
void *LibraryHandle,
void *LegacyLibraryHandle,
uint8_t PointerSize,
FreeBytesFunction FreeBytes,
ReadBytesFunction ReadBytes,
GetStringLengthFunction GetStringLength,
GetSymbolAddressFunction GetSymbolAddress);

/// Add a library handle to the interop context. Returns 1 if the
/// library was added successfully, 0 if a symbol couldn't be looked up
/// or the reported metadata version is too old.
static inline int
swift_reflection_interop_addLibrary(
SwiftReflectionInteropContextRef ContextRef, void *LibraryHandle);

static inline void
swift_reflection_interop_destroyReflectionContext(
SwiftReflectionInteropContextRef ContextRef);
Expand Down Expand Up @@ -283,6 +289,7 @@ struct SwiftReflectionInteropContextLegacyImageRangeList {

struct SwiftReflectionInteropContext {
void *ReaderContext;
uint8_t PointerSize;
FreeBytesFunction FreeBytes;
ReadBytesFunction ReadBytes;
uint64_t (*GetStringLength)(void *reader_context,
Expand All @@ -291,8 +298,7 @@ struct SwiftReflectionInteropContext {
const char *name,
uint64_t name_length);

// Currently we support at most two libraries.
struct SwiftReflectionInteropContextLibrary Libraries[2];
struct SwiftReflectionInteropContextLibrary *Libraries;
int LibraryCount;

struct SwiftReflectionInteropContextFreeList *FreeList;
Expand Down Expand Up @@ -381,12 +387,11 @@ swift_reflection_interop_libraryForObject(
return swift_reflection_interop_libraryForAddress(ContextRef, Metadata);
}

static inline void
static inline int
swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Context,
void *Handle,
int IsLegacy) {
void *Handle) {
if (Handle == NULL)
return;
return 0;

struct SwiftReflectionInteropContextLibrary *Library = &Context
->Libraries[Context->LibraryCount];
Expand All @@ -397,14 +402,16 @@ swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Con
#endif
#define LOAD_NAMED(field, symbol) do { \
Functions->field = (decltype(Functions->field))dlsym(Handle, symbol); \
if (Functions->field == NULL) return; \
if (Functions->field == NULL) return 0; \
} while (0)
#define LOAD(name) LOAD_NAMED(name, "swift_reflection_" #name)

LOAD(getSupportedMetadataVersion);
uint16_t version = Functions->getSupportedMetadataVersion();
if (version < SWIFT_LEGACY_METADATA_MIN_VERSION)
return;
return 0;

int IsLegacy = dlsym(Handle, "swift_reflection_addImage") == NULL;

if (IsLegacy) {
LOAD_NAMED(createReflectionContextLegacy, "swift_reflection_createReflectionContext");
Expand Down Expand Up @@ -438,7 +445,7 @@ swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Con
Library->IsLegacy = IsLegacy;
Context->LibraryCount++;

return;
return 1;

#undef LOAD
#undef LOAD_NAMED
Expand Down Expand Up @@ -470,6 +477,7 @@ swift_reflection_interop_readBytesAdapter(void *reader_context,
static inline uint8_t
swift_reflection_interop_getSizeAdapter(void *reader_context) {
// Legacy library doesn't pay attention to these anyway.
(void)reader_context;
return sizeof(void *);
}

Expand All @@ -492,8 +500,6 @@ swift_reflection_interop_GetSymbolAddressAdapter(
static inline SwiftReflectionInteropContextRef
swift_reflection_interop_createReflectionContext(
void *ReaderContext,
void *LibraryHandle,
void *LegacyLibraryHandle,
uint8_t PointerSize,
FreeBytesFunction FreeBytes,
ReadBytesFunction ReadBytes,
Expand All @@ -503,15 +509,27 @@ swift_reflection_interop_createReflectionContext(
SwiftReflectionInteropContextRef ContextRef =
(SwiftReflectionInteropContextRef)calloc(sizeof(*ContextRef), 1);

swift_reflection_interop_loadFunctions(ContextRef, LibraryHandle, 0);
swift_reflection_interop_loadFunctions(ContextRef, LegacyLibraryHandle, 1);
ContextRef->ReaderContext = ReaderContext;
ContextRef->PointerSize = PointerSize;
ContextRef->FreeBytes = FreeBytes;
ContextRef->ReadBytes = ReadBytes;
ContextRef->GetStringLength = GetStringLength;
ContextRef->GetSymbolAddress = GetSymbolAddress;

if (ContextRef->LibraryCount == 0) {
free(ContextRef);
return NULL;
}
ContextRef->AddressToLibraryCache = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);

FOREACH_LIBRARY {
return ContextRef;
}

static inline int
swift_reflection_interop_addLibrary(
SwiftReflectionInteropContextRef ContextRef, void *LibraryHandle) {
size_t NewSize = (ContextRef->LibraryCount + 1) * sizeof(*ContextRef->Libraries);
ContextRef->Libraries = realloc(ContextRef->Libraries, NewSize);
int Success = swift_reflection_interop_loadFunctions(ContextRef, LibraryHandle);
if (Success) {
struct SwiftReflectionInteropContextLibrary *Library =
&ContextRef->Libraries[ContextRef->LibraryCount - 1];
if (Library->IsLegacy) {
Library->Context = Library->Functions.createReflectionContextLegacy(
ContextRef,
Expand All @@ -520,20 +538,12 @@ swift_reflection_interop_createReflectionContext(
swift_reflection_interop_GetStringLengthAdapter,
swift_reflection_interop_GetSymbolAddressAdapter);
} else {
Library->Context = Library->Functions.createReflectionContext(ReaderContext,
PointerSize, FreeBytes, ReadBytes, GetStringLength, GetSymbolAddress);
Library->Context = Library->Functions.createReflectionContext(
ContextRef->ReaderContext,
ContextRef->PointerSize, ContextRef->FreeBytes, ContextRef->ReadBytes, ContextRef->GetStringLength, ContextRef->GetSymbolAddress);
}
}

ContextRef->ReaderContext = ReaderContext;
ContextRef->FreeBytes = FreeBytes;
ContextRef->ReadBytes = ReadBytes;
ContextRef->GetStringLength = GetStringLength;
ContextRef->GetSymbolAddress = GetSymbolAddress;

ContextRef->AddressToLibraryCache = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);

return ContextRef;
return Success;
}

static inline void
Expand All @@ -542,6 +552,7 @@ swift_reflection_interop_destroyReflectionContext(
FOREACH_LIBRARY {
Library->Functions.destroyReflectionContext(Library->Context);
}
free(ContextRef->Libraries);
struct SwiftReflectionInteropContextLegacyImageRangeList *LegacyImageRangeList
= ContextRef->LegacyImageRangeList;
while (LegacyImageRangeList != NULL) {
Expand Down Expand Up @@ -668,14 +679,14 @@ swift_reflection_interop_addImageLegacy(
}

info.LocalStartAddress = (uintptr_t)Buf;
info.RemoteStartAddress = ImageStart;
info.RemoteStartAddress = (uintptr_t)ImageStart;

Library->Functions.addReflectionInfoLegacy(Library->Context, info);

// Find the data segment and add it to our list.
unsigned long DataSize;
const uint8_t *DataSegment = getsegmentdata(Header, "__DATA", &DataSize);
uintptr_t DataSegmentStart = DataSegment - (const uint8_t *)Buf + ImageStart;
uintptr_t DataSegmentStart = (uintptr_t)(DataSegment - (const uint8_t *)Buf + ImageStart);

struct SwiftReflectionInteropContextLegacyImageRangeList *Node =
(struct SwiftReflectionInteropContextLegacyImageRangeList *)malloc(sizeof(*Node));
Expand All @@ -687,12 +698,12 @@ swift_reflection_interop_addImageLegacy(
// If the buffer needs to be freed, save buffer and free context to free it when the
// reflection context is destroyed.
if (ContextRef->FreeBytes != NULL) {
struct SwiftReflectionInteropContextFreeList *Node =
(struct SwiftReflectionInteropContextFreeList *)malloc(sizeof(*Node));
Node->Next = ContextRef->FreeList;
Node->Pointer = Buf;
Node->Context = FreeContext;
ContextRef->FreeList = Node;
struct SwiftReflectionInteropContextFreeList *FreeListNode =
(struct SwiftReflectionInteropContextFreeList *)malloc(sizeof(*FreeListNode));
FreeListNode->Next = ContextRef->FreeList;
FreeListNode->Pointer = Buf;
FreeListNode->Context = FreeContext;
ContextRef->FreeList = FreeListNode;
}

return 1;
Expand Down Expand Up @@ -736,7 +747,7 @@ swift_reflection_interop_lookupMetadata(SwiftReflectionInteropContextRef Context
swift_reflection_interop_libraryForAddress(ContextRef, Metadata);
if (Library != NULL) {
Result.Metadata = Metadata;
Result.Library = LIBRARY_INDEX;
Result.Library = (int)LIBRARY_INDEX;
}
return Result;
}
Expand All @@ -762,7 +773,7 @@ swift_reflection_interop_typeRefForInstance(SwiftReflectionInteropContextRef Con
swift_typeref_t Typeref = Library->Functions.typeRefForInstance(Library->Context,
Object);
Result.Typeref = Typeref;
Result.Library = LIBRARY_INDEX;
Result.Library = (int)LIBRARY_INDEX;
}
return Result;
}
Expand All @@ -780,7 +791,7 @@ swift_reflection_interop_typeRefForMangledTypeName(
continue;

Result.Typeref = Typeref;
Result.Library = LIBRARY_INDEX;
Result.Library = (int)LIBRARY_INDEX;
return Result;
}

Expand Down Expand Up @@ -867,7 +878,7 @@ swift_reflection_interop_childOfInstance(SwiftReflectionInteropContextRef Contex
Result.Offset = LibResult.Offset;
Result.Kind = LibResult.Kind;
Result.TR.Typeref = LibResult.TR;
Result.TR.Library = LIBRARY_INDEX;
Result.TR.Library = (int)LIBRARY_INDEX;
} else {
Result.Kind = SWIFT_UNKNOWN;
}
Expand Down
6 changes: 3 additions & 3 deletions include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ typedef enum swift_layout_kind {

// References to other objects in the heap.
SWIFT_STRONG_REFERENCE,
#define REF_STORAGE(Name, name, NAME) \
SWIFT_##NAME##_REFERENCE,
#include "swift/AST/ReferenceStorage.def"
SWIFT_UNOWNED_REFERENCE,
SWIFT_WEAK_REFERENCE,
SWIFT_UNMANAGED_REFERENCE,

// Layouts of heap objects. These are only ever returned from
// swift_reflection_infoFor{Instance,Metadata}(), and not
Expand Down
34 changes: 25 additions & 9 deletions unittests/Reflection/RemoteMirrorInterop/test.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,34 +57,28 @@ uint64_t GetStringLength(void *context, swift_addr_t address) {
}

swift_addr_t GetSymbolAddress(void *context, const char *name, uint64_t name_length) {
(void)name_length;
assert(context == (void *)0xdeadbeef);
return (swift_addr_t)dlsym(RTLD_DEFAULT, name);
}

int main(int argc, char **argv) {
if (argc != 4) {
fprintf(stderr, "usage: %s <libtestswift.dylib> <libswiftRemoteMirror4.dylib> "
"<libswiftRemoteMirror5.dylib>\n",
if (argc < 2) {
fprintf(stderr, "usage: %s <libtestswift.dylib> <libswiftRemoteMirror.dylib ...>\n",
argv[0]);
exit(1);
}

char *TestLibPath = argv[1];
char *Mirror4Path = argv[2];
char *Mirror5Path = argv[3];

void *TestHandle = Load(TestLibPath);
intptr_t (*Test)(void) = dlsym(TestHandle, "test");

uintptr_t Obj = Test();

void *Mirror4Handle = Mirror4Path[0] == '-' ? NULL : Load(Mirror4Path);
void *Mirror5Handle = Mirror5Path[0] == '-' ? NULL : Load(Mirror5Path);
SwiftReflectionInteropContextRef Context =
swift_reflection_interop_createReflectionContext(
(void *)0xdeadbeef,
Mirror5Handle,
Mirror4Handle,
sizeof(void *),
Free,
ReadBytes,
Expand All @@ -95,6 +89,28 @@ int main(int argc, char **argv) {
exit(1);
}

for (int i = 2; i < argc; i++) {
void *Handle = Load(argv[i]);
int Success = swift_reflection_interop_addLibrary(Context, Handle);
if (!Success) {
fprintf(stderr, "Failed to add library at %s\n", argv[i]);
exit(1);
}
}

int hasLegacy = 0;
int hasNonLegacy = 0;
for (int i = 0; i < Context->LibraryCount; i++) {
if (Context->Libraries[i].IsLegacy)
hasLegacy = 1;
else
hasNonLegacy = 1;
}
if (hasLegacy && !hasNonLegacy) {
printf("We can't run tests with only a legacy library. Giving up.\n");
exit(0);
}

uint32_t ImageCount = _dyld_image_count();
for (uint32_t i = 0; i < ImageCount; i++) {
swift_addr_t Image = (swift_addr_t)_dyld_get_image_header(i);
Expand Down
60 changes: 60 additions & 0 deletions unittests/Reflection/RemoteMirrorInterop/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python

# Exercise the SwiftRemoteMirrorLegacyInterop API. This works with
# multiple versions of Swift. It builds Swift code using all versions,
# and exercises the Interop API using various combinations of those
# versions' Remote Mirror libraries.
#
# Invoke by passing the various Swift build directories as parameters.

import itertools
import os
import subprocess
import sys

args = sys.argv[1:]
if len(args) == 0:
print >> sys.stderr, "Usage:", sys.argv[0], "swift-build-dirs..."
print >> sys.stderr, ("Note: pass paths to the swift-macosx-x86_64"
" directories.")
sys.exit(1)

absoluteArgs = [os.path.abspath(arg) for arg in args]
swiftcs = [os.path.join(arg, 'bin', 'swiftc') for arg in absoluteArgs]
mirrorlibs = [os.path.join(arg, 'lib', 'swift', 'macosx',
'libswiftRemoteMirror.dylib')
for arg in absoluteArgs]

os.chdir(os.path.dirname(sys.argv[0]))

# Build the remote mirror test harness program.
subprocess.check_call(['clang',
'-framework', 'Foundation',
'-I', '../../../include/swift/SwiftRemoteMirror',
'-I', '../../../include/',
'-o', '/tmp/test',
'-Wall', '-Wextra',
'-g', 'test.m'])

# Build a test library with each Swift compiler passed in.
for i, swiftc in enumerate(swiftcs):
subprocess.check_call(
['xcrun', swiftc, '-emit-library', 'test.swift',
'-o', os.path.join('/tmp', 'libtest' + str(i) + '.dylib')])

# Run the test harness with all combinations of the remote mirror libraries.
for i in range(len(swiftcs) + 1):
for localMirrorlibs in itertools.combinations(mirrorlibs, i):
for i, arg in enumerate(absoluteArgs):
print 'Testing', arg, 'with mirror libs:'
for l in localMirrorlibs:
print '\t', l
callArgs = ['/tmp/test']
dylibPath = os.path.join('/tmp', 'libtest' + str(i) + '.dylib')
callArgs.append(dylibPath)
callArgs += list(localMirrorlibs)
print ' '.join(callArgs)
subprocess.call(callArgs)
print 'DONE'
print ''
print localMirrorlibs
Loading