[PATCH 1/2] jscript: Handle detached scope objects 'this' in Object.toString.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Thu May 12 12:09:15 CDT 2022
Hi Jacek,
After analyzing the spec and the current code, I think my patches are
correct.
So, the patch you attached this time fails because 'window' is not a JS
object (proxy), so Object.toString returns [object Object] since it's a
non-JS object, but it *is* passed to it properly as 'window', so I don't
think there's any problem? It seems it's unrelated. With proxies this is
fixed, actually. It's the same as Object.prototype.toString.call(window)
which returns [object Object] right now.
What happens in that test is that 'this' is replaced with the global
object (window), this.f assigns to the window, so this.f() uses window
as 'this', which is correct and works as expected.
I've been reading the spec, which seems to differ quite a bit between
ES3 and ES5 in this matter, but it basically has similar end result for us:
3rd Edition 10.1.6: This mentions the 'Activation Object', which in our
case is the "abstract" scope, whether detached or not. It mentions:
`The activation object is purely a specification mechanism. It is
impossible for an ECMAScript program to access the activation object. It
can access members of the activation object, but not the activation
object itself.`
...which is what I mentioned earlier that the scope object itself should
never be accessible. exec_source and the part of the patch I moved
mentions 11.2.3.7, which says:
`If Result(6) is an activation object, Result(7) is null. Otherwise,
Result(7) is the same as Result(6).`
this means that the way it's done (checking for scope object, or NONE
class), it is pretty much correct and follows the spec. The GLOBAL check
is due to native jscript (not ES5) using two objects for the "global",
so it has to return the host object instead, if any, instead of the js
global. This might be a quirk on Windows implementation rather than
something in the spec, but anyway it's how it works right now.
This is why my patch adds the ES5 workaround for this; once the global
object *is* both 'window' and the js global, this is cleanly removed.
ES5 is different. 11.2.3.6 and 11.2.3.7 basically say that:
If the evaluated MemberExpression is a "PropertyReference", use its base
as 'this'. Otherwise, set it to 'undefined'.
(there's also a case where base is an "Environment Record", where it
uses the "ImplicitThisValue" of the record, but in all cases it's
'undefined', so it's the same thing, except for 'with' statements, which
are handled already IIRC).
So what does this mean? As far as I can see, a "PropertyReference" is
when you do a call like:
a.foo()
instead of
foo()
Both are handled right now in interp_call_member, via exprval_call, but
the ref type is different. For the former, we have EXPRVAL_IDREF, and
for latter we have EXPRVAL_STACK_REF.
This actually does the right thing: EXPRVAL_STACK_REF is clearly not a
"PropertyReference", while EXPRVAL_IDREF is clearly a
"PropertyReference", and I'm not sure about EXPRVAL_JSVAL. Anyway, the
former passes NULL to disp_call_value, which is correct for a
non-PropertyReference. It is fixed by resent patch 2/2, since in ES5 it
treats it as undefined instead of null, but otherwise works as intended
(null is pretty much same as undefined for almost all functions, except
for rare ones like Object.toString).
The latter uses disp_call which ends up calling it with proper 'this'.
In your patch, this is actually 'window' which is correct.
With that said, I think the patches are correct as-is. They follow
exactly what the spec says, except that maybe it could be moved to
interpreter instead of call itself, but I don't think it's worth it. The
code currently *does* seem to handle the spec properly, it just needs
some minor tweaks. Do you have other suggestions?
Perhaps do you think it's better to handle this in exprval_call itself
somehow? Because that's where we *truly* have distinction between
PropertyReference and other kind of refs. This would need extending
disp_call, though, I don't think it's worth it as I said.
Also as far as checking for JSCLASS_NONE to figure out if it's a scope
object: I don't mind any other type of check here, if you have a better
idea. I just merely copied it from exec_source.
Thanks,
Gabriel
More information about the wine-devel
mailing list