From 75ebaa75be62e0b526b1669eccdfe67f70e99653 Mon Sep 17 00:00:00 2001 From: hns Date: Wed, 19 Apr 2006 13:52:50 +0000 Subject: [PATCH] * ALWAYS try to tetermine the proper thread scope dynamically in GlobalObject.get(), otherwise we risk to run on the wrong thread scope for nested functions, which will result in buggy behaviour _only_ if the baked-in thread scope is currently active in another request (otherwise most of its properties will be unset and the lookup forwarded to the shared global object, which will proxy it to the proper thread scope). This means we do dynamic lookup in both the shared and the thread scopes, which means we can use the same class for both cases and dump DynamicGlobalObject. In return, dynamic lookup should be somewhat optimized, so we don't do double lookups for both thread and shared scope. --- .../scripting/rhino/DynamicGlobalObject.java | 50 -------------- src/helma/scripting/rhino/GlobalObject.java | 65 ++++++++++++++----- src/helma/scripting/rhino/RhinoCore.java | 4 +- src/helma/scripting/rhino/RhinoEngine.java | 6 +- 4 files changed, 53 insertions(+), 72 deletions(-) delete mode 100644 src/helma/scripting/rhino/DynamicGlobalObject.java diff --git a/src/helma/scripting/rhino/DynamicGlobalObject.java b/src/helma/scripting/rhino/DynamicGlobalObject.java deleted file mode 100644 index 0f6a03be..00000000 --- a/src/helma/scripting/rhino/DynamicGlobalObject.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.scripting.rhino; - -import helma.framework.core.Application; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.Context; - - -/** - * This class implements a global scope object that is a dynamic proxy - * to a shared global scope and a per-thread dynamic scope. - */ -public class DynamicGlobalObject extends GlobalObject { - - public DynamicGlobalObject(RhinoCore core, Application app) { - super(core, app); - } - - public Object get(String s, Scriptable scriptable) { - Context cx = Context.getCurrentContext(); - Scriptable scope = (Scriptable) cx.getThreadLocal("threadscope"); - if (scope != null) { - Object obj = scope.get(s, scope); - if (obj != null && obj != NOT_FOUND) { - return obj; - } - // make thread scope accessible as "global" - if ("global".equals(s)) { - return scope; - } - } - return super.get(s, scriptable); - } - -} diff --git a/src/helma/scripting/rhino/GlobalObject.java b/src/helma/scripting/rhino/GlobalObject.java index 706bdf0c..219410fe 100644 --- a/src/helma/scripting/rhino/GlobalObject.java +++ b/src/helma/scripting/rhino/GlobalObject.java @@ -39,6 +39,7 @@ import java.io.*; public class GlobalObject extends ImporterTopLevel implements PropertyRecorder { Application app; RhinoCore core; + GlobalObject sharedGlobal = null; // fields to implement PropertyRecorder private boolean isRecording = false; @@ -50,9 +51,14 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder { * @param core ... * @param app ... */ - public GlobalObject(RhinoCore core, Application app) { + public GlobalObject(RhinoCore core, Application app, boolean perThread) { this.core = core; this.app = app; + if (perThread) { + sharedGlobal = core.global; + setPrototype(sharedGlobal); + setParentScope(null); + } } /** @@ -92,21 +98,6 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder { return "GlobalObject"; } - /** - * Override ScriptableObject.get() to synchronize it. - * - * @param name - * @param start - * @return the property for the given name - */ - public synchronized Object get(String name, Scriptable start) { - // register property for PropertyRecorder interface - if (isRecording) { - changedProperties.add(name); - } - return super.get(name, start); - } - /** * Override ScriptableObject.put() to implement PropertyRecorder interface * and to synchronize method. @@ -123,6 +114,48 @@ public class GlobalObject extends ImporterTopLevel implements PropertyRecorder { super.put(name, start, value); } + /** + * Override ScriptableObject.get() to synchronize it, use the per-thread scope if possible, + * and return the per-thread scope for "global". + * + * @param name + * @param start + * @return the property for the given name + */ + public synchronized Object get(String name, Scriptable start) { + // register property for PropertyRecorder interface + if (isRecording) { + changedProperties.add(name); + } + Context cx = Context.getCurrentContext(); + GlobalObject scope = (GlobalObject) cx.getThreadLocal("threadscope"); + if (scope != null) { + Object obj = scope.get(name); + if (obj != null && obj != NOT_FOUND) { + return obj; + } + // make thread scope accessible as "global" + if ("global".equals(name)) { + return scope; + } + } + if (sharedGlobal != null) { + return sharedGlobal.get(name); + } else { + return super.get(name, start); + } + } + + /** + * Directly get a property, bypassing the extra stuff in get(String, Scriptable) + * + * @param name + * @return the property for the given name + */ + protected synchronized Object get(String name) { + return super.get(name, this); + } + /** * * diff --git a/src/helma/scripting/rhino/RhinoCore.java b/src/helma/scripting/rhino/RhinoCore.java index ff8bf613..6f666376 100644 --- a/src/helma/scripting/rhino/RhinoCore.java +++ b/src/helma/scripting/rhino/RhinoCore.java @@ -42,7 +42,7 @@ public final class RhinoCore implements ScopeProvider { public final Application app; // the global object - DynamicGlobalObject global; + GlobalObject global; // caching table for JavaScript object wrappers CacheMap wrappercache; @@ -104,7 +104,7 @@ public final class RhinoCore implements ScopeProvider { try { // create global object - global = new DynamicGlobalObject(this, app); + global = new GlobalObject(this, app, false); // call the initStandardsObject in ImporterTopLevel so that // importClass() and importPackage() are set up. global.initStandardObjects(context, false); diff --git a/src/helma/scripting/rhino/RhinoEngine.java b/src/helma/scripting/rhino/RhinoEngine.java index 45af486a..6257dc35 100644 --- a/src/helma/scripting/rhino/RhinoEngine.java +++ b/src/helma/scripting/rhino/RhinoEngine.java @@ -49,7 +49,7 @@ public class RhinoEngine implements ScriptingEngine { Context context; // the per-thread global object - Scriptable global; + GlobalObject global; // the request evaluator instance owning this fesi evaluator RequestEvaluator reval; @@ -87,9 +87,7 @@ public class RhinoEngine implements ScriptingEngine { context.setApplicationClassLoader(app.getClassLoader()); try { - global = new GlobalObject(core, app); - global.setPrototype(core.global); - global.setParentScope(null); + global = new GlobalObject(core, app, true); extensionGlobals = new HashMap();