-----
The patch changes NativeCall to use IdScriptable. This is done mostly
for uniformity with other Native* classes plus it would allow to call
NativeCall.init directly and make NativeCall package private.
-----
The patch changes NativeScript to use id-based properties. Due to
inheritance from NativeFunction, id support requires to take into
account the fact that there are instance ids available from
BaseFunction. This is the reason to use "int prototypeIdShift" instead
of "boolean prototypeFlag" so it can store instance id offset.

The patch updates ScriptRuntime.callOrNewSpecial to check against
IdFunction and not FunctionObject for the Script exec method where it
also add finally clause to make sure that Context.exit would always be
called after Context.enter in the evalScript method.
-----
After converting NativeScript and NativeFunction to use IdScriptable,
they get scope argument directly as a parameter of execMethod call, so
cx.ctorScope is not used any more. The patch removes code to set/unset
cx.ctorScope.
-----
[This patch depends on conversion of NativeScript and NativeCall to use
IdScriptable and the patch to remove access of ctorScope from
FunctionObject]

The patch changes Context.initStandardObjects to call NativeCall.init
and NativeScript.init directly plus it unrolls the lazily initialization
loop. Due to rather poor support of an array initialization in Java byte
code, it actually decreases code size while eliminating are creation of
array object. The patch also removes ctorScope field as unused.
-----
The patch makes sure that ids used by NativeGlobal are visible only in
the object instance that initializes global scope and removes some junk
white space at line ends.
-----
To use the idswitch tool to generate map for strings that can not be
part of Id_ Java identifier like $*, I added code to the tool to look
for "// #string=...#" in the id definition line. The attached README
file also contains some documentation about the tool and should go to
idswitch directory.

The patch was made from toolsrc/org/mozilla/javascript/tools via:
cvs diff -u > idswitch_patch
This commit is contained in:
nboyd%atg.com 2001-05-25 13:24:17 +00:00
Родитель 91badd7c66
Коммит d589083a1e
11 изменённых файлов: 630 добавлений и 198 удалений

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

