On 12/02/2010 23:02, Attila Szegedi wrote:
Hi again,
Sorry for taking so long.
I've started playing with the patch in the context of my ESXX project and while
I haven't had time to finish yet I have a couple of questions:
1) I already have a path array in ESXX, which also happens to be a JS array
that is searched from the front. However, having two path objects is weired, so
I'm wondering if we could either perhaps replace the 'secure' argument with a
'paths' argument (Scriptable) so I can inject mine, or add a method that
returns Require's paths object so I can use that one instead?
You can easily obtain the paths of a require instance. Remember, a require()
function is just a JS object, so you can do:
Require require = ...;
NativeArray paths = ScriptableObject.getTypedProperty(require, "paths",
NativeArray.class);
Right. The problem is that it turned out that my existing path array is
not an array of Strings but an array of (my custom) URI objects, so I
would need to provide a custom JS object that automatically presents a
string "view" but at the same time allow modifications. However, even if
I was to putProperty() that object onto Require(), the Require code will
still use its internal reference.
Anyway, I ended up simply require.delete("paths") for now. From what I
see, the paths property is optional according to CommonJS.
2) I have a special property named 'esxx.location' that contains the URI of the
currently executing file. For this to work I need to know when the Script is
executed. It could be solved by making Require.executeModuleScript protected,
or better, adding an exec method to ModuleScript.
I see - you need a post-exec hook. Okay, that's a reasonable thing. I actually at
one point in time had ModuleScript.exec(), but I scrapped it. The reason is in the
way SoftCachingModuleScriptProvider is implemented; if you look into it,
ModuleScript instances in it are not even preserved, but they are
deconstructed/reconstructed into/from the ScriptReference as needed. This is done
so that there's no strong reference Script objects being held, so unused scripts
can indeed get unloaded. (functions have pointers to their parent scripts, so as
long as there's any function from the script reachable in any of the currently
running JS program instance, they won't get GCed, otherwise they can be). For the
same reason, you shouldn't create such post-exec hook by creating a wrapper around
Script that itself implements Script with pre/post processing - you'd screw up soft
caching as you can't sneak in a strong reference to your wrapper Script object into
the Script object that Rhino compiles for you, which'd be required to ensure soft
cache doesn't load multiple reachable copies of scripts (& functions).
So, an explicit way to register a post-exec hook is the cleanest solution -
I'll look into where would this fit best.
Unfortunately, that didn't really help much, since
1. The code I'm interested in running is Java, not JS
2. No reference to the ModuleScript in question is passed to the
pre/post hooks
3. I would need hold state using a custom stack in order to restore
the location in the post-hook
I ended up with the following (somewhat hackish) ModuleScript
implementation instead:
public class ESXXScript
extends ModuleScript
implements Script {
public ESXXScript(Script script, URI uri) {
super(script, uri.toString());
this.uri = uri;
}
@Override public Script getScript() {
return this;
}
@Override public Object exec(Context cx, Scriptable scope) {
URI old_location = setCurrentLocation(uri);
try {
return super.getScript().exec(cx, scope);
}
finally {
setCurrentLocation(old_location);
}
}
private URI uri;
}
However, I still think it would be better if ModuleScript extended
Script and used public Object exec(Context cx, Scriptable scope) instead
of public Script getScript(). I can't see how that would prevent
soft-references from working as intended, but anyway, ESXXScript works
for me and I'm happy with it as it is.
More importantly, however, is the installation of the main module. I'm
setting up the application scope using custom code and not loading it as
a module, so Require.requireMain() is not applicable here.
Require.install() only installs the require() function, it does not set
up a main module.
I modified Require() to include an installMain() method. Patch attached.
Would you consider to include it? (The patch is against your 3rd
Bugzilla patch; I'm on the Rhino 7r2 branch.)
--
---- Martin Blom --------------------------- [email protected] ----
Eccl 1:18 http://martin.blom.org/
diff -ru --exclude=CVS
./src/org/mozilla/javascript/commonjs/module/Require.java
/export/home/lcs/source/rhino-7r2-commonjs/src/org/mozilla/javascript/commonjs/module/Require.java
--- ./src/org/mozilla/javascript/commonjs/module/Require.java 2010-03-02
21:36:23.139462018 +0100
+++
/export/home/lcs/source/rhino-7r2-commonjs/src/org/mozilla/javascript/commonjs/module/Require.java
2010-03-02 19:06:41.795157699 +0100
@@ -107,10 +107,41 @@
throw new IllegalStateException("main module already set to " +
this.mainModuleId);
}
- final Scriptable mainExports = getExportedModuleInterface(cx,
- mainModuleId, true);
- this.mainModuleId = mainModuleId;
- return mainExports;
+ return getExportedModuleInterface(cx, mainModuleId, true);
+ }
+
+ public void installMain(Context cx, Scriptable scope,
+ String id, String uri,
+ Scriptable exports) {
+ install(cx, scope, id, uri, exports, true);
+ exportedModuleInterfaces.put(id, exports);
+ }
+
+ private void install(Context cx, Scriptable scope,
+ String id, String uri,
+ Scriptable exports, boolean isMain) {
+ if (isMain && mainModuleId != null) {
+ throw new IllegalStateException("main module already set to " +
+ mainModuleId);
+ }
+
+ final ScriptableObject moduleObject = (ScriptableObject)cx.newObject(
+ nativeScope);
+
+ defineReadOnlyProperty(moduleObject, "id", id);
+
+ if(uri != null) {
+ defineReadOnlyProperty(moduleObject, "uri", uri);
+ }
+
+ ScriptableObject.putProperty(scope, "exports", exports);
+ ScriptableObject.putProperty(scope, "module", moduleObject);
+ install(scope);
+
+ if(isMain) {
+ defineReadOnlyProperty(this, "main", moduleObject);
+ mainModuleId = id;
+ }
}
/**
@@ -266,27 +297,14 @@
private void executeModuleScript(Context cx, String id,
Scriptable exports, ModuleScript moduleScript, boolean isMain)
{
- final ScriptableObject moduleObject = (ScriptableObject)cx.newObject(
- nativeScope);
- defineReadOnlyProperty(moduleObject, "id", id);
- if(!sandboxed) {
- final String uri = moduleScript.getUri();
- if(uri != null) {
- defineReadOnlyProperty(moduleObject, "uri", uri);
- }
- }
+ final String uri = sandboxed ? null : moduleScript.getUri();
final Scriptable executionScope = cx.newObject(nativeScope);
// Set this so it can access the global JS environment objects.
// This means we're currently using the "MGN" approach (ModuleScript
// with Global Natives) as specified here:
// <http://wiki.commonjs.org/wiki/Modules/ProposalForNativeExtension>
- ScriptableObject.putProperty(executionScope, "exports", exports);
- ScriptableObject.putProperty(executionScope, "module", moduleObject);
- install(executionScope);
+ install(cx, executionScope, id, uri, exports, isMain);
executionScope.setPrototype(nativeScope);
- if(isMain) {
- defineReadOnlyProperty(this, "main", moduleObject);
- }
moduleScript.getScript().exec(cx, executionScope);
}
_______________________________________________
dev-tech-js-engine-rhino mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino