-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[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
Conversation
@swift-ci please test |
Build failed |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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."); |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
ed9631f
to
4045edf
Compare
@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. |
@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 |
Awesome! Thanks! |
@swift-ci please test |
Build failed |
Build failed |
@swift-ci please test |
Build failed |
Build failed |
…an blindly casting to ClassMetada, which turns out to be completely incorrect.
@swift-ci please test |
Build failed |
Build failed |
stdlib/public/runtime/Demangle.cpp
Outdated
//// define what these will be. | ||
/// \returns the demangled name. Returns nullptr if the input String is not a | ||
/// Swift mangled name. | ||
SWIFT_RUNTIME_EXPORT |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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") { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 = |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
rdar://problem/20356017
…it when +0 is enabled. rdar://problem/20356017
… export it. rdar://problem/20356017
af33c06
to
c250a84
Compare
@swift-ci please test |
Build failed |
Build failed |
@swift-ci please test |
Build failed |
Build failed |
D'oh https://github.com/johnno1962/TwoWayMirror .. Oh well, It was fun while it lasted (2 days) 😁 |
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. |
My fault for using apis with “Legacy” stamped all over it. I’ll just have to be more ingenious next time ;) |
… Mirror reimplementation in swiftlang#14678. rdar://problem/20356017
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