зеркало из https://github.com/mozilla/pjs.git
I chaged JavaAdapter to store ContextFactory in the proxy object directly instead of extracting it from scope. It ensures that the proper factory is used to reenter Context objects even if scope stored in the adapter is manipulated and no longer contains the reference to factory.
This commit is contained in:
Родитель
a0bed70a5b
Коммит
26f82f20b1
|
@ -475,8 +475,9 @@ public class Context
|
|||
Object[] args)
|
||||
{
|
||||
if (factory == null) {
|
||||
factory = ScriptRuntime.getContextFactory(scope);
|
||||
factory = ContextFactory.getGlobal();
|
||||
}
|
||||
|
||||
Object[] storage = getThreadContextStorage();
|
||||
Context cx;
|
||||
if (storage != null) {
|
||||
|
@ -489,6 +490,7 @@ public class Context
|
|||
if (cx.factory != null) {
|
||||
return callable.call(cx, scope, thisObj, args);
|
||||
} else {
|
||||
// Context was associated with the thread via Context.enter
|
||||
cx.factory = factory;
|
||||
try {
|
||||
return callable.call(cx, scope, thisObj, args);
|
||||
|
|
|
@ -190,8 +190,11 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
Class adapterClass = getAdapterClass(scope, superClass, interfaces,
|
||||
obj);
|
||||
|
||||
Class[] ctorParms = { ScriptRuntime.ScriptableClass };
|
||||
Object[] ctorArgs = { obj };
|
||||
Class[] ctorParms = {
|
||||
ScriptRuntime.ContextFactoryClass,
|
||||
ScriptRuntime.ScriptableClass
|
||||
};
|
||||
Object[] ctorArgs = { cx.getFactory(), obj };
|
||||
try {
|
||||
Object adapter = adapterClass.getConstructor(ctorParms).
|
||||
newInstance(ctorArgs);
|
||||
|
@ -232,6 +235,14 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
ContextFactory factory;
|
||||
Context cx = Context.getCurrentContext();
|
||||
if (cx != null) {
|
||||
factory = cx.getFactory();
|
||||
} else {
|
||||
factory = null;
|
||||
}
|
||||
|
||||
Class superClass = Class.forName((String)in.readObject());
|
||||
|
||||
String[] interfaceNames = (String[])in.readObject();
|
||||
|
@ -246,10 +257,11 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
delegee);
|
||||
|
||||
Class[] ctorParms = {
|
||||
ScriptRuntime.ContextFactoryClass,
|
||||
ScriptRuntime.ScriptableClass,
|
||||
ScriptRuntime.ScriptableClass
|
||||
};
|
||||
Object[] ctorArgs = { delegee, self };
|
||||
Object[] ctorArgs = { factory, delegee, self };
|
||||
try {
|
||||
return adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
|
||||
} catch(InstantiationException e) {
|
||||
|
@ -316,6 +328,9 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
ClassFileWriter cfw = new ClassFileWriter(adapterName,
|
||||
superClass.getName(),
|
||||
"<adapter>");
|
||||
cfw.addField("factory", "Lorg/mozilla/javascript/ContextFactory;",
|
||||
(short) (ClassFileWriter.ACC_PUBLIC |
|
||||
ClassFileWriter.ACC_FINAL));
|
||||
cfw.addField("delegee", "Lorg/mozilla/javascript/Scriptable;",
|
||||
(short) (ClassFileWriter.ACC_PUBLIC |
|
||||
ClassFileWriter.ACC_FINAL));
|
||||
|
@ -456,7 +471,8 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
* Utility method which dynamically binds a Context to the current thread,
|
||||
* if none already exists.
|
||||
*/
|
||||
public static Object callMethod(final Scriptable thisObj,
|
||||
public static Object callMethod(ContextFactory factory,
|
||||
final Scriptable thisObj,
|
||||
final Function f, final Object[] args,
|
||||
final long argsToWrap)
|
||||
{
|
||||
|
@ -464,16 +480,19 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
// See comments in getFunction
|
||||
return Undefined.instance;
|
||||
}
|
||||
if (factory == null) {
|
||||
factory = ContextFactory.getGlobal();
|
||||
}
|
||||
|
||||
final Scriptable scope = f.getParentScope();
|
||||
if (argsToWrap == 0) {
|
||||
return Context.call(null, f, scope, thisObj, args);
|
||||
return Context.call(factory, f, scope, thisObj, args);
|
||||
}
|
||||
|
||||
Context cx = Context.getCurrentContext();
|
||||
if (cx != null) {
|
||||
return doCall(cx, scope, thisObj, f, args, argsToWrap);
|
||||
} else {
|
||||
ContextFactory factory = ScriptRuntime.getContextFactory(scope);
|
||||
return factory.call(new ContextAction() {
|
||||
public Object run(Context cx)
|
||||
{
|
||||
|
@ -516,22 +535,29 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
String superName)
|
||||
{
|
||||
cfw.startMethod("<init>",
|
||||
"(Lorg/mozilla/javascript/Scriptable;)V",
|
||||
"(Lorg/mozilla/javascript/ContextFactory;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;)V",
|
||||
ClassFileWriter.ACC_PUBLIC);
|
||||
|
||||
// Invoke base class constructor
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V");
|
||||
|
||||
// Save parameter in instance variable "factory"
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.add(ByteCode.ALOAD_1); // first arg: ContextFactory instance
|
||||
cfw.add(ByteCode.PUTFIELD, adapterName, "factory",
|
||||
"Lorg/mozilla/javascript/ContextFactory;");
|
||||
|
||||
// Save parameter in instance variable "delegee"
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.add(ByteCode.ALOAD_1); // first arg
|
||||
cfw.add(ByteCode.ALOAD_2); // second arg: Scriptable delegee
|
||||
cfw.add(ByteCode.PUTFIELD, adapterName, "delegee",
|
||||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
|
||||
cfw.add(ByteCode.ALOAD_0); // this for the following PUTFIELD for self
|
||||
// create a wrapper object to be used as "this" in method calls
|
||||
cfw.add(ByteCode.ALOAD_1); // the Scriptable
|
||||
cfw.add(ByteCode.ALOAD_2); // the Scriptable delegee
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.addInvoke(ByteCode.INVOKESTATIC,
|
||||
"org/mozilla/javascript/JavaAdapter",
|
||||
|
@ -543,7 +569,7 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
|
||||
cfw.add(ByteCode.RETURN);
|
||||
cfw.stopMethod((short)3); // 2: this + delegee
|
||||
cfw.stopMethod((short)3); // 3: this + factory + delegee
|
||||
}
|
||||
|
||||
private static void generateSerialCtor(ClassFileWriter cfw,
|
||||
|
@ -551,7 +577,8 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
String superName)
|
||||
{
|
||||
cfw.startMethod("<init>",
|
||||
"(Lorg/mozilla/javascript/Scriptable;"
|
||||
"(Lorg/mozilla/javascript/ContextFactory;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")V",
|
||||
ClassFileWriter.ACC_PUBLIC);
|
||||
|
@ -560,20 +587,25 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V");
|
||||
|
||||
// Save parameter in instance variable "factory"
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.add(ByteCode.ALOAD_1); // first arg: ContextFactory instance
|
||||
cfw.add(ByteCode.PUTFIELD, adapterName, "factory",
|
||||
"Lorg/mozilla/javascript/ContextFactory;");
|
||||
|
||||
// Save parameter in instance variable "delegee"
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.add(ByteCode.ALOAD_1); // first arg
|
||||
cfw.add(ByteCode.ALOAD_2); // second arg: Scriptable delegee
|
||||
cfw.add(ByteCode.PUTFIELD, adapterName, "delegee",
|
||||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
|
||||
// save self
|
||||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.add(ByteCode.ALOAD_2); // second arg
|
||||
cfw.add(ByteCode.ALOAD_3); // second arg: Scriptable self
|
||||
cfw.add(ByteCode.PUTFIELD, adapterName, "self",
|
||||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
|
||||
cfw.add(ByteCode.RETURN);
|
||||
cfw.stopMethod((short)20); // TODO: magic number "20"
|
||||
cfw.stopMethod((short)4); // 4: this + factory + delegee + self
|
||||
}
|
||||
|
||||
private static void generateEmptyCtor(ClassFileWriter cfw,
|
||||
|
@ -587,6 +619,11 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
cfw.add(ByteCode.ALOAD_0); // this
|
||||
cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V");
|
||||
|
||||
// Set factory to null to use current global when necessary
|
||||
cfw.add(ByteCode.ACONST_NULL);
|
||||
cfw.add(ByteCode.PUTFIELD, adapterName, "factory",
|
||||
"Lorg/mozilla/javascript/ContextFactory;");
|
||||
|
||||
// Load script class
|
||||
cfw.add(ByteCode.NEW, scriptClassName);
|
||||
cfw.add(ByteCode.DUP);
|
||||
|
@ -793,14 +830,24 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
Class returnType)
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int firstLocal = appendMethodSignature(parms, returnType, sb);
|
||||
int paramsEnd = appendMethodSignature(parms, returnType, sb);
|
||||
String methodSignature = sb.toString();
|
||||
cfw.startMethod(methodName, methodSignature,
|
||||
ClassFileWriter.ACC_PUBLIC);
|
||||
|
||||
int FUNCTION = firstLocal;
|
||||
int LOCALS_END = firstLocal + 1;
|
||||
// Prepare stack to call calMethod
|
||||
|
||||
// push factory
|
||||
cfw.add(ByteCode.ALOAD_0);
|
||||
cfw.add(ByteCode.GETFIELD, genName, "factory",
|
||||
"Lorg/mozilla/javascript/ContextFactory;");
|
||||
|
||||
// push self
|
||||
cfw.add(ByteCode.ALOAD_0);
|
||||
cfw.add(ByteCode.GETFIELD, genName, "self",
|
||||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
|
||||
// push function
|
||||
cfw.add(ByteCode.ALOAD_0);
|
||||
cfw.add(ByteCode.GETFIELD, genName, "delegee",
|
||||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
|
@ -811,16 +858,6 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
"(Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+")Lorg/mozilla/javascript/Function;");
|
||||
cfw.add(ByteCode.DUP);
|
||||
cfw.addAStore(FUNCTION);
|
||||
|
||||
// Prepare stack to call calMethod
|
||||
// push thisObj
|
||||
cfw.add(ByteCode.ALOAD_0);
|
||||
cfw.add(ByteCode.GETFIELD, genName, "self",
|
||||
"Lorg/mozilla/javascript/Scriptable;");
|
||||
// push function
|
||||
cfw.addALoad(FUNCTION);
|
||||
|
||||
// push arguments
|
||||
generatePushWrappedArgs(cfw, parms, parms.length);
|
||||
|
@ -846,7 +883,8 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
cfw.addInvoke(ByteCode.INVOKESTATIC,
|
||||
"org/mozilla/javascript/JavaAdapter",
|
||||
"callMethod",
|
||||
"(Lorg/mozilla/javascript/Scriptable;"
|
||||
"(Lorg/mozilla/javascript/ContextFactory;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Lorg/mozilla/javascript/Function;"
|
||||
+"[Ljava/lang/Object;"
|
||||
+"J"
|
||||
|
@ -854,7 +892,7 @@ public final class JavaAdapter implements IdFunctionCall
|
|||
|
||||
generateReturnResult(cfw, returnType, true);
|
||||
|
||||
cfw.stopMethod((short)LOCALS_END);
|
||||
cfw.stopMethod((short)paramsEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -96,6 +96,7 @@ public class ScriptRuntime {
|
|||
|
||||
public final static Class
|
||||
ContextClass = Kit.classOrNull("org.mozilla.javascript.Context"),
|
||||
ContextFactoryClass = Kit.classOrNull("org.mozilla.javascript.ContextFactory"),
|
||||
FunctionClass = Kit.classOrNull("org.mozilla.javascript.Function"),
|
||||
ScriptableClass = Kit.classOrNull("org.mozilla.javascript.Scriptable"),
|
||||
ScriptableObjectClass = Kit.classOrNull("org.mozilla.javascript.ScriptableObject"),
|
||||
|
@ -118,7 +119,6 @@ public class ScriptRuntime {
|
|||
};
|
||||
|
||||
private static final Object LIBRARY_SCOPE_KEY = new Object();
|
||||
private static final Object CONTEXT_FACTORY_KEY = new Object();
|
||||
|
||||
public static ScriptableObject initStandardObjects(Context cx,
|
||||
ScriptableObject scope,
|
||||
|
@ -128,13 +128,6 @@ public class ScriptRuntime {
|
|||
scope = new NativeObject();
|
||||
}
|
||||
scope.associateValue(LIBRARY_SCOPE_KEY, scope);
|
||||
ContextFactory factory = cx.getFactory();
|
||||
if (factory == null) {
|
||||
// factory is null for Context asociated with the current thread
|
||||
// via Context.enter()
|
||||
factory = ContextFactory.getGlobal();
|
||||
}
|
||||
scope.associateValue(CONTEXT_FACTORY_KEY, factory);
|
||||
(new ClassCache()).associate(scope);
|
||||
|
||||
BaseFunction.init(cx, scope, sealed);
|
||||
|
@ -189,17 +182,6 @@ public class ScriptRuntime {
|
|||
return libScope;
|
||||
}
|
||||
|
||||
public static ContextFactory getContextFactory(Scriptable scope)
|
||||
{
|
||||
ContextFactory factory;
|
||||
factory = (ContextFactory)ScriptableObject.
|
||||
getTopScopeValue(scope, CONTEXT_FACTORY_KEY);
|
||||
if (factory == null) {
|
||||
throw new IllegalStateException("Failed to find ContextFactory");
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
// It is public so NativeRegExp can access it .
|
||||
public static boolean isJSLineTerminator(int c)
|
||||
{
|
||||
|
@ -267,6 +249,7 @@ public class ScriptRuntime {
|
|||
public static boolean toBoolean(Object[] args, int index) {
|
||||
return (index < args.length) ? toBoolean(args[index]) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a number.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче