This commit is contained in:
Jason Orendorff 2010-01-05 12:48:42 -06:00
Родитель aa3edeeafe 8ed2d1a4d3
Коммит 1d338d9580
9 изменённых файлов: 126 добавлений и 58 удалений

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

@ -6699,24 +6699,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
ok = EmitNumberOp(cx, pn->pn_dval, cg);
break;
case TOK_REGEXP: {
case TOK_REGEXP:
/*
* If the regexp's script is one-shot and the regexp is not used in a
* loop, we can avoid the extra fork-on-exec costs of JSOP_REGEXP by
* selecting JSOP_OBJECT. Otherwise, to avoid incorrect proto, parent,
* and lastIndex sharing, select JSOP_REGEXP.
* If the regexp's script is one-shot, we can avoid the extra
* fork-on-exec costs of JSOP_REGEXP by selecting JSOP_OBJECT.
* Otherwise, to avoid incorrect proto, parent, and lastIndex
* sharing among threads and sequentially across re-execution,
* select JSOP_REGEXP.
*/
JS_ASSERT(pn->pn_op == JSOP_REGEXP);
bool singleton = !cg->fun && (cg->flags & TCF_COMPILE_N_GO);
if (singleton) {
for (JSStmtInfo *stmt = cg->topStmt; stmt; stmt = stmt->down) {
if (STMT_IS_LOOP(stmt)) {
singleton = false;
break;
}
}
}
if (singleton) {
if (cg->flags & TCF_COMPILE_N_GO) {
ok = EmitObjectOp(cx, pn->pn_objbox, JSOP_OBJECT, cg);
} else {
ok = EmitIndexOp(cx, JSOP_REGEXP,
@ -6724,7 +6716,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
cg);
}
break;
}
#if JS_HAS_XML_SUPPORT
case TOK_ANYNAME:

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

@ -1785,7 +1785,12 @@ JSFunction::countInterpretedReservedSlots() const
{
JS_ASSERT(FUN_INTERPRETED(this));
return (u.i.nupvars == 0) ? 0 : u.i.script->upvars()->length;
uint32 nslots = (u.i.nupvars == 0)
? 0
: u.i.script->upvars()->length;
if (u.i.script->regexpsOffset != 0)
nslots += u.i.script->regexps()->length;
return nslots;
}
static uint32

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

@ -181,8 +181,13 @@ JSStackFrame::assertValidStackDepth(uintN depth)
static JS_INLINE uintN
GlobalVarCount(JSStackFrame *fp)
{
uintN n;
JS_ASSERT(!fp->fun);
return fp->script->nfixed;
n = fp->script->nfixed;
if (fp->script->regexpsOffset != 0)
n -= fp->script->regexps()->length;
return n;
}
typedef struct JSInlineFrame {

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

@ -2284,7 +2284,7 @@ class AutoDescriptorArray : private JSTempValueRooter
JS_POP_TEMP_ROOT(cx, this);
}
PropertyDescriptor *append() {
PropertyDescriptor * append() {
if (!descriptors.append(PropertyDescriptor()))
return NULL;
return &descriptors.back();

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

@ -2438,21 +2438,117 @@ BEGIN_CASE(JSOP_OBJECT)
END_CASE(JSOP_OBJECT)
BEGIN_CASE(JSOP_REGEXP)
{
JSObject *funobj;
/*
* Push a regexp object cloned from the regexp literal object mapped by the
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
* flouted by many browser-based implementations.
* Push a regexp object for the atom mapped by the bytecode at pc, cloning
* the literal's regexp object if necessary, to simulate in the
* pre-compile/execute-later case what ECMA specifies for the
* compile-and-go case: that scanning each regexp literal creates a single
* corresponding RegExp object.
*
* To support pre-compilation transparently, we must handle the case where
* a regexp object literal is used in a different global at execution time
* from the global with which it was scanned at compile time. We do this
* by re-wrapping the JSRegExp private data struct with a cloned object
* having the right prototype and parent, and having its own lastIndex
* property value storage.
*
* Unlike JSOP_DEFFUN and other prolog bytecodes that may clone literal
* objects, we don't want to pay a script prolog execution price for all
* regexp literals in a script (many may not be used by a particular
* execution of that script, depending on control flow), so we initialize
* lazily here.
*
* XXX This code is specific to regular expression objects. If we need a
* similar op for other kinds of object literals, we should push cloning
* down under JSObjectOps and reuse code here.
*/
index = GET_FULL_INDEX(0);
obj = js_CloneRegExpObject(cx, script->getRegExp(index), NULL);
if (!obj)
goto error;
rval = OBJECT_TO_JSVAL(obj);
JS_ASSERT(index < script->regexps()->length);
slot = index;
if (fp->fun) {
/*
* We're in function code, not global or eval code (in eval code,
* JSOP_REGEXP is never emitted). The cloned funobj contains
* script->regexps()->length reserved slots for the cloned regexps; see
* fun_reserveSlots, jsfun.c.
*/
funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
if (script->upvarsOffset != 0)
slot += script->upvars()->length;
if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
goto error;
if (JSVAL_IS_VOID(rval))
rval = JSVAL_NULL;
} else {
/*
* We're in global code. The code generator reserved a slot for the
* regexp among script->nfixed slots. All such slots are initialized to
* null, not void, for faster testing in JSOP_*GVAR cases. To simplify
* index calculations we count regexps in the reverse order down from
* script->nslots - 1.
*/
JS_ASSERT(slot < script->nfixed);
slot = script->nfixed - slot - 1;
rval = fp->slots[slot];
#ifdef __GNUC__
funobj = NULL; /* suppress bogus gcc warnings */
#endif
}
if (JSVAL_IS_NULL(rval)) {
/* Compute the current global object in obj2. */
obj2 = fp->scopeChain;
while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
obj2 = parent;
/*
* If obj's parent is not obj2, we must clone obj so that it has the
* right parent, and therefore, the right prototype.
*
* Yes, this means we assume that the correct RegExp.prototype to which
* regexp instances (including literals) delegate can be distinguished
* solely by the instance's parent, which was set to the parent of the
* RegExp constructor function object when the instance was created.
* In other words,
*
* (/x/.__parent__ == RegExp.__parent__) implies
* (/x/.__proto__ == RegExp.prototype)
*
* (unless you assign a different object to RegExp.prototype at
* runtime, in which case, ECMA doesn't specify operation, and you get
* what you deserve).
*
* This same coupling between instance parent and constructor parent
* turns up everywhere (see jsobj.c's FindClassObject,
* js_ConstructObject, and js_NewObject). It's fundamental to the
* design of the language when you consider multiple global objects and
* separate compilation and execution, even though it is not specified
* fully in ECMA.
*/
obj = script->getRegExp(index);
if (OBJ_GET_PARENT(cx, obj) != obj2) {
obj = js_CloneRegExpObject(cx, obj, obj2);
if (!obj)
goto error;
}
rval = OBJECT_TO_JSVAL(obj);
/* Store the regexp object value in its cloneIndex slot. */
if (fp->fun) {
if (!JS_SetReservedSlot(cx, funobj, slot, rval))
goto error;
} else {
fp->slots[slot] = rval;
}
}
PUSH_OPND(rval);
}
END_CASE(JSOP_REGEXP)
BEGIN_CASE(JSOP_ZERO)

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

@ -951,11 +951,11 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal
#endif
/*
* Global variables (gvars) share the atom index space with locals. Due to
* Global variables and regexps share the index space with locals. Due to
* incremental code generation we need to patch the bytecode to adjust the
* local references to skip the globals.
*/
scriptGlobals = cg.ngvars;
scriptGlobals = cg.ngvars + cg.regexpList.length;
if (scriptGlobals != 0 || cg.hasSharps()) {
jsbytecode *code, *end;
JSOp op;

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

@ -1596,7 +1596,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
nfixed = (cg->flags & TCF_IN_FUNCTION)
? cg->fun->u.i.nvars
: cg->ngvars + cg->sharpSlots();
: cg->ngvars + cg->regexpList.length + cg->sharpSlots();
JS_ASSERT(nfixed < SLOTNO_LIMIT);
script->nfixed = (uint16) nfixed;
js_InitAtomMap(cx, &script->atomMap, &cg->atomList);

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

@ -1,27 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = '7.8.5-1.js';
var BUGNUMBER = 98409;
var summary = 'regular expression literal evaluates to new RegExp instance';
printBugNumber(BUGNUMBER);
printStatus(summary);
function flip(x) {
return /hi/g.test(x);
}
function flop(x) {
return r.test(x);
}
var r = /hi/g;
var s = "hi there";
var actual = [flip(s), flip(s), flip(s), flip(s), flop(s), flop(s), flop(s), flop(s)].join(',');
var expect = "true,true,true,true,true,false,true,false";
reportCompare(expect, actual, summary);
printStatus("All tests passed!");

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

@ -1,2 +0,0 @@
url-prefix ../../jsreftest.html?test=ecma_5/RegExp/
script 7.8.5-1.js