Skip to content
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

Add Table example; fix local Table and Memory metadata ownership #1687

Merged
merged 10 commits into from
Oct 27, 2020

Conversation

MarkMcCaskey
Copy link
Contributor

@MarkMcCaskey MarkMcCaskey commented Oct 7, 2020

Adds an example using the Table API.

Work in progress, debugging an issue with growing using the Table API...

Things I'd like to have before shipping:

  • Code / comments clear enough that what's happening is fully understandable with no extra context
  • Test for dynamic memory (I don't know how to test this actually works with dynamic memory without editing code, this bug manifests most strongly with dynamic memory -- it may be possible to test memory without it though) - deferred, see Add test for dynamic memory #1769

Review

  • Add a short description of the the change to the CHANGELOG.md file

@Hywan
Copy link
Contributor

Hywan commented Oct 8, 2020

Thanks for working on this.

Copy link
Contributor

@Hywan Hywan left a comment

Choose a reason for hiding this comment

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

Please don't forget to update examples/README.md.

This commit contains a ton of debug code that we'll need to remove
@MarkMcCaskey MarkMcCaskey changed the title Add Table example Add Table example; fix local Table and Memory metadata ownership Oct 14, 2020
@MarkMcCaskey
Copy link
Contributor Author

bors try

bors bot added a commit that referenced this pull request Oct 14, 2020
@bors
Copy link
Contributor

bors bot commented Oct 15, 2020

@MarkMcCaskey MarkMcCaskey requested review from Hywan and removed request for losfair October 15, 2020 00:36
lib/vm/src/memory.rs Outdated Show resolved Hide resolved
Comment on lines +147 to +156
#[derive(Debug)]
enum VMMemoryDefinitionOwnership {
/// The `VMMemoryDefinition` is owned by the `Instance` and we should use
/// its memory. This is how a local memory that's exported should be stored.
VMOwned(NonNull<VMMemoryDefinition>),
/// The `VMMemoryDefinition` is owned by the host and we should manage its
/// memory. This is how an imported memory that doesn't come from another
/// Wasm module should be stored.
HostOwned(Box<UnsafeCell<VMMemoryDefinition>>),
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not super fan of this division. A memory is a memory, regardless of who owns it.

Copy link
Contributor Author

@MarkMcCaskey MarkMcCaskey Oct 15, 2020

Choose a reason for hiding this comment

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

Yeah, this is encapsulated internally and the reason we store it this way is so that freeing memory works correctly:

VMMemoryDefinitionOwnership::VMOwned won't free the memory when it gets dropped but VMMemoryDefinitionOwnership::HostOwned will.

I agree that it might make sense to define methods on this type to avoid having to match in the implementation code.

Let me know if that's not what you had in mind.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hypothetically if we don't fix it this way, then here's another thing we could do, not that it wouldn't be a ton of work. Make sure that VM* objects exist only inside the VMContext/Instance. wasmer_api:: would need two objects for memory, one that would be a handle to any kind of memory and the other which would be a host memory (detached from instance/vmcontext) and would contain the backing store. The VMMemoryImport would no longer point to a VMMemoryDefinition because a host Memory wouldn't have one, it would have to point to all the relevant parts (the backing, the enough to call grow and size, etc.) directly. The user has to keep the host memory and backing store alive, probably by Rc or Arc, and we could somewhat fold it into the handle (api::Memory) with an enum that indicates whether it's holding a whole backing store, or pointing to a VMMemoryDefinition.

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 idea being that VMMemoryImport would never own its metadata?

I'm not sure I fully understood what you're suggesting but to make sure we're on the same page:

  • The generated code always needs a VMMemoryDefinition.
    • If it's local, it lives in VM-owned memory
    • if it's imported it lives somewhere else (either another VM's memory or the host)
  • In the current code, due to Arc, an Instance using an imported host type will ensure that it's never freed while the Instance is using it.
  • We need an extra layer of indirection for imported VM Objects to make sure that modifications are reflected in the generated code. It's possible to remove this layer of indirection but it means we'd need update logic.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, the idea being that VMMemoryImport would never own its metadata. In this model the generated code would need to change to work with a VMMemoryImport.

The compiler-generated code needs to know the base pointer and the size. It also has to be able to grow and size, both of which go through libcalls (even in the local owned memory case). More subtly we need invalidation rules for the base pointer and the size, for instance can we assume they never change at any time the function is executing?

One possible solution. You could have the VMMemoryImport have ptr_to_ versions of the fields the VMMemoryDefinition has. Instead of ptr-to-vmmemorydefinition and arc it would have a ptr_to_base and ptr_to_current_length, then the Arc (or whatever we call the object that keeps the pointed-to-memory alive, if anything) goes in the Instance::memories, not the VMContext objects.

The important part of my suggestion is to start with a rule that VM* objects are only ever part of a VMContext and then follow that through the rest of the design.

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 important part of my suggestion is to start with a rule that VM* objects are only ever part of a VMContext and then follow that through the rest of the design.

I think this makes ownership harder in the case of a VM object imported into multiple instances, who is responsible for freeing it? What about memories created when there are no Instances created?

I'm not necessarily opposed to the changes but I think we should land this PR first, this change is self-contained and fixes user-facing bugs; the implementation can easily be changed later in my opinion.

examples/README.md Outdated Show resolved Hide resolved
examples/memory.rs Outdated Show resolved Hide resolved
examples/memory.rs Outdated Show resolved Hide resolved
@Hywan
Copy link
Contributor

Hywan commented Oct 16, 2020

I did a very quick review, but discussion happens on Slack, easier for the moment.

examples/README.md Outdated Show resolved Hide resolved
examples/memory.rs Outdated Show resolved Hide resolved
examples/memory.rs Outdated Show resolved Hide resolved
lib/api/src/tunables.rs Outdated Show resolved Hide resolved
lib/engine/src/tunables.rs Outdated Show resolved Hide resolved
let num_memories = offsets.num_local_memories;
let num_memories = usize::try_from(num_memories).unwrap();
let mut out = Vec::with_capacity(num_memories);
// TODO: better encapsulate this logic, this shouldn't be duplicated
Copy link
Contributor

Choose a reason for hiding this comment

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

(No action required:) I feel like this is a great example of a TODO that shouldn't have a bug filed.

lib/vm/src/instance.rs Outdated Show resolved Hide resolved
lib/vm/src/instance.rs Outdated Show resolved Hide resolved
Comment on lines +147 to +156
#[derive(Debug)]
enum VMMemoryDefinitionOwnership {
/// The `VMMemoryDefinition` is owned by the `Instance` and we should use
/// its memory. This is how a local memory that's exported should be stored.
VMOwned(NonNull<VMMemoryDefinition>),
/// The `VMMemoryDefinition` is owned by the host and we should manage its
/// memory. This is how an imported memory that doesn't come from another
/// Wasm module should be stored.
HostOwned(Box<UnsafeCell<VMMemoryDefinition>>),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hypothetically if we don't fix it this way, then here's another thing we could do, not that it wouldn't be a ton of work. Make sure that VM* objects exist only inside the VMContext/Instance. wasmer_api:: would need two objects for memory, one that would be a handle to any kind of memory and the other which would be a host memory (detached from instance/vmcontext) and would contain the backing store. The VMMemoryImport would no longer point to a VMMemoryDefinition because a host Memory wouldn't have one, it would have to point to all the relevant parts (the backing, the enough to call grow and size, etc.) directly. The user has to keep the host memory and backing store alive, probably by Rc or Arc, and we could somewhat fold it into the handle (api::Memory) with an enum that indicates whether it's holding a whole backing store, or pointing to a VMMemoryDefinition.

lib/vm/src/table.rs Outdated Show resolved Hide resolved
@MarkMcCaskey MarkMcCaskey mentioned this pull request Oct 21, 2020
bors bot added a commit that referenced this pull request Oct 27, 2020
1752: Add more examples for the Rust API r=syrusakbary a=jubianchi

# Description

The goal is to cover most of the Rust API with examples (and thus tests).

Some other PRs already exist for that purpose:
* #1730
* #1687 

# Review

- [ ] Add a short description of the the change to the CHANGELOG.md file


Co-authored-by: jubianchi <[email protected]>
@MarkMcCaskey
Copy link
Contributor Author

bors r+

@bors
Copy link
Contributor

bors bot commented Oct 27, 2020

@bors bors bot merged commit 04091d8 into master Oct 27, 2020
@bors bors bot deleted the feature/add-table-example branch October 27, 2020 19:54
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.

4 participants