-
Notifications
You must be signed in to change notification settings - Fork 250
C# future simple codegen #1357
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
Open
yowl
wants to merge
2
commits into
bytecodealliance:main
Choose a base branch
from
yowl:csharp-future-simple
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
C# future simple codegen #1357
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /** | ||
| * Helpers for future support. | ||
| */ | ||
|
|
||
| public readonly struct WaitableStatus (int status) | ||
| { | ||
| public int State => status & 0xf; | ||
| public int Count => (int)(status >> 4); | ||
| public bool IsBlocked => status == -1; | ||
| public bool IsCompleted => State == 0; | ||
| public bool IsDropped => State == 1; | ||
| } | ||
|
|
||
| public enum EventCode | ||
| { | ||
| None, | ||
| Subtask, | ||
| StreamRead, | ||
| StreamWrite, | ||
| FutureRead, | ||
| FutureWrite, | ||
| Cancel, | ||
| } | ||
|
|
||
| public readonly struct EventWaitable | ||
| { | ||
| public EventWaitable(EventCode eventCode, int waitable, int code) | ||
| { | ||
| Event = eventCode; | ||
| Waitable = waitable; | ||
| Status = new WaitableStatus(code); | ||
| } | ||
| public readonly EventCode Event; | ||
| public readonly int Waitable; | ||
| public readonly int Code; | ||
|
|
||
| public readonly WaitableStatus Status; | ||
| } | ||
|
|
||
| public partial class WaitableSet(int handle) : IDisposable | ||
| { | ||
| public int Handle { get; } = handle; | ||
|
|
||
| void Dispose(bool _disposing) | ||
| { | ||
| {{interop_name}}.WaitableSetDrop(Handle); | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| Dispose(true); | ||
| GC.SuppressFinalize(this); | ||
| } | ||
|
|
||
| ~WaitableSet() | ||
| { | ||
| Dispose(false); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| /** | ||
| * Helpers for future reader support. | ||
| */ | ||
|
|
||
| public abstract class FutureReader(int handle) : IDisposable // : TODO Waitable | ||
| { | ||
| public int Handle { get; } = handle; | ||
|
|
||
| // TODO: Generate per type for this instrinsic. | ||
| public Task Read() | ||
| { | ||
| // TODO: Generate for the interop name and the namespace. | ||
|
|
||
| var status = new WaitableStatus(ReadInternal()); | ||
| if (status.IsBlocked) | ||
| { | ||
| //TODO: store somewhere so we can complete it later. | ||
| var tcs = new TaskCompletionSource(); | ||
|
|
||
| return tcs.Task; | ||
| } | ||
| if (status.IsCompleted) | ||
| { | ||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| throw new NotImplementedException(); | ||
| } | ||
|
|
||
| void Dispose(bool _disposing) | ||
| { | ||
| // Free unmanaged resources if any. | ||
| Drop(); | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| Dispose(true); | ||
| GC.SuppressFinalize(this); | ||
| } | ||
|
|
||
| ~FutureReader() | ||
| { | ||
| Dispose(false); | ||
| } | ||
|
|
||
| protected abstract int ReadInternal(); | ||
| protected abstract void Drop(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /** | ||
| * Helpers for future writer support. | ||
| */ | ||
|
|
||
| public abstract class FutureWriter(int handle) // : TODO Waitable | ||
| { | ||
| public int Handle { get; } = handle; | ||
|
|
||
| // TODO: Generate per type for this instrinsic. | ||
| public Task Write() | ||
| { | ||
| // TODO: Generate for the interop name. | ||
| var status = new WaitableStatus(Write(Handle, IntPtr.Zero)); | ||
| if (status.IsBlocked) | ||
| { | ||
| //TODO: store somewhere so we can complete it later. | ||
| var tcs = new TaskCompletionSource(); | ||
| return tcs.Task; | ||
| } | ||
|
|
||
| throw new NotImplementedException(); | ||
| } | ||
|
|
||
| protected abstract void Drop(); | ||
|
|
||
| void Dispose(bool _disposing) | ||
| { | ||
| // Free unmanaged resources if any. | ||
| Drop(); | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| Dispose(true); | ||
| GC.SuppressFinalize(this); | ||
| } | ||
|
|
||
| ~FutureWriter() | ||
| { | ||
| Dispose(false); | ||
| } | ||
|
|
||
| protected abstract int Write(int handle, IntPtr buffer); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,7 @@ pub(crate) struct FunctionBindgen<'a, 'b> { | |
| fixed_statments: Vec<Fixed>, | ||
| parameter_type: ParameterType, | ||
| result_type: Option<Type>, | ||
| pub(crate) resource_type_name: Option<String>, | ||
| } | ||
|
|
||
| impl<'a, 'b> FunctionBindgen<'a, 'b> { | ||
|
|
@@ -70,6 +71,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { | |
| fixed_statments: Vec::new(), | ||
| parameter_type: parameter_type, | ||
| result_type: result_type, | ||
| resource_type_name: None, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1062,9 +1064,32 @@ impl Bindgen for FunctionBindgen<'_, '_> { | |
| None => operands.join(", "), | ||
| }; | ||
|
|
||
| let (_namespace, interface_name) = | ||
| &CSharp::get_class_name_from_qualified_name(self.interface_gen.name); | ||
| let mut interop_name = format!("{}ImportsInterop", interface_name.strip_prefix("I").unwrap() | ||
| .strip_suffix(if self.interface_gen.direction == Direction::Import { "Imports" } else { "Exports" }).unwrap().to_upper_camel_case()); | ||
|
|
||
| if self.interface_gen.is_world && self.interface_gen.direction == Direction::Import { | ||
| interop_name = format!("Imports.{interop_name}"); | ||
| } | ||
|
|
||
| let resource_type_name = match self.kind { | ||
| FunctionKind::Method(resource_type_id) | | ||
| FunctionKind::Static(resource_type_id) | | ||
| FunctionKind::Constructor(resource_type_id) => { | ||
| format!( | ||
| ".{}", | ||
| self.interface_gen.csharp_gen.all_resources[resource_type_id] | ||
| .name | ||
| .to_upper_camel_case() | ||
| ) | ||
| } | ||
| _ => String::new(), | ||
| }; | ||
|
|
||
| uwriteln!( | ||
| self.src, | ||
| "{assignment} {func_name}WasmInterop.wasmImport{func_name}({operands});" | ||
| "{assignment} {interop_name}{resource_type_name}.{func_name}WasmInterop.wasmImport{func_name}({operands});" | ||
| ); | ||
|
|
||
| if let Some(buffer) = async_return_buffer { | ||
|
|
@@ -1364,6 +1389,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { | |
| } else { | ||
| uwriteln!(self.src, "var {resource} = ({export_name}) {export_name}.repTable.Get({op});"); | ||
| } | ||
| self.resource_type_name = Some(export_name); | ||
| } | ||
| } | ||
| results.push(resource); | ||
|
|
@@ -1375,15 +1401,27 @@ impl Bindgen for FunctionBindgen<'_, '_> { | |
|
|
||
| Instruction::FutureLower { .. } => { | ||
| let op = &operands[0]; | ||
| self.interface_gen.add_future(self.func_name); | ||
|
|
||
| results.push(format!("{op}.Handle")); | ||
| } | ||
|
|
||
| Instruction::AsyncTaskReturn { name: _, params: _ } => { | ||
| uwriteln!(self.src, "// TODO_task_cancel.forget();"); | ||
| } | ||
|
|
||
| Instruction::FutureLift { .. } | ||
| | Instruction::StreamLower { .. } | ||
| Instruction::FutureLift { payload: _, ty: _ } => { | ||
| // TODO get the prefix for the type | ||
| let sig_type_name = "Void"; | ||
| uwriteln!(self.src, "var reader = new {}.FutureReader{}({});", self.interface_gen.name, sig_type_name, operands[0]); | ||
|
||
| self.interface_gen.csharp_gen.needs_future_reader_support = true; | ||
| results.push("reader".to_string()); | ||
|
|
||
| self.interface_gen.add_future(self.func_name); | ||
| self.interface_gen.csharp_gen.needs_future_reader_support = true; | ||
| } | ||
|
|
||
| Instruction::StreamLower { .. } | ||
| | Instruction::StreamLift { .. } | ||
| | Instruction::ErrorContextLower { .. } | ||
| | Instruction::ErrorContextLift { .. } | ||
|
|
@@ -1418,7 +1456,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { | |
| uwrite!( | ||
| self.src, | ||
| " | ||
| var {ret_area} = stackalloc {element_type}[{array_size}+1]; | ||
| var {ret_area} = stackalloc {element_type}[{array_size} + 1]; | ||
| var {ptr} = ((int){ret_area}) + ({align} - 1) & -{align}; | ||
| ", | ||
| align = align.align_wasm32() | ||
|
|
@@ -1487,7 +1525,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { | |
| } | ||
|
|
||
| /// Dereference any number `TypeDefKind::Type` aliases to retrieve the target type. | ||
| fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId { | ||
| pub fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId { | ||
| loop { | ||
| match &resolve.types[id].kind { | ||
| TypeDefKind::Type(Type::Id(that_id)) => id = *that_id, | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
FutureReadershould probably have aTakeHandle()method that zeros out the handle field (and asserts that it wasn't already zero) before returning the original value so that the application won't accidentally try to use the no-longer-valid handle.