@ -21,6 +21,7 @@
* Norris Boyd
* Roger Lawrence
* Patrick Beard
* 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
@ -55,11 +56,10 @@ public class DefiningClassLoader extends ClassLoader {
if (clazz == null) {
ClassLoader loader = getClass().getClassLoader();
if (loader != null) {
clazz = ClassManager.loadClass(loader, name, resolve);
if (clazz != null)
return clazz;
clazz = loader.loadClass(name);
} else {
clazz = findSystemClass(name);
}
clazz = findSystemClass(name);
}
if (resolve)
resolveClass(clazz);

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

@ -657,25 +657,30 @@ public class Context {
NativeNumber.init(this, scope, sealed);
NativeDate.init(this, scope, sealed);
NativeMath.init(this, scope, sealed);
NativeWith.init(this, scope, sealed);
NativeCall.init(this, scope, sealed);
NativeScript.init(this, scope, sealed);
String[] classes = {
"org.mozilla.javascript.NativeCall", "Call",
"org.mozilla.javascript.regexp.NativeRegExp", "RegExp",
"org.mozilla.javascript.NativeScript", "Script",
// This creates the Packages and java package roots.
"org.mozilla.javascript.NativeJavaPackage", "Packages",
"org.mozilla.javascript.NativeJavaPackage", "java",
"org.mozilla.javascript.NativeJavaPackage", "getClass",
};
for (int i=0; i < classes.length; i+=2) {
String property = classes[i+1];
String javaClass = classes[i];
new LazilyLoadedCtor(scope, property, javaClass, sealed);
}
new LazilyLoadedCtor(scope,
"RegExp",
"org.mozilla.javascript.regexp.NativeRegExp",
sealed);
// This creates the Packages and java package roots.
new LazilyLoadedCtor(scope,
"Packages",
"org.mozilla.javascript.NativeJavaPackage",
sealed);
new LazilyLoadedCtor(scope,
"java",
"org.mozilla.javascript.NativeJavaPackage",
sealed);
new LazilyLoadedCtor(scope,
"getClass",
"org.mozilla.javascript.NativeJavaPackage",
sealed);
// Define the JavaAdapter class, allowing it to be overridden.
String adapterClass = "org.mozilla.javascript.JavaAdapter";
String adapterProperty = "JavaAdapter";
@ -694,7 +699,7 @@ public class Context {
return scope;
}
/**
* Get the singleton object that represents the JavaScript Undefined value.
*/
@ -1904,7 +1909,6 @@ public class Context {
Hashtable iterating;
Object interpreterSecurityDomain;
Scriptable ctorScope;
int version;
int errorCount;

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

@ -394,14 +394,7 @@ public class FunctionObject extends NativeFunction {
throws JavaScriptException
{
if (parmsLength < 0) {
// Ugly: allow variable-arg constructors that need access to the
// scope to get it from the Context. Cleanest solution would be
// to modify the varargs form, but that would require users with
// the old form to change their code.
cx.ctorScope = scope;
Object result = callVarargs(cx, thisObj, args, false);
cx.ctorScope = null;
return result;
return callVarargs(cx, thisObj, args, false);
}
if (!isStatic) {
// OPT: cache "clazz"?
@ -473,13 +466,7 @@ public class FunctionObject extends NativeFunction {
if (method == null || parmsLength == VARARGS_CTOR) {
Scriptable result;
if (method != null) {
// Ugly: allow variable-arg constructors that need access to the
// scope to get it from the Context. Cleanest solution would be
// to modify the varargs form, but that would require users with
// the old form to change their code.
cx.ctorScope = scope;
result = (Scriptable) callVarargs(cx, null, args, true);
cx.ctorScope = null;
} else {
result = (Scriptable) call(cx, scope, null, args);
}

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

@ -43,7 +43,13 @@ package org.mozilla.javascript;
* @see org.mozilla.javascript.Arguments
* @author Norris Boyd
*/
public final class NativeCall extends ScriptableObject {
public final class NativeCall extends IdScriptable {
static void init(Context cx, Scriptable scope, boolean sealed) {
NativeCall obj = new NativeCall();
obj.prototypeFlag = true;
obj.addAsPrototype(MAX_PROTOTYPE_ID, cx, scope, sealed);
}
NativeCall(Context cx, Scriptable scope, NativeFunction funObj,
Scriptable thisObj, Object[] args)
@ -79,16 +85,15 @@ public final class NativeCall extends ScriptableObject {
cx.currentActivation = this;
}
// Needed in order to use this class with ScriptableObject.defineClass
public NativeCall() {
NativeCall() {
}
public String getClassName() {
return "Call";
}
public static Object jsConstructor(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
private static Object jsConstructor(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
if (!inNewExpr) {
throw Context.reportRuntimeError1("msg.only.from.new", "Call");
@ -125,9 +130,47 @@ public final class NativeCall extends ScriptableObject {
return thisObj;
}
public int methodArity(int methodId) {
if (prototypeFlag) {
if (methodId == Id_constructor) return 1;
}
return super.methodArity(methodId);
}
public Object execMethod
(int methodId, IdFunction f,
Context cx, Scriptable scope, Scriptable thisObj, Object[] args)
throws JavaScriptException
{
if (prototypeFlag) {
if (methodId == Id_constructor) {
return jsConstructor(cx, args, f, thisObj == null);
}
}
return super.execMethod(methodId, f, cx, scope, thisObj, args);
}
protected String getIdName(int id) {
if (prototypeFlag) {
if (id == Id_constructor) return "constructor";
}
return null;
}
protected int mapNameToId(String s) {
if (!prototypeFlag) { return 0; }
return s.equals("constructor") ? Id_constructor : 0;
}
private static final int
Id_constructor = 1,
MAX_PROTOTYPE_ID = 1;
NativeCall caller;
NativeFunction funObj;
Scriptable thisObj;
Object[] originalArgs;
public int debugPC;
private boolean prototypeFlag;
}

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

@ -18,7 +18,7 @@
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
* Norris Boyd
* Igor Bukanov
* Mike McCabe
@ -42,9 +42,9 @@ import java.io.IOException;
import java.lang.reflect.Method;
/**
* This class implements the global native object (function and value
* This class implements the global native object (function and value
* properties only).
*
*
* See ECMA 15.1.[12].
*
* @author Mike Shaver
@ -53,46 +53,44 @@ import java.lang.reflect.Method;
public class NativeGlobal implements IdFunctionMaster {
public static void init(Context cx, Scriptable scope, boolean sealed) {
(new NativeGlobal()).scopeInit(cx, scope, sealed);
}
private void scopeInit(Context cx, Scriptable scope, boolean sealed) {
NativeGlobal obj = new NativeGlobal();
obj.scopeSlaveFlag = true;
for (int id = 1; id <= MAX_ID; ++id) {
for (int id = 1; id <= LAST_SCOPE_FUNCTION_ID; ++id) {
String name = getMethodName(id);
IdFunction f = new IdFunction(this, name, id);
IdFunction f = new IdFunction(obj, name, id);
f.setParentScope(scope);
if (sealed) { f.sealObject(); }
ScriptableObject.defineProperty(scope, name, f,
ScriptableObject.DONTENUM);
}
ScriptableObject.defineProperty(scope, "NaN",
ScriptableObject.defineProperty(scope, "NaN",
ScriptRuntime.NaNobj,
ScriptableObject.DONTENUM);
ScriptableObject.defineProperty(scope, "Infinity",
ScriptableObject.defineProperty(scope, "Infinity",
new Double(Double.POSITIVE_INFINITY),
ScriptableObject.DONTENUM);
ScriptableObject.defineProperty(scope, "undefined",
ScriptableObject.defineProperty(scope, "undefined",
Undefined.instance,
ScriptableObject.DONTENUM);
String[] errorMethods = { "ConversionError",
"EvalError",
"EvalError",
"RangeError",
"ReferenceError",
"SyntaxError",
"TypeError",
"URIError"
};
};
/*
Each error constructor gets its own Error object as a prototype,
with the 'name' property set to the name of the error.
*/
for (int i = 0; i < errorMethods.length; i++) {
String name = errorMethods[i];
IdFunction ctor = new IdFunction(this, name, Id_new_CommonError);
IdFunction ctor = new IdFunction(obj, name, Id_new_CommonError);
ctor.setFunctionType(IdFunction.FUNCTION_AND_CONSTRUCTOR);
ctor.setParentScope(scope);
ScriptableObject.defineProperty(scope, name, ctor,
@ -100,62 +98,87 @@ public class NativeGlobal implements IdFunctionMaster {
Scriptable errorProto = ScriptRuntime.newObject
(cx, scope, "Error", ScriptRuntime.emptyArgs);
errorProto.put("name", errorProto, name);
ctor.put("prototype", ctor, errorProto);
if (sealed) {
ctor.sealObject();
if (errorProto instanceof ScriptableObject) {
((ScriptableObject)errorProto).sealObject();
((ScriptableObject)errorProto).sealObject();
}
}
}
}
public Object execMethod(int methodId, IdFunction function, Context cx,
Scriptable scope, Scriptable thisObj,
Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
switch (methodId) {
case Id_decodeURI: return js_decodeURI(cx, args);
case Id_decodeURIComponent: return js_decodeURIComponent(cx, args);
case Id_encodeURI: return js_encodeURI(cx, args);
case Id_encodeURIComponent: return js_encodeURIComponent(cx, args);
case Id_escape: return js_escape(cx, args);
case Id_eval: return js_eval(cx, scope, args);
case Id_isFinite: return js_isFinite(cx, args);
case Id_isNaN: return js_isNaN(cx, args);
case Id_parseFloat: return js_parseFloat(cx, args);
case Id_parseInt: return js_parseInt(cx, args);
case Id_unescape: return js_unescape(cx, args);
if (scopeSlaveFlag) {
switch (methodId) {
case Id_decodeURI:
return js_decodeURI(cx, args);
case Id_new_CommonError:
return new_CommonError(function, cx, scope, args);
case Id_decodeURIComponent:
return js_decodeURIComponent(cx, args);
case Id_encodeURI:
return js_encodeURI(cx, args);
case Id_encodeURIComponent:
return js_encodeURIComponent(cx, args);
case Id_escape:
return js_escape(cx, args);
case Id_eval:
return js_eval(cx, scope, args);
case Id_isFinite:
return js_isFinite(cx, args);
case Id_isNaN:
return js_isNaN(cx, args);
case Id_parseFloat:
return js_parseFloat(cx, args);
case Id_parseInt:
return js_parseInt(cx, args);
case Id_unescape:
return js_unescape(cx, args);
case Id_new_CommonError:
return new_CommonError(function, cx, scope, args);
}
}
throw IdFunction.onBadMethodId(this, methodId);
}
public int methodArity(int methodId) {
switch (methodId) {
case Id_new_CommonError: return 1;
if (scopeSlaveFlag) {
switch (methodId) {
case Id_decodeURI: return 1;
case Id_decodeURIComponent: return 1;
case Id_encodeURI: return 1;
case Id_encodeURIComponent: return 1;
case Id_escape: return 1;
case Id_eval: return 1;
case Id_isFinite: return 1;
case Id_isNaN: return 1;
case Id_parseFloat: return 1;
case Id_parseInt: return 2;
case Id_unescape: return 1;
case Id_decodeURI: return 1;
case Id_decodeURIComponent: return 1;
case Id_encodeURI: return 1;
case Id_encodeURIComponent: return 1;
case Id_escape: return 1;
case Id_eval: return 1;
case Id_isFinite: return 1;
case Id_isNaN: return 1;
case Id_parseFloat: return 1;
case Id_parseInt: return 2;
case Id_unescape: return 1;
case Id_new_CommonError: return 1;
}
}
return -1;
}
private String getMethodName(int methodId) {
private static String getMethodName(int methodId) {
switch (methodId) {
case Id_decodeURI: return "decodeURI";
case Id_decodeURIComponent: return "decodeURIComponent";
@ -178,7 +201,7 @@ public class NativeGlobal implements IdFunctionMaster {
private Object js_parseInt(Context cx, Object[] args) {
String s = ScriptRuntime.toString(args, 0);
int radix = ScriptRuntime.toInt32(args, 1);
int len = s.length();
if (len == 0)
return ScriptRuntime.NaNobj;
@ -220,7 +243,7 @@ public class NativeGlobal implements IdFunctionMaster {
}
}
}
double d = ScriptRuntime.stringToNumber(s, start, radix);
return new Double(negative ? -d : d);
}
@ -365,7 +388,7 @@ public class NativeGlobal implements IdFunctionMaster {
}
return R.toString();
}
private static char hex_digit_to_char(int x) {
return (char)(x <= 9 ? x + '0' : x + ('A' - 10));
}
@ -425,7 +448,7 @@ public class NativeGlobal implements IdFunctionMaster {
if (args.length < 1)
return Boolean.FALSE;
double d = ScriptRuntime.toNumber(args[0]);
return (d != d || d == Double.POSITIVE_INFINITY ||
return (d != d || d == Double.POSITIVE_INFINITY ||
d == Double.NEGATIVE_INFINITY)
? Boolean.FALSE
: Boolean.TRUE;
@ -437,14 +460,14 @@ public class NativeGlobal implements IdFunctionMaster {
String m = ScriptRuntime.getMessage1("msg.cant.call.indirect", "eval");
throw NativeGlobal.constructError(cx, "EvalError", m, scope);
}
/**
* The eval function property of the global object.
*
* See ECMA 15.1.2.1
*/
public static Object evalSpecial(Context cx, Scriptable scope,
Object thisArg, Object[] args,
public static Object evalSpecial(Context cx, Scriptable scope,
Object thisArg, Object[] args,
String filename, int lineNumber)
throws JavaScriptException
{
@ -464,19 +487,19 @@ public class NativeGlobal implements IdFunctionMaster {
linep[0] = 1;
}
}
try {
StringReader in = new StringReader((String) x);
Object securityDomain = cx.getSecurityDomainForStackDepth(3);
// Compile the reader with opt level of -1 to force interpreter
// mode.
int oldOptLevel = cx.getOptimizationLevel();
cx.setOptimizationLevel(-1);
Script script = cx.compileReader(scope, in, filename, linep[0],
Script script = cx.compileReader(scope, in, filename, linep[0],
securityDomain);
cx.setOptimizationLevel(oldOptLevel);
// if the compile fails, an error has been reported by the
// compiler, but we need to stop execution to avoid
// infinite looping on while(true) { eval('foo bar') } -
@ -489,7 +512,7 @@ public class NativeGlobal implements IdFunctionMaster {
InterpretedScript is = (InterpretedScript) script;
is.itsData.itsFromEvalCode = true;
Object result = is.call(cx, scope, (Scriptable) thisArg, null);
return result;
}
catch (IOException ioe) {
@ -497,15 +520,15 @@ public class NativeGlobal implements IdFunctionMaster {
throw new RuntimeException("unexpected io exception");
}
}
/**
* The NativeError functions
*
* See ECMA 15.11.6
*/
public static EcmaError constructError(Context cx,
String error,
public static EcmaError constructError(Context cx,
String error,
String message,
Object scope)
{
@ -514,7 +537,7 @@ public class NativeGlobal implements IdFunctionMaster {
return constructError(cx, error, message, scope,
filename, linep[0], 0, null);
}
static EcmaError typeError0(String messageId, Object scope) {
return constructError(Context.getContext(), "TypeError",
ScriptRuntime.getMessage0(messageId), scope);
@ -530,8 +553,8 @@ public class NativeGlobal implements IdFunctionMaster {
*
* See ECMA 15.11.6
*/
public static EcmaError constructError(Context cx,
String error,
public static EcmaError constructError(Context cx,
String error,
String message,
Object scope,
String sourceName,
@ -546,11 +569,11 @@ public class NativeGlobal implements IdFunctionMaster {
catch (ClassCastException x) {
throw new RuntimeException(x.toString());
}
Object args[] = { message };
try {
Object errorObject = cx.newObject(scopeObject, error, args);
return new EcmaError((NativeError)errorObject, sourceName,
return new EcmaError((NativeError)errorObject, sourceName,
lineNumber, columnNumber, lineSource);
}
catch (PropertyException x) {
@ -563,12 +586,12 @@ public class NativeGlobal implements IdFunctionMaster {
throw new RuntimeException(x.toString());
}
}
/**
* The implementation of all the ECMA error constructors (SyntaxError,
* The implementation of all the ECMA error constructors (SyntaxError,
* TypeError, etc.)
*/
private Object new_CommonError(IdFunction ctorObj, Context cx,
private Object new_CommonError(IdFunction ctorObj, Context cx,
Scriptable scope, Object[] args)
{
Scriptable newInstance = new NativeError();
@ -579,7 +602,7 @@ public class NativeGlobal implements IdFunctionMaster {
return newInstance;
}
/*
/*
* ECMA 3, 15.1.3 URI Handling Function Properties
*
* The following are implementations of the algorithms
@ -594,7 +617,7 @@ public class NativeGlobal implements IdFunctionMaster {
StringBuffer R;
R = new StringBuffer();
while (k < str.length()) {
C = str.charAt(k);
if (unescapedSet.indexOf(C) != -1) {
@ -626,7 +649,7 @@ public class NativeGlobal implements IdFunctionMaster {
}
k++;
}
return R.toString();
return R.toString();
}
private static boolean isHex(char c) {
@ -680,10 +703,10 @@ public class NativeGlobal implements IdFunctionMaster {
k++;
if (str.charAt(k) != '%')
throw cx.reportRuntimeError0("msg.bad.uri");
if (!isHex(str.charAt(k + 1))
if (!isHex(str.charAt(k + 1))
|| !isHex(str.charAt(k + 2)))
throw cx.reportRuntimeError0("msg.bad.uri");
B = unHex(str.charAt(k + 1)) * 16
B = unHex(str.charAt(k + 1)) * 16
+ unHex(str.charAt(k + 2));
if ((B & 0xC0) != 0x80)
throw cx.reportRuntimeError0("msg.bad.uri");
@ -715,31 +738,31 @@ public class NativeGlobal implements IdFunctionMaster {
}
return R.toString();
}
private static String uriReservedPlusPound = ";/?:@&=+$,#";
private static String uriUnescaped =
private static String uriUnescaped =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";
private String js_decodeURI(Context cx, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return decode(cx, str, uriReservedPlusPound);
}
}
private String js_decodeURIComponent(Context cx, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return decode(cx, str, "");
}
}
private Object js_encodeURI(Context cx, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return encode(cx, str, uriReservedPlusPound + uriUnescaped);
}
}
private String js_encodeURIComponent(Context cx, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return encode(cx, str, uriUnescaped);
}
}
/* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be
* at least 6 bytes long. Return the number of UTF-8 bytes of data written.
*/
@ -789,14 +812,7 @@ public class NativeGlobal implements IdFunctionMaster {
return ucs4Char;
}
protected int getMinimumId() { return MIN_ID; }
protected int getMaximumId() { return MAX_ID; }
private static final int
MIN_ID = -1,
Id_new_CommonError = -1,
private static final int
Id_decodeURI = 1,
Id_decodeURIComponent = 2,
Id_encodeURI = 3,
@ -808,7 +824,11 @@ public class NativeGlobal implements IdFunctionMaster {
Id_parseFloat = 9,
Id_parseInt = 10,
Id_unescape = 11,
MAX_ID = 11;
LAST_SCOPE_FUNCTION_ID = 11,
Id_new_CommonError = 12;
private boolean scopeSlaveFlag;
}

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

@ -59,9 +59,29 @@ import java.io.IOException;
public class NativeScript extends NativeFunction implements Script {
public static void init(Context cx, Scriptable scope, boolean sealed) {
NativeScript obj = new NativeScript();
obj.scopeInit(cx, scope, sealed);
}
public NativeScript() {
}
private void scopeInit(Context cx, Scriptable scope, boolean sealed) {
// prototypeIdShift != 0 serves as indicator of prototype instance
// and as id offset to take into account ids present in each instance
// of the base class NativeFunction.
// Not to depend on the assumption NativeFunction.maxInstanceId() != 0,
// 1 is added super.maxInstanceId() to make sure that
// prototypeIdShift != 0 in the NativeScript prototype.
// In a similar way the following methods use
// methodId - prototypeIdShift + 1, not methodId - prototypeIdShift
// to unshift prototype id to [1 .. MAX_PROTOTYPE_ID] interval
prototypeIdShift = super.maxInstanceId() + 1;
addAsPrototype(MAX_PROTOTYPE_ID + prototypeIdShift - 1,
cx, scope, sealed);
}
/**
* Returns the name of this JavaScript class, "Script".
*/
@ -78,19 +98,63 @@ public class NativeScript extends NativeFunction implements Script {
public void initScript(Scriptable scope) {
}
public int methodArity(int methodId) {
if (prototypeIdShift != 0) {
switch (methodId - prototypeIdShift + 1) {
case Id_constructor: return 1;
case Id_toString: return 0;
case Id_exec: return 0;
case Id_compile: return 1;
}
}
return super.methodArity(methodId);
}
public Object execMethod(int methodId, IdFunction f, Context cx,
Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (prototypeIdShift != 0) {
switch (methodId - prototypeIdShift + 1) {
case Id_constructor:
return jsConstructor(cx, scope, args);
case Id_toString:
return realThis(thisObj, f, true).
jsFunction_toString(cx, args);
case Id_exec:
return realThis(thisObj, f, true).jsFunction_exec();
case Id_compile:
return realThis(thisObj, f, false).
jsFunction_compile(ScriptRuntime.toString(args, 0));
}
}
return super.execMethod(methodId, f, cx, scope, thisObj, args);
}
private NativeScript realThis(Scriptable thisObj, IdFunction f,
boolean readOnly)
{
while (!(thisObj instanceof NativeScript)) {
thisObj = nextInstanceCheck(thisObj, f, readOnly);
}
return (NativeScript)thisObj;
}
/**
* The Java method defining the JavaScript Script constructor.
*
*/
public static Object jsConstructor(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
private static Object jsConstructor(Context cx, Scriptable scope,
Object[] args)
{
String source = args.length == 0
? ""
: ScriptRuntime.toString(args[0]);
Scriptable scope = cx.ctorScope;
if (scope == null)
scope = ctorObj;
return compile(scope, source);
}
@ -114,23 +178,21 @@ public class NativeScript extends NativeFunction implements Script {
}
}
public Scriptable jsFunction_compile(String source) {
private Scriptable jsFunction_compile(String source) {
script = compile(null, source);
return this;
}
public Object jsFunction_exec() throws JavaScriptException {
private Object jsFunction_exec() throws JavaScriptException {
throw Context.reportRuntimeError1
("msg.cant.call.indirect", "exec");
}
public static Object jsFunction_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
private Object jsFunction_toString(Context cx, Object[] args)
{
Script thisScript = ((NativeScript) thisObj).script;
if (thisScript == null)
thisScript = (Script) thisObj;
Scriptable scope = getTopLevelScope(thisObj);
Script thisScript = script;
if (thisScript == null) { thisScript = this; }
Scriptable scope = getTopLevelScope(this);
return cx.decompileScript(thisScript, scope, 0);
}
@ -165,6 +227,60 @@ public class NativeScript extends NativeFunction implements Script {
throw Context.reportRuntimeError0("msg.script.is.not.constructor");
}
protected String getIdName(int id) {
if (prototypeIdShift != 0) {
switch (id - prototypeIdShift + 1) {
case Id_constructor: return "constructor";
case Id_toString: return "toString";
case Id_exec: return "exec";
case Id_compile: return "compile";
}
}
return super.getIdName(id);
}
protected int mapNameToId(String s) {
if (prototypeIdShift != 0) {
int id = toPrototypeId(s);
if (id != 0) {
// Shift [1, MAX_PROTOTYPE_ID] to
// [super.maxInstanceId() + 1,
// super.maxInstanceId() + MAX_PROTOTYPE_ID]
return id + prototypeIdShift - 1;
}
}
return super.mapNameToId(s);
}
// #string_id_map#
private static int toPrototypeId(String s) {
int id;
// #generated# Last update: 2001-05-23 13:25:01 GMT+02:00
L0: { id = 0; String X = null;
L: switch (s.length()) {
case 4: X="exec";id=Id_exec; break L;
case 7: X="compile";id=Id_compile; break L;
case 8: X="toString";id=Id_toString; break L;
case 11: X="constructor";id=Id_constructor; break L;
}
if (X!=null && X!=s && !X.equals(s)) id = 0;
}
// #/generated#
return id;
}
private static final int
Id_constructor = 1,
Id_toString = 2,
Id_compile = 3,
Id_exec = 4,
MAX_PROTOTYPE_ID = 4;
// #/string_id_map#
private Script script;
private int prototypeIdShift;
}

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

@ -1204,7 +1204,8 @@ public class ScriptRuntime {
}
private static Object callOrNewSpecial(Context cx, Scriptable scope,
Object fun, Object jsThis, Object thisArg,
Object fun, Object jsThis,
Object thisArg,
Object[] args, boolean isCall,
String filename, int lineNumber)
throws JavaScriptException
@ -1212,13 +1213,25 @@ public class ScriptRuntime {
if (fun instanceof IdFunction) {
IdFunction f = (IdFunction)fun;
String name = f.getFunctionName();
Class cl = f.master.getClass();
if (name.equals("eval") && cl == NativeGlobal.class) {
return NativeGlobal.evalSpecial(cx, scope, thisArg, args,
filename, lineNumber);
}
if (name.equals("With") && cl == NativeWith.class) {
return NativeWith.newWithSpecial(cx, args, f, !isCall);
if (name.length() == 4) {
if (name.equals("eval")) {
if (f.master.getClass() == NativeGlobal.class) {
return NativeGlobal.evalSpecial(cx, scope,
thisArg, args,
filename, lineNumber);
}
}
else if (name.equals("With")) {
if (f.master.getClass() == NativeWith.class) {
return NativeWith.newWithSpecial(cx, args, f, !isCall);
}
}
else if (name.equals("exec")) {
if (f.master.getClass() == NativeScript.class) {
return ((NativeScript)jsThis).
exec(cx, ScriptableObject.getTopLevelScope(scope));
}
}
}
}
else if (fun instanceof FunctionObject) {
@ -1226,8 +1239,6 @@ public class ScriptRuntime {
Member m = fo.method;
Class cl = m.getDeclaringClass();
String name = m.getName();
if (name.equals("jsFunction_exec") && cl == NativeScript.class)
return ((NativeScript)jsThis).exec(cx, ScriptableObject.getTopLevelScope(scope));
if (name.equals("exec")
&& (cx.getRegExpProxy() != null)
&& (cx.getRegExpProxy().isRegExp(jsThis)))
@ -1887,8 +1898,9 @@ public class ScriptRuntime {
script.exec(cx, global);
} catch (JavaScriptException e) {
throw new Error(e.toString());
} finally {
Context.exit();
}
Context.exit();
return global;
}

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

@ -2136,7 +2136,7 @@ public class Main extends JFrame implements Debugger, ContextListener {
v.addElement(entry);
if(fnOrScript.getScriptable() instanceof NativeFunction) {
NativeFunction f = (NativeFunction)fnOrScript.getScriptable();
String name = f.jsGet_name();
String name = f.getFunctionName();
if(name.length() > 0 && !name.equals("anonymous")) {
functionMap.put(name, entry);
}

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

@ -0,0 +1,147 @@
Notes on StringIdMap (main class org.mozilla.javascript.tools.idswitch.StringIdMap) utility
The main purpose of this utility is to generate Java code to map strings to some ids that can be used, for example, in switch statement.
The utility scans the file for lines with the following structure:
// #string_id_map#
... <DEFINITION AREA>
// #generated#
...<GENERATED AREA>
// #/generated#
... <DEFINITION AREA>
// #/string_id_map#
Then every line in <DEFINITION AREA> is scanned for the pattern:
^[ \t]*Id_([0-9a-zA-Z_]+)[ \t]*=.*$
Each such patterns adds a mapping form string $1 to Id_\$ or if the line also contains the pattern //\s*#string=\s*([^#]+)\s*#, then it adds map of $1 in this pattern to Id_\$
After that lines in <GENERATED AREA> are replaced by a code block that sets variable "id" to Id_<name> if variable "s" equals <name> or 0 otherwise.
If the new code is not identical to the old one, then time stamp is appended after #generated#.
For example, if file x.java contains:
// #string_id_map#
private int getId(String s) {
int id;
// #generated# Initial version
// #/generated#
return id;
}
private static final int
Id_x = 1,
Id_y = 2,
Id_hello = 3,
Id_nice = 4,
Id_world = 5,
Id_for = 6,
Id_bar = 7;
// #/string_id_map#
....
private double getFieldValue(String s) {
// #string_id_map#
final int
Id_field1 = 1,
Id_field2 = 2,
Id_field3 = 3,
Id_one_more_field = 4;
int id;
// #generated# Initial version
// #/generated#
// #/string_id_map#
switch (id) {
case Id_field1: return field1;
case Id_field2: return field2;
case Id_field3: return field3;
case Id_one_more_field: return one_more_field;
}
throw new RuntimeException("No such field");
}
then invocation
java org.mozilla.javascript.tools.string_switch.StringIdMap x.java
would replace that by a code fragment similar to:
// #string_id_map#
private int getId(String s) {
int id;
// #generated# Last update: 2001-03-23 13:34:10 GMT+01:00
L0: { id = 0; String X = null; int c;
L: switch (s.length()) {
case 1: c=s.charAt(0);
if (c=='x') { id=Id_x; break L0; }
else if (c=='y') { id=Id_y; break L0; }
break L;
case 3: c=s.charAt(0);
if (c=='b') { if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_bar; break L0;} }
else if (c=='f') { if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_for; break L0;} }
break L;
case 4: X="nice";id=Id_nice; break L;
case 5: c=s.charAt(0);
if (c=='h') { X="hello";id=Id_hello; }
else if (c=='w') { X="world";id=Id_world; }
break L;
}
if (X!=null && X!=s && !X.equals(s)) id = 0;
}
// #/generated#
return id;
}
private static final int
Id_x = 1,
Id_y = 2,
Id_hello = 3,
Id_nice = 4,
Id_world = 5,
Id_for = 6,
Id_bar = 7;
// #/string_id_map#
....
private double getFieldValue(String s) {
// #string_id_map#
final int
Id_field1 = 1,
Id_field2 = 2,
Id_field3 = 3,
Id_one_more_field = 4;
int id;
// #generated# Last update: 2001-03-23 13:34:10 GMT+01:00
L0: { id = 0; String X = null; int c;
int s_length = s.length();
if (s_length==6) {
c=s.charAt(5);
if (c=='1') { X="field1";id=Id_field1; }
else if (c=='2') { X="field2";id=Id_field2; }
else if (c=='3') { X="field3";id=Id_field3; }
}
else if (s_length==14) { X="one_more_field";id=Id_one_more_field; }
if (X!=null && X!=s && !X.equals(s)) id = 0;
}
// #/generated#
// #/string_id_map#
switch (id) {
case Id_field1: return field1;
case Id_field2: return field2;
case Id_field3: return field3;
case Id_one_more_field: return one_more_field;
}
throw new RuntimeException("No such field");
}

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

@ -47,11 +47,13 @@ public class StringIdMap {
private static final String SWITCH_TAG_STR = "string_id_map";
private static final String GENERATED_TAG_STR = "generated";
private static final String STRING_TAG_STR = "string";
private static final int
NORMAL_LINE = 0,
SWITCH_TAG = 1,
GENERATED_TAG = 2;
GENERATED_TAG = 2,
STRING_TAG = 3;
private final Vector all_pairs = new Vector();
@ -61,6 +63,14 @@ public class StringIdMap {
private String source_file;
private int tag_definition_end;
private int tag_value_start;
private int tag_value_end;
private static boolean is_value_type(int id) {
if (id == STRING_TAG) { return true; }
return false;
}
private static String tag_name(int id) {
switch (id) {
@ -137,7 +147,10 @@ public class StringIdMap {
break;
case SWITCH_TAG:
if (tag_id == 0) {
look_for_id_definitions(buffer, begin, end);
look_for_id_definitions(buffer, begin, end, false);
}
else if (tag_id == STRING_TAG) {
look_for_id_definitions(buffer, begin, end, true);
}
else if (tag_id == GENERATED_TAG) {
if (generated_begin >= 0) { bad_tag = true; }
@ -222,33 +235,61 @@ public class StringIdMap {
private int extract_line_tag_id(char[] array, int cursor, int end) {
int id = 0;
cursor = skip_white_space(array, cursor, end);
if (cursor + 2 <= end) {
if (array[cursor] == '/' || array[cursor + 1] == '/') {
cursor += 2;
cursor = skip_white_space(array, cursor, end);
if (cursor != end && array[cursor] == '#') {
++cursor;
boolean end_tag = false;
if (cursor != end && array[cursor] == '/') {
++cursor; end_tag = true;
}
int tag_start = cursor;
for (; cursor != end; ++cursor) {
int c = array[cursor];
if (c == '#' || is_white_space(c)) { break; }
}
int after_leading_white_space = cursor;
cursor = look_for_slash_slash(array, cursor, end);
if (cursor != end) {
boolean at_line_start = (after_leading_white_space + 2 == cursor);
cursor = skip_white_space(array, cursor, end);
if (cursor != end && array[cursor] == '#') {
++cursor;
boolean end_tag = false;
if (cursor != end && array[cursor] == '/') {
++cursor; end_tag = true;
}
int tag_start = cursor;
for (; cursor != end; ++cursor) {
int c = array[cursor];
if (c == '#' || c == '=' ||is_white_space(c)) { break; }
}
if (cursor != end) {
int tag_end = cursor;
cursor = skip_white_space(array, cursor, end);
if (cursor != end) {
int tag_end = cursor;
cursor = skip_white_space(array, cursor, end);
if (cursor != end && array[cursor] == '#') {
id = get_tag_id(array, tag_start, tag_end);
int c = array[cursor];
if (c == '=' || c == '#') {
id = get_tag_id
(array, tag_start, tag_end, at_line_start);
if (id != 0) {
if (end_tag) { id = -id; }
tag_definition_end = cursor + 1;
String bad = null;
if (c == '#') {
if (end_tag) {
id = -id;
if (is_value_type(id)) {
bad = "msg.idswitch.no_end_usage";
}
}
tag_definition_end = cursor + 1;
}
else {
if (end_tag) {
bad = "msg.idswitch.no_end_with_value";
}
else if (!is_value_type(id)) {
bad = "msg.idswitch.no_value_allowed";
}
id = extract_tag_value
(array, cursor + 1, end, id);
}
if (bad != null) {
String s = R.getMessage(bad, tag_name(id));
throw R.runtimeError
(s, source_file, body.getLineNumber(),
null, 0);
}
}
}
}
@ -258,17 +299,65 @@ public class StringIdMap {
return id;
}
private int get_tag_id(char[] array, int begin, int end) {
if (equals(SWITCH_TAG_STR, array, begin, end)) {
return SWITCH_TAG;
// Return position after first of // or end if not found
private int look_for_slash_slash(char[] array, int cursor, int end) {
while (cursor + 2 <= end) {
int c = array[cursor++];
if (c == '/') {
c = array[cursor++];
if (c == '/') {
return cursor;
}
}
}
if (equals(GENERATED_TAG_STR, array, begin, end)) {
return GENERATED_TAG;
return end;
}
private int extract_tag_value(char[] array, int cursor, int end, int id) {
// cursor points after #[^#=]+=
// ALERT: implement support for quoted strings
boolean found = false;
cursor = skip_white_space(array, cursor, end);
if (cursor != end) {
int value_start = cursor;
for (; cursor != end; ++cursor) {
int c = array[cursor];
if (c == '#' || is_white_space(c)) { break; }
}
if (cursor != end) {
int value_end = cursor;
cursor = skip_white_space(array, cursor, end);
if (cursor != end && array[cursor] == '#') {
found = true;
tag_value_start = value_start;
tag_value_end = value_end;
tag_definition_end = cursor + 1;
}
}
}
return (found) ? id : 0;
}
private int get_tag_id
(char[] array, int begin, int end, boolean at_line_start)
{
if (at_line_start) {
if (equals(SWITCH_TAG_STR, array, begin, end)) {
return SWITCH_TAG;
}
if (equals(GENERATED_TAG_STR, array, begin, end)) {
return GENERATED_TAG;
}
}
if (equals(STRING_TAG_STR, array, begin, end)) {
return STRING_TAG;
}
return 0;
}
private void look_for_id_definitions(char[] array, int begin, int end)
private void look_for_id_definitions
(char[] array, int begin, int end, boolean use_tag_value_as_string)
{
// Look for the pattern
// '^[ \t]+Id_([a-zA-Z0-9_]+)[ \t]*=.*$'
@ -287,8 +376,13 @@ public class StringIdMap {
cursor = skip_white_space(array, cursor, end);
if (cursor != end) {
if (array[cursor] == '=') {
int id_end = name_end;
if (use_tag_value_as_string) {
name_start = tag_value_start;
name_end = tag_value_end;
}
// Got the match
add_id(array, id_start, name_end, name_start, name_end);
add_id(array, id_start, id_end, name_start, name_end);
}
}
}

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

@ -137,6 +137,15 @@ msg.idswitch.file_end_in_switch =\
msg.idswitch.bad_tag_order =\
String switch tag {0} is not allowed here
msg.idswitch.no_end_with_value =\
End for tag {0} can not contain value
msg.idswitch.no_value_allowed =\
Tag {0} can not contain value
msg.idswitch.no_end_usage =\
Tag {0} can not be used as end tag
msg.idswitch.no_file_argument =\
File argument should be given
@ -171,4 +180,4 @@ Note: the original file will be overwritten without any backup actions\n\
\ and all code inside #generated# tag will be replaced by new one.
msg.idswitch.version = \
org.mozilla.javascript.tools.idswitch.StringIdMap version 0.1
org.mozilla.javascript.tools.idswitch.StringIdMap version 0.2