Skip to content

[Runtime] Remove old-style mirrors in ReflectionLegacy.swift. #14678

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 10 commits into from
Feb 22, 2018

Conversation

mikeash
Copy link
Contributor

@mikeash mikeash commented Feb 16, 2018

The old-style mirrors were the basis for non-custom, reflection based Mirrors. As part of removing old-style mirrors, reflection based Mirrors are reimplemented without them. Reflection.mm is deleted and replaced with ReflectionMirror.mm, which borrows a chunk of the old code but presents a simpler API to the Swift side. ReflectionMirror.swift then uses that API to implement a reflection-based Mirror init.

rdar://problem/20356017

@mikeash
Copy link
Contributor Author

mikeash commented Feb 16, 2018

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - ed9631f8b688a55fb69f55b47119af13826cfb26

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

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

This looks great. -1,000 woo hoo!

@end

// mangled Swift._SwiftObject
#define SwiftObject _TtCs12_SwiftObject
Copy link
Member

Choose a reason for hiding this comment

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

You can get this #define from SwiftObject.h

subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
Copy link
Member

Choose a reason for hiding this comment

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

Hate to make this my first comment, but... spaces rather than tabs please, because GitHub's rendering mangles the layout.

let superclass = _getSuperclass(subjectClass) {
// Handle custom ancestors. If we've hit the custom ancestor's subject type,
// or descendants are suppressed, return it. Otherwise continue reflecting.
if let customAncestor = customAncestor {
Copy link
Member

Choose a reason for hiding this comment

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

Tabs :(

swift::crash("Swift mirror subscript bounds check failure");

// Load the type and offset from their respective vectors.
auto fieldType = Struct->getFieldTypes()[i];
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, this is going to conflict with @xedin 's current work in #13926, which eliminates the field-type vector. There will be an accessor of some sort, so the conflict resolution should be simple either way.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it shouldn't be too bad :)

/// \returns the demangled name. Returns nullptr if the input String is not a
/// Swift mangled name.
SWIFT_RUNTIME_EXPORT
char *swift_demangle(const char *mangledName,
Copy link
Member

Choose a reason for hiding this comment

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

It's so weird to have this function in this file. swift_demangle is a reasonable entrypoint to export from the runtime, but it's not specific to reflection at all. Maybe we can move it elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. It's there pretty much because it used to be in Reflection.mm and I mindlessly copied it over. I've now moved it to Demangle.cpp, which seems more appropriate.

size_t *outputBufferSize,
uint32_t flags) {
if (flags != 0) {
swift::fatalError(0, "Only 'flags' value of '0' is currently supported.");
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should fatalError here, because it provides no backward compatibility for this entrypoint. We should ignore flags we don't understand, not fail on them.

@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
@_silgen_name("swift_reflectionMirror_displayStyle")
internal func _getDisplayStyle<T>(_: T) -> CChar
Copy link
Member

Choose a reason for hiding this comment

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

I was going to grumble about the use of magic character constants here, but I see that there's one caller, and exposing an enum via SwiftShims just for this purpose seems.. excessive.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That was pretty much my thought process as well. Magic constants aren't the best, but it seems like the right solution in this particular case.

The old-style mirrors were the basis for non-custom, reflection based Mirrors. As part of removing old-style mirrors, reflection based Mirrors are reimplemented without them. Reflection.mm is deleted and replaced with ReflectionMirror.mm, which borrows a chunk of the old code but presents a simpler API to the Swift side. ReflectionMirror.swift then uses that API to implement a reflection-based Mirror init.

rdar://problem/20356017
@mikeash mikeash force-pushed the remove-reflectionlegacy branch from ed9631f to 4045edf Compare February 16, 2018 21:05
@gottesmm
Copy link
Contributor

@mikeash I haven't completely reviewed this, but can you in the C++ code be sure to update it so that the conventions work at +1 or +0 for functions that have swift calling convention. If you look at the old legacy reflection c++, you will see that I did that in a bunch of places using a few different macros, i.e.: SWIFT_CC_PLUS{ZERO,ONE}_GUARD, to guard retain/release calls appropriately.

@mikeash
Copy link
Contributor Author

mikeash commented Feb 16, 2018

@gottesmm If I've understood everything correctly (which is definitely not a given, so please correct me where I've gotten it wrong), that's not necessary here. The old code tried to keep a persistent interior pointer alive with an owner object, which got passed around everywhere and thus had to be treated differently with +1 or +0 semantics. The new code doesn't try to keep an interior pointer around, and works on generic OpaqueValues everywhere.

@gottesmm
Copy link
Contributor

Awesome! Thanks!

@mikeash
Copy link
Contributor Author

mikeash commented Feb 17, 2018

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - ed9631f8b688a55fb69f55b47119af13826cfb26

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - ed9631f8b688a55fb69f55b47119af13826cfb26

@mikeash
Copy link
Contributor Author

mikeash commented Feb 19, 2018

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 44d9b2f

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 44d9b2f

…an blindly casting to ClassMetada, which turns out to be completely incorrect.
@mikeash
Copy link
Contributor Author

mikeash commented Feb 20, 2018

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - fa2ea03

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - fa2ea03

//// define what these will be.
/// \returns the demangled name. Returns nullptr if the input String is not a
/// Swift mangled name.
SWIFT_RUNTIME_EXPORT
Copy link
Contributor

Choose a reason for hiding this comment

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

SWIFT_RUNTIME_EXPORT is for declarations. This definition should not use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I gather that a declaration for this function wasn't desired because it's not used by the other Swift code. Should we stick a declaration in the header anyway? I don't think there's anything that says it must not be used if someone decides it would be useful.

Copy link
Contributor

@gottesmm gottesmm left a comment

Choose a reason for hiding this comment

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

Comments around +0 and some general style comments.

internal func _getClassPlaygroundQuickLook(
_ object: AnyObject
) -> PlaygroundQuickLook? {
if _is(object, kindOf: "NSNumber") {
Copy link
Contributor

Choose a reason for hiding this comment

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

This whole function should not use else-if chains. Please use early-exits.

return Mirror(internalReflecting: subject,
subjectType: superclass,
customAncestor: customAncestor)
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not move the return nil early into a guard statement?


// If the output buffer is not provided, malloc memory ourselves.
if (outputBuffer == nullptr || *outputBufferSize == 0) {
return strdup(result.c_str());
Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't read too deeply here, but isn't strdup one of those unsafe APIs to use? Shouldn't you be using strndup? Not sure. I guess you are getting input from the demangler so it isn't unsafe input.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's OK here. c_str is guaranteed to return a NUL terminated string. strndup would be useful with a parameter where the NUL terminator may not be present.

// - the witness table for Protocol1
// - the witness table for Protocol2

auto weakContainer =
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you put a * next to the auto to show it is a pointer?

}

// Get a field name from a doubly-null-terminated list.
static const char *getFieldName(const char *fieldNames, size_t i) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally in LLVM style we just use unsigned instead of size_t. But if people are using size_t in the runtime, better to be consistent. I would see what people are using.


// Get the nth element.
auto &elt = Tuple->getElement(i);
auto bytes = reinterpret_cast<const char*>(value);
Copy link
Contributor

Choose a reason for hiding this comment

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

You missed the space between const char and *.

auto fieldType = Struct->getFieldTypes()[i];
auto fieldOffset = Struct->getFieldOffsets()[i];

auto bytes = reinterpret_cast<char*>(value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Another place that deviates from the pattern of ptr *

}

void getInfo(unsigned *tagPtr, const Metadata **payloadTypePtr, bool *indirectPtr) {
const auto Enum = static_cast<const EnumMetadata *>(type);
Copy link
Contributor

Choose a reason for hiding this comment

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

const auto Enum => const auto *Enum

const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
BoxPair pair = swift_allocBox(boxType);

type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value));
Copy link
Contributor

Choose a reason for hiding this comment

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

In a +0 context (unless mirrors copy value always), this worries me. I think you may need to perform a full copy of value to be safe.

impl->type = type;
impl->value = value;
auto result = f(impl);
T->vw_destroy(passedValue);
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be guarded by SWIFT_CC_PLUSONE_GUARD.

@mikeash mikeash force-pushed the remove-reflectionlegacy branch 2 times, most recently from af33c06 to c250a84 Compare February 22, 2018 01:07
@mikeash
Copy link
Contributor Author

mikeash commented Feb 22, 2018

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 0cff498

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 0cff498

@mikeash
Copy link
Contributor Author

mikeash commented Feb 22, 2018

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 03476e9

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 03476e9

@mikeash mikeash merged commit 2f810b4 into swiftlang:master Feb 22, 2018
@johnno1962
Copy link
Contributor

johnno1962 commented Feb 22, 2018

D'oh https://github.com/johnno1962/TwoWayMirror .. Oh well, It was fun while it lasted (2 days) 😁

@mikeash
Copy link
Contributor Author

mikeash commented Feb 23, 2018

Oh no! Sorry. 😿

Once the metadata format stabilizes, it should be possible to do this robustly and without the risk of breaking when people like me start slashing and burning old stuff. For whatever that's worth.

@johnno1962
Copy link
Contributor

My fault for using apis with “Legacy” stamped all over it. I’ll just have to be more ingenious next time ;)

johnno1962 added a commit to johnno1962/TwoWayMirror that referenced this pull request Feb 27, 2018
johnno1962 added a commit to johnno1962/TwoWayMirror that referenced this pull request Feb 27, 2018
johnno1962 added a commit to johnno1962/TwoWayMirror that referenced this pull request Feb 27, 2018
mikeash added a commit to mikeash/swift that referenced this pull request Mar 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants