Making Script implementations by Interpreter and Optimizer scope independent while keeping while still supporting compiling of regexp literals only once per Script instance.
This commit is contained in:
igor%mir2.org 2003-09-10 11:06:25 +00:00
Родитель fb94e6375f
Коммит f0adcfbccd
7 изменённых файлов: 182 добавлений и 64 удалений

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

@ -66,5 +66,6 @@ final class InterpretedFunction extends NativeFunction
InterpreterData itsData;
boolean itsUseDynamicScope;
Scriptable[] itsRegExps;
}

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

@ -270,7 +270,7 @@ public class Interpreter
for (int i = 0; i != N; i++) {
String string = scriptOrFn.getRegexpString(i);
String flags = scriptOrFn.getRegexpFlags(i);
array[i] = rep.newRegExp(cx, scope, string, flags);
array[i] = rep.compileRegExp(cx, scope, string, flags);
}
itsData.itsRegExpLiterals = array;
}
@ -1578,12 +1578,29 @@ public class Interpreter
idata.encodedSourceEnd);
}
private static Scriptable[] wrapRegExps(Context cx, Scriptable scope,
InterpreterData idata)
{
if (idata.itsRegExpLiterals == null) Context.codeBug();
RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx);
int N = idata.itsRegExpLiterals.length;
Scriptable[] array = new Scriptable[N];
for (int i = 0; i != N; ++i) {
array[i] = rep.wrapRegExp(cx, scope, idata.itsRegExpLiterals[i]);
}
return array;
}
private static InterpretedFunction createFunction(Context cx,
Scriptable scope,
InterpreterData idata,
boolean fromEvalCode)
{
InterpretedFunction fn = new InterpretedFunction(idata);
if (idata.itsRegExpLiterals != null) {
fn.itsRegExps = wrapRegExps(cx, scope, idata);
}
if (cx.hasCompileFunctionsWithDynamicScope()) {
// Nested functions are not affected by the dynamic scope flag
// as dynamic scope is already a parent of their scope
@ -1693,6 +1710,11 @@ public class Interpreter
}
}
// Wrapped regexps for functions are stored in InterpretedFunction
// but for script which should not contain references to scope
// the regexps re-wrapped during each script execution
Scriptable[] scriptRegExps = null;
boolean useActivationVars = false;
if (debuggerFrame != null) {
if (argsDbl != null) {
@ -2620,7 +2642,16 @@ public class Interpreter
}
case Token.REGEXP : {
int i = getIndex(iCode, pc + 1);
stack[++stackTop] = idata.itsRegExpLiterals[i];
Scriptable regexp;
if (idata.itsFunctionType != 0) {
regexp = ((InterpretedFunction)fnOrScript).itsRegExps[i];
} else {
if (scriptRegExps == null) {
scriptRegExps = wrapRegExps(cx, scope, idata);
}
regexp = scriptRegExps[i];
}
stack[++stackTop] = regexp;
pc += 2;
break;
}

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

@ -412,7 +412,7 @@ final class NativeString extends IdScriptable {
*/
private static int find_split(Context cx, Scriptable scope, String target,
String separator, int version,
RegExpProxy reProxy, Object re,
RegExpProxy reProxy, Scriptable re,
int[] ip, int[] matchlen, boolean[] matched,
String[][] parensp)
{
@ -548,12 +548,19 @@ final class NativeString extends IdScriptable {
}
String separator = null;
int[] matchlen = { 0 };
Object re = null;
RegExpProxy reProxy = ScriptRuntime.getRegExpProxy(cx);
if (reProxy != null && reProxy.isRegExp(args[0])) {
re = args[0];
} else {
int[] matchlen = new int[1];
Scriptable re = null;
RegExpProxy reProxy = null;
if (args[0] instanceof Scriptable) {
reProxy = ScriptRuntime.getRegExpProxy(cx);
if (reProxy != null) {
Scriptable test = (Scriptable)args[0];
if (reProxy.isRegExp(test)) {
re = test;
}
}
}
if (re == null) {
separator = ScriptRuntime.toString(args[0]);
matchlen[0] = separator.length();
}

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

@ -46,10 +46,13 @@ package org.mozilla.javascript;
public interface RegExpProxy
{
public boolean isRegExp(Object obj);
public boolean isRegExp(Scriptable obj);
public Object newRegExp(Context cx, Scriptable scope,
String source, String global);
public Object compileRegExp(Context cx, Scriptable scope,
String source, String global);
public Scriptable wrapRegExp(Context cx, Scriptable scope,
Object compiled);
public Object match(Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
@ -64,7 +67,7 @@ public interface RegExpProxy
throws JavaScriptException;
public int find_split(Context cx, Scriptable scope, String target,
String separator, Object re,
String separator, Scriptable re,
int[] ip, int[] matchlen,
boolean[] matched, String[][] parensp);
}

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

@ -332,6 +332,7 @@ public class Codegen extends Interpreter {
}
}
emitRegExpInit(cfw);
emitConstantDudeInitializers(cfw);
mainClassBytes = cfw.toByteArray();
@ -653,7 +654,7 @@ public class Codegen extends Interpreter {
// precompile all regexp literals
int regexpCount = fn.getRegexpCount();
if (regexpCount != 0) {
cfw.addLoadThis();
cfw.addLoadThis();
pushRegExpArray(cfw, fn, CONTEXT_ARG, SCOPE_ARG);
cfw.add(ByteCode.PUTFIELD, mainClassName,
REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE);
@ -727,6 +728,68 @@ public class Codegen extends Interpreter {
cfw.stopMethod((short)1, null);
}
private void emitRegExpInit(ClassFileWriter cfw)
{
// precompile all regexp literals
int totalRegCount = 0;
for (int i = 0; i != scriptOrFnNodes.length; ++i) {
totalRegCount += scriptOrFnNodes[i].getRegexpCount();
}
if (totalRegCount == 0) {
return;
}
cfw.startMethod(REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE,
(short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE
| ClassFileWriter.ACC_SYNCHRONIZED));
cfw.addField("_reInitDone", "Z",
(short)(ClassFileWriter.ACC_STATIC
| ClassFileWriter.ACC_PRIVATE));
cfw.add(ByteCode.GETSTATIC, mainClassName, "_reInitDone", "Z");
int doInit = cfw.acquireLabel();
cfw.add(ByteCode.IFEQ, doInit);
cfw.add(ByteCode.RETURN);
cfw.markLabel(doInit);
for (int i = 0; i != scriptOrFnNodes.length; ++i) {
ScriptOrFnNode n = scriptOrFnNodes[i];
int regCount = n.getRegexpCount();
for (int j = 0; j != regCount; ++j) {
String reFieldName = getCompiledRegexpName(n, j);
String reFieldType = "Ljava/lang/Object;";
String reString = n.getRegexpString(j);
String reFlags = n.getRegexpFlags(j);
cfw.addField(reFieldName, reFieldType,
(short)(ClassFileWriter.ACC_STATIC
| ClassFileWriter.ACC_PRIVATE));
cfw.addALoad(0); // proxy
cfw.addALoad(1); // context
cfw.addALoad(2); // scope
cfw.addPush(reString);
if (reFlags == null) {
cfw.add(ByteCode.ACONST_NULL);
} else {
cfw.addPush(reFlags);
}
cfw.addInvoke(ByteCode.INVOKEINTERFACE,
"org/mozilla/javascript/RegExpProxy",
"compileRegExp",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;Ljava/lang/String;"
+")Ljava/lang/Object;");
cfw.add(ByteCode.PUTSTATIC, mainClassName,
reFieldName, reFieldType);
}
}
cfw.addPush(1);
cfw.add(ByteCode.PUTSTATIC, mainClassName, "_reInitDone", "Z");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)3, null);
}
private void emitConstantDudeInitializers(ClassFileWriter cfw)
{
int N = itsConstantListSize;
@ -774,12 +837,9 @@ public class Codegen extends Interpreter {
}
}
static void pushRegExpArray(ClassFileWriter cfw,
ScriptOrFnNode n,
int contextArg,
int scopeArg)
void pushRegExpArray(ClassFileWriter cfw, ScriptOrFnNode n,
int contextArg, int scopeArg)
{
// precompile all regexp literals
int regexpCount = n.getRegexpCount();
if (regexpCount == 0) badTree();
@ -792,34 +852,32 @@ public class Codegen extends Interpreter {
"checkRegExpProxy",
"(Lorg/mozilla/javascript/Context;"
+")Lorg/mozilla/javascript/RegExpProxy;");
// Stack: proxy, array
cfw.add(ByteCode.DUP);
cfw.addALoad(contextArg);
cfw.addALoad(scopeArg);
cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName,
REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE);
for (int i = 0; i != regexpCount; ++i) {
// Stack: proxy, array
cfw.add(ByteCode.DUP2);
// Stack structure: proxy, array, proxy, array
cfw.addALoad(contextArg);
cfw.addALoad(scopeArg);
cfw.addPush(n.getRegexpString(i));
String regexpFlags = n.getRegexpFlags(i);
if (regexpFlags == null) {
cfw.add(ByteCode.ACONST_NULL);
} else {
cfw.addPush(regexpFlags);
}
cfw.add(ByteCode.GETSTATIC, mainClassName,
getCompiledRegexpName(n, i), "Ljava/lang/Object;");
// Stack: compiledRegExp, scope, cx, proxy, array, proxy, array
cfw.addInvoke(ByteCode.INVOKEINTERFACE,
"org/mozilla/javascript/RegExpProxy",
"newRegExp",
"wrapRegExp",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;Ljava/lang/String;"
+")Ljava/lang/Object;");
// Stack structure: result of newRegExp, array, proxy, array
+"Ljava/lang/Object;"
+")Lorg/mozilla/javascript/Scriptable;");
// Stack: wrappedRegExp, array, proxy, array
cfw.addPush(i);
cfw.add(ByteCode.SWAP);
cfw.add(ByteCode.AASTORE);
// Stack structure: proxy, array
// Stack: proxy, array
}
// remove proxy
cfw.add(ByteCode.POP);
@ -962,6 +1020,11 @@ public class Codegen extends Interpreter {
return "_i"+getIndex(fn);
}
String getCompiledRegexpName(ScriptOrFnNode n, int regexpIndex)
{
return "_re"+getIndex(n)+"_"+regexpIndex;
}
static RuntimeException badTree()
{
throw new RuntimeException("Bad tree in codegen");
@ -974,6 +1037,12 @@ public class Codegen extends Interpreter {
private static final String ID_FIELD_NAME = "_id";
private static final String REGEXP_INIT_METHOD_NAME = "_reInit";
private static final String REGEXP_INIT_METHOD_SIGNATURE
= "(Lorg/mozilla/javascript/RegExpProxy;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")V";
static final String REGEXP_ARRAY_FIELD_NAME = "_re";
static final String REGEXP_ARRAY_FIELD_TYPE = "[Ljava/lang/Object;";
@ -1139,7 +1208,7 @@ class BodyCodegen
// See comments in visitRegexp
if (scriptOrFn.getRegexpCount() != 0) {
scriptRegexpLocal = getNewWordLocal();
Codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
variableObjectLocal);
cfw.addAStore(scriptRegexpLocal);
}

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

@ -131,7 +131,7 @@ public class NativeRegExp extends IdScriptable implements Function {
{
NativeRegExp proto = new NativeRegExp();
proto.re = compileRE(cx, scope, "", null, false);
proto.re = (RECompiled)compileRE(cx, scope, "", null, false);
proto.prototypeFlag = true;
proto.setMaxId(MAX_PROTOTYPE_ID);
proto.setParentScope(scope);
@ -151,10 +151,9 @@ public class NativeRegExp extends IdScriptable implements Function {
defineProperty(scope, "RegExp", ctor, ScriptableObject.DONTENUM);
}
public NativeRegExp(Context cx, Scriptable scope, String source,
String global, boolean flat)
NativeRegExp(Scriptable scope, Object regexpCompiled)
{
this.re = compileRE(cx, scope, source, global, flat);
this.re = (RECompiled)regexpCompiled;
this.lastIndex = 0;
scope = getTopLevelScope(scope);
setPrototype(getClassPrototype(scope, "RegExp"));
@ -196,7 +195,7 @@ public class NativeRegExp extends IdScriptable implements Function {
String global = args.length > 1 && args[1] != Undefined.instance
? ScriptRuntime.toString(args[1])
: null;
this.re = compileRE(cx, scope, s, global, false);
this.re = (RECompiled)compileRE(cx, scope, s, global, false);
this.lastIndex = 0;
return this;
}
@ -254,9 +253,8 @@ public class NativeRegExp extends IdScriptable implements Function {
return rval;
}
private static RECompiled
compileRE(Context cx, Scriptable scope,
String str, String global, boolean flat)
static Object compileRE(Context cx, Scriptable scope,
String str, String global, boolean flat)
{
RECompiled regexp = new RECompiled();
regexp.source = str.toCharArray();

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

@ -45,14 +45,20 @@ public class RegExpImpl implements RegExpProxy {
parens = new ObjArray();
}
public boolean isRegExp(Object obj) {
public boolean isRegExp(Scriptable obj) {
return obj instanceof NativeRegExp;
}
public Object newRegExp(Context cx, Scriptable scope,
String source, String global)
public Object compileRegExp(Context cx, Scriptable scope,
String source, String global)
{
return new NativeRegExp(cx, scope, source, global, false);
return NativeRegExp.compileRE(cx, scope, source, global, false);
}
public Scriptable wrapRegExp(Context cx, Scriptable scope,
Object compiled)
{
return new NativeRegExp(scope, compiled);
}
public Object match(Context cx, Scriptable scope,
@ -148,22 +154,25 @@ public class RegExpImpl implements RegExpProxy {
data.str = str;
Scriptable topScope = ScriptableObject.getTopLevelScope(scope);
if (args.length == 0)
re = new NativeRegExp(cx, topScope, "", "", false);
else
if (args[0] instanceof NativeRegExp) {
re = (NativeRegExp) args[0];
if (args.length == 0) {
Object compiled = NativeRegExp.compileRE(cx, topScope, "", "",
false);
re = new NativeRegExp(topScope, compiled);
} else if (args[0] instanceof NativeRegExp) {
re = (NativeRegExp) args[0];
} else {
String src = ScriptRuntime.toString(args[0]);
String opt;
if (data.optarg < args.length) {
args[0] = src;
opt = ScriptRuntime.toString(args[data.optarg]);
} else {
String src = ScriptRuntime.toString(args[0]);
String opt;
if (data.optarg < args.length) {
args[0] = src;
opt = ScriptRuntime.toString(args[data.optarg]);
} else {
opt = null;
}
re = new NativeRegExp(cx, topScope, src, opt, forceFlat);
opt = null;
}
Object compiled = NativeRegExp.compileRE(cx, topScope, src, opt,
forceFlat);
re = new NativeRegExp(topScope, compiled);
}
data.regexp = re;
data.global = (re.getFlags() & NativeRegExp.JSREG_GLOB) != 0;
@ -203,7 +212,7 @@ public class RegExpImpl implements RegExpProxy {
public int find_split(Context cx, Scriptable scope, String target,
String separator, Object reObj,
String separator, Scriptable reObj,
int[] ip, int[] matchlen,
boolean[] matched, String[][] parensp)
{