Skip to content

[SILVerifier] UnmanagedToRef and RefToUnmanaged must be loadable #16279

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

davezarzycki
Copy link
Contributor

In #16237, @rjmccall wrote: "Unmanaged is never not loadable. It's possible that we're messing that up somewhere."

Let's add a SIL verifier and sort this out.

@davezarzycki davezarzycki requested review from rjmccall and eeckstein May 1, 2018 11:22
@davezarzycki
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented May 1, 2018

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

@davezarzycki davezarzycki force-pushed the qoi_verify_unmanaged_is_loadable branch from 0ab281d to 72639be Compare May 1, 2018 11:32
@davezarzycki
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented May 1, 2018

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

@swift-ci
Copy link
Contributor

swift-ci commented May 1, 2018

Build failed
Swift Test Linux Platform
Git Sha - 0ab281df216cec4aa7e14e9a03a98ed5eb262177

@davezarzycki
Copy link
Contributor Author

Hey @rjmccall – Here is an example build failure when SIL verifies Unmanaged loadability:

SIL verification failed: unmanaged_to_ref requires unowned type to be loadable: operandType->isLoadable(ResilienceExpansion::Maximal)
Verifying instruction:
     %2 = struct_extract %0 : $Unmanaged<Instance>, #Unmanaged._value // user: %3
->   %3 = unmanaged_to_ref %2 : $@sil_unmanaged Instance to $Instance // user: %4
     %4 = copy_value %3 : $Instance               // user: %5
In function:
// Unmanaged._value.getter
sil [transparent] [serialized] @$Ss9UnmanagedV6_valuexXuvg : $@convention(method) <Instance where Instance : AnyObject> (Unmanaged<Instance>) -> @owned Instance {
// %0                                             // users: %2, %1
bb0(%0 : @trivial $Unmanaged<Instance>):
  debug_value %0 : $Unmanaged<Instance>, let, name "self", argno 1 // id: %1
  %2 = struct_extract %0 : $Unmanaged<Instance>, #Unmanaged._value // user: %3
  %3 = unmanaged_to_ref %2 : $@sil_unmanaged Instance to $Instance // user: %4
  %4 = copy_value %3 : $Instance                  // user: %5
  return %4 : $Instance                           // id: %5
} // end sil function '$Ss9UnmanagedV6_valuexXuvg'

@davezarzycki davezarzycki requested a review from jckarter May 1, 2018 19:16
@rjmccall
Copy link
Contributor

rjmccall commented May 1, 2018

That's because the isLoadable method that you've added in this patch is implemented incorrectly.

I think we're talking past each other. WeakStorageType is never loadable, UnmanagedStorageType is always loadable, and UnownedStorageType is loadable only when the referent type uses native reference counting.

@davezarzycki
Copy link
Contributor Author

Hi @rjmccall – Thanks. I agree that we're talking past each other. I just don't feel like I fully appreciate what "loadable" means in this context, and I don't appreciate why the referent being native or not would change load-ability.

Does "loadable" refer to reading the reference pointer from memory? If so, then why does the referent nativeness matter? It clearly doesn't matter for Unmanaged, so what is different about Unowned?

Does this have anything to do with magic ObjC pointers that aren't actually pointers (inline object storage, the non-ponter ISA, etc)?

@rjmccall
Copy link
Contributor

rjmccall commented May 1, 2018

"Loadable" means, essentially, that it's semantically okay to load a value of the type into registers — i.e. that it's not tied to being in memory and can safely be moved around with things like memcpy.

  • Weak references aren't loadable because we register the storage address with the runtime.
  • Unowned references are loadable when they're to native Swift objects because we just increment/decrement the weak reference count, but if they might be Objective-C objects they're no longer loadable because the implementation may have to reserve something with the ObjC runtime in order to perform the checking.
  • Unmanaged references are raw pointers that we don't reference-count and so can be freely copied around.

@davezarzycki
Copy link
Contributor Author

Would "isMovable" or "isCopyable" be a better name then? It feels confusing to have isLoadable() == false generate LoadUnownedInst and friends.

@rjmccall
Copy link
Contributor

rjmccall commented May 1, 2018

No, because those types are still movable and copyable; they just can't be moved with memcpy. Also, "loadable" is a pretty inextricable term of art in the compiler at this point.

@davezarzycki
Copy link
Contributor Author

Thanks for the feedback John. I think I get it now. I'll have to think about how to add this extra dimension of complexity to #16237.

@davezarzycki davezarzycki deleted the qoi_verify_unmanaged_is_loadable branch May 1, 2018 22:03
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.

3 participants