Make JSTreeContext::fun and JSTreeContext::scopeChain private (they share a union), and provide accessors that assert that the tree context is or is not in a function, as appropriate. r=dvander
authorJeff Walden <jwalden@mit.edu>
Tue, 16 Nov 2010 14:13:29 -0800
changeset 57829 c5b733682ecef38251b07cb6811f2ccbdcae522a
parent 57828 9baf4ce0920b157152e6f17323ea2fb08a01d498
child 57830 22273789b140291466a9d5076f954a49b498e2c8
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersdvander
milestone2.0b8pre
Make JSTreeContext::fun and JSTreeContext::scopeChain private (they share a union), and provide accessors that assert that the tree context is or is not in a function, as appropriate. r=dvander
js/src/jsemit.cpp
js/src/jsemit.h
js/src/jsfun.h
js/src/jsparse.cpp
js/src/jsscript.cpp
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1317,20 +1317,20 @@ JSTreeContext::ensureSharpSlots()
     JS_ASSERT(!(flags & TCF_HAS_SHARPS));
     if (inFunction()) {
         JSContext *cx = parser->context;
         JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6, 0);
         JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6, 0);
         if (!sharpArrayAtom || !sharpDepthAtom)
             return false;
 
-        sharpSlotBase = fun->u.i.nvars;
-        if (!fun->addLocal(cx, sharpArrayAtom, JSLOCAL_VAR))
+        sharpSlotBase = fun()->u.i.nvars;
+        if (!fun()->addLocal(cx, sharpArrayAtom, JSLOCAL_VAR))
             return false;
-        if (!fun->addLocal(cx, sharpDepthAtom, JSLOCAL_VAR))
+        if (!fun()->addLocal(cx, sharpDepthAtom, JSLOCAL_VAR))
             return false;
     } else {
         /*
          * Compiler::compileScript will rebase immediate operands indexing
          * the sharp slots to come at the end of the global script's |nfixed|
          * slots storage, after gvars and regexps.
          */
         sharpSlotBase = 0;
@@ -1701,21 +1701,21 @@ LookupCompileTimeConstant(JSContext *cx,
             /*
              * Try looking in the variable object for a direct property that
              * is readonly and permanent.  We know such a property can't be
              * shadowed by another property on obj's prototype chain, or a
              * with object or catch variable; nor can prop's value be changed,
              * nor can prop be deleted.
              */
             if (cg->inFunction()) {
-                if (cg->fun->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE)
+                if (cg->fun()->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE)
                     break;
             } else {
                 JS_ASSERT(cg->compileAndGo());
-                obj = cg->scopeChain;
+                obj = cg->scopeChain();
 
                 const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom));
                 if (shape) {
                     /*
                      * We're compiling code that will be executed immediately,
                      * not re-executed against a different scope chain and/or
                      * variable object.  Therefore we can get constant values
                      * from our variable object here.
@@ -1878,17 +1878,17 @@ JSCodeGenerator::shouldNoteClosedName(JS
  *
  * The function returns -1 on failures.
  */
 static jsint
 AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)
 {
     JS_ASSERT((jsuint) slot < cg->maxStackDepth);
     if (cg->inFunction()) {
-        slot += cg->fun->u.i.nvars;
+        slot += cg->fun()->u.i.nvars;
         if ((uintN) slot >= SLOTNO_LIMIT) {
             ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS);
             slot = -1;
         }
     }
     return slot;
 }
 
