-
Notifications
You must be signed in to change notification settings - Fork 27
Conversation
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.
very initial. didn't go over everything yet.
arbitrator/jit/src/gostack.rs
Outdated
self.refresh(env, store) | ||
} | ||
|
||
/// Refreshes the stack pointer after potentially the Go runtime was potentially resumed. |
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.
potentially *2
} | ||
|
||
impl PartialEq for JsValue { | ||
fn eq(&self, other: &Self) -> bool { |
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.
Is this SameValueZero (worth a comment)?
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.
also - maybe a small comment why you chose that
JsValue::String(x) => write!(f, "{x:?}"), | ||
JsValue::Object(x) => write!(f, "{x:?}"), | ||
JsValue::Uint8Array(x) => write!(f, "{x:?}"), | ||
JsValue::Array(x) => write!(f, "{x:?}"), |
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.
type should also be displayed somehow..
} | ||
|
||
/// Warning: this increments the reference count for the returned id | ||
pub fn value_to_id(&self, value: JsValue) -> JsValueId { |
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.
function name should reflect the fact we add a refcount
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.
Renamed to assign_id
+ a comment :)
// Treat all NaN values as equal | ||
JsValue::Number(x) if x.is_nan() => JsValueEquality::Number(CANONICAL_NAN_BITS), | ||
// Treat all zero values as equal | ||
JsValue::Number(x) if *x == 0. => JsValueEquality::Number(0_f64.to_bits()), |
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 assume this works for both +0. and -0.? even so.. better to just check against both to make it apparent
I've added some additional commits, and think the PR is pretty much good to go. Highlights include
|
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## stylus #166 +/- ##
==========================================
- Coverage 59.80% 58.31% -1.50%
==========================================
Files 56 280 +224
Lines 11763 43102 +31339
==========================================
+ Hits 7035 25135 +18100
- Misses 4728 15502 +10774
- Partials 0 2465 +2465 |
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 is still quite initial review and requires some talking.. specifically about when we want to panic and when we don't
We should also add (at least) two tests:
- some version of the go-js test with necessary adaptations:
https://go.dev/src/syscall/js/js_test.go - a test for reference counting, which will create many objects, have them as fields in other objects/instances in arrays etc, probably pass them between different gofuncs, and have some hook to test we have many references in the middle and no unexpected references after all objects are destroyed,
match String::from_utf8(bytes) { | ||
Ok(s) => s, | ||
Err(e) => { | ||
let bytes = e.as_bytes(); |
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.
was that intentional? won't it just print the error twice in the print below?
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.
The second print calls Debug
which includes extra info, and may change across updates to the stdlib. I've tweaked the message to provide the data in hex either way :)
} | ||
|
||
/// Assigns an id for the given value, incrementing its reference count if already present. | ||
pub fn assign_id(&self, value: JsValue) -> JsValueId { |
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.
Not mandatory in any way, but wanted to point out the original go-js implementation's version is "storeValue", which gets both the value and an address to store it. There isn't much representation through the code of value ids - only values that are stored/loaded as 8-bytes into/from memory. It has some downside, but makes the code overall less confusing, especially ref counting seems to make sense to me (because you only increase refcount when you actually store this reference)
pub fn copy_bytes_to_go(&self, src: JsValueId, write_bytes: impl FnOnce(&[u8])) { | ||
match self.values.id_to_value(src) { | ||
JsValue::Uint8Array(array) => write_bytes(&array.lock()), | ||
x => { |
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.
should return an error, caller should write 0 (instead of 1) to stack
should not panic
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, refactored :)
match self.values.id_to_value(dest) { | ||
JsValue::Uint8Array(array) => write_bytes(&mut array.lock()), | ||
x => { | ||
panic!("Go attempted to call copyBytesToJs on invalid type: {x:?}"); |
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.
should return an error, caller should write 0 (instead of 1) to stack
should not panic
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, refactored :)
let len = match self.values.id_to_value(array) { | ||
JsValue::Array(array) => array.lock().len(), | ||
JsValue::Uint8Array(array) => array.lock().len(), | ||
x => { |
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.
exists for String
exists for functions
could exist for object
returns "undefined" for bool / number and doesn't panic
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.
Go expects an integer rather than a type, so we should probs panic in our case if the result is not a number. I've updated the panic message to clarify this a bit, as well as added an implementation for String
.
env.js_state.pool.remove(id); | ||
} | ||
let js_env = &mut WasmerJsEnv::new(sp, &mut store, exports, &mut env.go_state)?; | ||
let outs = js_state.call_stylus_func(api_id, method, args, js_env)?; | ||
respond.send(outs).unwrap(); |
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 js_value_new (below):
is it o.k we're returning nil for error in case an error is returned? maybe better to create some simple error 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.
Sorry which part / error? Did you mean to add this comment somewhere else?
contracts
Outdated
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.
probably doesn't belong in this PR
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 just bumps us to the latest stylus-contracts/stylus
after a previous merge :)
go-ethereum
Outdated
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.
probably doesn't belong in this PR
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 just bumps us to the latest stylus/stylus
after a previous merge :)
system_tests/program_test.go
Outdated
@@ -40,6 +39,7 @@ import ( | |||
"github.com/offchainlabs/nitro/validator/valnode" | |||
"github.com/wasmerio/wasmer-go/wasmer" | |||
|
|||
"github.com/ethereum/go-ethereum/eth/tracers" |
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.
remove change.. or move tracers/js to be with the rest of go-ethereum imports
Fix tracing memory leak
We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign the linked documents below to get yourself added. https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=b15c81cc-b5ea-42a6-9107-3992526f2898&env=na3&acct=6e152afc-6284-44af-a4c1-d8ef291db402&v=2 |
We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign the linked documents below to get yourself added. https://na3.docusign.net/Member/PowerFormSigning.aspx?PowerFormId=b15c81cc-b5ea-42a6-9107-3992526f2898&env=na3&acct=6e152afc-6284-44af-a4c1-d8ef291db402&v=2 |
Go Js Tests
This PR was co-authored with @rachel-bousfield so it should be reviewed by someone else.
This PR is currently a draft because it doesn't implement stylus-specific functionality like callbacks into Go (and comments out stylus tests for now). That said, I think it'd make sense to review this PR in its current state to make sure this approach makes sense before adding on Stylus callbacks. Everything implemented in this PR should be complete and ready for review.
Broadly speaking, this PR largely combines the go-stub wasm-libraries Go JS implementation and the JIT Go JS implementation into a single go-js library, and switches from an imperative programming style to a declarative style.
Before this PR, methods would be implemented with a match statement against the object ID and the method name:
This had two problems. First, code was grouped by things like "object construction" and "method calls", as opposed to being grouped by "filesystem" and "crypto" objects. Second, this relied heavily on assigning static IDs for everything, which didn't work out well as the system got more complicated. When manually assigning IDs, it's easy to mess up reference counting and such. The new approach separates the implementation of JS methods from the implementation details of the JS engine. Instead of the imperative style of a match statement for every possible method, this PR changes to a declarative style where objects and their methods are created as they would be in JS. This is slightly slower, but much clearer, and it's harder to make mistakes in this model. Here's an example:
The JS method implementations in
runtime.rs
never need to care about reference counting or object IDs. They can operate solely on high-level JS values.