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

Reply via email to