-
Notifications
You must be signed in to change notification settings - Fork 745
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
feat(js): Extract *info functions into individual functions #4751
base: main
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be on something like self['memoryImport']
?
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 think it's ok as it is.
src/js/binaryen.js-post.js
Outdated
'max'() { | ||
if (Module['_BinaryenMemoryHasMax'](module)) { | ||
return Module['_BinaryenMemoryGetMax'](module); | ||
} |
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.
Wasn't sure if this should have the if
condition inside the function.
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 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 |
src/js/binaryen.js-post.js
Outdated
'max'() { | ||
if (Module['_BinaryenMemoryHasMax'](module)) { | ||
return Module['_BinaryenMemoryGetMax'](module); | ||
} |
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 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)); | ||
}, |
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 think it's ok as it is.
src/js/binaryen.js-post.js
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should all these Function
be ElementSegment
?
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. 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kripken I'm not sure, I copied this from the existing code. Who wrote that?
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.
@kripken how about this?
if (max) { | |
if (max !== Infinity) { |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: |
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.
Same
Module['ElementSegment'] = (() => { | ||
// Closure compiler doesn't allow multiple `ElementSegment`s at top-level, so: |
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.
Same :)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
getMemorySegmentInfoByIndex
helper 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.