зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
fb94e6375f
Коммит
f0adcfbccd
|
@ -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)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче