зеркало из https://github.com/mozilla/pjs.git
1. Allow to monitor from application top script or function calls: now they go through ContextFactory.doTopCall which can be overridden.
2. Context.observeInstructionCount now calls ContxtFactory.observeInstructionCount so it can overridden without extra Context class.
This commit is contained in:
Родитель
26d7b8a8f8
Коммит
35acfd58fc
|
@ -640,11 +640,17 @@ public class Context
|
|||
}
|
||||
|
||||
/**
|
||||
* Return {@link ContextFactory} instance used to create this Context.
|
||||
* Return {@link ContextFactory} instance used to create this Context
|
||||
* or the result of {@link ContextFactory#getGlobal()} if no factory
|
||||
* was used for Context creation.
|
||||
*/
|
||||
public ContextFactory getFactory()
|
||||
public final ContextFactory getFactory()
|
||||
{
|
||||
return factory;
|
||||
ContextFactory result = factory;
|
||||
if (result == null) {
|
||||
result = ContextFactory.getGlobal();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2073,6 +2079,7 @@ public class Context
|
|||
* that allows to customize Context behavior without introducing
|
||||
* Context subclasses. {@link ContextFactory} documentation gives
|
||||
* an example of hasFeature implementation.
|
||||
*
|
||||
* @param featureIndex feature index to check
|
||||
* @return true if the <code>featureIndex</code> feature is turned on
|
||||
* @see #FEATURE_NON_ECMA_GET_YEAR
|
||||
|
@ -2084,10 +2091,7 @@ public class Context
|
|||
*/
|
||||
public boolean hasFeature(int featureIndex)
|
||||
{
|
||||
ContextFactory f = factory;
|
||||
if (f == null) {
|
||||
f = ContextFactory.getGlobal();
|
||||
}
|
||||
ContextFactory f = getFactory();
|
||||
return f.hasFeature(this, featureIndex);
|
||||
}
|
||||
|
||||
|
@ -2121,6 +2125,13 @@ public class Context
|
|||
* <p>
|
||||
* The instruction counting support is available only for interpreted
|
||||
* scripts generated when the optimization level is set to -1.
|
||||
* <p>
|
||||
* The default implementation calls
|
||||
* {@link ContextFactory#observeInstructionCount(Context cx,
|
||||
* int instructionCount)}
|
||||
* that allows to customize Context behavior without introducing
|
||||
* Context subclasses.
|
||||
*
|
||||
* @param instructionCount amount of script instruction executed since
|
||||
* last call to <code>observeInstructionCount</code>
|
||||
* @throws Error to terminate the script
|
||||
|
@ -2128,6 +2139,8 @@ public class Context
|
|||
*/
|
||||
protected void observeInstructionCount(int instructionCount)
|
||||
{
|
||||
ContextFactory f = getFactory();
|
||||
f.observeInstructionCount(this, instructionCount);
|
||||
}
|
||||
|
||||
public GeneratedClassLoader createClassLoader(ClassLoader parent)
|
||||
|
|
|
@ -61,6 +61,13 @@ package org.mozilla.javascript;
|
|||
*
|
||||
* class MyFactory extends ContextFactory
|
||||
* {
|
||||
*
|
||||
* // Custom {@link Context} to store execution time.
|
||||
* private static class MyContext extends Context
|
||||
* {
|
||||
* long startTime;
|
||||
* }
|
||||
*
|
||||
* static {
|
||||
* // Initialize GlobalFactory with custom factory
|
||||
* ContextFactory.initGlobal(new MyFactory());
|
||||
|
@ -71,9 +78,9 @@ package org.mozilla.javascript;
|
|||
* {
|
||||
* MyContext cx = new MyContext();
|
||||
* // Use pure interpreter mode to allow for
|
||||
* // {@link Context#observeInstructionCount(int)} to work
|
||||
* // {@link #observeInstructionCount(Context, int)} to work
|
||||
* cx.setOptimizationLevel(-1);
|
||||
* // Make Rhino runtime to call MyContext.observeInstructionCount(int)
|
||||
* // Make Rhino runtime to call observeInstructionCount
|
||||
* // each 10000 bytecode instructions
|
||||
* cx.setInstructionObserverThreshold(10000);
|
||||
* return cx;
|
||||
|
@ -82,33 +89,29 @@ package org.mozilla.javascript;
|
|||
* // Override {@link #hasFeature(Context, int)}
|
||||
* public boolean hasFeature(Context cx, int featureIndex)
|
||||
* {
|
||||
* // Turn on maximim compatibility with MSIE scripts
|
||||
* // Turn on maximum compatibility with MSIE scripts
|
||||
* switch (featureIndex) {
|
||||
* case Context.FEATURE_NON_ECMA_GET_YEAR:
|
||||
* case {@link Context#FEATURE_NON_ECMA_GET_YEAR}:
|
||||
* return true;
|
||||
*
|
||||
* case Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME:
|
||||
* case {@link Context#FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME}:
|
||||
* return true;
|
||||
*
|
||||
* case Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER:
|
||||
* case {@link Context#FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER}:
|
||||
* return true;
|
||||
*
|
||||
* case Context.FEATURE_PARENT_PROTO_PROPRTIES:
|
||||
* case {@link Context#FEATURE_PARENT_PROTO_PROPRTIES}:
|
||||
* return false;
|
||||
* }
|
||||
* return super.hasFeature(cx, featureIndex);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class MyContext extends Context
|
||||
* {
|
||||
* private long creationTime = System.currentTimeMillis();
|
||||
*
|
||||
* // Override {@link Context#observeInstructionCount(int)}
|
||||
* protected void observeInstructionCount(int instructionCount)
|
||||
* // Override {@link #observeInstructionCount(Context, int)}
|
||||
* protected void observeInstructionCount(Context cx, int instructionCount)
|
||||
* {
|
||||
* MyContext mcx = (MyContext)cx;
|
||||
* long currentTime = System.currentTimeMillis();
|
||||
* if (currentTime - creationTime > 10000) {
|
||||
* if (currentTime - mcx.startTime > 10*1000) {
|
||||
* // More then 10 seconds from Context creation time:
|
||||
* // it is time to stop the script.
|
||||
* // Throw Error instance to ensure that script will never
|
||||
|
@ -117,7 +120,19 @@ package org.mozilla.javascript;
|
|||
* }
|
||||
* }
|
||||
*
|
||||
* // Override {@link #doTopCall(Callable, Context, Scriptable scope, Scriptable thisObj, Object[] args)}
|
||||
* protected Object doTopCall(Callable callable,
|
||||
* Context cx, Scriptable scope,
|
||||
* Scriptable thisObj, Object[] args)
|
||||
* {
|
||||
* MyContext mcx = (MyContext)cx;
|
||||
* mcx.startTime = System.currentTimeMillis();
|
||||
*
|
||||
* return super.doTopCall(callable, cx, scope, thisObj, args);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
@ -258,6 +273,30 @@ public class ContextFactory
|
|||
throw new IllegalArgumentException(String.valueOf(featureIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute top call to script or function.
|
||||
* When the runtime is about to execute a script or function that will
|
||||
* create the first stack frame with scriptable code, it calls this method
|
||||
* to perform the real call. In this way execution of any script
|
||||
* happens inside this function.
|
||||
*/
|
||||
protected Object doTopCall(Callable callable,
|
||||
Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
return callable.call(cx, scope, thisObj, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of
|
||||
* {@link Context#observeInstructionCount(int instructionCount)}.
|
||||
* This can be used to customize {@link Context} without introducing
|
||||
* additional subclasses.
|
||||
*/
|
||||
protected void observeInstructionCount(Context cx, int instructionCount)
|
||||
{
|
||||
}
|
||||
|
||||
protected void onContextCreated(Context cx)
|
||||
{
|
||||
Object listeners = this.listeners;
|
||||
|
|
|
@ -2787,6 +2787,33 @@ public class ScriptRuntime {
|
|||
return (cx.topCallScope != null);
|
||||
}
|
||||
|
||||
public static Object doTopCall(Callable callable,
|
||||
Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
if (scope == null) throw new IllegalArgumentException();
|
||||
if (cx.topCallScope != null) throw new IllegalStateException();
|
||||
|
||||
Object result;
|
||||
cx.topCallScope = ScriptableObject.getTopLevelScope(scope);
|
||||
cx.useDynamicScope = cx.hasFeature(Context.FEATURE_DYNAMIC_SCOPE);
|
||||
ContextFactory f = cx.getFactory();
|
||||
try {
|
||||
result = f.doTopCall(callable, cx, scope, thisObj, args);
|
||||
} finally {
|
||||
cx.topCallScope = null;
|
||||
// Cleanup cached references
|
||||
cx.cachedXMLLib = null;
|
||||
|
||||
if (cx.currentActivationCall != null) {
|
||||
// Function should always call exitActivationFunction
|
||||
// if it creates activation record
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Scriptable locateDynamicScope(Context cx, Scriptable scope)
|
||||
{
|
||||
// Return cx.topCallScope is scope is present on its prototype chain
|
||||
|
@ -2807,37 +2834,6 @@ public class ScriptRuntime {
|
|||
}
|
||||
}
|
||||
|
||||
public static Object doTopCall(Callable callable,
|
||||
Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
if (cx.topCallScope != null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
Object result;
|
||||
cx.topCallScope = ScriptableObject.getTopLevelScope(scope);
|
||||
cx.useDynamicScope = cx.hasFeature(Context.FEATURE_DYNAMIC_SCOPE);
|
||||
try {
|
||||
result = callable.call(cx, scope, thisObj, args);
|
||||
} finally {
|
||||
releaseTopCall(cx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void releaseTopCall(Context cx)
|
||||
{
|
||||
cx.topCallScope = null;
|
||||
// Cleanup cached references
|
||||
cx.cachedXMLLib = null;
|
||||
|
||||
if (cx.currentActivationCall != null) {
|
||||
// Function should always call exitActivationFunction
|
||||
// if it creates activation record
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void initScript(NativeFunction funObj, Scriptable thisObj,
|
||||
Context cx, Scriptable scope,
|
||||
boolean evalScript)
|
||||
|
|
Загрузка…
Ссылка в новой задаче