Page 1 of 1

defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 12:48 am
by al_9x
Fx 3.6.6, NS 1.9.9.98rc3

@ surrugate:

Code: Select all

__defineGetter__('test',function(){alert('test getter');return function(){alert('replacement test');};});__defineSetter__('test',function(){alert('test setter');});
file loaded through local server:

Code: Select all

<html>
<head>
<script>
function test()
{
	alert('original test');
}
test();
window.test();
</script>
</head>
<body>
<button onclick="test();">test()</button><br>
<button onclick="window.test();">window.test()</button>
</body>
</html>
The function statement does not result in the call to the the setter and references to "test" without the "window." prefix do not result in calls to the getter. However, it does work with a function expression (var test = function()...)

I never tried this before, did it use to work?

Also, is it possible to log surrogate execution errors. It looks like they are being swallowed, currently.

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 10:37 am
by Giorgio Maone
al_9x wrote: I never tried this before, did it use to work?
Not sure, but I tend to believe it didn't.

A way to pre-emptively override a function, at the price of making the script block which later re-declares it fail, is the following:

Code: Select all

window.eval("const test=function(){}");
Notice that the scoped eval call is needed because surrogates are run inside a function block, in order to isolate their different scopes.
al_9x wrote: Also, is it possible to log surrogate execution errors. It looks like they are being swallowed, currently.
I'm gonna add a "noscript.surrogate.debug" preference in next build, which will enable console logging for all the surrogate uncaught exceptions.

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 4:57 pm
by al_9x
Giorgio Maone wrote:
al_9x wrote: I never tried this before, did it use to work?
Not sure, but I tend to believe it didn't.
What do you think is going on?
Giorgio Maone wrote:I'm gonna add a "noscript.surrogate.debug" preference in next build, which will enable console logging for all the surrogate uncaught exceptions.
Since you are making it a pref and default to off I presume, is there a down side to it?

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 5:20 pm
by Giorgio Maone
al_9x wrote: What do you think is going on?
Nothing special. Function definition <> property creation. It's just because of a side effect of global scope definition that a function declared in the window scope appears also as a property of the window. But if you invoke it by name, you're not accessing any property (and therefore you're not calling any accessor).
Another "trap" of this kind is the Function constructor: contrarily to what you may expect, it doesn't get called when you define a function the "usual" way:

Code: Select all

function () {}
but only when you use it directly for dynamic function definition:

Code: Select all

new Function("")
Giorgio Maone wrote:I'm gonna add a "noscript.surrogate.debug" preference in next build, which will enable console logging for all the surrogate uncaught exceptions.
Giorgio Maone wrote:Since you are making it a pref and default to off I presume, is there a down side to it?
Yes, performance. Logging errors for surrogates requires them to be processed (compiled and executed) one by one, while the current non-logging implementation collapse all the surrogates which apply to a certain page in one single script block.

BTW, change available in latest development build.

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 7:03 pm
by al_9x
Giorgio Maone wrote:Nothing special. Function definition <> property creation. It's just because of a side effect of global scope definition that a function declared in the window scope appears also as a property of the window. But if you invoke it by name, you're not accessing any property (and therefore you're not calling any accessor).
10.1.3 wrote:For each FunctionDeclaration in the code, in source text order, create a property of the variable object whose name is the Identifier in the FunctionDeclaration, whose value is the result returned by creating a Function object
as described in section 13, and whose attributes are determined by the type of code. If the variable object
already has a property with this name, replace its value and attributes. Semantically, this step must follow the
creation of FormalParameterList properties.

For each VariableDeclaration or VariableDeclarationNoIn in the code, create a property of the variable object
whose name is the Identifier in the VariableDeclaration or VariableDeclarationNoIn, whose value is undefined
and whose attributes are determined by the type of code. If there is already a property of the variable object with
the name of a declared variable, the value of the property and its attributes are not changed. Semantically, this
step must follow the creation of the FormalParameterList and FunctionDeclaration properties. In particular, if a
declared variable has the same name as a declared function or formal parameter, the variable declaration does
not disturb the existing property
It seems clear that "function test() {}" should be equivalent to "var test = function() {};" and both should become properties of the window in the global scope. I still don't understand why the difference in behavior.

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 7:12 pm
by Giorgio Maone
Looks like SpiderMonkey does not conform to the specification. It behaves more like I describe it earlier.

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 7:44 pm
by al_9x
Giorgio Maone wrote:Looks like SpiderMonkey does not conform to the specification.
Do you think it's worth filing a bug? This technique seems to be the only way to guarantee function replacement, so it would be good it it worked.

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 8:14 pm
by Giorgio Maone
al_9x wrote:
Giorgio Maone wrote:Looks like SpiderMonkey does not conform to the specification.
Do you think it's worth filing a bug?
Probably yes, but a conforming implementation could still not help for the original purpose: the "If the variable object
already has a property with this name, replace its value and attributes" statement could still be intepreted as

Code: Select all

delete object.property // this deletes getters and setters as well
object.property = newValue

Re: defineGetter function replacement technique not working

Posted: Thu Jul 01, 2010 11:07 pm
by al_9x
Here's a test page that takes NS out of the equation

Code: Select all

<html>
<head>
<script>
window.__defineGetter__('foo', function() {alert('foo getter'); return function() {alert('new foo');};});
window.__defineSetter__('foo', function() {alert('foo setter');});
</script>
<script>
function foo()
{
	alert('original foo');
}
</script>
</head>
<body>
<button onclick="foo();">foo()</button><br>
<button onclick="window.foo();">window.foo()</button>
</body>
</html>
In both chrome and opera it works as we would want, function statement triggers the setter and both foo() and window.foo() call the getter.

Do you want to ask them about it or create a bug or should I?

Re: defineGetter function replacement technique not working

Posted: Fri Jul 02, 2010 7:54 am
by Giorgio Maone
al_9x wrote: Do you want to ask them about it or create a bug or should I?
It's your discover, I think it would be useful at least for cross-browser consistency (if not standard conformance, which is debatable), so I think you should go ahead and file a bug against the SpiderMonkey component (please CC me, too).

Re: defineGetter function replacement technique not working

Posted: Wed Jul 07, 2010 7:35 pm
by al_9x
Created Bug 577325 and added you to its cc list.

Re: defineGetter function replacement technique not working

Posted: Wed Jul 07, 2010 9:07 pm
by Giorgio Maone
al_9x wrote:Created Bug 577325 and added you to its cc list.
Congrats, you got Brendan Eich's eyes on it :)

Re: defineGetter function replacement technique not working

Posted: Wed Jul 07, 2010 11:32 pm
by al_9x
Giorgio Maone wrote:
al_9x wrote:Created Bug 577325 and added you to its cc list.
Congrats, you got Brendan Eich's eyes on it :)
Evidently ES5 is more precise on this, i.e. the preexisting property should not be removed, but modified.
ES5 10.5 wrote:
  • For each FunctionDeclaration f in code, in source text order do
    1. Let fn be the Identifier in FunctionDeclaration f.
    2. Let fo be the result of instantiating FunctionDeclaration f as described in Clause 13.
    3. Let funcAlreadyDeclared be the result of calling env’s HasBinding concrete method passing fn as the argument.
    4. If funcAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing fn and configurableBindings as the arguments.
    5. Call env’s SetMutableBinding concrete method passing fn, fo, and strict as the arguments
Though Brendan doesn't seem to like it.
Brendan Eich wrote:It's a little nasty for integrity (such as it is in JS) that a function
declaration no longer blows away any prior configurable property of the same
name.
Likely, it will be fixed only for Fx4.

I still think this is not a change from ES3, though the spec is less precise, the English phrase "replace its value" means modify the value of an existing property (it), just as "replace its engine (with this new one)" does not mean "make a new car (with this new engine)"

Re: defineGetter function replacement technique not working

Posted: Sat Jun 18, 2011 9:57 pm
by al_9x
Giorgio Maone wrote:
al_9x wrote:Created Bug 577325 and added you to its cc list.
Congrats, you got Brendan Eich's eyes on it :)
Well, they changed the ES5 spec in response to my bug, so now this technique doesn't work by explicit design.