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:
igor%mir2.org 2004-09-13 13:19:17 +00:00
parent afaadbeab9
commit 5ebef36b9a
3 changed files with 101 additions and 53 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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)