@@ -2006,17 +2006,17 @@ MakeUpvarForEval(JSParseNode *pn, JSCode
         return true;
 
     JS_ASSERT(cg->staticLevel > upvarLevel);
     if (cg->staticLevel >= UpvarCookie::UPVAR_LEVEL_LIMIT)
         return true;
 
     JSAtomListElement *ale = cg->upvarList.lookup(atom);
     if (!ale) {
-        if (cg->inFunction() && !cg->fun->addLocal(cx, atom, JSLOCAL_UPVAR))
+        if (cg->inFunction() && !cg->fun()->addLocal(cx, atom, JSLOCAL_UPVAR))
             return false;
 
         ale = cg->upvarList.add(cg->parser, atom);
         if (!ale)
             return false;
         JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
 
         UpvarCookie *vector = cg->upvarMap.vector;
@@ -2208,18 +2208,18 @@ BindNameToSlot(JSContext *cx, JSCodeGene
 
             /*
              * Make sure the variable object used by the compiler to initialize
              * parent links matches the caller's varobj. Compile-n-go compiler-
              * created function objects have the top-level cg's scopeChain set
              * as their parent by Parser::newFunction.
              */
             JSObject *scopeobj = cg->inFunction()
-                                 ? FUN_OBJECT(cg->fun)->getParent()
-                                 : cg->scopeChain;
+                                 ? FUN_OBJECT(cg->fun())->getParent()
+                                 : cg->scopeChain();
             if (scopeobj != cg->parser->callerVarObj)
                 return JS_TRUE;
 
             /*
              * We are compiling eval or debug script inside a function frame
              * and the scope chain matches the function's variable object.
              * Optimize access to function's arguments and variable and the
              * arguments object.
@@ -2318,17 +2318,18 @@ BindNameToSlot(JSContext *cx, JSCodeGene
 
         JSTreeContext *tc = cg;
         while (tc->staticLevel != level)
             tc = tc->parent;
         JS_ASSERT(tc->compiling());
 
         JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
         JS_ASSERT(evalcg->compileAndGo());
-        JS_ASSERT(caller->isFunctionFrame() && cg->parser->callerVarObj == evalcg->scopeChain);
+        JS_ASSERT(caller->isFunctionFrame());
+        JS_ASSERT(cg->parser->callerVarObj == evalcg->scopeChain());
 
         /*
          * Don't generate upvars on the left side of a for loop. See
          * bug 470758 and bug 520513.
          */
         if (evalcg->flags & TCF_IN_FOR_INIT)
             return JS_TRUE;
 
@@ -2342,30 +2343,30 @@ BindNameToSlot(JSContext *cx, JSCodeGene
         return MakeUpvarForEval(pn, cg);
     }
 
     const uintN skip = cg->staticLevel - level;
     if (skip != 0) {
         JS_ASSERT(cg->inFunction());
         JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom));
         JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
-        JS_ASSERT(cg->fun->u.i.skipmin <= skip);
+        JS_ASSERT(cg->fun()->u.i.skipmin <= skip);
 
         /*
          * If op is a mutating opcode, this upvar's lookup skips too many levels,
          * or the function is heavyweight, we fall back on JSOP_*NAME*.
          */
         if (op != JSOP_NAME)
             return JS_TRUE;
         if (level >= UpvarCookie::UPVAR_LEVEL_LIMIT)
             return JS_TRUE;
         if (cg->flags & TCF_FUN_HEAVYWEIGHT)
             return JS_TRUE;
 
-        if (FUN_FLAT_CLOSURE(cg->fun)) {
+        if (cg->fun()->isFlatClosure()) {
             op = JSOP_GETFCSLOT;
         } else {
             /*
              * The function we're compiling may not be heavyweight, but if it
              * escapes as a funarg, we can't use JSOP_GETUPVAR/JSOP_CALLUPVAR.
              * Parser::analyzeFunctions has arranged for this function's
              * enclosing functions to be heavyweight, so we can safely stick
              * with JSOP_NAME/JSOP_CALLNAME.
@@ -2383,17 +2384,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
 
             op = JSOP_GETUPVAR;
         }
 
         ale = cg->upvarList.lookup(atom);
         if (ale) {
             index = ALE_INDEX(ale);
         } else {
-            if (!cg->fun->addLocal(cx, atom, JSLOCAL_UPVAR))
+            if (!cg->fun()->addLocal(cx, atom, JSLOCAL_UPVAR))
                 return JS_FALSE;
 
             ale = cg->upvarList.add(cg->parser, atom);
             if (!ale)
                 return JS_FALSE;
             index = ALE_INDEX(ale);
             JS_ASSERT(index == cg->upvarList.count - 1);
 
@@ -2412,17 +2413,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
 
             uintN slot = cookie.slot();
             if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != JSDefinition::ARG) {
                 JSTreeContext *tc = cg;
                 do {
                     tc = tc->parent;
                 } while (tc->staticLevel != level);
                 if (tc->inFunction())
-                    slot += tc->fun->nargs;
+                    slot += tc->fun()->nargs;
             }
 
             vector[index].set(skip, slot);
         }
 
         pn->pn_op = op;
         JS_ASSERT((index & JS_BITMASK(16)) == index);
         pn->pn_cookie.set(0, index);
@@ -2464,21 +2465,21 @@ BindNameToSlot(JSContext *cx, JSCodeGene
           default: JS_NOT_REACHED("arg");
         }
         JS_ASSERT(!pn->isConst());
         break;
 
       case JSDefinition::VAR:
         if (PN_OP(dn) == JSOP_CALLEE) {
             JS_ASSERT(op != JSOP_CALLEE);
-            JS_ASSERT((cg->fun->flags & JSFUN_LAMBDA) && atom == cg->fun->atom);
+            JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
 
             /*
-             * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight, as we
-             * cannot be sure cg->fun is not something of the form:
+             * Leave pn->pn_op == JSOP_NAME if cg->fun() is heavyweight, as we
+             * cannot be sure cg->fun() is not something of the form:
              *
              *   var ff = (function f(s) { eval(s); return f; });
              *
              * where a caller invokes ff("var f = 42"). The result returned for
              * such an invocation must be 42, since the callee name is
              * lexically bound in an outer declarative environment from the
              * function's activation. See jsfun.cpp:call_resolve.
              */
@@ -3815,17 +3816,17 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
             return JS_FALSE;
         EMIT_INDEX_OP(prologOp, atomIndex);
         CG_SWITCH_TO_MAIN(cg);
     }
 
     if (cg->inFunction() &&
         JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
-        pn->pn_cookie.slot() < cg->fun->u.i.nvars &&
+        pn->pn_cookie.slot() < cg->fun()->u.i.nvars &&
         cg->shouldNoteClosedName(pn))
     {
         if (!cg->closedVars.append(pn->pn_cookie.slot()))
             return JS_FALSE;
     }
 
     if (result)
         *result = atomIndex;
@@ -4600,17 +4601,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         cg2->flags = pn->pn_funbox->tcflags | TCF_IN_FUNCTION;
 #if JS_HAS_SHARP_VARS
         if (cg2->flags & TCF_HAS_SHARPS) {
             cg2->sharpSlotBase = fun->sharpSlotBase(cx);
             if (cg2->sharpSlotBase < 0)
                 return JS_FALSE;
         }
 #endif
-        cg2->fun = fun;
+        cg2->setFunction(fun);
         cg2->funbox = pn->pn_funbox;
         cg2->parent = cg;
 
         /*
          * jsparse.cpp:SetStaticLevel limited static nesting depth to fit in 16
          * bits and to reserve the all-ones value, thereby reserving the magic
          * FREE_UPVAR_COOKIE value. Note the cg2->staticLevel assignment below.
          */
@@ -4670,17 +4671,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
             /* Emit NOP for the decompiler. */
             if (!EmitFunctionDefNop(cx, cg, index))
                 return JS_FALSE;
         } else {
 #ifdef DEBUG
             JSLocalKind localKind =
 #endif
-                cg->fun->lookupLocal(cx, fun->atom, &slot);
+                cg->fun()->lookupLocal(cx, fun->atom, &slot);
             JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
             JS_ASSERT(index < JS_BIT(20));
             pn->pn_index = index;
             op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
             if (pn->isClosed() &&
                 !cg->callsEval() &&
                 !cg->closedVars.append(pn->pn_cookie.slot())) {
                 return JS_FALSE;
@@ -6996,17 +6997,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
       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.
          */
         JS_ASSERT(pn->pn_op == JSOP_REGEXP);
-        bool singleton = !cg->fun && cg->compileAndGo();
+        bool singleton = !(cg->inFunction() ? cg->fun() : cg->scopeChain()) && cg->compileAndGo();
         if (singleton) {
             for (JSStmtInfo *stmt = cg->topStmt; stmt; stmt = stmt->down) {
                 if (STMT_IS_LOOP(stmt)) {
                     singleton = false;
                     break;
                 }
             }
         }
--- a/js/src/jsemit.h
+++ b/js/src/jsemit.h
@@ -285,22 +285,41 @@ struct JSTreeContext {              /* t
     JSObjectBox     *blockChainBox; /* compile time block scope chain (NB: one
                                        deeper than the topScopeStmt/downScope
                                        chain when in head of let block/expr) */
     JSParseNode     *blockNode;     /* parse node for a block with let declarations
                                        (block with its own lexical scope)  */
     JSAtomList      decls;          /* function, const, and var declarations */
     js::Parser      *parser;        /* ptr to common parsing and lexing data */
 
+  private:
     union {
-        JSFunction  *fun;           /* function to store argument and variable
+        JSFunction  *fun_;          /* function to store argument and variable
                                        names when flags & TCF_IN_FUNCTION */
-        JSObject    *scopeChain;    /* scope chain object for the script */
+        JSObject    *scopeChain_;   /* scope chain object for the script */
     };
 
+  public:
+    JSFunction *fun() const {
+        JS_ASSERT(inFunction());
+        return fun_;
+    }
+    void setFunction(JSFunction *fun) {
+        JS_ASSERT(inFunction());
+        fun_ = fun;
+    }
+    JSObject *scopeChain() const {
+        JS_ASSERT(!inFunction());
+        return scopeChain_;
+    }
+    void setScopeChain(JSObject *scopeChain) {
+        JS_ASSERT(!inFunction());
+        scopeChain_ = scopeChain;
+    }
+
     JSAtomList      lexdeps;        /* unresolved lexical name dependencies */
     JSTreeContext   *parent;        /* enclosing function or global context */
     uintN           staticLevel;    /* static compilation unit nesting level */
 
     JSFunctionBox   *funbox;        /* null or box for function we're compiling
                                        if (flags & TCF_IN_FUNCTION) and not in
                                        Compiler::compileFunctionBody */
     JSFunctionBox   *functionList;
@@ -310,17 +329,17 @@ struct JSTreeContext {              /* t
 #ifdef JS_SCOPE_DEPTH_METER
     uint16          scopeDepth;     /* current lexical scope chain depth */
     uint16          maxScopeDepth;  /* maximum lexical scope chain depth */
 #endif
 
     JSTreeContext(js::Parser *prs)
       : flags(0), bodyid(0), blockidGen(0),
         topStmt(NULL), topScopeStmt(NULL), blockChainBox(NULL), blockNode(NULL),
-        parser(prs), scopeChain(NULL), parent(prs->tc), staticLevel(0),
+        parser(prs), scopeChain_(NULL), parent(prs->tc), staticLevel(0),
         funbox(NULL), functionList(NULL), innermostWith(NULL), sharpSlotBase(-1)
     {
         prs->tc = this;
         JS_SCOPE_DEPTH_METERING(scopeDepth = maxScopeDepth = 0);
     }
 
     /*
      * For functions the tree context is constructed and destructed a second
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -171,16 +171,17 @@ struct JSFunction : public JSObject_Slot
     JSAtom          *atom;        /* name for diagnostics and decompiling */
 
     bool optimizedClosure()  const { return FUN_KIND(this) > JSFUN_INTERPRETED; }
     bool needsWrapper()      const { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; }
     bool isInterpreted()     const { return FUN_INTERPRETED(this); }
     bool isNative()          const { return !FUN_INTERPRETED(this); }
     bool isConstructor()     const { return flags & JSFUN_CONSTRUCTOR; }
     bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
+    bool isFlatClosure()     const { return FUN_KIND(this) == JSFUN_FLAT_CLOSURE; }
 
     bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
 
     inline bool inStrictMode() const;
 
     bool acceptsPrimitiveThis() const { return flags & JSFUN_PRIMITIVE_THIS; }
 
     uintN countVars() const {
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -696,17 +696,17 @@ Parser::parse(JSObject *chain)
      * Protect atoms from being collected by a GC activation, which might
      * - nest on this thread due to out of memory (the so-called "last ditch"
      *   GC attempted within js_NewGCThing), or
      * - run for any reason on another thread if this thread is suspended on
      *   an object lock before it finishes generating bytecode into a script
      *   protected from the GC by a root or a stack frame reference.
      */
     JSTreeContext globaltc(this);
-    globaltc.scopeChain = chain;
+    globaltc.setScopeChain(chain);
     if (!GenerateBlockId(&globaltc, globaltc.bodyid))
         return NULL;
 
     JSParseNode *pn = statements();
     if (pn) {
         if (!tokenStream.matchToken(TOK_EOF)) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             pn = NULL;
@@ -799,17 +799,17 @@ Compiler::compileScript(JSContext *cx, J
         JS_ASSERT((globalObj->getClass()->flags & JSCLASS_GLOBAL_FLAGS) == JSCLASS_GLOBAL_FLAGS);
     }
 
     /* Null script early in case of error, to reduce our code footprint. */
     script = NULL;
 
     globalScope.cg = &cg;
     cg.flags |= tcflags;
-    cg.scopeChain = scopeChain;
+    cg.setScopeChain(scopeChain);
     compiler.globalScope = &globalScope;
     if (!SetStaticLevel(&cg, staticLevel))
         goto out;
 
     /* If this is a direct call to eval, inherit the caller's strictness.  */
     if (callerFrame &&
         callerFrame->isScriptFrame() &&
         callerFrame->script()->strictModeCode) {
@@ -1228,20 +1228,18 @@ HasFinalReturn(JSParseNode *pn)
     }
 }
 
 static JSBool
 ReportBadReturn(JSContext *cx, JSTreeContext *tc, uintN flags, uintN errnum,
                 uintN anonerrnum)
 {
     JSAutoByteString name;
-
-    JS_ASSERT(tc->inFunction());
-    if (tc->fun->atom) {
-        if (!js_AtomToPrintableString(cx, tc->fun->atom, &name))
+    if (tc->fun()->atom) {
+        if (!js_AtomToPrintableString(cx, tc->fun()->atom, &name))
             return false;
     } else {
         errnum = anonerrnum;
     }
     return ReportCompileErrorNumber(cx, TS(tc->parser), NULL, flags, errnum, name.ptr());
 }
 
 static JSBool
@@ -1660,17 +1658,17 @@ Compiler::compileFunctionBody(JSContext 
     Parser &parser = compiler.parser;
     TokenStream &tokenStream = parser.tokenStream;
 
     JSCodeGenerator funcg(&parser, &codePool, &notePool, tokenStream.getLineno());
     if (!funcg.init())
         return NULL;
 
     funcg.flags |= TCF_IN_FUNCTION;
-    funcg.fun = fun;
+    funcg.setFunction(fun);
     if (!GenerateBlockId(&funcg, funcg.bodyid))
         return NULL;
 
     /* FIXME: make Function format the source for a function definition. */
     tokenStream.mungeCurrentToken(TOK_NAME);
     JSParseNode *fn = FunctionNode::create(&funcg);
     if (fn) {
         fn->pn_body = NULL;
@@ -1792,30 +1790,30 @@ BindDestructuringArg(JSContext *cx, Bind
     /* Flag tc so we don't have to lookup arguments on every use. */
     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
         tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
     if (atom == tc->parser->context->runtime->atomState.evalAtom)
         tc->flags |= TCF_FUN_PARAM_EVAL;
 
     JS_ASSERT(tc->inFunction());
 
-    JSLocalKind localKind = tc->fun->lookupLocal(cx, atom, NULL);
+    JSLocalKind localKind = tc->fun()->lookupLocal(cx, atom, NULL);
     if (localKind != JSLOCAL_NONE) {
         ReportCompileErrorNumber(cx, TS(tc->parser), NULL, JSREPORT_ERROR,
                                  JSMSG_DESTRUCT_DUP_ARG);
         return JS_FALSE;
     }
     JS_ASSERT(!tc->decls.lookup(atom));
 
     pn = data->pn;
     if (!Define(pn, atom, tc))
         return JS_FALSE;
 
-    uintN index = tc->fun->u.i.nvars;
-    if (!BindLocalVariable(cx, tc->fun, atom, JSLOCAL_VAR, true))
+    uintN index = tc->fun()->u.i.nvars;
+    if (!BindLocalVariable(cx, tc->fun(), atom, JSLOCAL_VAR, true))
         return JS_FALSE;
     pn->pn_op = JSOP_SETLOCAL;
     pn->pn_cookie.set(tc->staticLevel, index);
     pn->pn_dflags |= PND_BOUND;
     return JS_TRUE;
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
@@ -1830,21 +1828,19 @@ Parser::newFunction(JSTreeContext *tc, J
     /*
      * Find the global compilation context in order to pre-set the newborn
      * function's parent slot to tc->scopeChain. If the global context is a
      * compile-and-go one, we leave the pre-set parent intact; otherwise we
      * clear parent and proto.
      */
     while (tc->parent)
         tc = tc->parent;
-    parent = tc->inFunction() ? NULL : tc->scopeChain;
-
-    fun = js_NewFunction(context, NULL, NULL, 0, JSFUN_INTERPRETED | lambda,
-                         parent, atom);
-
+    parent = tc->inFunction() ? NULL : tc->scopeChain();
+
+    fun = js_NewFunction(context, NULL, NULL, 0, JSFUN_INTERPRETED | lambda, parent, atom);
     if (fun && !tc->compileAndGo()) {
         FUN_OBJECT(fun)->clearParent();
         FUN_OBJECT(fun)->clearProto();
     }
     return fun;
 }
 
 static JSBool
@@ -2524,17 +2520,17 @@ EnterFunction(JSParseNode *fn, JSTreeCon
     if (!funbox)
         return NULL;
 
     /* Initialize non-default members of funtc. */
     funtc->flags |= funbox->tcflags;
     funtc->blockidGen = tc->blockidGen;
     if (!GenerateBlockId(funtc, funtc->bodyid))
         return NULL;
-    funtc->fun = fun;
+    funtc->setFunction(fun);
     funtc->funbox = funbox;
     if (!SetStaticLevel(funtc, tc->staticLevel + 1))
         return NULL;
 
     return funbox;
 }
 
 static bool
@@ -2955,22 +2951,22 @@ Parser::functionDef(JSAtom *funAtom, Fun
 
                 /*
                  * Define a local in the outer function so that BindNameToSlot
                  * can properly optimize accesses. Note that we need a local
                  * variable, not an argument, for the function statement. Thus
                  * we add a variable even if a parameter with the given name
                  * already exists.
                  */
-                localKind = tc->fun->lookupLocal(context, funAtom, &index);
+                localKind = tc->fun()->lookupLocal(context, funAtom, &index);
                 switch (localKind) {
                   case JSLOCAL_NONE:
                   case JSLOCAL_ARG:
-                    index = tc->fun->u.i.nvars;
-                    if (!tc->fun->addLocal(context, funAtom, JSLOCAL_VAR))
+                    index = tc->fun()->u.i.nvars;
+                    if (!tc->fun()->addLocal(context, funAtom, JSLOCAL_VAR))
                         return NULL;
                     /* FALL THROUGH */
 
                   case JSLOCAL_VAR:
                     pn->pn_cookie.set(tc->staticLevel, index);
                     pn->pn_dflags |= PND_BOUND;
                     break;
 
@@ -3750,30 +3746,30 @@ BindVarOrConst(JSContext *cx, BindData *
         return BindGvar(pn, tc);
 
     if (atom == cx->runtime->atomState.argumentsAtom) {
         pn->pn_op = JSOP_ARGUMENTS;
         pn->pn_dflags |= PND_BOUND;
         return JS_TRUE;
     }
 
-    JSLocalKind localKind = tc->fun->lookupLocal(cx, atom, NULL);
+    JSLocalKind localKind = tc->fun()->lookupLocal(cx, atom, NULL);
     if (localKind == JSLOCAL_NONE) {
         /*
          * Property not found in current variable scope: we have not seen this
          * variable before. Define a new local variable by adding a property to
          * the function's scope and allocating one slot in the function's vars
          * frame. Any locals declared in a with statement body are handled at
          * runtime, by script prolog JSOP_DEFVAR opcodes generated for global
          * and heavyweight-function-local vars.
          */
         localKind = (data->op == JSOP_DEFCONST) ? JSLOCAL_CONST : JSLOCAL_VAR;
 
-        uintN index = tc->fun->u.i.nvars;
-        if (!BindLocalVariable(cx, tc->fun, atom, localKind, false))
+        uintN index = tc->fun()->u.i.nvars;
+        if (!BindLocalVariable(cx, tc->fun(), atom, localKind, false))
             return JS_FALSE;
         pn->pn_op = JSOP_GETLOCAL;
         pn->pn_cookie.set(tc->staticLevel, index);
         pn->pn_dflags |= PND_BOUND;
         return JS_TRUE;
     }
 
     if (localKind == JSLOCAL_ARG) {
@@ -8068,17 +8064,17 @@ JSParseNode *
 Parser::parseXMLText(JSObject *chain, bool allowList)
 {
     /*
      * Push a compiler frame if we have no frames, or if the top frame is a
      * lightweight function activation, or if its scope chain doesn't match
      * the one passed to us.
      */
     JSTreeContext xmltc(this);
-    xmltc.scopeChain = chain;
+    xmltc.setScopeChain(chain);
 
     /* Set XML-only mode to turn off special treatment of {expr} in XML. */
     tokenStream.setXMLOnlyMode();
     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
 
     JSParseNode *pn;
     if (tt != TOK_XMLSTAGO) {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1114,18 +1114,18 @@ JSScript::NewScriptFromCG(JSContext *cx,
         {
             /*
              * We can probably use the immutable empty script singleton, just
              * two hard cases (nupvars != 0, strict mode code) may stand in our
              * way.
              */
             JSScript *empty = JSScript::emptyScript();
 
-            if (cg->flags & TCF_IN_FUNCTION) {
-                fun = cg->fun;
+            if (cg->inFunction()) {
+                fun = cg->fun();
                 JS_ASSERT(fun->isInterpreted() && !FUN_SCRIPT(fun));
                 if (cg->flags & TCF_STRICT_MODE_CODE) {
                     /*
                      * We can't use a script singleton for empty strict mode
                      * functions because they have poison-pill caller and
                      * arguments properties:
                      *
                      * function strict() { "use strict"; }
@@ -1168,18 +1168,18 @@ JSScript::NewScriptFromCG(JSContext *cx,
                        cg->closedVars.length());
     if (!script)
         return NULL;
 
     /* Now that we have script, error control flow must go to label bad. */
     script->main += prologLength;
     memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
     memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
-    nfixed = (cg->flags & TCF_IN_FUNCTION)
-             ? cg->fun->u.i.nvars
+    nfixed = cg->inFunction()
+             ? cg->fun()->u.i.nvars
              : cg->sharpSlots();
     JS_ASSERT(nfixed < SLOTNO_LIMIT);
     script->nfixed = (uint16) nfixed;
     js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
 
     filename = cg->parser->tokenStream.getFilename();
     if (filename) {
         script->filename = js_SaveScriptFilename(cx, filename);
@@ -1241,18 +1241,18 @@ JSScript::NewScriptFromCG(JSContext *cx,
                script->nClosedVars * sizeof(uint32));
     }
 
     /*
      * We initialize fun->u.script to be the script constructed above
      * so that the debugger has a valid FUN_SCRIPT(fun).
      */
     fun = NULL;
-    if (cg->flags & TCF_IN_FUNCTION) {
-        fun = cg->fun;
+    if (cg->inFunction()) {
+        fun = cg->fun();
         JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
         if (script->upvarsOffset != 0)
             JS_ASSERT(script->upvars()->length == fun->u.i.nupvars);
         else
             fun->u.i.nupvars = 0;
 
         fun->freezeLocalNames(cx);
         fun->u.i.script = script;