GlobalScope is removed as its introduction had to serious consequences with compatibility and usage. Instead a special purpose class ClassCache is introduces to hold various caches. The class binds itself to an arbitrary object by using new SciptableObject.associateValue method so arbitrary ScriptableObject can be used as a scope without performance penalties.

This commit is contained in:
igor%mir2.org 2003-11-01 15:34:23 +00:00
Родитель 5346dbdacf
Коммит 16dcc44df0
16 изменённых файлов: 327 добавлений и 261 удалений

Просмотреть файл

@ -1,4 +1,5 @@
apiClasses=\
src/org/mozilla/javascript/ClassCache.java,\
src/org/mozilla/javascript/ClassDefinitionException.java,\
src/org/mozilla/javascript/ClassRepository.java,\
src/org/mozilla/javascript/ClassShutter.java,\
@ -8,7 +9,6 @@ apiClasses=\
src/org/mozilla/javascript/ErrorReporter.java,\
src/org/mozilla/javascript/Function.java,\
src/org/mozilla/javascript/FunctionObject.java,\
src/org/mozilla/javascript/GlobalScope.java,\
src/org/mozilla/javascript/ImporterTopLevel.java,\
src/org/mozilla/javascript/JavaScriptException.java,\
src/org/mozilla/javascript/PropertyException.java,\

Просмотреть файл

@ -70,7 +70,7 @@ the scripts are responsible for coordinating any accesses to shared variables.
<p>A top-level scope is created by calling <tt>Context.initStandardObjects</tt>
to create all the standard objects: </p>
<pre>
GlobalScope scope = cx.initStandardObjects();
ScriptableObject scope = cx.initStandardObjects();
</pre>
The easiest way to embed Rhino is just to create a new scope this way whenever
you need one. However, <tt>initStandardObjects</tt> is an expensive method
@ -146,7 +146,7 @@ can be used concurrently. <br>
<p>The ECMAScript standard defines that scripts can add properties to all standard library objects and in many cases it is also possible to change or delete their properties as well. Such behavior may not be suitable with shared scopes since if a script by mistake adds a property to a library object from the shared scope, that object would not be garbage collected until there re active references to the shared scope potentially leading to memory leaks. In addition if a script alters some of the standard objects, the library may not work properly for other scripts. Such bugs are hard to debug and to remove a possibility for them to occur one can use seal the shared scope and all its objects.
<p>
A notion of a sealed object is a JavaScript extension supported by Rhino and it means that properties can not be added/deleted to the object and the existing object properties can not be changed. Any attempt to modify sealed object throws an exception. To seal all objects in the standard library pass <tt>true</tt> for the sealed argument when calling <tt>Context.initStandardObjects(boolean)</tt>:
<pre> GlobalScope sealedSharedScope = cx.initStandardObjects(true);</pre>
<pre> ScriptableObject sealedSharedScope = cx.initStandardObjects(true);</pre>
This seals only all standard library objects, it does not seal the shared scope itself thus after calling <tt>initStandardObjects</tt>, <tt>sealedSharedScope</tt> cab be farther populated with application-specific objects and functions. Then after a custom initialization is done, one can seal the shared scope by calling <tt>ScriptableObject.sealObject()</tt>:
<pre> sealedSharedScope.sealObject();</pre>

Просмотреть файл

