Marc,
your original problem description in Bugzilla says that the problem is
that "the protoype of a string primitive is always resolved to the one
in the context's top call scope rather than to the one in the
executing code's top scope." From my understanding of that problem
statement, if the "top scope of the executing code" were always passed
to the toObjectOrNull, instead of relying on a thread local (current
context's current top level scope), that'd solve the problem by
breaking the assumption that any scope that's active within a Context
ultimately has getCurrentContext().getTopLevelScope() as its ancestor.
You however now seem to operate with a different problem, one where
you no longer need "executing code's top scope" but rather "the top
scope of the context in which the primitive was created". That's
problematic from multiple points of view.
- First, there's no semantical definition of primitive creation at
runtime. When do you create the number literal 42? Each occurrence of
it in source code doesn't necessarily mean a new "instance" is being
generated.
- Second, the "current context's top level scope" and "scope of
currently executing code" are neatly constrained to the currently
executing code/thread. A "scope that was active when a primitive was
created" could linger around indefinitely. Is that really desirable?
Now back to the assumption that
"getCurrentContext().getTopLevelScope() is ancestor of every currently
active scope". As I said, adding a scope param to toObjectOrNull would
break this assumption and supposedly solve the original problem
reported in Bugzilla.
Honestly. I'm still fairly anxious about breaking this assumption. The
semantics of sharing objects between Contexts that use different
global standard object instances is totally out of the ECMA spec, and
if allowed, is completely implementation dependent. From point of view
of the spec, these are two different programs. Therefore, if we want
to embrace this, we need to make sure that we get it right and don't
shoot ourselves in the foot (or make it easy for other people to do so).
Also, as an ol' rule of thumb, if the architectural complexity starts
to look too hairy, that's usually a good indication we're heading in
the wrong direction. And it starts to look hairy to me. It seems like
it needs too heavy changes to support a use case that's, from my point
of view, quite marginal, and I'm not even 100% sure it's justified.
Can you maybe set up a little set of HTML pages that demonstrate the
behaviour in a web browser, so I can poke around to see what is the
exact semantics we're trying to arrive at?
But even without knowing it, let me propose a different solution to
your original problem in HtmlUnit, which seems to be cross-frame
scripting, and that I believe (for now, without seeing behaviour of
browsers) would work:
- create one scope for the master html page (with framesets) (S0),
call initStandardObjects() in it
- create one additional scope per frame (S1, S2, ...)
- call setPrototype(S0) and setParent(null) on S1, S2,...
That way, S1, S2, ... will share all standard objects (i.e. String and
String.prototype) which are defined in S0. Modifications made from S1
will be visible from S2 etc. (if S1 defines String.prototype.foo, S2
will see it).
The only caveat is that if you need to add any additional JS code into
S0 (to support browser specific functions and/or objects), you'll need
to remember to use explicit "this." in the code running in S0 to
access global variables, as S0 won't have S1 or S2 in its parent scope
chain, but I think you can probably live with that.
Attila.
On 2008.11.12., at 11:21, Marc Guillemot wrote:
sadly not :-(
If you haven't "stored" the right scope at the time where the
primitive
was "created", you can't pass it to ScriptRuntime.toObjectOrNull.
Cheers,
Marc.
Attila Szegedi wrote:
I'd prefer to just modify ScriptRuntime.toObjectOrNull signature to
take
a "Scriptable topLevelScope" argument, and then propagate the change
through the code. Is that not sufficient?
Attila.
On 2008.11.12., at 10:48, Marc Guillemot wrote:
Hi all,
as far as I know, it isn't explicitly documented anywhere how Rhino
exposes JavaScript primitives.
Current implementation exposes types as follows:
JS String primitive -> java.lang.String
JS Boolean primitive -> java.lang.Boolean
JS Number primitive -> mostly as java.lang.Double but not
consistently
(see bug https://bugzilla.mozilla.org/show_bug.cgi?id=367692)
As described in bug #374918
(https://bugzilla.mozilla.org/show_bug.cgi?id=374918), these java
types
are not appropriate to represent JS primitives correctly because
they
don't allow to store any information on the attached scope. This
means
that we have to use new classes, lets say for instance
PrimitiveString,
PrimitiveNumber and PrimitiveBoolean that hold both the value and
the
scope to fix the problem. This requires significant changes but this
works.
The problem with this PrimitiveXxxx change is that it is
automatically
visible to Java host objects, at least in following cases:
- methods accepting an Object as parameter
- methods accepting an Object[] as parameter
in the other case it is probably possible to hide the details of the
implementation and to get the java.lang.X from the PrimitiveX.
Now my question:
is it a change that can be imposed to Rhino users or has this design
error to remain here for ever to avoid breaking existing code?
Of course, I'd prefer the first way as I'd really like to see this
bug
fixed ;-)
Cheers,
Marc.
_______________________________________________
dev-tech-js-engine-rhino mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino