-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Add Function#caller and Function#arguments to Annex B #562
Comments
In fact, |
EDIT 2019-12-09: Modified the test functions in order to prevent PTC to be triggered, and added Safari 13 result. Different browsers have different semantics for Consider the function: function f() {
var r = f.caller;
return r;
} Consider the testcases: // the caller is a sloppy-mode function
(function g() {
var r = f();
return r;
})();
// the caller is a strict-mode function
(function h() {
"use strict";
var r = f();
return r;
})();
// the caller is a built-in function
[1,2].reduce(f);
// the following additional test may show that PTC has not eliminated reduce() in Safari:
[1,2].reduce(function f () { throw new Error; }); // and inspect the stack of the error Here are the results:
The question is: Do we pick the semantics of Firefox or the one of Chrome? |
The goal here is to specify the absolute minimum observable semantics required to run web code. Edge 15 throws a TypeError for case If caller is built-in, null seems best. I'd prefer a TypeError but that seems unlikely to be web compatible? Function#arguments and Function#caller should be disabled for functions with non-simple parameter lists (ie. not have the own properties, so look up to throwers). Spidermonkey seems to do this now so we can probably get away with this too? |
I'm not sure if divergence among browsers is enough to prove that picking one of them will not cause issues for users of a particular browser. Ideally, to make a decision, we would have some more data about how often a case occurs (infrequent cases are more OK to change semantics) as we got for |
@littledan which of the proposed semantics are you worried about? I guess the type error for accessing caller when caller is strict is most concerning. I doubt that non-simple parameter lists not supporting this is worrying from a compat perspective. |
The effect of Note that the specified behavior was to throw a TypeError. That was removed from the ES6 spec. after Mark Miller and I convinced ourselves that it was no longer necessary because of other ES6 spec. changes. But I don't remember the details right now. It is probably captured somewhere in bugs.ecmascript.org. |
I vaguely recall us just hoping browsers would just leave that property off ( It seems like nobody does that though, either defining a property with value |
I vaguely recall we had a different semantics prior to putting throwers on Function.prototype (and that the change came somewhat late). I wonder if making that change made it so we shoul dhave added the ES5.1 15.3.5.4 semantics back? |
It is covered in http://tc39.github.io/ecma262/#sec-forbidden-extensions |
The bigger question is what is the result of: // the caller is a sloppy-mode function
function g() {
return f(0);
};
function f(n) {
var caller1 = f.caller;
if (n==0) f(1);
var caller2 = f.caller;
if (n==0) console.log(caller1===caller2);
} Does it log true or false? Presumably depends upon whether or not there is a single state slot in the function object. I think we talked about this at a TC39 meeting but nobody really want to put energy into fullyspecifying this highly deprecated "feature" so it didn't go into Annex B. It probably isn't interoperable for cases like the above now. I suspect that no implementation would really want to waste time changing their implementation to make it inter-operable for such cases. What value comes from specifying it? |
possibly no value, but that "quiz" is easy to solve. Recursion makes the The answer is It'd be worst/unreasonable practice, in my opinion, to ask twice for a Just my 2 cents On Thu, May 12, 2016 at 12:11 AM, Allen Wirfs-Brock <
|
@allenwb Good point
Good point. Fortunately, it logs
It is useful to make sure that implementations does not do unadvisable things; and it may be easier or safer to achieve that by a simple specification. |
if it's about setting it up at the beginning and dropping it at the end (or A non-issue to solve, probably not even needed to be specified? On Thu, May 12, 2016 at 8:46 AM, Claude Pache [email protected]
|
Are you sure? I just tested this in Firefox Nightly web console: function f(x = 1) { return f.caller }
(function g(x = 1) { return f() })(); // returns: function g() In case there is confusion about the absence of own properties: Firefox doesn't have own properties anymore on individual functions, but it doesn't mean that the functionality is gone. Instead, all logic has been displaced inside the |
In V8, these properties have a purely "best effort" implementation. Whether they work, and with what specific semantics, depends on a variety of static and dynamic factors, like optimisation levels. IOW, there is not even a consistent "Chrome semantics". Changing this would introduce significant overhead and complexity, in particular wrt Function#arguments. We hence see zero -- or even negative -- value in elevating these (mis)features to the standard, even if it's just Annex B. We can serve the community better by spending our resources elsewhere. |
@claudepache I am not sure! Confirmed your example is correct. I wish I had the sample I was using before as js.exe was the only one throwing on it. Alas, it is missing. I also updated today so possibly it's a recent change. Anyway, I would still hope we could not do this. @rossberg-chromium would you agree that there is some semantics here required to run the web? If so, that is what we should spec. If not, you (and all of us) should just remove this functionality. You can always choose when to fix bugs (or, not to fix them) :) |
@bterlson, not necessarily. They are probably used primarily for debugging and other diagnostics, rather than actual programmatic logic. In that case, a best-effort implementation is still useful, despite the reliable intersection semantics being practically empty. |
In that case, they could probably be neutered (by returning Otherwise, if they are bound to remain, I think that a minimal specification, allowing implementation-defined behaviour at some well-guarded places if desired, is useful. For example, here are two points that could be improved relatively to the current situation:
function B() {}
var C = (function() {
"use strict"
return class C extends B {}
})()
C.arguments // will return B.arguments ... oops |
Given the turmoil we are seeing around tail call elimination, we might not At the same time, there is no good reason to encourage new code to use Otherwise, if they are bound to remain, I think that a minimal
Why are you saying that access to built-in callers is unwarranted? Not |
On May 17, 2016 5:56 AM, Claude Pache [email protected] wrote:
|
On 17 May 2016 at 15:36, Allen Wirfs-Brock [email protected] wrote:
Allen, in what sense is "implemented via a strict ES function" a meaningful |
No, something can be done, and Firefox has done it: remove those own properties on every individual functions, including sloppy-mode ones, and define "arguments" and "caller" accessor properties on |
Plus one's aren't very helpful, I know. But +1 all the same (particularly to the second point). |
Minus ones are nevertheless useful to point to actions that people don’t want to be taken. I have updated the proposed spec in order to allow some implementation-defined behaviour, while keeping safety and soundness for non-sloppy functions. In particular, V8 is allowed to keep its nondeterministic semantics in order to discourage their use :-) |
On May 17, 2016 8:58 AM, rossberg-chromium [email protected] wrote:
See https://tc39.github.io/ecma262/#sec-built-in-function-objects |
I still don't understand how this is observable. An implementation can |
After reflection, I understand that putting this in Annex B may not be desirable. However, there is still room for improvement w.r.t. the current situation, maybe by putting more constraints in Section 16.2 Forbidden Extensions. Concretely:
And, in order to minimise API surface and avoid the issue of function objects inheriting from others, the following may be nice (implemented by Firefox):
|
I like the first two suggestions. I'm less thrilled about the latter, because that means that all functions, including strict ones, will have these properties (even if they throw on some). That seems strictly worse than the own property approach, where they only show up on non-sloppy functions in some inheritance corner cases. |
This is already the case according to the current spec, because the AddRestrictedFunctionProperties() operation is applied to %FunctionPrototype%, see CreateIntrisics(). One could just kill AddRestrictedFunctionProperties() instead; but really, I don’t think that it is in any way better than the current inherit-from-sloppy-mode-function hazard. |
@evilpie any update? |
I am not working on this. Maybe @claudepache could refresh their old proposal. Firefox seems to have some more restrictions: https://searchfox.org/mozilla-central/rev/c43240cef5829b8a2dec118faff8a5e1fec6ae1b/js/src/vm/JSFunction.cpp#132-179. We only allow FunctionDeclaration or FunctionExpression, which aren't async, generators etc. Also no methods/getters etc.
|
( |
Good point. I've opened claudepache/es-legacy-function-reflection#1. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Is there anything we can do to help this work land? We got a bug report about Function Would love to see this standardized so implementations can converge. |
I believe we next need a PR, unless i missed one farther upthread. |
The relevant issue is: Given that the caller of // "don't use strict"
function g() { "use strict"; return f() }
function f() { return f.caller; }
g(); Chrome and Safari return null. Firefox throws a TypeError (and that, since long ago: I've just tested FF17 released in 2012). Both behaviours are OK, although throwing a TypeError is subjectively strictly better in the sense that it is a better incitation for 🔥ing that from their code. Whether Firefox should change behaviour depends, I think, on how hard it is needed for web compatibility. |
@claudepache what does edge do, and what did IE do? |
Every difference in behavior is a web compatibility risk, so there's some pressure to converge regardless of what TC39 does. But standardizing things to improve web compatibility and the developer experience is TC39's mandate, right? By all means, please go ahead and do it. Since implementations currently differ, you can have your pick of behavior. Just don't leave this unspecified for our (Mozilla's) benefit. We'll implement the standard. |
@ljharb Both IE and Edge throw a TypeError. |
In that case, it seems like half the web does one thing, and half another, so we can pick what either pair of them do, as long as at least one of the other two are willing to change? |
Since we still have a choice, throwing the TypeError is much better. We should specify that. |
Would someone like to make a PR, reach out to the engines that will need to make a change, and write test262 tests? |
In fact, Safari does throw (like Firefox and Edge) when the caller property is about to reveal a strict-mode function: I've been tripped by PTC. A non-tail-call-sensitive test case is: // "don't use strict"
function g() { "use strict"; var r = f(); return r; }
function f() { return f.caller; }
g(); I’ve tested some other cases, see: claudepache/es-legacy-function-reflection#1; from those results, I’ll amend my proposal. |
Hi, I have completed the analysis of how browsers currently implement .caller and .arguments, and I have modified the proposed spec in a way that is both as near as possible to what implementations do, while being as secure and consistent as possible. The good news is that implementations are remarkably consistent between each other, except for small — but sometimes important — details; so that they’ll need to do minimal changes. @erights is intending to present the proposal at the next meeting. |
... because I doubt that any browser vendor would kill them.
I have written a strawman here: https://github.com/claudepache/es-legacy-function-reflection
Some notes:
Function#caller
andFunction#arguments
are specced as configurable getters onFunction.prototype
rather than properties of individual functions, following Firefox's example.arguments.caller
is not supported by any browser, I think that step 9 of CreateUnmappedArgumentsObject can be removed.arguments.callee
is currently specced in ECMA262 as unavailable for sloppy-mode functions with nonsimple parameter list. Question: ShouldFunction#arguments
andFunction#caller
be disabled for those functions as well?The text was updated successfully, but these errors were encountered: