-
Notifications
You must be signed in to change notification settings - Fork 570
WIP: Ability to call overridden functions from the std library #798
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
Conversation
@r-l-x - can you update the example in the description to be concrete, i.e. a real situation where we would use this? I'm struggling to understand how/where this would be used (sorry, probably being slow). Thanks |
Ah, presumably https://github.com/r-l-x/gopherjs/blob/bcfda31b2bc688a9dce31c1402629ad44d949d14/compiler/natives/src/crypto/sha256/sha256.go#L28-L38 is such an example? |
@myitcv Yes exactly. |
My suggestion would be we use this directive for at least one function as part of this PR to demonstrate it actually works, passes tests, minifies properly etc. Then we can add additional functions etc as proposed in #558 and anything else in future PRs. |
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.
Adding as a review
My suggestion would be we use this directive for at least one function as part of this PR to demonstrate it actually works, passes tests, minifies properly etc.
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.
Adding as a review
My suggestion would be we use this directive for at least one function as part of this PR to demonstrate it actually works, passes tests, minifies properly etc.
Sorry for the noise in my last few comments/reviews... |
Well, actually, #558 is the prefect exemple for this (and it's based on this branch). @shurcooL suggested issuing a separate PR for this, so that's what I did, but if you prefer considering #558 directly, I don't mind. It's not easy to add a "minimalist" use for this feature without risking breaking something or adding useless code. |
I think this is the key. Either there needs to be a test or some minimal use of what's being committed in this PR, some way we can "know" it's working. |
Ok, I just used this in the gopherjs regexp test "TestOnePassCutoff". This test was systematically skipped, because apparently it may raise "Maximum call stack size exceeded" errors. I rewrote the test using And actually both on my configuration and on circleci the test runs well (so it seems like it could be re-enabled):
|
Perfect.
Thanks for flagging. I suspect this got fixed by #687. I've raised #801 to follow up on re-enabling this and other tests. |
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.
Minor proposed fix.
return false | ||
} | ||
for _, comment := range doc.List { | ||
text := comment.Text |
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.
Might I suggest the following is slightly clearer in its intention?
text := strings.TrimRightFunc(comment.Text, unicode.IsSpace)
if text == "//gopherjs:keep_overridden" {
return true
}
i.e. you're looking for a line that contains only the special comment, save any trailing space.
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 actually took this part from the go pragma directive parser:
https://github.com/golang/go/blob/master/src/cmd/compile/internal/gc/noder.go#L1435
It seems like you can add text after a go pragma directive, and it will be ignored, and I think it's a good idea to do the same here.
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.
Got it. I think you'll find that is effectively the parse phase of the compiler; so it has to deal with all types of pragma. Many of which take arguments.
In this case we've already parsed into the AST and we know we have a comment group.
And specifically, I'm guessing you want //gopherjs:keep_overridden
to be used without arguments, because there are none. Hence it doesn't make sense for anything to follow that special 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.
Considering the pragma function from the standard library, my understanding is that pragmas expecing arguments (go:linkname
, go:cgo_*
) are treated in the non-default cases of the switch. The default case, from which this code is taken, only treats pragmas with no arguments (go:nointerface
, go:noescape
, etc., see the implementation of pragmaValues)
So it looks like the standard library allows putting any text (so basically a comment) after a pragma without argument. I think it's appropriate to have the same behaviour here (even if I agree that it's not the typical use case).
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.
So it looks like the standard library allows putting any text (so basically a comment) after a pragma without argument. I think it's appropriate to have the same behaviour here (even if I agree that it's not the typical use case).
You're absolutely right, thanks for correcting me.
I'm easy either way; in this PR I think you can be very specific and prescriptive because you're defining the pragma so it's in your gift to do what you want 😄 - to my mind doing so keeps the documentation (on how to use your pragma) simple as well as the implementation.
But, as I said earlier, it's a minor point in any case.
Before this commit, every overriden standard library function was renamed '_'. Now, if there is the following directive in the function comment: "//gopherjs:keep_overridden", they are prefixed with "_gopherjs_overridden_" so that they can be called from the overriding function. This is typically useful to use the standard library implementation as a fallback.
Before this commit, TestOnePassCutoff was skipped because a 'Maximum call stack size exceeded' message may occur. Now we use gopherjs:keep_overridden to try the original test, and skip only if the original test failed.
I just rebased to fix conflicts and fixed a typo in the code. |
This LGTM 👍 |
Hi @r-l-x, I'm finally getting through the backlog of issues and pull requests, sorry it took this long. This seems like a very useful change, would you be able to rebase it on top of the current master? |
Hi @nevkontakte, when trying to rebase this, I saw that a new |
@r-l-x yes, renaming to |
Rebased and merged as #1216 |
Gopherjs overrides some functions from the go standard library. The original implementation from the standard library gets removed from the compilation process.
This PR implements the ability to retain designated overridden functions from the go standard library.
#558 is a typical use case for this (try an optimized way to get the result, but if this doesn't work, fallback to the standard library).
Here is how to use it:
If a function in
compiler/natives
overrides a function from the standard library and has thegopherjs:keep_overridden
directive in the function comment, then the overridden function from the standard library will be compile, and can be called under the name_gopherjs_overridden_<function_name>
.A typical use would look like (in a file in
compiler/natives
):