@ -79,7 +79,7 @@ public class DynamicScopes {
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed. The call
// returns a new scope that we will share.
GlobalScope scope = cx.initStandardObjects(true);
ScriptableObject scope = cx.initStandardObjects(true);
// Now we can evaluate a script and functions will be compiled to
// use dynamic scope if the Context is so initialized.

Просмотреть файл

@ -43,8 +43,13 @@ import java.io.*;
*
* @author Norris Boyd
*/
public class Shell extends GlobalScope
public class Shell extends ScriptableObject
{
public String getClassName()
{
return "global";
}
/**
* Main entry point.
*
@ -213,7 +218,7 @@ public class Shell extends GlobalScope
public static void load(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Shell shell = (Shell)GlobalScope.get(thisObj);
Shell shell = (Shell)getTopLevelScope(thisObj);
for (int i = 0; i < args.length; i++) {
shell.processSource(cx, cx.toString(args[i]));
}

Просмотреть файл

@ -0,0 +1,199 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is cache holder of generated code for Java reflection
*
* The Initial Developer of the Original Code is
* RUnit Software AS.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Igor Bukanov, igor@fastmail.fm
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.javascript;
import java.io.*;
import java.util.Hashtable;
/**
* Cache of generated classes and data structures to access Java runtime
* from JavaScript.
*
* @author Igor Bukanov
*
* @since Rhino 1.5 Release 5
*/
public class ClassCache
{
private static final Object AKEY = new Object();
private volatile boolean cachingIsEnabled = true;
Hashtable classTable = new Hashtable();
boolean invokerOptimization = true;
Invoker invokerMaster;
Hashtable javaAdapterGeneratedClasses = new Hashtable();
Hashtable javaAdapterIFGlueMasters = new Hashtable();
private int generatedClassSerial;
/**
* Search for ClassCache object in the given scope.
* The method first calls
* {@link ScriptableObject.getTopLevelScope(Scriptable scope)}
* to get the top most scope and then tries to locate associated
* ClassCache object in the prototype chain of the top scope.
*
* @param scope scope to search for ClassCache object.
* @return previously associated ClassCache object or a new instance of
* ClassCache if no ClassCache object was found.
*
* @see #associate(ScriptableObject topScope)
*/
public static ClassCache get(Scriptable scope)
{
scope = ScriptableObject.getTopLevelScope(scope);
Scriptable obj = scope;
do {
if (obj instanceof ScriptableObject) {
ScriptableObject so = (ScriptableObject)obj;
ClassCache lc = (ClassCache)so.getAssociatedValue(AKEY);
if (lc != null) {
return lc;
}
}
obj = obj.getPrototype();
} while (obj != null);
// ALERT: warn somehow about wrong cache usage ?
return new ClassCache();
}
/**
* Associate ClassCache object with the given top-level scope.
* The ClassCache object can only be associated with the given scope once.
*
* @param topScope scope to associate this ClassCache object with.
* @return true if no prevous ClassCache objects were embedded into
* the scope and this ClassCache were successfully associated
* or false otherwise.
*
* @see #get(Scriptable scope)
*/
public boolean associate(ScriptableObject topScope)
{
if (topScope.getParentScope() != null) {
// Can only associate cache with top level scope
throw new IllegalArgumentException();
}
return this != topScope.associateValue(AKEY, this);
}
/**
* Empty caches of generated Java classes and Java reflection information.
*/
public synchronized void clearCaches()
{
classTable = new Hashtable();
javaAdapterGeneratedClasses = new Hashtable();
javaAdapterIFGlueMasters = new Hashtable();
Invoker im = invokerMaster;
if (im != null) {
im.clearMasterCaches();
}
}
/**
* Check if generated Java classes and Java reflection information
* is cached.
*/
public final boolean isCachingEnabled()
{
return cachingIsEnabled;
}
/**
* Set whether to cache some values.
* <p>
* By default, the engine will cache generated classes and
* results of <tt>Class.getMethods()</tt> and similar calls.
* This can speed execution dramatically, but increases the memory
* footprint. Also, with caching enabled, references may be held to
* objects past the lifetime of any real usage.
* <p>
* If caching is enabled and this method is called with a
* <code>false</code> argument, the caches will be emptied.
* <p>
* Caching is enabled by default.
*
* @param cachingEnabled if true, caching is enabled
*
* @see #clearCaches()
*/
public synchronized void setCachingEnabled(boolean enabled)
{
if (enabled == cachingIsEnabled)
return;
if (!enabled)
clearCaches();
cachingIsEnabled = enabled;
}
/**
* To optimize invocation of reflected Java methods, the engine generates
* special glue classes that will call the methods directly. By default
* the optimization is enabled since it allows to speedup method invocation
* compared with calling <tt>Method.invoke</tt> by factor 2-2.5 under JDK
* 1.4.2 and by factor 10-15 under JDK 1.3.1. If increase memory
* consumption is too high or the optimization brings no benefits in a
* particular VM, then the optimization can be disabled.
*
* @param enabled if true, invoke optimization is enabled.
*/
public synchronized void setInvokerOptimizationEnabled(boolean enabled)
{
if (invokerOptimization == enabled)
return;
if (!enabled)
invokerMaster = null;
invokerOptimization = enabled;
}
/**
* Internal engine method to return serial number for generated classes
* to ensure name uniqueness.
*/
public final synchronized int newClassSerialNumber()
{
return ++generatedClassSerial;
}
}

Просмотреть файл

@ -671,7 +671,7 @@ public class Context {
*
* @return the initialized scope
*/
public GlobalScope initStandardObjects()
public ScriptableObject initStandardObjects()
{
return initStandardObjects(false);
}
@ -699,11 +699,11 @@ public class Context {
* cannot be modified.
* @return the initialized scope
*/
public GlobalScope initStandardObjects(boolean sealed)
public ScriptableObject initStandardObjects(boolean sealed)
{
GlobalScope global = new GlobalScope();
initStandardObjects(global, sealed);
return global;
NativeObject scope = new NativeObject();
initStandardObjects(scope, sealed);
return scope;
}
/**
@ -718,10 +718,6 @@ public class Context {
*
* This method does not affect the Context it is called upon.
*
* If the explicit scope argument is not null and is not an instance of
* {@link GlobalScope} or its subclasses, parts of the standard library
* will be run slower.
*
* @param scope the scope to initialize, or null, in which case a new
* object will be created to serve as the scope
* @return the initialized scope
@ -750,10 +746,6 @@ public class Context {
* the current ECMA/ISO language specification, but is likely for
* the next version.
*
* If the explicit scope argument is not null and is not an instance of
* {@link GlobalScope} or its subclasses, parts of the standard library
* will be run slower.
*
* @param scope the scope to initialize, or null, in which case a new
* object will be created to serve as the scope
* @param sealed whether or not to create sealed standard objects that
@ -765,10 +757,9 @@ public class Context {
boolean sealed)
{
if (scope == null) {
scope = new GlobalScope();
} else if (!(scope instanceof GlobalScope)) {
GlobalScope.embed(scope);
scope = new NativeObject();
}
(new ClassCache()).associate(scope);
BaseFunction.init(this, scope, sealed);
NativeObject.init(this, scope, sealed);
@ -1529,8 +1520,8 @@ public class Context {
/**
* @deprecated To enable/disable caching for a particular top scope,
* use {@link GlobalScope#get(Scriptable)} and
* {@link GlobalScope#setCachingEnabled(boolean)}.
* use {@link ClassCache#get(Scriptable)} and
* {@link ClassCache#setReflectionCachingEnabled(boolean)}.
* The function is kept only for compatibility and does nothing.
*/
public static void setCachingEnabled(boolean cachingEnabled)

Просмотреть файл

@ -115,12 +115,12 @@ public class FunctionObject extends BaseFunction
public FunctionObject(String name, Member methodOrConstructor,
Scriptable scope)
{
GlobalScope global = GlobalScope.get(scope);
ClassCache cache = ClassCache.get(scope);
if (methodOrConstructor instanceof Constructor) {
member = new MemberBox((Constructor) methodOrConstructor, global);
member = new MemberBox((Constructor) methodOrConstructor, cache);
isStatic = true; // well, doesn't take a 'this'
} else {
member = new MemberBox((Method) methodOrConstructor, global);
member = new MemberBox((Method) methodOrConstructor, cache);
isStatic = member.isStatic();
}
String methodName = member.getName();

Просмотреть файл

@ -1,150 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Igor Bukanov
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.io.*;
import java.util.Hashtable;
/**
* Object to use as a top-level scope for the standard library objects.
* @since 1.5 Release 5
*/
public class GlobalScope extends ScriptableObject
{
public String getClassName()
{
return "global";
}
public static GlobalScope get(Scriptable scope)
{
if (scope instanceof GlobalScope) {
return (GlobalScope)scope;
}
scope = ScriptableObject.getTopLevelScope(scope);
Scriptable obj = scope;
do {
if (obj instanceof GlobalScope) {
return (GlobalScope)obj;
}
obj = obj.getPrototype();
} while (obj != null);
Object x = ScriptableObject.getProperty(scope, "__globalScope");
if (x instanceof GlobalScope) {
return (GlobalScope)x;
}
return new GlobalScope();
}
/**
* Set whether to cache some values.
* <p>
* By default, the engine will cache some values
* (reflected Java classes, for instance). This can speed
* execution dramatically, but increases the memory footprint.
* Also, with caching enabled, references may be held to
* objects past the lifetime of any real usage.
* <p>
* If caching is enabled and this method is called with a
* <code>false</code> argument, the caches will be emptied.
* So one strategy could be to clear the caches at times
* appropriate to the application.
* <p>
* Caching is enabled by default.
*
* @param cachingEnabled if true, caching is enabled
*
* @see #clearCaches()
*/
public void setCachingEnabled(boolean cachingEnabled)
{
if (isCachingEnabled && !cachingEnabled) {
// Caching is being turned off. Empty caches.
clearCaches();
// For compatibility disable invoker optimization as well
setInvokerOptimizationEnabled(false);
}
isCachingEnabled = cachingEnabled;
}
public void setInvokerOptimizationEnabled(boolean enabled)
{
if (invokerOptimization == enabled) {
return;
}
if (!enabled) {
invokerMaster = null;
}
invokerOptimization = enabled;
}
/**
* Empty internal caches.
* @see #setCachingEnabled(boolean)
*/
public void clearCaches()
{
classTable.clear();
javaAdapterGeneratedClasses.clear();
javaAdapterIFGlueMasters.clear();
invokerMaster = null;
}
static void embed(ScriptableObject top)
{
if (top instanceof GlobalScope) Kit.codeBug();
GlobalScope global = new GlobalScope();
top.defineProperty("__globalScope", global,
ScriptableObject.PERMANENT
| ScriptableObject.READONLY
| ScriptableObject.DONTENUM);
}
boolean isCachingEnabled = true;
transient final Hashtable classTable = new Hashtable();
boolean invokerOptimization = true;
transient Object invokerMaster;
transient int javaAdapterSerial;
transient final Hashtable javaAdapterGeneratedClasses = new Hashtable(7);
transient int javaAdapterIFGlueSerial;
transient final Hashtable javaAdapterIFGlueMasters = new Hashtable(7);
}

Просмотреть файл

@ -70,25 +70,27 @@ import java.io.Serializable;
*
* @author Norris Boyd
*/
public class ImporterTopLevel extends GlobalScope {
/**
* @deprecated
*/
public ImporterTopLevel() {
init();
}
public class ImporterTopLevel extends ScriptableObject
{
public ImporterTopLevel() { }
public ImporterTopLevel(Context cx) {
this(cx, false);
}
public ImporterTopLevel(Context cx, boolean sealed) {
cx.initStandardObjects(this, sealed);
init();
public ImporterTopLevel(Context cx, boolean sealed)
{
initStandardObjects(cx, sealed);
}
private void init() {
public String getClassName()
{
return "global";
}
public void initStandardObjects(Context cx, boolean sealed)
{
cx.initStandardObjects(this, sealed);
ImporterFunctions.setup(this);
}

Просмотреть файл

@ -48,7 +48,15 @@ public abstract class Invoker {
public abstract Object invoke(Object that, Object [] args);
/** Factory method to get invoker for given method */
public Invoker createInvoker(Method method, Class[] types)
public Invoker createInvoker(ClassCache cache,
Method method, Class[] types)
{
// should not be called unless master
throw new IllegalStateException();
}
/** Factory method to clear internal cache if any */
public void clearMasterCaches()
{
// should not be called unless master
throw new IllegalStateException();

Просмотреть файл

@ -319,23 +319,23 @@ public final class JavaAdapter
private static Class getAdapterClass(Scriptable scope, Class superClass,
Class[] interfaces, Scriptable obj)
{
GlobalScope global = GlobalScope.get(scope);
Hashtable generated = global.javaAdapterGeneratedClasses;
ClassCache cache = ClassCache.get(scope);
Hashtable generated = cache.javaAdapterGeneratedClasses;
ObjToIntMap names = getObjectFunctionNames(obj);
JavaAdapterSignature sig;
sig = new JavaAdapterSignature(superClass, interfaces, names);
Class adapterClass = (Class) generated.get(sig);
if (adapterClass == null) {
String adapterName;
synchronized (generated) {
adapterName = "adapter" + global.javaAdapterSerial++;
}
String adapterName = "adapter"
+ cache.newClassSerialNumber();
byte[] code = createAdapterCode(names, adapterName,
superClass, interfaces, null);
adapterClass = loadAdapterClass(adapterName, code);
generated.put(sig, adapterClass);
if (cache.isCachingEnabled()) {
generated.put(sig, adapterClass);
}
}
return adapterClass;
}
@ -470,8 +470,8 @@ public final class JavaAdapter
*/
static IFGlue getIFGlueMaster(Class cl, Scriptable scope)
{
GlobalScope global = GlobalScope.get(scope);
Hashtable masters = global.javaAdapterIFGlueMasters;
ClassCache cache = ClassCache.get(scope);
Hashtable masters = cache.javaAdapterIFGlueMasters;
IFGlue glue = (IFGlue)masters.get(cl);
if (glue == null) {
@ -481,11 +481,8 @@ public final class JavaAdapter
if (interfaceMethods.length != 1)
return null;
int serial;
synchronized (masters) {
serial = global.javaAdapterIFGlueSerial++;
}
String glueName = "ifglue"+serial;
String glueName = "ifglue"
+cache.newClassSerialNumber();
Method method = interfaceMethods[0];
Class[] argTypes = method.getParameterTypes();
byte[] code = createIFGlueCode(cl, method, argTypes, glueName);
@ -497,7 +494,9 @@ public final class JavaAdapter
}
int[] argsToConvert = getArgsToConvert(argTypes);
glue.ifglue_initMaster(argsToConvert);
masters.put(cl, glue);
if (cache.isCachingEnabled()) {
masters.put(cl, glue);
}
}
return glue;
}

Просмотреть файл

@ -464,23 +464,23 @@ class JavaMembers
Constructor[] constructors = cl.getConstructors();
int N = constructors.length;
ctors = new MemberBox[N];
GlobalScope global = GlobalScope.get(scope);
ClassCache cache = ClassCache.get(scope);
for (int i = 0; i != N; ++i) {
ctors[i] = new MemberBox(constructors[i], global);
ctors[i] = new MemberBox(constructors[i], cache);
}
}
private static void initNativeMethods(Hashtable ht, Scriptable scope)
{
Enumeration e = ht.keys();
GlobalScope global = GlobalScope.get(scope);
ClassCache cache = ClassCache.get(scope);
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
MemberBox[] methods;
Object value = ht.get(name);
if (value instanceof Method) {
methods = new MemberBox[1];
methods[0] = new MemberBox((Method)value, global);
methods[0] = new MemberBox((Method)value, cache);
} else {
ObjArray overloadedMethods = (ObjArray)value;
int N = overloadedMethods.size();
@ -488,7 +488,7 @@ class JavaMembers
methods = new MemberBox[N];
for (int i = 0; i != N; ++i) {
Method method = (Method)overloadedMethods.get(i);
methods[i] = new MemberBox(method, global);
methods[i] = new MemberBox(method, cache);
}
}
NativeJavaMethod fun = new NativeJavaMethod(methods);
@ -595,8 +595,8 @@ class JavaMembers
Class staticType)
{
JavaMembers members;
GlobalScope global = GlobalScope.get(scope);
Hashtable ct = global.classTable;
ClassCache cache = ClassCache.get(scope);
Hashtable ct = cache.classTable;
Class cl = dynamicType;
for (;;) {
@ -630,7 +630,7 @@ class JavaMembers
}
}
if (global.isCachingEnabled)
if (cache.isCachingEnabled())
ct.put(cl, members);
return members;
}

Просмотреть файл

@ -50,15 +50,15 @@ import java.io.*;
final class MemberBox implements Serializable
{
MemberBox(Method method, GlobalScope scope)
MemberBox(Method method, ClassCache cache)
{
this.scope = scope;
this.cache = cache;
init(method);
}
MemberBox(Constructor constructor, GlobalScope scope)
MemberBox(Constructor constructor, ClassCache cache)
{
this.scope = scope;
this.cache = cache;
init(constructor);
}
@ -70,21 +70,21 @@ final class MemberBox implements Serializable
void prepareInvokerOptimization()
{
if (scope.invokerOptimization) {
Invoker master = (Invoker)scope.invokerMaster;
if (cache.invokerOptimization) {
Invoker master = (Invoker)cache.invokerMaster;
if (master == null) {
master = Invoker.makeMaster();
if (master == null) {
scope.invokerOptimization = false;
cache.invokerOptimization = false;
} else {
scope.invokerMaster = master;
cache.invokerMaster = master;
}
}
if (master != null) {
try {
invoker = master.createInvoker(method(), argTypes);
invoker = master.createInvoker(cache, method(), argTypes);
} catch (RuntimeException ex) {
scope.invokerOptimization = false;
cache.invokerOptimization = false;
}
}
}
@ -398,7 +398,7 @@ final class MemberBox implements Serializable
return result;
}
private GlobalScope scope;
private ClassCache cache;
private transient Member memberObject;
transient Class[] argTypes;
transient Invoker invoker;

Просмотреть файл

@ -1150,13 +1150,13 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
}
}
GlobalScope global = GlobalScope.get(this);
ClassCache cache = ClassCache.get(this);
GetterSlot slot = new GetterSlot();
slot.delegateTo = delegateTo;
slot.getter = new MemberBox(getter, global);
slot.getter = new MemberBox(getter, cache);
slot.getter.prepareInvokerOptimization();
if (setter != null) {
slot.setter = new MemberBox(setter, global);
slot.setter = new MemberBox(setter, cache);
slot.setter.prepareInvokerOptimization();
slot.setterReturnsValue = setter.getReturnType() != Void.TYPE;
}

Просмотреть файл

@ -39,11 +39,8 @@ package org.mozilla.javascript.optimizer;
import java.util.Hashtable;
import java.lang.reflect.Method;
import org.mozilla.javascript.Invoker;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.GeneratedClassLoader;
import org.mozilla.classfile.ByteCode;
import org.mozilla.classfile.ClassFileWriter;
import org.mozilla.javascript.*;
import org.mozilla.classfile.*;
/**
* Avoid cost of java.lang.reflect.Method.invoke() by compiling a class to
@ -51,28 +48,13 @@ import org.mozilla.classfile.ClassFileWriter;
*/
public class InvokerImpl extends Invoker {
public Invoker createInvoker(Method method, Class[] types) {
public Invoker createInvoker(ClassCache cache,
Method method, Class[] types)
{
Invoker result = (Invoker)invokersCache.get(method);
if (result != null) { return result; }
Invoker result;
int classNum;
synchronized (this) {
if (invokersCache == null) {
Context cx = Context.getCurrentContext();
ClassLoader parentLoader = cx.getApplicationClassLoader();
classLoader = cx.createClassLoader(parentLoader);
// Initialize invokersCache after creation of classloader
// since it can throw SecurityException. It prevents
// NullPointerException when accessing classLoader on
// the second Invoker invocation.
invokersCache = new Hashtable();
} else {
result = (Invoker)invokersCache.get(method);
if (result != null) { return result; }
}
classNum = ++classNumber;
}
String className = "inv" + classNum;
String className = "inv"+cache.newClassSerialNumber();
ClassFileWriter cfw = new ClassFileWriter(className,
"org.mozilla.javascript.Invoker", "");
@ -290,6 +272,21 @@ public class InvokerImpl extends Invoker {
byte[] bytes = cfw.toByteArray();
// Add class to our classloader.
boolean canCache = cache.isCachingEnabled();
GeneratedClassLoader classLoader;
synchronized (this) {
if (canCache && cachedClassLoader != null) {
classLoader = cachedClassLoader;
} else {
Context cx = Context.getCurrentContext();
ClassLoader parentLoader = cx.getApplicationClassLoader();
classLoader = cx.createClassLoader(parentLoader);
if (canCache) {
cachedClassLoader = classLoader;
}
}
}
Class c = classLoader.defineClass(className, bytes);
classLoader.linkClass(c);
try {
@ -305,15 +302,24 @@ public class InvokerImpl extends Invoker {
+" on "+method.getDeclaringClass().getName()+" :: "
+params.toString()+" :: "+types);
}
invokersCache.put(method, result);
if (canCache) {
invokersCache.put(method, result);
}
return result;
}
public void clearMasterCaches()
{
synchronized (this) {
cachedClassLoader = null;
}
invokersCache = new Hashtable();
}
public Object invoke(Object that, Object [] args) {
return null;
}
int classNumber;
Hashtable invokersCache;
GeneratedClassLoader classLoader;
private Hashtable invokersCache = new Hashtable();
private GeneratedClassLoader cachedClassLoader;
}

Просмотреть файл

@ -598,10 +598,16 @@ public class Global extends ImporterTopLevel {
errStream = err;
}
public static Global getInstance(Scriptable scope) {
GlobalScope global = GlobalScope.get(scope);
if (global instanceof Global)
return (Global)global;
public static Global getInstance(Scriptable scope)
{
scope = ScriptableObject.getTopLevelScope(scope);
do {
if (scope instanceof Global) {
return (Global)scope;
}
scope = scope.getPrototype();
} while (scope != null);
return null;
}