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

Reply via email to