feat(js): Extract *info functions into individual functions#4751
feat(js): Extract *info functions into individual functions#4751phated wants to merge 11 commits into
Conversation
|
Reminds me of the existing classes for Here's what's done for functions, for example: binaryen/src/js/binaryen.js-post.js Lines 4766 to 4818 in 9801693 |
|
Yeah, I was wondering if doing something similar to Expressions was desirable. I'm fine implementing like that, but it'll add more work, which I'll have to find some time to do. Is there a way to move forward with the straightforward "instance logic" that I did or would the PR only be accepted if the static/class implementation were completed? |
0206660 to
b061058
Compare
| 'module'() { | ||
| return UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module)); | ||
| }, | ||
| 'base'() { | ||
| return UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module)); | ||
| }, |
There was a problem hiding this comment.
Should these be on something like self['memoryImport']?
| 'max'() { | ||
| if (Module['_BinaryenMemoryHasMax'](module)) { | ||
| return Module['_BinaryenMemoryGetMax'](module); | ||
| } |
There was a problem hiding this comment.
Wasn't sure if this should have the if condition inside the function.
There was a problem hiding this comment.
I think if there is no maximum then we should probably either error or return Infinity. Doing it here in JS makes the most sense to me (we couldn't return Infinity from C).
|
Thanks for the guidance folks! I tried to replicate patterns I had seen elsewhere in I've updated the |
| 'max'() { | ||
| if (Module['_BinaryenMemoryHasMax'](module)) { | ||
| return Module['_BinaryenMemoryGetMax'](module); | ||
| } |
There was a problem hiding this comment.
I think if there is no maximum then we should probably either error or return Infinity. Doing it here in JS makes the most sense to me (we couldn't return Infinity from C).
| 'module'() { | ||
| return UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module)); | ||
| }, | ||
| 'base'() { | ||
| return UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module)); | ||
| }, |
| // ElementSegment wrapper | ||
| Module['ElementSegment'] = (() => { | ||
| // Closure compiler doesn't allow multiple `Function`s at top-level, so: | ||
| function Function(func) { |
There was a problem hiding this comment.
Should all these Function be ElementSegment?
There was a problem hiding this comment.
Probably. I wasn't sure if these constructors should match the key or if Function was meant to be generic (due to the comment). I'll change them.
|
@kripken thanks for the feedback! I've made the updates you suggested |
| if (Module['_BinaryenMemoryHasMax'](module)) { | ||
| memoryInfo['max'] = Module['_BinaryenMemoryGetMax'](module); | ||
| var max = self['memory']['max'](); | ||
| if (max) { |
There was a problem hiding this comment.
What is this checking? If the max is 0?
I'd expect this to check if the max is Infinity, but maybe I'm missing something...
There was a problem hiding this comment.
@kripken I'm not sure, I copied this from the existing code. Who wrote that?
There was a problem hiding this comment.
@kripken how about this?
| if (max) { | |
| if (max !== Infinity) { |
There was a problem hiding this comment.
FWIW, I guess the NFC value here would be undefined. Apart from this, if my other suggestions are agreed upon to be considered, there will be a HasMax function around that can be used instead, closely matching the previous code.
| 'module'() { | ||
| return UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module)); | ||
| }, | ||
| 'base'() { | ||
| return UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module)); | ||
| }, | ||
| 'initial'() { | ||
| return Module['_BinaryenMemoryGetInitial'](module); | ||
| }, | ||
| 'shared'() { | ||
| return Boolean(Module['_BinaryenMemoryIsShared'](module)); | ||
| }, | ||
| 'max'() { | ||
| if (Module['_BinaryenMemoryHasMax'](module)) { | ||
| return Module['_BinaryenMemoryGetMax'](module); | ||
| } else { | ||
| return Infinity; | ||
| } |
There was a problem hiding this comment.
Is it intended that these are mixed with the instructions like memory.fill? Seems that it's quite easy to mistake them for instructions like memory.shared. Also, in light of multi memory, there'll likely need to be a memory wrapper anyhow to deal with any memory, so I wouldn't expect these to last for very long.
There was a problem hiding this comment.
Yes, see where Alon said "I think it's ok as it is." above.
I'm just making these easier to use, if this hasn't been updated for multiple memory, than someone else will need to help make those changes.
There was a problem hiding this comment.
Hmm, has the following variant been considered?
Module#getMemoryModule
Module#getMemoryBase
Module#getMemoryInitial
Module#isMemoryShared
Module#hasMemoryMax
Module#getMemoryMax
Those would about match Module#setMemory for now, which is similarly subject to change, with all of them not conflicting with instructions.
There was a problem hiding this comment.
I've not considered anything (maybe others have) because I'm just converting what is here from "expensive grab-bag" to "individual functions". Further improvements can be done later, as @tlively mentioned in the primary thread.
There was a problem hiding this comment.
Perhaps this is a misunderstanding. I am not suggesting any significant changes in the above variant, just to move / rename these from memory (which so far covers exclusively instructions) to the Module instance (where methods of this kind without wrappers would typically go). Basically next to setMemory.
There was a problem hiding this comment.
I'm going to leave that up to @kripken since he said it was fine to have these here when I asked.
There was a problem hiding this comment.
Hmm, good point @dcodeIO , you're right that this would mix instructions like memory.fill() with helpers. We've put the helpers on the relevant JS objects using makeExpressionWrapper. So I agree that adding new getX/setX functions alongside those is more consistent. That seems best.
@phated Sorry for not reading this more in detail the first time! (I am not as up to date on the JS API as I used to be, since I've been busy with other things...)
There was a problem hiding this comment.
Can someone else pick up these changes? We really need these changes in Grain and I don't have time to continue to make these large changes, as I'm actively needing to interview for jobs.
| Module['GlobalImport'] = (() => { | ||
| // Closure compiler doesn't allow multiple `GlobalImport`s at top-level, so: |
There was a problem hiding this comment.
The IIFE here is not necessary. Only affects JS built-ins like Function.
| Module['Global'] = (() => { | ||
| // Closure compiler doesn't allow multiple `Global`s at top-level, so: |
There was a problem hiding this comment.
Similarly, the IIFE here is not necessary. Only affects Function.
| Module['FunctionImport'] = (() => { | ||
| // Closure compiler doesn't allow multiple `FunctionImport`s at top-level, so: |
There was a problem hiding this comment.
As well: The IIFE here is not necessary. Only affects JS built-ins like Function.
| Module['Export'] = (() => { | ||
| // Closure compiler doesn't allow multiple `Export`s at top-level, so: |
| Module['ElementSegment'] = (() => { | ||
| // Closure compiler doesn't allow multiple `ElementSegment`s at top-level, so: |
| self['memorySegment'] = { | ||
| 'offset'(id) { | ||
| return Module['_BinaryenGetMemorySegmentByteOffset'](module, id); | ||
| }, | ||
| 'data'(id) { | ||
| const size = Module['_BinaryenGetMemorySegmentByteLength'](module, id); | ||
| const ptr = _malloc(size); | ||
| Module['_BinaryenCopyMemorySegmentData'](module, id, ptr); | ||
| const res = new Uint8Array(size); | ||
| res.set(new Uint8Array(buffer, ptr, size)); | ||
| _free(ptr); | ||
| return res.buffer; | ||
| }, | ||
| 'passive'(id) { | ||
| return Boolean(Module['_BinaryenGetMemorySegmentPassive'](module, id)); | ||
| } | ||
| } |
There was a problem hiding this comment.
Another suggestion to make this more uniform with other code. Move / rename these to
Module#getMemorySegmentByteOffset
Module#getMemorySegmentData
Module#isMemorySegmentPassive
Then becomes
myModule.getMemorySegmentByteOffset(segmentIndex)instead of
myModule.memorySegment.offset(id)Apart from adhering to surrounding code style, this also has the advantage that these won't conflict with eventual setters.
This is a draft that builds upon #4750
Binaryen.ml provides separate functions for each of these utilities, but using the
getMemorySegmentInfoByIndexhelper function does a lot of extra work on each function call. By providing these under a namespace, the individual functions can be provided and then used in the "info" helper.I'd like to do this to the other "info" helpers in the JS wrapper, but wanted to gather feedback first.