Comments (19)
fwiw by changing my bindings to use this
function myEncode(s, realloc, memory) {
let encodedLen
if (typeof s !== 'string') throw new TypeError('expected a string');
if (s.length === 0) {
encodedLen = 0;
return 1;
}
let allocLen = 0;
let ptr = 0;
let writtenTotal = 0;
while (s.length > 0) {
ptr = realloc(ptr, allocLen, 1, allocLen + s.length);
allocLen += s.length;
const { read, written } = utf8Encoder.encodeInto(
s,
new Uint8Array(memory.buffer, ptr + writtenTotal, allocLen - writtenTotal),
);
writtenTotal += written;
s = s.slice(read);
}
if (allocLen > writtenTotal)
ptr = realloc(ptr, allocLen, 1, writtenTotal);
encodedLen = writtenTotal;
return {ptr, encodedLen};
}
instead of utf8Encode
and replacing the above usage with
const var1 = myEncode(v0_0, realloc1, memory0);
const var2 = myEncode(v0_1, realloc1, memory0);
const {logRoot: v3_0, logLength: v3_1, mapRoot: v3_2 } = arg1;
const var4 = myEncode(v3_0, realloc1, memory0);
const var5 = myEncode(v3_2, realloc1, memory0);
exports1['protocol#prove-inclusion'](var1.ptr, var1.encodedLen, var2.ptr, var2.encodedLen, var4.ptr, var4.encodedLen, toUint32(v3_1), var5.ptr, var5.encodedLen);
I was able to resolve my bugs
from jco.
It looks like what you say is true and the global value is used to return part of the result, but I'm not clear what part of that is the "bug". Is there some sort of reentrancy, concurrency, parallelism type issue you hit with this approach or is it more that you would prefer it to return an object?
from jco.
Ah sorry I guess I was a little unclear on that. As things are, the lengths of the different variables are incorrect when I pass them to my guest code. The bytes are written to memory properly, but the first value will contain bytes from the second variable in my case, due to having a length associated with the most recent value of utf8EncodedLength
, rather than the value from from when utf8Encode
was originally called. I'd guess that one could also produce cases where the length is too short, and guest input variables end up missing bytes of data in their value, even though the bytes were written to memory properly.
from jco.
Is this mismatch between values in utf8EncodedLength
when utf8Encode
was initially called vs. when the value is needed something that happens in generated code or in your calling code? If it's in your calling code, then I would expect you can store the values as an object together yourself without needing a jco
change and if it's in generator code then we should probably fix that code.
from jco.
It's in the generated code. Actually, in the current code I'm working with, the exposed guest function takes three args, the first of which is a struct with two string fields, and the issue is happening in those two fields. The first field is getting the first handful of characters from the second field appended to the end, because the generated code communicates the wrong length of the first field to the guest export from what I can tell. So it's happening even though a single object argument containing two strings is passed to it, or so it seems to me.
from jco.
@macovedj can you share a simple example of the case here? Sounds like a bug we need to fix to me.
from jco.
Here are js bindings https://github.com/macovedj/package-explorer/blob/main/src/protocol/protocol_wasm.js#L884
generated from a component created using this wit file https://github.com/bytecodealliance/registry/pull/93/files#diff-15d3507a7e5943bee0c1ece505f3bfe26e781745ceb0fdd330d207a4d8750336R80. Snippets above were sourced from this, and I got the code to behave as I expected by implementing the myEncode
function in the above snippet over in the bindings I just linked. I have made some changes to the project since opening this issue, but I think it should still display what's going on well.
from jco.
I'll try and generate some logs that show the appended bytes
from jco.
from jco.
from jco.
@macovedj it's hard to speculate without having a full end to end example here, because there could be a number of reasons for this.
If you'd like to add some logging, I'd suggest adding console.log(utf8EncodedLen)
at each point at which an assignment occurs, and comparing that to your own implementation. I'd be very surprised if you truly are seeing different numbers. Execution in JavaScript is very much deterministic (thankfully, the language isn't that bad :P), so that the utf8EncodedLen
global variable should always take the correct value when used immediately after the last call. And because numbers are assigned by copy in JavaScript, the len1
and len2
values should be copies of the length at that point in time in the execution.
So there must be some other factor going on here (or a browser bug..!). Which environment are you testing on? Again if you can share a direct replicable example I can run I can happily investigate further. If I clone the repo, how would I set up the web server to get the bad output?
from jco.
Another thing to check - in your build process output, are you running the script as a global somehow so that window.utf8EncodedLen
is a number?
(in JS, scripts treat top-level assignments as globals, while modules treat top-level assignments as locals)
from jco.
So you should be able to just clone this repo, then do npm i
followed by npm run preview
, and click the update button in order to reproduce. There's some caching of some web/service worker stuff going on, so I'd maybe use an incognito window. The protocol
folder in components
contains the jco generated javascript. If you want to dig into the wasm, you can rebuild the wasm component by running cargo component build
in the protocol-wasm
folder in this branch of this repo. Traveling to Europe from Texas for CNCF today, but I intend to spend some time thinking about this some more soon.
from jco.
So you should be able to just clone this repo, then do
npm i
followed bynpm run preview
, and click the update button in order to reproduce. There's some caching of some web/service worker stuff going on, so I'd maybe use an incognito window. Theprotocol
folder incomponents
contains the jco generated javascript. If you want to dig into the wasm, you can rebuild the wasm component by runningcargo component build
in theprotocol-wasm
folder in this branch of this repo. Traveling to Europe from Texas for CNCF today, but I intend to spend some time thinking about this some more soon.
Actually, you'll also need to run the warg server, which you can do by running the setup-server.sh
script in the registry repo, and then use the cli to publish a package. I'll try and move that logic into one repo, to make it easier to reproduce when I can.
from jco.
Ok, sorry for the complicated steps I described prior. I just made a new repo for displaying the bug. A clone and npm i
and npm run preview
should do the trick. Generated javascript is in example-wasm
, and there's a component crate called example
if you want to rebuild the wasm. You should be able to just click the button titled "Wasm Functions" and observe that chars from one field of the input object are being added to the other in the dev tools.
from jco.
@macovedj thanks, I took a look and here's the generated code for that same section you mentioned before:
D || re();
const {a: r, b: l} = e
, o = h(r, E, i)
, s = h(l, E, i);
A["foo#hello-world"](o, p, s, p)
In the above, h
is the utf8Encode
function and p
is the global utf8EncodedLen
value.
As you can see, the JS optimization code has replaced the intermediate len1
and len2
with a direct inlining at the function call location of a single p
variable, which misses the intermediate assignment value.
This is therefore a bug with the quik optimizer in that it is assuming that the assignment can be inlined when it cannot due to it being a multi-assigned variable.
We could potentially alter our output - but the quik optimizer will have other bugs from this optimization issue, so it's probably worth reporting there. Let me know if I can help with creating that issue at all, and feel free to copy me in.
from jco.
@guybedford Ah wow thanks for looking into it. Makes sense. Will try and put some thought into an issue soon, and keep you in the loop.
from jco.
I wonder if we could wrap utf8EncodedLen
with a function that returns the global so that optimizers treat it more opaquely as a function which might have side causes and side effects.
from jco.
This issue has now been resolved in the Quik optimizer. This isn't a normal JS build bug by any means - most JS build tools would support this fine. So I'm confident we can mark this as resolved for the next Quik release and that will be the end of it.
from jco.
Related Issues (20)
- How do I use `js-component-bindgen`? HOT 1
- Incorrect codegen for `wasi:http` resource `RequestOptions` HOT 2
- JCO serve error on composed component HOT 1
- Are TypeScript definitions generated by transpile supposed to include comments from the WIT file? HOT 2
- Validity of file descriptors in the context of the `SyncKit` worker HOT 3
- Unsupported URL wasi when running in Node.js HOT 2
- Transpile bindings for `u32` map to `number` in *.d.ts HOT 3
- Non-conformant exceptions should unwrap as traps HOT 2
- Jco transpile: implementation of wasi-nn for Web HOT 2
- Source phase imports output
- Performance
- JS/WIT Reference
- Lifting `list<borrow<res>>` during transpilation emits invalid code HOT 3
- Resource transferring seems not working with wasi-virt HOT 1
- Crash on startup with an out-of-memory error when environment variables are large HOT 3
- Provide wasm-tools APIs in the browser HOT 2
- `definedResourceTables` codegen generates invalid JS with `--instantiation async` HOT 1
- plain enums are generating complex typescript HOT 8
- Question: `jco types` generating namespaces instead of modules? HOT 1
- Better instantiation workflows
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jco.