- Shaver hacked this fix with advice from me, and I carried it to check-in. We now avoid a heavyweight outer function when the inner one is defined at top-level or in an expression (is not a JSOP_CLOSURE, IOW), and it doesn't refer to any non-local names. See bug 65308 for details on the win. (r=rogerl, sr=brendan)

- Fix scope chain for nested functions at top-level (JSOP_DEFFUN), in a part of another statement (JSOP_CLOSURE), and unnamed in an expression (JSOP_ANONFUNOBJ) to match ECMA-262 13.2.  My bad: fp->varobj was used up till now, instead of fp->scopeChain; we still *bind* the name of a statement-level (top or not) nested function in fp->varobj.  This fixes bug 69559.  (r=rogerl, sr=jband)
- Add an Intern command to the shell, for GC vs. intern'ed atom testing.


git-svn-id: svn://10.0.0.236/trunk@87871 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
brendan%mozilla.org 2001-02-24 03:00:56 +00:00
parent ce4e310532
commit 713ac17d77
9 changed files with 239 additions and 74 deletions

View File

@ -991,6 +991,24 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
if (!script)
continue;
if (JSVAL_IS_FUNCTION(cx, argv[i])) {
JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
if (fun && (fun->flags & JSFUN_FLAGS_MASK)) {
uint8 flags = fun->flags;
fputs("flags:", stderr);
#define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
SHOW_FLAG(SETTER);
SHOW_FLAG(GETTER);
SHOW_FLAG(BOUND_METHOD);
SHOW_FLAG(HEAVYWEIGHT);
#undef SHOW_FLAG
putchar('\n');
}
}
js_Disassemble(cx, script, lines, stdout);
SrcNotes(cx, script);
TryNotes(cx, script);
@ -999,7 +1017,8 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
static JSBool
DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
#define LINE_BUF_LEN 512
uintN i, len, line1, line2, bupline;
@ -1386,6 +1405,21 @@ Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_TRUE;
}
static JSBool
Intern(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSString *str;
str = JS_ValueToString(cx, argv[0]);
if (!str)
return JS_FALSE;
if (!JS_InternUCStringN(cx, JS_GetStringChars(str),
JS_GetStringLength(str))) {
return JS_FALSE;
}
return JS_TRUE;
}
static JSFunctionSpec shell_functions[] = {
{"version", Version, 0},
{"options", Options, 0},
@ -1413,6 +1447,7 @@ static JSFunctionSpec shell_functions[] = {
#endif
{"build", BuildDate, 0},
{"clear", Clear, 0},
{"intern", Intern, 1},
{0}
};

View File

@ -499,10 +499,11 @@ LookupArgOrVar(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
return JS_TRUE;
/*
* We can't optimize if var and function collide.
* We can't optimize if var and closure (a local function not in a larger
* expression and not at top-level within another's body) collide.
* XXX suboptimal: keep track of colliding names and deoptimize only those
*/
if (tc->flags & TCF_FUN_VS_VAR)
if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)
return JS_TRUE;
/*
@ -587,6 +588,11 @@ LookupArgOrVar(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
}
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
}
if (pn->pn_slot < 0) {
/* We couldn't optimize it, so it's not an arg or local var name. */
tc->flags |= TCF_FUN_USES_NONLOCALS;
}
return JS_TRUE;
}
@ -912,11 +918,15 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
cg->principals)) {
return JS_FALSE;
}
cg2.treeContext.flags = pn->pn_flags;
cg2.treeContext.flags = pn->pn_flags | TCF_IN_FUNCTION;
cg2.treeContext.tryCount = pn->pn_tryCount;
fun = pn->pn_fun;
if (!js_EmitFunctionBody(cx, &cg2, pn2, fun))
return JS_FALSE;
/* We need an activation object if an inner peeks out. */
if (cg2.treeContext.flags & TCF_FUN_USES_NONLOCALS)
cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;
js_FinishCodeGenerator(cx, &cg2);
/* Make the function object a literal in the outer script's pool. */
@ -943,10 +953,40 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
return JS_FALSE;
}
/* Top-levels also need a prolog op to predefine their names. */
/*
* Top-levels also need a prolog op to predefine their names in the
* variable object, or if local, to fill their stack slots.
*/
CG_SWITCH_TO_PROLOG(cg);
EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex);
#if JS_HAS_LEXICAL_CLOSURE
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
JSObject *obj, *pobj;
JSScopeProperty *sprop;
uintN slot;
jsbytecode *pc;
obj = OBJ_GET_PARENT(cx, pn->pn_fun->object);
if (!js_LookupProperty(cx, obj, (jsid)fun->atom, &pobj,
(JSProperty **)&sprop)) {
return JS_FALSE;
}
JS_ASSERT(sprop && pobj == obj);
slot = (uintN) JSVAL_TO_INT(sprop->id);
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
/* Emit [JSOP_DEFLOCALFUN, local variable slot, atomIndex]. */
off = js_EmitN(cx, cg, JSOP_DEFLOCALFUN, VARNO_LEN+ATOM_INDEX_LEN);
if (off < 0)
return JS_FALSE;
pc = CG_CODE(cg, off);
SET_VARNO(pc, slot);
pc += VARNO_LEN;
SET_ATOM_INDEX(pc, atomIndex);
} else
#endif
EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex);
CG_SWITCH_TO_MAIN(cg);
break;
}

View File

@ -91,14 +91,15 @@ struct JSTreeContext { /* tree context for semantic checks */
JSParseNode *nodeList; /* list of recyclable parse-node structs */
};
#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
#define TCF_FUN_VS_VAR 0x20 /* function and var with same name */
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */
#define TCF_FUN_FLAGS 0x60 /* flags to propagate from FunctionBody */
#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
#define TCF_FUN_CLOSURE_VS_VAR 0x20 /* function and var with same name */
#define TCF_FUN_USES_NONLOCALS 0x40 /* function refers to non-local names */
#define TCF_FUN_HEAVYWEIGHT 0x80 /* function needs Call object per call */
#define TCF_FUN_FLAGS 0xE0 /* flags to propagate from FunctionBody */
#define TREE_CONTEXT_INIT(tc) \
((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL, \

View File

@ -170,8 +170,6 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
* elements of argsobj.
*/
argsobj = fp->argsobj;
if (!argsobj)
return JS_TRUE;
ok = args_enumerate(cx, argsobj);
/*
@ -380,10 +378,12 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
/*
* Get the arguments object to snapshot fp's actual argument values.
*/
argsid = (jsid) cx->runtime->atomState.argumentsAtom;
ok &= js_GetProperty(cx, callobj, argsid, &aval);
ok &= js_SetProperty(cx, callobj, argsid, &aval);
ok &= js_PutArgsObject(cx, fp);
if (fp->argsobj) {
argsid = (jsid) cx->runtime->atomState.argumentsAtom;
ok &= js_GetProperty(cx, callobj, argsid, &aval);
ok &= js_SetProperty(cx, callobj, argsid, &aval);
ok &= js_PutArgsObject(cx, fp);
}
/*
* Clear the private pointer to fp, which is about to go away (js_Invoke).

View File

@ -3109,7 +3109,14 @@ js_Interpret(JSContext *cx, jsval *result)
/*
* We must be at top-level (default "box", either function body or
* global) scope, not inside a with or other compound statement.
* global) scope, not inside a with or other compound statement in
* the same compilation unit (ECMA Program).
*
* However, we could be in a Program being eval'd from inside a
* with statement, so we need to distinguish variables object from
* scope chain head. Hence the two assignments to parent below.
* First we make sure the function object we're defining has the
* right scope chain. Then we define its name in fp->varobj.
*
* If static link is not current scope, clone fun's object to link
* to the current scope via parent. This clause exists to enable
@ -3129,7 +3136,7 @@ js_Interpret(JSContext *cx, jsval *result)
* promote compile-cost sharing and amortizing, and because Script
* is not and will not be standardized.
*/
parent = fp->varobj;
parent = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != parent) {
obj = js_CloneFunctionObject(cx, obj, parent);
if (!obj) {
@ -3148,6 +3155,7 @@ js_Interpret(JSContext *cx, jsval *result)
* here at runtime as well as at compile-time, to handle eval
* as well as multiple HTML script tags.
*/
parent = fp->varobj;
ok = js_CheckRedeclaration(cx, parent, id, attrs, &cond);
if (!ok)
goto out;
@ -3168,13 +3176,39 @@ js_Interpret(JSContext *cx, jsval *result)
}
#if JS_HAS_LEXICAL_CLOSURE
case JSOP_DEFLOCALFUN:
/*
* Define a local function (i.e., one nested at the top level of
* another function), parented by the current scope chain, and
* stored in a local variable slot that the compiler allocated.
* This is an optimization over JSOP_DEFFUN that avoids requiring
* a call object for the outer function's activation.
*/
pc2 = pc;
slot = GET_VARNO(pc2);
pc2 += VARNO_LEN;
atom = GET_ATOM(cx, script, pc2);
obj = ATOM_TO_OBJECT(atom);
fun = (JSFunction *) JS_GetPrivate(cx, obj);
parent = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != parent) {
obj = js_CloneFunctionObject(cx, obj, parent);
if (!obj) {
ok = JS_FALSE;
goto out;
}
}
fp->vars[slot] = OBJECT_TO_JSVAL(obj);
break;
case JSOP_ANONFUNOBJ:
/* Push the specified function object literal. */
atom = GET_ATOM(cx, script, pc);
obj = ATOM_TO_OBJECT(atom);
/* If re-parenting, push a clone of the function object. */
parent = fp->varobj;
parent = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != parent) {
obj = js_CloneFunctionObject(cx, obj, parent);
if (!obj) {
@ -3253,41 +3287,15 @@ js_Interpret(JSContext *cx, jsval *result)
case JSOP_CLOSURE:
/*
* ECMA ed. 3 extension: a named function expression in a compound
* statement (not at top-level or "box" scope, either global code
* or in a function body).
* statement (not at the top statement level of global code, or at
* the top level of a function body).
*
* Name the closure in the object at the head of the scope chain,
* referenced by parent. Even if it's a With object? Not for the
* current version (1.5), which uses the object named by the with
* statement's head.
*/
parent = fp->varobj;
if (fp->scopeChain != parent) {
parent = fp->scopeChain;
JS_ASSERT(OBJ_GET_CLASS(cx, parent) == &js_WithClass);
#if JS_BUG_WITH_CLOSURE
/*
* If in a with statement, set parent to the With object's
* prototype, i.e., the object specified in the head of
* the with statement.
*/
while (OBJ_GET_CLASS(cx, parent) == &js_WithClass) {
proto = OBJ_GET_PROTO(cx, parent);
if (!proto)
break;
parent = proto;
}
#endif
}
/*
* Get immediate operand atom, which is a function object literal.
* From it, get the function to close.
*/
atom = GET_ATOM(cx, script, pc);
JS_ASSERT(JSVAL_IS_FUNCTION(cx, ATOM_KEY(atom)));
obj = ATOM_TO_OBJECT(atom);
fun = (JSFunction *) JS_GetPrivate(cx, obj);
/*
* Clone the function object with the current scope chain as the
@ -3296,6 +3304,7 @@ js_Interpret(JSContext *cx, jsval *result)
* have seen the right parent already and created a sufficiently
* well-scoped function object.
*/
parent = fp->scopeChain;
if (OBJ_GET_PARENT(cx, obj) != parent) {
obj = js_CloneFunctionObject(cx, obj, parent);
if (!obj) {
@ -3305,12 +3314,13 @@ js_Interpret(JSContext *cx, jsval *result)
}
/*
* Define a property in parent with id fun->atom and value obj,
* unless fun is a getter or setter (in which case, obj is cast
* to a JSPropertyOp and passed accordingly).
* Make a property in fp->varobj with id fun->atom and value obj,
* unless fun is a getter or setter (in which case, obj is cast to
* a JSPropertyOp and passed accordingly).
*/
fun = (JSFunction *) JS_GetPrivate(cx, obj);
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
ok = OBJ_DEFINE_PROPERTY(cx, fp->varobj, (jsid)fun->atom,
attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
(attrs & JSFUN_GETTER)
? (JSPropertyOp) obj

View File

@ -208,7 +208,6 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
{
jsbytecode *pc2 = pc;
jsint npairs;
jsval key;
off = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
@ -221,8 +220,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
off = GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
key = ATOM_KEY(atom);
str = js_ValueToSource(cx, key);
str = js_ValueToSource(cx, ATOM_KEY(atom));
if (!str)
return 0;
cstr = js_DeflateString(cx, str->chars, str->length);
@ -245,6 +243,22 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
fprintf(fp, " %u", GET_VARNO(pc));
break;
#if JS_HAS_LEXICAL_CLOSURE
case JOF_DEFLOCALVAR:
fprintf(fp, " %u", GET_VARNO(pc));
pc += VARNO_LEN;
atom = GET_ATOM(cx, script, pc);
str = js_ValueToSource(cx, ATOM_KEY(atom));
if (!str)
return 0;
cstr = js_DeflateString(cx, str->chars, str->length);
if (!cstr)
return 0;
fprintf(fp, " %s", cstr);
JS_free(cx, cstr);
break;
#endif
default: {
char numBuf[12];
JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format);

View File

@ -65,6 +65,7 @@ typedef enum JSOp {
#define JOF_LOOKUPSWITCH 5 /* lookup switch */
#define JOF_QARG 6 /* quickened get/set function argument ops */
#define JOF_QVAR 7 /* quickened get/set local variable ops */
#define JOF_DEFLOCALVAR 8 /* define local var with initial value */
#define JOF_TYPEMASK 0x000f /* mask for above immediate types */
#define JOF_NAME 0x0010 /* name operation */
#define JOF_PROP 0x0020 /* obj.prop operation */
@ -109,8 +110,10 @@ typedef enum JSOp {
/* Synonyms for quick JOF_QARG and JOF_QVAR bytecodes. */
#define GET_ARGNO(pc) GET_ARGC(pc)
#define SET_ARGNO(pc,argno) SET_JUMP_OFFSET(pc,argno)
#define ARGNO_LEN JUMP_OFFSET_LEN
#define GET_VARNO(pc) GET_ARGC(pc)
#define SET_VARNO(pc,varno) SET_JUMP_OFFSET(pc,varno)
#define VARNO_LEN JUMP_OFFSET_LEN
struct JSCodeSpec {
const char *name; /* JS bytecode name */

View File

@ -204,7 +204,7 @@ OPDEF(JSOP_FORPROP, 105,"forprop", NULL, 3, 1, 1, 0, JOF_CONST|
OPDEF(JSOP_FORELEM, 106,"forelem", NULL, 1, 2, 4, 0, JOF_BYTE |JOF_ELEM)
OPDEF(JSOP_POP2, 107,"pop2", NULL, 1, 2, 0, 0, JOF_BYTE)
/* ECMA-complaint assignment ops. */
/* ECMA-compliant assignment ops. */
OPDEF(JSOP_BINDNAME, 108,"bindname", NULL, 3, 0, 1, 0, JOF_CONST|JOF_NAME)
OPDEF(JSOP_SETNAME, 109,"setname", NULL, 3, 2, 1, 1, JOF_CONST|JOF_NAME|JOF_SET)
@ -297,3 +297,10 @@ OPDEF(JSOP_SWAP, 135,"swap", NULL, 1, 2, 2, 0, JOF_BYTE)
*/
OPDEF(JSOP_ARGSUB, 136,"argsub", NULL, 3, 0, 1, 12, JOF_QARG |JOF_NAME)
OPDEF(JSOP_ARGCNT, 137,"argcnt", NULL, 1, 0, 1, 12, JOF_BYTE)
/*
* Define a local function object as a local variable.
* The local variable's slot number is the first immediate two-byte operand.
* The function object's atom index is the second immediate operand.
*/
OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL, 5, 0, 0, 0, JOF_DEFLOCALVAR)

View File

@ -719,16 +719,30 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
#if JS_HAS_LEXICAL_CLOSURE
/*
* If we collected flags that indicate nested functions or with statements
* while compiling our body, flag the function as heavyweight (requiring
* a call object per invocation). Therefore, update tc->flags to reflect
* the fact that the outer context contains this function, and may also be
* heavy if it is a function body.
* If we collected flags that indicate nested heavyweight functions, or
* this function contains heavyweight-making statements (references to
* __parent__ or __proto__; use of with, eval, import, or export; and
* assignment to arguments), flag the function as heavyweight (requiring
* a call object per invocation).
*/
if (funtc.flags & TCF_FUN_HEAVYWEIGHT)
if (funtc.flags & TCF_FUN_HEAVYWEIGHT) {
fun->flags |= JSFUN_HEAVYWEIGHT;
tc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->flags |= TCF_FUN_HEAVYWEIGHT;
} else {
/*
* If this function is a named statement function not at top-level
* (i.e. a JSOP_CLOSURE), or if it refers to unqualified names that
* are not local args or vars (TCF_FUN_USES_NONLOCALS), then our
* enclosing function, if any, must be heavyweight.
*/
if ((!lambda && funAtom && tc->topStmt) ||
(funtc.flags & TCF_FUN_USES_NONLOCALS)) {
tc->flags |= TCF_FUN_HEAVYWEIGHT;
}
}
#endif
/*
* Record names for function statements in tc->decls so we know when to
@ -744,7 +758,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
? JSREPORT_WARNING|JSREPORT_STRICT
: JSREPORT_ERROR,
JSMSG_REDECLARED_VAR,
(prevop == JSOP_DEFFUN)
(prevop == JSOP_DEFFUN ||
prevop == JSOP_CLOSURE)
? js_function_str
: (prevop == JSOP_DEFCONST)
? js_const_str
@ -752,18 +767,57 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
ATOM_BYTES(funAtom))) {
return NULL;
}
if (prevop == JSOP_DEFVAR)
tc->flags |= TCF_FUN_VS_VAR;
if (tc->topStmt && prevop == JSOP_DEFVAR)
tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
} else {
ale = js_IndexAtom(cx, funAtom, &tc->decls);
if (!ale)
return NULL;
}
ALE_SET_JSOP(ale, JSOP_DEFFUN);
ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);
#if JS_HAS_LEXICAL_CLOSURE
/*
* A function nested at top level inside another's body needs only a
* local variable to bind its name to its value, and not an activation
* object property (it might also need the activation property, if the
* outer function contains with statements, e.g., but the stack slot
* wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a
* JSOP_GETVAR bytecode).
*/
if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) {
JSStackFrame *fp;
JSObject *varobj;
/*
* Define a property on the outer function so that LookupArgOrVar
* can properly optimize accesses.
*
* XXX Here and in Variables, we use the function object's scope,
* XXX arguably polluting it, when we could use a compiler-private
* XXX scope structure. Tradition!
*/
fp = cx->fp;
varobj = fp->varobj;
JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));
if (!js_DefineProperty(cx, varobj, (jsid)funAtom,
OBJECT_TO_JSVAL(fun->object),
js_GetLocalVariable, js_SetLocalVariable,
JSPROP_ENUMERATE,
(JSProperty **)&sprop)) {
return NULL;
}
/* Allocate a slot for this property. */
sprop->id = INT_TO_JSVAL(fp->fun->nvars++);
OBJ_DROP_PROPERTY(cx, varobj, (JSProperty *)sprop);
}
#endif
}
#if JS_HAS_LEXICAL_CLOSURE
if (lambda || !fun->atom) {
if (lambda || !funAtom) {
/*
* ECMA ed. 3 standard: function expression, possibly anonymous (even
* if at top-level, an unnamed function is an expression statement, not
@ -1871,7 +1925,8 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
? JSREPORT_WARNING|JSREPORT_STRICT
: JSREPORT_ERROR,
JSMSG_REDECLARED_VAR,
(prevop == JSOP_DEFFUN)
(prevop == JSOP_DEFFUN ||
prevop == JSOP_CLOSURE)
? js_function_str
: (prevop == JSOP_DEFCONST)
? js_const_str
@ -1879,8 +1934,8 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
ATOM_BYTES(atom))) {
return NULL;
}
if (pn->pn_op == JSOP_DEFVAR && prevop == JSOP_DEFFUN)
tc->flags |= TCF_FUN_VS_VAR;
if (pn->pn_op == JSOP_DEFVAR && prevop == JSOP_CLOSURE)
tc->flags |= TCF_FUN_CLOSURE_VS_VAR;
} else {
ale = js_IndexAtom(cx, atom, &tc->decls);
if (!ale)