[INFER] Reduce inference-related script overhead, bug 674609.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 28 Jul 2011 09:16:53 -0700
changeset 76080 65c33bba9d01dc819ff0c68d8a0c057aaeb42598
parent 76079 235a8bfe2665082640941e8247c119c8cde3fed6
child 76081 d37f88fa371317e0c890e508225e62091ae7f021
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
bugs674609
milestone8.0a1
[INFER] Reduce inference-related script overhead, bug 674609.
js/src/imacro_asm.py
js/src/jit-test/tests/basic/bug657975.js
js/src/jit-test/tests/basic/testTrapOnEval.js
js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js
js/src/jit-test/tests/jaeger/bug563000/eif-trap.js
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
js/src/jit-test/tests/jaeger/bug563000/trap-parent.js
js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js
js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js
js/src/jit-test/tests/jaeger/bug563000/trap-self.js
js/src/jit-test/tests/jaeger/bug563000/untrap-self.js
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jscompartment.cpp
js/src/jsemit.cpp
js/src/jsemit.h
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsobj.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState-inl.h
js/src/methodjit/FrameState.cpp
js/src/methodjit/FrameState.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/LoopState.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
--- a/js/src/imacro_asm.py
+++ b/js/src/imacro_asm.py
@@ -351,18 +351,16 @@ def assemble(filename, outfile):
 
                     for imacro in igroup.imacros:
                         depth = 0
                         write("    {\n")
                         for op in imacro.code:
                             operand = ""
                             if op.imm1 is not None:
                                 operand = ", " + immediate(op)
-                            if 'JOF_TYPESET' in op.info.flags:
-                                operand = operand + ", 0, 0"
                             write("/*%2d*/  %s%s,\n" % (op.offset, op.info.jsop, operand))
 
                         imacro.maxdepth = imacro.initdepth
                         simulate_cfg(igroup, imacro, imacro.initdepth, 0)
                         if imacro.maxdepth > maxdepth:
                             maxdepth = imacro.maxdepth
 
                         write("    },\n")
--- a/js/src/jit-test/tests/basic/bug657975.js
+++ b/js/src/jit-test/tests/basic/bug657975.js
@@ -37,17 +37,17 @@ function f6() {
 }
 trap(f6, 10, '')
 f6()
 
 // bug 658491
 function f7() {
   try { y = w; } catch(y) {}
 }
-trap(f7, 16, '')
+trap(f7, 14, '')
 f7()
 
 // bug 658950
 f8 = (function() {
   let x;
   yield
 })
 trap(f8, 6, undefined);
--- a/js/src/jit-test/tests/basic/testTrapOnEval.js
+++ b/js/src/jit-test/tests/basic/testTrapOnEval.js
@@ -1,4 +1,4 @@
 // |jit-test| debug
 function f() { eval(''); }
-trap(f, 8, '');
+trap(f, 6, '');
 f();
--- a/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js
@@ -1,10 +1,10 @@
 // |jit-test| mjitalways;debug
 setDebug(true);
 
 function nop(){}
 function caller(code, obj) {
   eval(code); // Make the compiler give up on binding analysis.
   return x;
 }
-trap(caller, 16, "var x = 'success'; nop()");
+trap(caller, 14, "var x = 'success'; nop()");
 assertEq(caller("var y = 'ignominy'", this), "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/eif-trap.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/eif-trap.js
@@ -2,10 +2,10 @@
 setDebug(true);
 
 function nop(){}
 function caller(obj) {
   assertJit();
   var x = "failure";
   return x;
 }
-trap(caller, 18, "x = 'success'; nop()");
+trap(caller, 14, "x = 'success'; nop()");
 assertEq(caller(this), "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
@@ -1,13 +1,13 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in a. */
-  a = { valueOf: function () { trap(main, 38, "success()"); } };
+  a = { valueOf: function () { trap(main, 36, "success()"); } };
   a + "";
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
 assertEq(x, "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in a. */
-  a = { valueOf: function () { trap(main, 65, "success()"); } };
+  a = { valueOf: function () { trap(main, 58, "success()"); } };
   b = "";
   eval();
   a + b;
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-parent.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-parent.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function child() {
   /* JSOP_STOP in parent. */
-  trap(parent, 21, "success()");
+  trap(parent, 17, "success()");
 }
 function parent() {
   child();
   x = "failure";
 }
 function success() {
   x = "success";
 }
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js
@@ -1,16 +1,16 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 
 function myparent(nested) {
   if (nested) {
     /* noop call in myparent */
-    trap(myparent, 58, "success()");
+    trap(myparent, 50, "success()");
   } else {
     myparent(true);
     x = "failure";
     noop();
   }
 }
 function noop() { }
 function success() { x = "success"; }
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js
@@ -2,23 +2,23 @@
 setDebug(true);
 x = "notset";
 
 function doNothing() { }
 
 function myparent(nested) {
   if (nested) {
     /* JSOP_CALL to doNothing in myparent with nested = true. */
-    trap(myparent, 32, "success()");
+    trap(myparent, 24, "success()");
     doNothing();
   } else {
     doNothing();
   }
 }
 /* JSOP_CALL to doNothing in myparent with nested = false. */
-trap(myparent, 47, "myparent(true)");
+trap(myparent, 35, "myparent(true)");
 
 function success() {
   x = "success";
 }
 
 myparent(false);
 assertEq(x, "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-self.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-self.js
@@ -1,12 +1,12 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in a. */
-  trap(main, 31, "success()");
+  trap(main, 25, "success()");
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
 assertEq(x, "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/untrap-self.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/untrap-self.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* JSOP_STOP in main. */
-  untrap(main, 28);
+  untrap(main, 22);
   x = "success";
 }
 function failure() { x = "failure"; }
 
 /* JSOP_STOP in main. */
-trap(main, 28, "failure()");
+trap(main, 22, "failure()");
 main();
 assertEq(x, "success");
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -40,23 +40,16 @@
 #include "jsanalyze.h"
 #include "jsautooplen.h"
 #include "jscompartment.h"
 #include "jscntxt.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
-void
-JSScript::makeAnalysis(JSContext *cx)
-{
-    JS_ASSERT(!analysis_);
-    analysis_ = js::ArenaNew<js::analyze::ScriptAnalysis>(cx->compartment->pool, this);
-}
-
 namespace js {
 namespace analyze {
 
 /////////////////////////////////////////////////////////////////////
 // Bytecode
 /////////////////////////////////////////////////////////////////////
 
 bool
@@ -283,17 +276,17 @@ BytecodeNoFallThrough(JSOp op)
 void
 ScriptAnalysis::analyzeBytecode(JSContext *cx)
 {
     JS_ASSERT(cx->compartment->activeAnalysis);
     JS_ASSERT(!ranBytecode());
     JSArenaPool &pool = cx->compartment->pool;
 
     unsigned length = script->length;
-    unsigned nargs = script->fun ? script->fun->nargs : 0;
+    unsigned nargs = script->hasFunction ? script->function()->nargs : 0;
 
     numSlots = TotalSlots(script);
 
     codeArray = ArenaArray<Bytecode*>(pool, length);
     definedLocals = ArenaArray<uint32>(pool, script->nfixed);
     escapedSlots = ArenaArray<JSPackedBool>(pool, numSlots);
 
     if (!codeArray || !definedLocals || !escapedSlots) {
@@ -348,23 +341,23 @@ ScriptAnalysis::analyzeBytecode(JSContex
      * If the script is in debug mode, JS_SetFrameReturnValue can be called at
      * any safe point.
      */
     if (cx->compartment->debugMode)
         usesRval = true;
 
     isInlineable = true;
     if (script->nClosedArgs || script->nClosedVars || script->nfixed >= LOCAL_LIMIT ||
-        (script->fun && script->fun->isHeavyweight()) ||
+        (script->hasFunction && script->function()->isHeavyweight()) ||
         script->usesEval || script->usesArguments || cx->compartment->debugMode) {
         isInlineable = false;
     }
 
     modifiesArguments_ = false;
-    if (script->nClosedArgs || (script->fun && script->fun->isHeavyweight()))
+    if (script->nClosedArgs || (script->hasFunction && script->function()->isHeavyweight()))
         modifiesArguments_ = true;
 
     canTrackVars = true;
 
     /*
      * If we are in the middle of one or more jumps, the offset of the highest
      * target jumping over this bytecode.  Includes implicit jumps from
      * try/catch/finally blocks.
@@ -382,16 +375,20 @@ ScriptAnalysis::analyzeBytecode(JSContex
     if (!startcode) {
         setOOM(cx);
         return;
     }
 
     startcode->stackDepth = 0;
     codeArray[0] = startcode;
 
+    /* Number of JOF_TYPESET opcodes we have encountered. */
+    unsigned nTypeSets = 0;
+    types::TypeSet *typeArray = script->types->typeArray();
+
     unsigned offset, nextOffset = 0;
     while (nextOffset < length) {
         offset = nextOffset;
 
         JS_ASSERT(forwardCatch <= forwardJump);
 
         /* Check if the current forward jump/try-block has finished. */
         if (forwardJump && forwardJump == offset)
@@ -471,16 +468,32 @@ ScriptAnalysis::analyzeBytecode(JSContex
             unsigned nuses = GetUseCount(script, offset);
             unsigned ndefs = GetDefCount(script, offset);
 
             JS_ASSERT(stackDepth >= nuses);
             stackDepth -= nuses;
             stackDepth += ndefs;
         }
 
+        /*
+         * Assign an observed type set to each reachable JOF_TYPESET opcode.
+         * This may be less than the number of type sets in the script if some
+         * are unreachable, and may be greater in case the number of type sets
+         * overflows a uint16. In the latter case a single type set will be
+         * used for the observed types of all ops after the overflow.
+         */
+        if ((js_CodeSpec[op].format & JOF_TYPESET) && cx->typeInferenceEnabled()) {
+            if (nTypeSets < script->nTypeSets) {
+                code->observedTypes = &typeArray[nTypeSets++];
+            } else {
+                JS_ASSERT(nTypeSets == UINT16_MAX);
+                code->observedTypes = &typeArray[nTypeSets - 1];
+            }
+        }
+
         switch (op) {
 
           case JSOP_RETURN:
           case JSOP_STOP:
             numReturnSites_++;
             break;
 
           case JSOP_SETRVAL:
@@ -836,17 +849,17 @@ ScriptAnalysis::analyzeLifetimes(JSConte
         if (loop && code->safePoint)
             loop->hasSafePoints = true;
 
         jsbytecode *pc = script->code + offset;
         UntrapOpcode untrap(cx, script, pc);
 
         JSOp op = (JSOp) *pc;
 
-        if (code->loop) {
+        if ((op == JSOP_TRACE || op == JSOP_NOTRACE) && code->loop) {
             /*
              * This is the head of a loop, we need to go and make sure that any
              * variables live at the head are live at the backedge and points prior.
              * For each such variable, look for the last lifetime segment in the body
              * and extend it to the end of the loop.
              */
             JS_ASSERT(loop == code->loop);
             unsigned backedge = code->loop->backedge;
@@ -1326,30 +1339,31 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
      * modified before the branch rejoins.
      */
     Vector<uint32> branchTargets(cx);
 
     uint32 offset = 0;
     while (offset < script->length) {
         jsbytecode *pc = script->code + offset;
         UntrapOpcode untrap(cx, script, pc);
+        JSOp op = (JSOp)*pc;
 
         uint32 successorOffset = offset + GetBytecodeLength(pc);
 
         Bytecode *code = maybeCode(pc);
         if (!code) {
             offset = successorOffset;
             continue;
         }
 
         if (code->stackDepth > stackDepth)
             PodZero(stack + stackDepth, code->stackDepth - stackDepth);
         stackDepth = code->stackDepth;
 
-        if (code->loop) {
+        if ((op == JSOP_TRACE || op == JSOP_NOTRACE) && code->loop) {
             /*
              * Make sure there is a pending value array for phi nodes at the
              * loop head. We won't be able to clear these until we reach the
              * loop's back edge.
              *
              * We need phi nodes for all variables which might be modified
              * during the loop. This ensures that in the loop body we have
              * already updated state to reflect possible changes that happen
@@ -1435,18 +1449,16 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
                 if (code->fallthrough || code->jumpFallthrough)
                     mergeValue(cx, offset, values[v.slot], &v);
                 mergeBranchTarget(cx, values[v.slot], v.slot, branchTargets);
                 values[v.slot] = v.value;
             }
             freezeNewValues(cx, offset);
         }
 
-        JSOp op = (JSOp)*pc;
-
         if (js_CodeSpec[op].format & JOF_DECOMPOSE) {
             offset = successorOffset;
             continue;
         }
 
         unsigned nuses = GetUseCount(script, offset);
         unsigned ndefs = GetDefCount(script, offset);
         JS_ASSERT(stackDepth >= nuses);
@@ -1896,17 +1908,17 @@ CrossScriptSSA::foldValue(const CrossSSA
 {
     const Frame &frame = getFrame(cv.frame);
     const SSAValue &v = cv.v;
 
     JSScript *parentScript = NULL;
     ScriptAnalysis *parentAnalysis = NULL;
     if (frame.parent != INVALID_FRAME) {
         parentScript = getFrame(frame.parent).script;
-        parentAnalysis = parentScript->analysis(cx);
+        parentAnalysis = parentScript->analysis();
     }
 
     if (v.kind() == SSAValue::VAR && v.varInitial() && parentScript) {
         uint32 slot = v.varSlot();
         if (slot >= ArgSlot(0) && slot < LocalSlot(frame.script, 0)) {
             uint32 argc = GET_ARGC(frame.parentpc);
             SSAValue argv = parentAnalysis->poppedValue(frame.parentpc, argc - 1 - (slot - ArgSlot(0)));
             return foldValue(CrossSSAValue(frame.parent, argv));
@@ -1936,18 +1948,18 @@ CrossScriptSSA::foldValue(const CrossSSA
             for (unsigned i = 0; i < numFrames(); i++) {
                 if (iterFrame(i).parent == cv.frame && iterFrame(i).parentpc == pc) {
                     if (callee)
                         return cv;  /* Multiple callees */
                     callee = iterFrame(i).script;
                     calleeFrame = iterFrame(i).index;
                 }
             }
-            if (callee && callee->analysis(cx)->numReturnSites() == 1) {
-                ScriptAnalysis *analysis = callee->analysis(cx);
+            if (callee && callee->analysis()->numReturnSites() == 1) {
+                ScriptAnalysis *analysis = callee->analysis();
                 uint32 offset = 0;
                 while (offset < callee->length) {
                     jsbytecode *pc = callee->code + offset;
                     UntrapOpcode untrap(cx, callee, pc);
                     if (analysis->maybeCode(pc) && JSOp(*pc) == JSOP_RETURN)
                         return foldValue(CrossSSAValue(calleeFrame, analysis->poppedValue(pc, 0)));
                     offset += GetBytecodeLength(pc);
                 }
@@ -1959,17 +1971,17 @@ CrossScriptSSA::foldValue(const CrossSSA
             /*
              * The second value pushed by CALLPROP is the same as its popped
              * value. We don't do this folding during the SSA analysis itself
              * as we still need to distinguish the two values during type
              * inference --- any popped null or undefined value will throw an
              * exception, and not actually end up in the pushed set.
              */
             if (v.pushedIndex() == 1) {
-                ScriptAnalysis *analysis = frame.script->analysis(cx);
+                ScriptAnalysis *analysis = frame.script->analysis();
                 return foldValue(CrossSSAValue(cv.frame, analysis->poppedValue(pc, 0)));
             }
             break;
           }
 
           default:;
         }
     }
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -146,20 +146,25 @@ class Bytecode
   private:
     /*
      * The set of locals defined at this point. This does not include locals which
      * were unconditionally defined at an earlier point in the script.
      */
     uint32 defineCount;
     uint32 *defineArray;
 
-    /* --------- Lifetime analysis --------- */
+    union {
+        /* If this is a JOF_TYPESET opcode, index into the observed types for the op. */
+        types::TypeSet *observedTypes;
 
-    /* If this is a loop head, information about the loop. */
-    LoopAnalysis *loop;
+        /* If this is a loop head (TRACE or NOTRACE), information about the loop. */
+        LoopAnalysis *loop;
+    };
+
+    /* --------- Lifetime analysis --------- */
 
     /* Any allocation computed downstream for this bytecode. */
     mjit::RegisterAllocation *allocation;
 
     /* --------- SSA analysis --------- */
 
     /* Generated location of each value popped by this bytecode. */
     SSAValue *poppedValues;
@@ -404,17 +409,17 @@ static inline uint32 CalleeSlot() {
 }
 static inline uint32 ThisSlot() {
     return 1;
 }
 static inline uint32 ArgSlot(uint32 arg) {
     return 2 + arg;
 }
 static inline uint32 LocalSlot(JSScript *script, uint32 local) {
-    return 2 + (script->fun ? script->fun->nargs : 0) + local;
+    return 2 + (script->hasFunction ? script->function()->nargs : 0) + local;
 }
 static inline uint32 TotalSlots(JSScript *script) {
     return LocalSlot(script, 0) + script->nfixed;
 }
 
 static inline uint32 StackSlot(JSScript *script, uint32 index) {
     return TotalSlots(script) + index;
 }
@@ -914,17 +919,17 @@ class ScriptAnalysis
     void analyzeLifetimes(JSContext *cx);
     void analyzeTypes(JSContext *cx);
 
     /* Analyze the effect of invoking 'new' on script. */
     void analyzeTypesNew(JSContext *cx);
 
     bool OOM() { return outOfMemory; }
     bool failed() { return hadFailure; }
-    bool inlineable(uint32 argc) { return isInlineable && argc == script->fun->nargs; }
+    bool inlineable(uint32 argc) { return isInlineable && argc == script->function()->nargs; }
 
     /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
     bool usesReturnValue() const { return usesRval; }
 
     /* Whether there are NAME bytecodes which can access the frame's scope chain. */
     bool usesScopeChain() const { return usesScope; }
 
     bool usesThisValue() const { return usesThis; }
@@ -965,16 +970,21 @@ class ScriptAnalysis
         return JSOp(*next) == JSOP_POP && !jumpTarget(next);
     }
 
     bool incrementInitialValueObserved(jsbytecode *pc) {
         const JSCodeSpec *cs = &js_CodeSpec[*pc];
         return (cs->format & JOF_POST) && !popGuaranteed(pc);
     }
 
+    types::TypeSet *bytecodeTypes(const jsbytecode *pc) {
+        JS_ASSERT(JSOp(*pc) == JSOP_TRAP || (js_CodeSpec[*pc].format & JOF_TYPESET));
+        return getCode(pc).observedTypes;
+    }
+
     const SSAValue &poppedValue(uint32 offset, uint32 which) {
         JS_ASSERT(offset < script->length);
         JS_ASSERT_IF(script->code[offset] != JSOP_TRAP,
                      which < GetUseCount(script, offset) +
                      (ExtendedUse(script->code + offset) ? 1 : 0));
         return getCode(offset).poppedValues[which];
     }
     const SSAValue &poppedValue(const jsbytecode *pc, uint32 which) {
@@ -1030,17 +1040,17 @@ class ScriptAnalysis
 
     types::TypeSet *getValueTypes(const SSAValue &v) {
         switch (v.kind()) {
           case SSAValue::PUSHED:
             return pushedTypes(v.pushedOffset(), v.pushedIndex());
           case SSAValue::VAR:
             JS_ASSERT(!slotEscapes(v.varSlot()));
             if (v.varInitial()) {
-                return script->types.slotTypes(v.varSlot());
+                return types::TypeScript::SlotTypes(script, v.varSlot());
             } else {
                 /*
                  * Results of intermediate assignments have the same type as
                  * the first type pushed by the assignment op. Note that this
                  * may not be the exact same value as was pushed, due to
                  * post-inc/dec ops.
                  */
                 return pushedTypes(v.varOffset(), 0);
@@ -1272,17 +1282,17 @@ class CrossScriptSSA
         if (i == 0)
             return outerFrame;
         return inlineFrames[i - 1];
     }
 
     JSScript *outerScript() { return outerFrame.script; }
 
     types::TypeSet *getValueTypes(const CrossSSAValue &cv) {
-        return getFrame(cv.frame).script->analysis(cx)->getValueTypes(cv.v);
+        return getFrame(cv.frame).script->analysis()->getValueTypes(cv.v);
     }
 
     bool addInlineFrame(JSScript *script, uint32 depth, uint32 parent, jsbytecode *parentpc)
     {
         uint32 index = inlineFrames.length();
         return inlineFrames.append(Frame(index, script, depth, parent, parentpc));
     }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4285,17 +4285,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
                 return NULL;
             }
             obj = obj->getParent();
         }
 
         Value v;
         if (!obj->getProperty(cx, r.front().propid, &v))
             return NULL;
-        fun->script()->types.setUpvar(cx, i, v);
+        TypeScript::SetUpvar(cx, fun->script(), i, v);
         clone->getFlatClosureUpvars()[i] = v;
     }
 
     return clone;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun)
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -598,25 +598,27 @@ JSCompartment::sweep(JSContext *cx, uint
          */
         if (types.inferenceEnabled) {
 #ifdef JS_METHODJIT
             mjit::ClearAllFrames(this);
 #endif
 
             for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
                 JSScript *script = reinterpret_cast<JSScript *>(cursor);
-                script->types.sweep(cx);
+                if (script->types)
+                    types::TypeScript::Sweep(cx, script);
             }
         }
 
         types.sweep(cx);
 
         for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
             JSScript *script = reinterpret_cast<JSScript *>(cursor);
-            script->clearAnalysis();
+            if (script->types)
+                script->types->analysis = NULL;
         }
 
         /* Reset the analysis pool, releasing all analysis and intermediate type data. */
         JS_FinishArenaPool(&pool);
 
         /*
          * Destroy eval'ed scripts, now that any type inference information referring
          * to eval scripts has been removed.
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -122,17 +122,17 @@ JSCodeGenerator::JSCodeGenerator(Parser 
     constList(parser->context),
     upvarIndices(parser->context),
     upvarMap(parser->context),
     globalUses(parser->context),
     globalMap(parser->context),
     closedArgs(parser->context),
     closedVars(parser->context),
     traceIndex(0),
-    typesetIndex(0)
+    typesetCount(0)
 {
     flags = TCF_COMPILING;
     memset(&prolog, 0, sizeof prolog);
     memset(&main, 0, sizeof main);
     current = &main;
     firstLine = prolog.currentLine = main.currentLine = lineno;
     prolog.noteMask = main.noteMask = SRCNOTE_CHUNK - 1;
 }
@@ -1411,45 +1411,38 @@ EmitTraceOp(JSContext *cx, JSCodeGenerat
     uint32 index = cg->traceIndex;
     if (index < UINT16_MAX)
         cg->traceIndex++;
     return js_Emit3(cx, cg, JSOP_TRACE, UINT16_HI(index), UINT16_LO(index));
 }
 
 /*
  * If op is JOF_TYPESET (see the type barriers comment in jsinfer.h), reserve
- * a type set to store its result and append that info to the already-emitted
- * opcode.
+ * a type set to store its result.
  */
-static inline bool
-MaybeEmitTypeSet(JSContext *cx, JSCodeGenerator *cg, JSOp op)
+static inline void
+CheckTypeSet(JSContext *cx, JSCodeGenerator *cg, JSOp op)
 {
     if (js_CodeSpec[op].format & JOF_TYPESET) {
-        uint32 index = (cg->typesetIndex < UINT16_MAX) ? cg->typesetIndex++ : cg->typesetIndex - 1;
-        if (EmitCheck(cx, cg, JSOP_NOP, 2) < 0)
-            return false;
-        *CG_NEXT(cg)++ = UINT16_HI(index);
-        *CG_NEXT(cg)++ = UINT16_LO(index);
-        return true;
-    }
-    return true;
+        if (cg->typesetCount < UINT16_MAX)
+            cg->typesetCount++;
+    }
 }
 
 /*
  * Macro to emit a bytecode followed by a uint16 immediate operand stored in
  * big-endian order, used for arg and var numbers as well as for atomIndexes.
  * NB: We use cx and cg from our caller's lexical environment, and return
  * false on error.
  */
 #define EMIT_UINT16_IMM_OP(op, i)                                             \
     JS_BEGIN_MACRO                                                            \
         if (js_Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0)             \
             return JS_FALSE;                                                  \
-        if (!MaybeEmitTypeSet(cx, cg, op))                                    \
-            return JS_FALSE;                                                  \
+        CheckTypeSet(cx, cg, op);                                             \
     JS_END_MACRO
 
 #define EMIT_UINT16PAIR_IMM_OP(op, i, j)                                      \
     JS_BEGIN_MACRO                                                            \
         ptrdiff_t off_ = js_EmitN(cx, cg, op, 2 * UINT16_LEN);                \
         if (off_ < 0)                                                         \
             return JS_FALSE;                                                  \
         jsbytecode *pc_ = CG_CODE(cg, off_);                                  \
@@ -2785,18 +2778,17 @@ EmitXMLName(JSContext *cx, JSParseNode *
 }
 #endif
 
 static inline bool
 EmitElemOpBase(JSContext *cx, JSCodeGenerator *cg, JSOp op)
 {
     if (js_Emit1(cx, cg, op) < 0)
         return false;
-    if (!MaybeEmitTypeSet(cx, cg, op))
-        return false;
+    CheckTypeSet(cx, cg, op);
     return true;
 }
 
 static bool
 EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     /*
      * Special case for obj.__proto__ to deoptimize away from fast paths in the
@@ -6793,18 +6785,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         }
         cg->flags |= oldflags & TCF_IN_FOR_INIT;
         if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
             return JS_FALSE;
 
         argc = pn->pn_count - 1;
         if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
             return JS_FALSE;
-        if (!MaybeEmitTypeSet(cx, cg, PN_OP(pn)))
-            return JS_FALSE;
+        CheckTypeSet(cx, cg, PN_OP(pn));
         if (PN_OP(pn) == JSOP_EVAL) {
             EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
             if (EmitBlockChain(cx, cg) < 0)
                 return JS_FALSE;
         }
         if (pn->pn_xflags & PNX_SETCALL) {
             if (js_Emit1(cx, cg, JSOP_SETCALL) < 0)
                 return JS_FALSE;
--- a/js/src/jsemit.h
+++ b/js/src/jsemit.h
@@ -653,17 +653,17 @@ struct JSCodeGenerator : public JSTreeCo
     js::OwnedAtomIndexMapPtr globalMap; /* per-script map of global name to globalUses vector */
 
     /* Vectors of pn_cookie slot values. */
     typedef js::Vector<uint32, 8> SlotVector;
     SlotVector      closedArgs;
     SlotVector      closedVars;
 
     uint16          traceIndex;     /* index for the next JSOP_TRACE instruction */
-    uint16          typesetIndex;   /* index for the next instruction with a type set */
+    uint16          typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
     /*
      * Initialize cg to allocate bytecode space from codePool, source note
      * space from notePool, and all other arena-allocated temporaries from
      * parser->context->tempPool.
      */
     JSCodeGenerator(js::Parser *parser,
                     JSArenaPool *codePool, JSArenaPool *notePool,
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -426,17 +426,17 @@ ArgSetter(JSContext *cx, JSObject *obj, 
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < argsobj->initialLength()) {
             if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate())) {
                 JSScript *script = fp->functionScript();
                 if (script->usesArguments) {
                     if (arg < fp->numFormalArgs())
-                        script->types.setArgument(cx, arg, *vp);
+                        TypeScript::SetArgument(cx, script, arg, *vp);
                     fp->canonicalActualArg(arg) = *vp;
                 }
                 return true;
             }
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
                   JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
@@ -1030,17 +1030,17 @@ SetCallArg(JSContext *cx, JSObject *obj,
 
     Value *argp;
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
         argp = &fp->formalArg(i);
     else
         argp = &obj->callObjArg(i);
 
     JSScript *script = obj->getCallObjCalleeFunction()->script();
-    script->types.setArgument(cx, i, *vp);
+    TypeScript::SetArgument(cx, script, i, *vp);
 
     GCPoke(cx, *argp);
     *argp = *vp;
     return true;
 }
 
 JSBool
 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
@@ -1103,17 +1103,17 @@ SetCallVar(JSContext *cx, JSObject *obj,
 
     Value *varp;
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
         varp = &fp->varSlot(i);
     else
         varp = &obj->callObjVar(i);
 
     JSScript *script = obj->getCallObjCalleeFunction()->script();
-    script->types.setLocal(cx, i, *vp);
+    TypeScript::SetLocal(cx, script, i, *vp);
 
     GCPoke(cx, *varp);
     *varp = *vp;
     return true;
 }
 
 } // namespace js
 
@@ -2445,17 +2445,18 @@ js_InitFunctionClass(JSContext *cx, JSOb
         return NULL;
     script->noScriptRval = true;
     script->code[0] = JSOP_STOP;
     script->code[1] = SRC_NULL;
 #ifdef CHECK_SCRIPT_OWNER
     script->owner = NULL;
 #endif
     fun->u.i.script = script;
-    script->fun = fun;
+    script->hasFunction = true;
+    script->where.fun = fun;
     js_CallNewScriptHook(cx, script, fun);
 
     if (obj->isGlobal()) {
         /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
         JSFunction *throwTypeError =
             js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0,
                            0, obj, NULL);
         if (!throwTypeError)
@@ -2641,17 +2642,17 @@ js_NewFlatClosure(JSContext *cx, JSFunct
         return closure;
 
     Value *upvars = closure->getFlatClosureUpvars();
     uintN level = fun->script()->staticLevel;
     JSUpvarArray *uva = fun->script()->upvars();
 
     for (uint32 i = 0, n = uva->length; i < n; i++) {
         upvars[i] = GetUpvar(cx, level, uva->vector[i]);
-        fun->script()->types.setUpvar(cx, i, upvars[i]);
+        TypeScript::SetUpvar(cx, fun->script(), i, upvars[i]);
     }
 
     return closure;
 }
 
 JSFunction *
 js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
                   uintN nargs, uintN attrs)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -560,17 +560,17 @@ public:
 void
 TypeSet::addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id)
 {
     /*
      * For calls which will go through JSOP_NEW, don't add any constraints to
      * modify the 'this' types of callees. The initial 'this' value will be
      * outright ignored.
      */
-    jsbytecode *callpc = script->analysis(cx)->getCallPC(pc);
+    jsbytecode *callpc = script->analysis()->getCallPC(pc);
     UntrapOpcode untrap(cx, script, callpc);
     if (JSOp(*callpc) == JSOP_NEW)
         return;
 
     add(cx, ArenaNew<TypeConstraintCallProp>(cx->compartment->pool, script, callpc, id));
 }
 
 /*
@@ -659,17 +659,17 @@ public:
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
 TypeSet::addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
 {
     /* Don't add constraints when the call will be 'new' (see addCallProperty). */
-    jsbytecode *callpc = script->analysis(cx)->getCallPC(pc);
+    jsbytecode *callpc = script->analysis()->getCallPC(pc);
     UntrapOpcode untrap(cx, script, callpc);
     if (JSOp(*callpc) == JSOP_NEW)
         return;
 
     add(cx, ArenaNew<TypeConstraintPropagateThis>(cx->compartment->pool, script, callpc, type));
 }
 
 /* Subset constraint which filters out primitive types. */
@@ -779,17 +779,17 @@ public:
         : TypeConstraint("subsetBarrier"), script(script), pc(pc), target(target)
     {
         JS_ASSERT(!target->intermediate());
     }
 
     void newType(JSContext *cx, TypeSet *source, Type type)
     {
         if (!target->hasType(type)) {
-            script->analysis(cx)->addTypeBarrier(cx, pc, target, type);
+            script->analysis()->addTypeBarrier(cx, pc, target, type);
             return;
         }
 
         target->addType(cx, type);
     }
 };
 
 void
@@ -884,25 +884,25 @@ GetPropertyObject(JSContext *cx, JSScrip
      * Handle properties attached to primitive types, treating this access as a
      * read on the primitive's new object.
      */
     TypeObject *object = NULL;
     switch (type.primitive()) {
 
       case JSVAL_TYPE_INT32:
       case JSVAL_TYPE_DOUBLE:
-        object = script->types.standardType(cx, JSProto_Number);
+        object = TypeScript::StandardType(cx, script, JSProto_Number);
         break;
 
       case JSVAL_TYPE_BOOLEAN:
-        object = script->types.standardType(cx, JSProto_Boolean);
+        object = TypeScript::StandardType(cx, script, JSProto_Boolean);
         break;
 
       case JSVAL_TYPE_STRING:
-        object = script->types.standardType(cx, JSProto_String);
+        object = TypeScript::StandardType(cx, script, JSProto_String);
         break;
 
       default:
         /* undefined, null and lazy arguments do not have properties. */
         return NULL;
     }
 
     if (!object)
@@ -920,17 +920,17 @@ UsePropertyTypeBarrier(jsbytecode *pc)
     uint32 format = js_CodeSpec[*pc].format;
     return (format & JOF_TYPESET) && !(format & JOF_INVOKE);
 }
 
 static inline void
 MarkPropertyAccessUnknown(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
 {
     if (UsePropertyTypeBarrier(pc))
-        script->analysis(cx)->addTypeBarrier(cx, pc, target, Type::UnknownType());
+        script->analysis()->addTypeBarrier(cx, pc, target, Type::UnknownType());
     else
         target->addType(cx, Type::UnknownType());
 }
 
 /*
  * Handle a property access on a specific object. All property accesses go through
  * here, whether via x.f, x[f], or global name accesses.
  */
@@ -1096,59 +1096,59 @@ TypeConstraintCall::newType(JSContext *c
         callee = type.typeObject()->functionScript;
         if (!callee)
             return;
     } else {
         /* Calls on non-objects are dynamically monitored. */
         return;
     }
 
-    unsigned nargs = callee->fun->nargs;
-
-    if (!callee->types.ensureTypeArray(cx))
+    unsigned nargs = callee->function()->nargs;
+
+    if (!callee->ensureHasTypes(cx))
         return;
 
     /* Analyze the function if we have not already done so. */
     if (!callee->ensureRanInference(cx)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     /* Add bindings for the arguments of the call. */
     for (unsigned i = 0; i < callsite->argumentCount && i < nargs; i++) {
         TypeSet *argTypes = callsite->argumentTypes[i];
-        TypeSet *types = callee->types.argTypes(i);
+        TypeSet *types = TypeScript::ArgTypes(callee, i);
         argTypes->addSubsetBarrier(cx, script, pc, types);
     }
 
     /* Add void type for any formals in the callee not supplied at the call site. */
     for (unsigned i = callsite->argumentCount; i < nargs; i++) {
-        TypeSet *types = callee->types.argTypes(i);
+        TypeSet *types = TypeScript::ArgTypes(callee, i);
         types->addType(cx, Type::UndefinedType());
     }
 
     if (callsite->isNew) {
         /*
          * If the script does not return a value then the pushed value is the
          * new object (typical case). Note that we don't model construction of
          * the new value, which is done dynamically; we don't keep track of the
          * possible 'new' types for a given prototype type object.
          */
-        callee->types.thisTypes()->addSubset(cx, callsite->returnTypes);
-        callee->types.returnTypes()->addFilterPrimitives(cx, callsite->returnTypes, false);
+        TypeScript::ThisTypes(callee)->addSubset(cx, callsite->returnTypes);
+        TypeScript::ReturnTypes(callee)->addFilterPrimitives(cx, callsite->returnTypes, false);
     } else {
         /*
          * Add a binding for the return value of the call. We don't add a
          * binding for the receiver object, as this is done with PropagateThis
          * constraints added by the original JSOP_CALL* op. The type sets we
          * manipulate here have lost any correlations between particular types
          * in the 'this' and 'callee' sets, which we want to maintain for
          * polymorphic JSOP_CALLPROP invocations.
          */
-        callee->types.returnTypes()->addSubset(cx, callsite->returnTypes);
+        TypeScript::ReturnTypes(callee)->addSubset(cx, callsite->returnTypes);
     }
 }
 
 void
 TypeConstraintPropagateThis::newType(JSContext *cx, TypeSet *source, Type type)
 {
     if (type.isUnknown() || type.isAnyObject()) {
         /*
@@ -1174,20 +1174,20 @@ TypeConstraintPropagateThis::newType(JSC
         if (!object->isFunction() || !object->functionScript)
             return;
         callee = object->functionScript;
     } else {
         /* Ignore calls to primitives, these will go through a stub. */
         return;
     }
 
-    if (!callee->types.ensureTypeArray(cx))
+    if (!callee->ensureHasTypes(cx))
         return;
 
-    callee->types.thisTypes()->addType(cx, this->type);
+    TypeScript::ThisTypes(callee)->addType(cx, this->type);
 }
 
 void
 TypeConstraintArith::newType(JSContext *cx, TypeSet *source, Type type)
 {
     /*
      * We only model a subset of the arithmetic behavior that is actually
      * possible. The following need to be watched for at runtime:
@@ -1252,23 +1252,23 @@ TypeConstraintTransformThis::newType(JSC
         target->addType(cx, Type::UnknownType());
         return;
     }
 
     TypeObject *object = NULL;
     switch (type.primitive()) {
       case JSVAL_TYPE_INT32:
       case JSVAL_TYPE_DOUBLE:
-        object = script->types.standardType(cx, JSProto_Number);
+        object = TypeScript::StandardType(cx, script, JSProto_Number);
         break;
       case JSVAL_TYPE_BOOLEAN:
-        object = script->types.standardType(cx, JSProto_Boolean);
+        object = TypeScript::StandardType(cx, script, JSProto_Boolean);
         break;
       case JSVAL_TYPE_STRING:
-        object = script->types.standardType(cx, JSProto_String);
+        object = TypeScript::StandardType(cx, script, JSProto_String);
         break;
       default:
         return;
     }
 
     if (!object) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
@@ -1538,34 +1538,33 @@ TypeSet::HasObjectFlags(JSContext *cx, T
 void
 types::MarkArgumentsCreated(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(!script->createdArgs);
 
     script->createdArgs = true;
     script->uninlineable = true;
 
-    MarkTypeObjectFlags(cx, script->fun,
+    MarkTypeObjectFlags(cx, script->function(),
                         OBJECT_FLAG_CREATED_ARGUMENTS | OBJECT_FLAG_UNINLINEABLE);
 
     if (!script->usedLazyArgs)
         return;
 
     AutoEnterTypeInference enter(cx);
 
 #ifdef JS_METHODJIT
     mjit::ExpandInlineFrames(cx->compartment, true);
 #endif
 
-    ScriptAnalysis *analysis = script->analysis(cx);
-    if (analysis && !analysis->ranBytecode())
-        analysis->analyzeBytecode(cx);
-    if (!analysis || analysis->OOM())
+    if (!script->ensureRanBytecode(cx))
         return;
 
+    ScriptAnalysis *analysis = script->analysis();
+
     for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
         StackFrame *fp = iter.fp();
         if (fp->isScriptFrame() && fp->script() == script) {
             /*
              * Check locals and stack slots, assignment to individual arguments
              * is treated as an escape on the arguments.
              */
             Value *sp = fp->base() + analysis->getCode(iter.pc()).stackDepth;
@@ -2071,17 +2070,17 @@ TypeCompartment::addPendingRecompile(JSC
     }
 #endif
 }
 
 void
 TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32 offset,
                                  bool returnOnly)
 {
-    ScriptAnalysis *analysis = script->analysis(cx);
+    ScriptAnalysis *analysis = script->analysis();
     JS_ASSERT(analysis->ranInference());
 
     jsbytecode *pc = script->code + offset;
     UntrapOpcode untrap(cx, script, pc);
 
     JS_ASSERT_IF(returnOnly, js_CodeSpec[*pc].format & JOF_INVOKE);
 
     Bytecode &code = analysis->getCode(pc);
@@ -2097,18 +2096,18 @@ TypeCompartment::monitorBytecode(JSConte
         code.monitoredTypesReturn = true;
 
     if (!returnOnly)
         code.monitoredTypes = true;
 
     cx->compartment->types.addPendingRecompile(cx, script);
 
     /* Trigger recompilation of any inline callers. */
-    if (script->fun && !script->fun->hasLazyType())
-        ObjectStateChange(cx, script->fun->type(), false, true);
+    if (script->hasFunction && !script->function()->hasLazyType())
+        ObjectStateChange(cx, script->function()->type(), false, true);
 }
 
 /*
  * State for keeping track of which property type sets contain an object we are
  * scrubbing from all properties in the compartment. We make a list of
  * properties to update and fix them afterwards, as adding types can't be done
  * with the GC locked (as is done in IterateCells), and can potentially make
  * new type objects as well.
@@ -2165,36 +2164,37 @@ TypeCompartment::markSetsUnknown(JSConte
 
     for (unsigned i = 0; i < state.pending.length(); i++)
         state.pending[i]->addType(cx, Type::AnyObjectType());
 
     for (JSCList *cursor = cx->compartment->scripts.next;
          cursor != &cx->compartment->scripts;
          cursor = cursor->next) {
         JSScript *script = reinterpret_cast<JSScript *>(cursor);
-        if (script->types.typeArray) {
-            unsigned count = script->types.numTypeSets();
+        if (script->types) {
+            unsigned count = TypeScript::NumTypeSets(script);
+            TypeSet *typeArray = script->types->typeArray();
             for (unsigned i = 0; i < count; i++) {
-                if (script->types.typeArray[i].hasType(Type::ObjectType(target)))
-                    script->types.typeArray[i].addType(cx, Type::AnyObjectType());
+                if (typeArray[i].hasType(Type::ObjectType(target)))
+                    typeArray[i].addType(cx, Type::AnyObjectType());
             }
         }
-        if (script->hasAnalysis() && script->analysis(cx)->ranInference()) {
+        if (script->hasAnalysis() && script->analysis()->ranInference()) {
             for (unsigned i = 0; i < script->length; i++) {
-                if (!script->analysis(cx)->maybeCode(i))
+                if (!script->analysis()->maybeCode(i))
                     continue;
                 jsbytecode *pc = script->code + i;
                 UntrapOpcode untrap(cx, script, pc);
                 if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
                     continue;
                 unsigned defCount = GetDefCount(script, i);
                 if (ExtendedDef(pc))
                     defCount++;
                 for (unsigned j = 0; j < defCount; j++) {
-                    TypeSet *types = script->analysis(cx)->pushedTypes(pc, j);
+                    TypeSet *types = script->analysis()->pushedTypes(pc, j);
                     if (types->hasType(Type::ObjectType(target)))
                         types->addType(cx, Type::AnyObjectType());
                 }
             }
         }
     }
 }
 
@@ -2215,18 +2215,18 @@ ScriptAnalysis::addTypeBarrier(JSContext
          * Adding type barriers at a bytecode which did not have them before
          * will trigger recompilation. If there were already type barriers,
          * however, do not trigger recompilation (the script will be recompiled
          * if any of the barriers is ever violated).
          */
         cx->compartment->types.addPendingRecompile(cx, script);
 
         /* Trigger recompilation of any inline callers. */
-        if (script->fun && !script->fun->hasLazyType())
-            ObjectStateChange(cx, script->fun->type(), false, true);
+        if (script->hasFunction && !script->function()->hasLazyType())
+            ObjectStateChange(cx, script->function()->type(), false, true);
     }
 
     /* Ignore duplicate barriers. */
     TypeBarrier *barrier = code.typeBarriers;
     while (barrier) {
         if (barrier->target == target && barrier->type == type)
             return;
         barrier = barrier->next;
@@ -2259,18 +2259,18 @@ TypeCompartment::print(JSContext *cx)
     JSCompartment *compartment = this->compartment();
 
     if (!InferSpewActive(ISpewResult) || JS_CLIST_IS_EMPTY(&compartment->scripts))
         return;
 
     for (JSScript *script = (JSScript *)compartment->scripts.next;
          &script->links != &compartment->scripts;
          script = (JSScript *)script->links.next) {
-        if (script->hasAnalysis() && script->analysis(cx)->ranInference())
-            script->analysis(cx)->printTypes(cx);
+        if (script->hasAnalysis() && script->analysis()->ranInference())
+            script->analysis()->printTypes(cx);
     }
 
 #ifdef DEBUG
     {
         AutoUnlockGC unlock(cx->runtime);
         IterateCells(cx, compartment, gc::FINALIZE_TYPE_OBJECT, NULL, PrintObjectCallback);
     }
 #endif
@@ -3048,26 +3048,24 @@ GetInitializerType(JSContext *cx, JSScri
         return NULL;
 
     UntrapOpcode untrap(cx, script, pc);
 
     JSOp op = JSOp(*pc);
     JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
 
     bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array));
-    return script->types.initObject(cx, pc, isArray ? JSProto_Array : JSProto_Object);
+    return TypeScript::InitObject(cx, script, pc, isArray ? JSProto_Array : JSProto_Object);
 }
 
 /* Analyze type information for a single bytecode. */
 bool
 ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
                                      TypeInferenceState &state)
 {
-    JS_ASSERT(!script->isUncachedEval);
-
     jsbytecode *pc = script->code + offset;
     JSOp op = (JSOp)*pc;
 
     Bytecode &code = getCode(offset);
     JS_ASSERT(!code.pushedTypes);
 
     InferSpew(ISpewOps, "analyze: #%u:%05u", script->id(), offset);
 
@@ -3226,35 +3224,35 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         pushed[0].addType(cx, Type::StringType());
         break;
       case JSOP_NULL:
         pushed[0].addType(cx, Type::NullType());
         break;
 
       case JSOP_REGEXP:
         if (script->hasGlobal()) {
-            TypeObject *object = script->types.standardType(cx, JSProto_RegExp);
+            TypeObject *object = TypeScript::StandardType(cx, script, JSProto_RegExp);
             if (!object)
                 return false;
             pushed[0].addType(cx, Type::ObjectType(object));
         } else {
             pushed[0].addType(cx, Type::UnknownType());
         }
         break;
 
       case JSOP_OBJECT: {
         JSObject *obj = GetScriptObject(cx, script, pc, 0);
         pushed[0].addType(cx, Type::ObjectType(obj));
         break;
       }
 
       case JSOP_STOP:
         /* If a stop is reachable then the return type may be void. */
-        if (script->fun)
-            script->types.returnTypes()->addType(cx, Type::UndefinedType());
+        if (script->hasFunction)
+            TypeScript::ReturnTypes(script)->addType(cx, Type::UndefinedType());
         break;
 
       case JSOP_OR:
       case JSOP_ORX:
       case JSOP_AND:
       case JSOP_ANDX:
         /* OR/AND push whichever operand determined the result. */
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
@@ -3287,17 +3285,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_GETGNAME:
       case JSOP_CALLGNAME: {
         jsid id;
         if (op == JSOP_GETGLOBAL || op == JSOP_CALLGLOBAL)
             id = GetGlobalId(cx, script, pc);
         else
             id = GetAtomId(cx, script, pc, 0);
 
-        TypeSet *seen = script->types.bytecodeTypes(pc);
+        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
         seen->addSubset(cx, &pushed[0]);
 
         /*
          * Normally we rely on lazy standard class initialization to fill in
          * the types of global properties the script can access. In a few cases
          * the method JIT will bypass this, and we need to add the types direclty.
          */
         if (id == ATOM_TO_JSID(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]))
@@ -3321,17 +3319,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       }
 
       case JSOP_NAME:
       case JSOP_CALLNAME: {
         /*
          * The first value pushed by NAME/CALLNAME must always be added to the
          * bytecode types, we don't model these opcodes with inference.
          */
-        TypeSet *seen = script->types.bytecodeTypes(pc);
+        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
         addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLNAME) {
             pushed[1].addType(cx, Type::UnknownType());
             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
         }
         break;
       }
@@ -3350,26 +3348,26 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_SETNAME:
       case JSOP_SETCONST:
         cx->compartment->types.monitorBytecode(cx, script, offset);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GETXPROP: {
-        TypeSet *seen = script->types.bytecodeTypes(pc);
+        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
         addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
         break;
       }
 
       case JSOP_GETFCSLOT:
       case JSOP_CALLFCSLOT: {
         unsigned index = GET_UINT16(pc);
-        TypeSet *types = script->types.upvarTypes(index);
+        TypeSet *types = TypeScript::UpvarTypes(script, index);
         types->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLFCSLOT) {
             pushed[1].addType(cx, Type::UndefinedType());
             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
         }
         break;
       }
 
@@ -3381,17 +3379,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         if (trackSlot(slot)) {
             /*
              * Normally these opcodes don't pop anything, but they are given
              * an extended use holding the variable's SSA value before the
              * access. Use the types from here.
              */
             poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         } else if (slot < TotalSlots(script)) {
-            TypeSet *types = script->types.slotTypes(slot);
+            TypeSet *types = TypeScript::SlotTypes(script, slot);
             types->addSubset(cx, &pushed[0]);
         } else {
             /* Local 'let' variable. Punt on types for these, for now. */
             pushed[0].addType(cx, Type::UnknownType());
         }
         if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL) {
             pushed[1].addType(cx, Type::UndefinedType());
             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
@@ -3399,17 +3397,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         break;
       }
 
       case JSOP_SETARG:
       case JSOP_SETLOCAL:
       case JSOP_SETLOCALPOP: {
         uint32 slot = GetBytecodeSlot(script, pc);
         if (!trackSlot(slot) && slot < TotalSlots(script)) {
-            TypeSet *types = script->types.slotTypes(slot);
+            TypeSet *types = TypeScript::SlotTypes(script, slot);
             poppedTypes(pc, 0)->addSubset(cx, types);
         }
 
         /*
          * For assignments to non-escaping locals/args, we don't need to update
          * the possible types of the var, as for each read of the var SSA gives
          * us the writes that could have produced that read.
          */
@@ -3424,28 +3422,28 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC: {
         uint32 slot = GetBytecodeSlot(script, pc);
         if (trackSlot(slot)) {
             poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
         } else if (slot < TotalSlots(script)) {
-            TypeSet *types = script->types.slotTypes(slot);
+            TypeSet *types = TypeScript::SlotTypes(script, slot);
             types->addArith(cx, types);
             types->addSubset(cx, &pushed[0]);
         } else {
             pushed[0].addType(cx, Type::UnknownType());
         }
         break;
       }
 
       case JSOP_ARGUMENTS: {
         /* Compute a precise type only when we know the arguments won't escape. */
-        TypeObject *funType = script->fun->getType(cx);
+        TypeObject *funType = script->function()->getType(cx);
         if (funType->unknownProperties() || funType->hasAnyFlags(OBJECT_FLAG_CREATED_ARGUMENTS)) {
             pushed[0].addType(cx, Type::UnknownType());
             break;
         }
         TypeSet *types = funType->getProperty(cx, JSID_EMPTY, false);
         if (!types)
             break;
         types->addLazyArguments(cx, &pushed[0]);
@@ -3460,17 +3458,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
 
       case JSOP_LENGTH:
       case JSOP_GETPROP:
       case JSOP_CALLPROP: {
         jsid id = GetAtomId(cx, script, pc, 0);
-        TypeSet *seen = script->types.bytecodeTypes(pc);
+        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
 
         poppedTypes(pc, 0)->addGetProperty(cx, script, pc, seen, id);
         if (op == JSOP_CALLPROP)
             poppedTypes(pc, 0)->addCallProperty(cx, script, pc, id);
 
         seen->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLPROP)
             poppedTypes(pc, 0)->addFilterPrimitives(cx, &pushed[1], true);
@@ -3481,17 +3479,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       /*
        * We only consider ELEM accesses on integers below. Any element access
        * which is accessing a non-integer property must be monitored.
        */
 
       case JSOP_GETELEM:
       case JSOP_CALLELEM: {
-        TypeSet *seen = script->types.bytecodeTypes(pc);
+        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
 
         poppedTypes(pc, 1)->addGetProperty(cx, script, pc, seen, JSID_VOID);
         if (op == JSOP_CALLELEM)
             poppedTypes(pc, 1)->addCallProperty(cx, script, pc, JSID_VOID);
 
         seen->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLELEM)
             poppedTypes(pc, 1)->addFilterPrimitives(cx, &pushed[1], true);
@@ -3510,23 +3508,23 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         /*
          * This is only used for element inc/dec ops; any id produced which
          * is not an integer must be monitored.
          */
         pushed[0].addType(cx, Type::Int32Type());
         break;
 
       case JSOP_THIS:
-        script->types.thisTypes()->addTransformThis(cx, script, &pushed[0]);
+        TypeScript::ThisTypes(script)->addTransformThis(cx, script, &pushed[0]);
         break;
 
       case JSOP_RETURN:
       case JSOP_SETRVAL:
-        if (script->fun)
-            poppedTypes(pc, 0)->addSubset(cx, script->types.returnTypes());
+        if (script->hasFunction)
+            poppedTypes(pc, 0)->addSubset(cx, TypeScript::ReturnTypes(script));
         break;
 
       case JSOP_ADD:
         poppedTypes(pc, 0)->addArith(cx, &pushed[0], poppedTypes(pc, 1));
         poppedTypes(pc, 1)->addArith(cx, &pushed[0], poppedTypes(pc, 0));
         break;
 
       case JSOP_SUB:
@@ -3556,17 +3554,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
             res = &pushed[0];
         } else if (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) {
             uint32 slot = GetBytecodeSlot(script, pc);
             if (trackSlot(slot)) {
                 res = &pushed[0];
             } else {
                 /* Should not see 'let' vars here. */
                 JS_ASSERT(slot < TotalSlots(script));
-                res = script->types.slotTypes(slot);
+                res = TypeScript::SlotTypes(script, slot);
             }
         }
 
         if (res) {
             if (script->hasGlobal())
                 res->addType(cx, Type::ObjectType(obj));
             else
                 res->addType(cx, Type::UnknownType());
@@ -3579,17 +3577,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_DEFVAR:
         break;
 
       case JSOP_CALL:
       case JSOP_EVAL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
       case JSOP_NEW: {
-        TypeSet *seen = script->types.bytecodeTypes(pc);
+        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
         seen->addSubset(cx, &pushed[0]);
 
         /* Construct the base call information about this site. */
         unsigned argCount = GetUseCount(script, offset) - 2;
         TypeCallsite *callsite = ArenaNew<TypeCallsite>(cx->compartment->pool,
                                                         cx, script, pc, op == JSOP_NEW, argCount);
         if (!callsite || (argCount && !callsite->argumentTypes)) {
             cx->compartment->types.setPendingNukeTypes(cx);
@@ -3788,24 +3786,24 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         poppedTypes(pc, 1)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_UNBRAND:
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GENERATOR:
-        if (script->fun) {
+        if (script->hasFunction) {
             if (script->hasGlobal()) {
-                TypeObject *object = script->types.standardType(cx, JSProto_Generator);
+                TypeObject *object = TypeScript::StandardType(cx, script, JSProto_Generator);
                 if (!object)
                     return false;
-                script->types.returnTypes()->addType(cx, Type::ObjectType(object));
+                TypeScript::ReturnTypes(script)->addType(cx, Type::ObjectType(object));
             } else {
-                script->types.returnTypes()->addType(cx, Type::UnknownType());
+                TypeScript::ReturnTypes(script)->addType(cx, Type::UnknownType());
             }
         }
         break;
 
       case JSOP_YIELD:
         pushed[0].addType(cx, Type::UnknownType());
         break;
 
@@ -3851,17 +3849,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         break;
 
       case JSOP_USESHARP:
         pushed[0].addType(cx, Type::UnknownType());
         break;
 
       case JSOP_CALLEE:
         if (script->hasGlobal())
-            pushed[0].addType(cx, Type::ObjectType(script->fun));
+            pushed[0].addType(cx, Type::ObjectType(script->function()));
         else
             pushed[0].addType(cx, Type::UnknownType());
         break;
 
       default:
         /* Display fine-grained debug information first */
         fprintf(stderr, "Unknown bytecode %02x at #%u:%05u\n", op, script->id(), offset);
         TypeFailure(cx, "Unknown bytecode %02x", op);
@@ -3870,16 +3868,24 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
     return true;
 }
 
 void
 ScriptAnalysis::analyzeTypes(JSContext *cx)
 {
     JS_ASSERT(!ranInference());
 
+    /*
+     * Types in uncached eval scripts cannot be analyzed. These are manually
+     * destroyed, rather than destroyed on GC, and we cannot ensure that type
+     * constraints do not refer to the script after it has been destroyed.are
+     * referring to 
+     */
+    JS_ASSERT(!script->isUncachedEval);
+
     if (OOM()) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     /*
      * Refuse to analyze the types in a script which is compileAndGo but is
      * running against a global with a cleared scope. Per GlobalObject::clear,
@@ -3892,30 +3898,25 @@ ScriptAnalysis::analyzeTypes(JSContext *
         return;
 
     if (!ranSSA()) {
         analyzeSSA(cx);
         if (failed())
             return;
     }
 
-    if (!script->types.ensureTypeArray(cx)) {
-        setOOM(cx);
-        return;
-    }
-
     /*
      * Set this early to avoid reentrance. Any failures are OOMs, and will nuke
      * all types in the compartment.
      */
     ranInference_ = true;
 
     /* Make sure the initial type set of all local vars includes void. */
     for (unsigned i = 0; i < script->nfixed; i++)
-        script->types.localTypes(i)->addType(cx, Type::UndefinedType());
+        TypeScript::LocalTypes(script, i)->addType(cx, Type::UndefinedType());
 
     TypeInferenceState state(cx);
 
     unsigned offset = 0;
     while (offset < script->length) {
         Bytecode *code = maybeCode(offset);
 
         jsbytecode *pc = script->code + offset;
@@ -3937,17 +3938,17 @@ ScriptAnalysis::analyzeTypes(JSContext *
         }
     }
 
     /*
      * Replay any dynamic type results which have been generated for the script
      * either because we ran the interpreter some before analyzing or because
      * we are reanalyzing after a GC.
      */
-    TypeResult *result = script->types.dynamicList;
+    TypeResult *result = script->types->dynamicList;
     while (result) {
         pushedTypes(result->offset)->addType(cx, result->type);
         result = result->next;
     }
 
     if (!script->usesArguments || script->createdArgs)
         return;
 
@@ -3958,17 +3959,17 @@ ScriptAnalysis::analyzeTypes(JSContext *
 
     /*
      * Note: don't check for strict mode code here, even though arguments
      * accesses in such scripts will always be deoptimized. These scripts can
      * have a JSOP_ARGUMENTS in their prologue which the usesArguments check
      * above does not account for. We filter in the interpreter and JITs
      * themselves.
      */
-    if (script->fun->isHeavyweight() || cx->compartment->debugMode) {
+    if (script->function()->isHeavyweight() || cx->compartment->debugMode) {
         MarkArgumentsCreated(cx, script);
         return;
     }
 
     offset = 0;
     while (offset < script->length) {
         Bytecode *code = maybeCode(offset);
         jsbytecode *pc = script->code + offset;
@@ -4136,17 +4137,17 @@ AnalyzeNewScriptProperties(JSContext *cx
         return false;
     }
 
     if (!script->ensureRanInference(cx)) {
         *pbaseobj = NULL;
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
-    ScriptAnalysis *analysis = script->analysis(cx);
+    ScriptAnalysis *analysis = script->analysis();
 
     /*
      * Offset of the last bytecode which popped 'this' and which we have
      * processed. For simplicity, we scan for places where 'this' is pushed
      * and immediately analyze the place where that pushed value is popped.
      * This runs the risk of doing things out of order, if the script looks
      * something like 'this.f  = (this.g = ...)', so we watch and bail out if
      * a 'this' is pushed before the previous 'this' value was popped.
@@ -4500,61 +4501,61 @@ ScriptAnalysis::printTypes(JSContext *cx
             } else {
                 compartment->typeCounts[typeCount-1]++;
             }
         }
     }
 
 #ifdef DEBUG
 
-    if (script->fun)
+    if (script->hasFunction)
         printf("Function");
     else if (script->isCachedEval || script->isUncachedEval)
         printf("Eval");
     else
         printf("Main");
     printf(" #%u %s (line %d):\n", script->id(), script->filename, script->lineno);
 
     printf("locals:");
     printf("\n    return:");
-    script->types.returnTypes()->print(cx);
+    TypeScript::ReturnTypes(script)->print(cx);
     printf("\n    this:");
-    script->types.thisTypes()->print(cx);
-
-    for (unsigned i = 0; script->fun && i < script->fun->nargs; i++) {
+    TypeScript::ThisTypes(script)->print(cx);
+
+    for (unsigned i = 0; script->hasFunction && i < script->function()->nargs; i++) {
         printf("\n    arg%u:", i);
-        script->types.argTypes(i)->print(cx);
+        TypeScript::ArgTypes(script, i)->print(cx);
     }
     for (unsigned i = 0; i < script->nfixed; i++) {
         if (!trackSlot(LocalSlot(script, i))) {
             printf("\n    local%u:", i);
-            script->types.localTypes(i)->print(cx);
+            TypeScript::LocalTypes(script, i)->print(cx);
         }
     }
     for (unsigned i = 0; i < script->bindings.countUpvars(); i++) {
         printf("\n    upvar%u:", i);
-        script->types.upvarTypes(i)->print(cx);
+        TypeScript::UpvarTypes(script, i)->print(cx);
     }
     printf("\n");
 
     for (unsigned offset = 0; offset < script->length; offset++) {
         if (!maybeCode(offset))
             continue;
 
         jsbytecode *pc = script->code + offset;
         UntrapOpcode untrap(cx, script, pc);
 
         PrintBytecode(cx, script, pc);
 
         if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
             continue;
 
         if (js_CodeSpec[*pc].format & JOF_TYPESET) {
-            TypeSet *types = script->types.bytecodeTypes(pc);
-            printf("  typeset %d:", (int) (types - script->types.typeArray));
+            TypeSet *types = script->analysis()->bytecodeTypes(pc);
+            printf("  typeset %d:", (int) (types - script->types->typeArray()));
             types->print(cx);
             printf("\n");
         }
 
         unsigned defCount = GetDefCount(script, offset);
         for (unsigned i = 0; i < defCount; i++) {
             printf("  type %d:", i);
             pushedTypes(offset, i)->print(cx);
@@ -4613,36 +4614,31 @@ MarkIteratorUnknownSlow(JSContext *cx)
 
 void
 TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
                     const CallArgs &args, bool constructing)
 {
     unsigned nargs = callee->getFunctionPrivate()->nargs;
     JSScript *script = callee->getFunctionPrivate()->script();
 
-    if (!script->types.ensureTypeArray(cx))
-        return;
-
-    if (!constructing) {
-        Type type = GetValueType(cx, args.thisv());
-        script->types.setThis(cx, type);
-    }
+    if (!constructing)
+        TypeScript::SetThis(cx, script, args.thisv());
 
     /*
      * Add constraints going up to the minimum of the actual and formal count.
      * If there are more actuals than formals the later values can only be
      * accessed through the arguments object, which is monitored.
      */
     unsigned arg = 0;
     for (; arg < args.argc() && arg < nargs; arg++)
-        script->types.setArgument(cx, arg, args[arg]);
+        TypeScript::SetArgument(cx, script, arg, args[arg]);
 
     /* Watch for fewer actuals than formals to the call. */
     for (; arg < nargs; arg++)
-        script->types.setArgument(cx, arg, UndefinedValue());
+        TypeScript::SetArgument(cx, script, arg, UndefinedValue());
 }
 
 static inline bool
 IsAboutToBeFinalized(JSContext *cx, TypeObjectKey *key)
 {
     /* Mask out the low bit indicating whether this is a type or JS object. */
     return !reinterpret_cast<const gc::Cell *>((jsuword) key & ~1)->isMarked();
 }
@@ -4652,17 +4648,21 @@ TypeDynamicResult(JSContext *cx, JSScrip
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     AutoEnterTypeInference enter(cx);
 
     UntrapOpcode untrap(cx, script, pc);
 
     /* Directly update associated type sets for applicable bytecodes. */
     if (js_CodeSpec[*pc].format & JOF_TYPESET) {
-        TypeSet *types = script->types.bytecodeTypes(pc);
+        if (!script->ensureRanBytecode(cx)) {
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
+        }
+        TypeSet *types = script->analysis()->bytecodeTypes(pc);
         if (!types->hasType(type)) {
             InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
                       script->id(), pc - script->code, TypeString(type));
             types->addType(cx, type);
         }
         return;
     }
 
@@ -4687,38 +4687,38 @@ TypeDynamicResult(JSContext *cx, JSScrip
             /*
              * Just mark the slot's type as holding the new type. This captures
              * the effect if the slot is not being tracked, and if the slot
              * doesn't escape we will update the pushed types below to capture
              * the slot's value after this write.
              */
             uint32 slot = GetBytecodeSlot(script, pc);
             if (slot < TotalSlots(script)) {
-                TypeSet *types = script->types.slotTypes(slot);
+                TypeSet *types = TypeScript::SlotTypes(script, slot);
                 types->addType(cx, type);
             }
             break;
           }
 
           default:;
         }
     }
 
-    if (script->hasAnalysis() && script->analysis(cx)->ranInference()) {
+    if (script->hasAnalysis() && script->analysis()->ranInference()) {
         /*
          * If the pushed set already has this type, we don't need to ensure
          * there is a TypeIntermediate. Either there already is one, or the
          * type could be determined from the script's other input type sets.
          */
-        TypeSet *pushed = script->analysis(cx)->pushedTypes(pc, 0);
+        TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
         if (pushed->hasType(type))
             return;
     } else {
         /* Scan all intermediate types on the script to check for a dupe. */
-        TypeResult *result, **pstart = &script->types.dynamicList, **presult = pstart;
+        TypeResult *result, **pstart = &script->types->dynamicList, **presult = pstart;
         while (*presult) {
             result = *presult;
             if (result->offset == unsigned(pc - script->code) && result->type == type) {
                 if (presult != pstart) {
                     /* Move to the head of the list, maintain LRU order. */
                     *presult = result->next;
                     result->next = *pstart;
                     *pstart = result;
@@ -4732,45 +4732,50 @@ TypeDynamicResult(JSContext *cx, JSScrip
     InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
               script->id(), pc - script->code, TypeString(type));
 
     TypeResult *result = cx->new_<TypeResult>(pc - script->code, type);
     if (!result) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
-    result->next = script->types.dynamicList;
-    script->types.dynamicList = result;
-
-    if (script->hasAnalysis() && script->analysis(cx)->ranInference()) {
-        TypeSet *pushed = script->analysis(cx)->pushedTypes(pc, 0);
+    result->next = script->types->dynamicList;
+    script->types->dynamicList = result;
+
+    if (script->hasAnalysis() && script->analysis()->ranInference()) {
+        TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
         pushed->addType(cx, type);
     }
 
     /* Trigger recompilation of any inline callers. */
-    if (script->fun && !script->fun->hasLazyType())
-        ObjectStateChange(cx, script->fun->type(), false, true);
+    if (script->hasFunction && !script->function()->hasLazyType())
+        ObjectStateChange(cx, script->function()->type(), false, true);
 }
 
 void
 TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
 {
     UntrapOpcode untrap(cx, script, pc);
 
     /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
     if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
         return;
 
+    AutoEnterTypeInference enter(cx);
+
+    if (!script->ensureRanBytecode(cx)) {
+        cx->compartment->types.setPendingNukeTypes(cx);
+        return;
+    }
+
     Type type = GetValueType(cx, rval);
-    TypeSet *types = script->types.bytecodeTypes(pc);
+    TypeSet *types = script->analysis()->bytecodeTypes(pc);
     if (types->hasType(type))
         return;
 
-    AutoEnterTypeInference enter(cx);
-
     InferSpew(ISpewOps, "bytecodeType: #%u:%05u: %s",
               script->id(), pc - script->code, TypeString(type));
     types->addType(cx, type);
 }
 
 } } /* namespace js::types */
 
 /////////////////////////////////////////////////////////////////////
@@ -4849,63 +4854,99 @@ IgnorePushed(const jsbytecode *pc, unsig
         return JSOp(pc[JSOP_GETLOCAL_LENGTH]) == JSOP_POP;
 
       default:
         return false;
     }
 }
 
 bool
-TypeScript::makeTypeArray(JSContext *cx)
+JSScript::makeTypes(JSContext *cx)
 {
-    JS_ASSERT(!typeArray);
+    JS_ASSERT(!types);
+
+    if (!cx->typeInferenceEnabled()) {
+        types = (TypeScript *) cx->calloc_(sizeof(TypeScript));
+        return types != NULL;
+    }
 
     AutoEnterTypeInference enter(cx);
 
-    unsigned count = numTypeSets();
-    typeArray = (TypeSet *) cx->calloc_(sizeof(TypeSet) * count);
-    if (!typeArray) {
+    unsigned count = TypeScript::NumTypeSets(this);
+    types = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(TypeSet) * count));
+    if (!types) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
 #ifdef DEBUG
-    unsigned id = script()->id();
-    for (unsigned i = 0; i < script()->nTypeSets; i++)
+    TypeSet *typeArray = types->typeArray();
+    for (unsigned i = 0; i < nTypeSets; i++)
         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
-                  i, id);
+                  i, id());
+    TypeSet *returnTypes = TypeScript::ReturnTypes(this);
     InferSpew(ISpewOps, "typeSet: %sT%p%s return #%u",
-              InferSpewColor(returnTypes()), returnTypes(), InferSpewColorReset(),
-              id);
+              InferSpewColor(returnTypes), returnTypes, InferSpewColorReset(),
+              id());
+    TypeSet *thisTypes = TypeScript::ThisTypes(this);
     InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
-              InferSpewColor(thisTypes()), thisTypes(), InferSpewColorReset(),
-              id);
-    unsigned nargs = script()->fun ? script()->fun->nargs : 0;
-    for (unsigned i = 0; i < nargs; i++)
+              InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
+              id());
+    unsigned nargs = hasFunction ? function()->nargs : 0;
+    for (unsigned i = 0; i < nargs; i++) {
+        TypeSet *types = TypeScript::ArgTypes(this, i);
         InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u #%u",
-                  InferSpewColor(argTypes(i)), argTypes(i), InferSpewColorReset(),
-                  i, id);
-    for (unsigned i = 0; i < script()->nfixed; i++)
+                  InferSpewColor(types), types, InferSpewColorReset(),
+                  i, id());
+    }
+    for (unsigned i = 0; i < nfixed; i++) {
+        TypeSet *types = TypeScript::LocalTypes(this, i);
         InferSpew(ISpewOps, "typeSet: %sT%p%s local%u #%u",
-                  InferSpewColor(localTypes(i)), localTypes(i), InferSpewColorReset(),
-                  i, id);
-    for (unsigned i = 0; i < script()->bindings.countUpvars(); i++)
+                  InferSpewColor(types), types, InferSpewColorReset(),
+                  i, id());
+    }
+    for (unsigned i = 0; i < bindings.countUpvars(); i++) {
+        TypeSet *types = TypeScript::UpvarTypes(this, i);
         InferSpew(ISpewOps, "typeSet: %sT%p%s upvar%u #%u",
-                  InferSpewColor(upvarTypes(i)), upvarTypes(i), InferSpewColorReset(),
-                  i, id);
+                  InferSpewColor(types), types, InferSpewColorReset(),
+                  i, id());
+    }
 #endif
 
     return true;
 }
 
 bool
+JSScript::makeAnalysis(JSContext *cx)
+{
+    JS_ASSERT(types && !types->analysis);
+
+    AutoEnterAnalysis enter(cx);
+
+    types->analysis = ArenaNew<ScriptAnalysis>(cx->compartment->pool, this);
+
+    if (!types->analysis)
+        return false;
+
+    types->analysis->analyzeBytecode(cx);
+
+    if (types->analysis->OOM()) {
+        types->analysis = NULL;
+        return false;
+    }
+
+    return true;
+}
+
+bool
 JSScript::typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton)
 {
-    this->fun = fun;
+    hasFunction = true;
+    where.fun = fun;
 
     if (!cx->typeInferenceEnabled())
         return true;
 
     char *name = NULL;
 #ifdef DEBUG
     name = (char *) alloca(10);
     JS_snprintf(name, 10, "#%u", id());
@@ -4926,49 +4967,48 @@ JSScript::typeSetFunction(JSContext *cx,
             return false;
 
         fun->setType(type);
         fun->setMap(shape);
 
         type->functionScript = this;
     }
 
-    this->fun = fun;
     return true;
 }
 
 #ifdef DEBUG
 
-void
-TypeScript::checkBytecode(JSContext *cx, jsbytecode *pc, const js::Value *sp)
+/* static */ void
+TypeScript::CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp)
 {
     AutoEnterTypeInference enter(cx);
-    UntrapOpcode untrap(cx, script(), pc);
+    UntrapOpcode untrap(cx, script, pc);
 
     if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
         return;
 
-    if (!script()->hasAnalysis() || !script()->analysis(cx)->ranInference())
+    if (!script->hasAnalysis() || !script->analysis()->ranInference())
         return;
-    ScriptAnalysis *analysis = script()->analysis(cx);
-
-    int defCount = GetDefCount(script(), pc - script()->code);
+    ScriptAnalysis *analysis = script->analysis();
+
+    int defCount = GetDefCount(script, pc - script->code);
 
     for (int i = 0; i < defCount; i++) {
         const js::Value &val = sp[-defCount + i];
         TypeSet *types = analysis->pushedTypes(pc, i);
         if (IgnorePushed(pc, i))
             continue;
 
         Type type = GetValueType(cx, val);
 
         if (!types->hasType(type)) {
             /* Display fine-grained debug information first */
             fprintf(stderr, "Missing type at #%u:%05u pushed %u: %s\n", 
-                    script()->id(), unsigned(pc - script()->code), i, TypeString(type));
+                    script->id(), unsigned(pc - script->code), i, TypeString(type));
             TypeFailure(cx, "Missing type pushed %u: %s", i, TypeString(type));
         }
     }
 }
 
 #endif
 
 /////////////////////////////////////////////////////////////////////
@@ -5423,39 +5463,36 @@ TypeCompartment::~TypeCompartment()
 
     if (objectTypeTable)
         Foreground::delete_(objectTypeTable);
 
     if (allocationSiteTable)
         Foreground::delete_(allocationSiteTable);
 }
 
-void
-TypeScript::sweep(JSContext *cx)
+/* static */ void
+TypeScript::Sweep(JSContext *cx, JSScript *script)
 {
-    JSCompartment *compartment = script()->compartment;
+    JSCompartment *compartment = script->compartment;
     JS_ASSERT(compartment->types.inferenceEnabled);
 
-    if (typeArray) {
-        unsigned num = numTypeSets();
-
-        if (script()->isAboutToBeFinalized(cx)) {
-            /* Release all memory associated with the persistent type sets. */
-            for (unsigned i = 0; i < num; i++)
-                typeArray[i].clearObjects();
-            cx->free_(typeArray);
-            typeArray = NULL;
-        } else {
-            /* Condense all constraints in the persistent type sets. */
-            for (unsigned i = 0; i < num; i++)
-                typeArray[i].sweep(cx, compartment);
-        }
+    unsigned num = NumTypeSets(script);
+    TypeSet *typeArray = script->types->typeArray();
+
+    if (script->isAboutToBeFinalized(cx)) {
+        /* Release all memory associated with the persistent type sets. */
+        for (unsigned i = 0; i < num; i++)
+            typeArray[i].clearObjects();
+    } else {
+        /* Remove constraints and references to dead objects from the persistent type sets. */
+        for (unsigned i = 0; i < num; i++)
+            typeArray[i].sweep(cx, compartment);
     }
 
-    TypeResult **presult = &dynamicList;
+    TypeResult **presult = &script->types->dynamicList;
     while (*presult) {
         TypeResult *result = *presult;
         Type type = result->type;
 
         if (!type.isUnknown() && !type.isAnyObject() && type.isObject() &&
             IsAboutToBeFinalized(cx, type.objectKey())) {
             *presult = result->next;
             cx->delete_(result);
@@ -5464,56 +5501,56 @@ TypeScript::sweep(JSContext *cx)
         }
     }
 
     /*
      * Method JIT code depends on the type inference data which is about to
      * be purged, so purge the jitcode as well.
      */
 #ifdef JS_METHODJIT
-    if (script()->jitNormal)
-        mjit::ReleaseScriptCode(cx, script(), true);
-    if (script()->jitCtor)
-        mjit::ReleaseScriptCode(cx, script(), false);
+    if (script->jitNormal)
+        mjit::ReleaseScriptCode(cx, script, true);
+    if (script->jitCtor)
+        mjit::ReleaseScriptCode(cx, script, false);
 #endif
 }
 
 void
 TypeScript::destroy()
 {
     while (dynamicList) {
         TypeResult *next = dynamicList->next;
         Foreground::delete_(dynamicList);
         dynamicList = next;
     }
-
-    Foreground::free_(typeArray);
 }
 
 size_t
 TypeSet::dynamicSize()
 {
     uint32 count = baseObjectCount();
     if (count >= 2)
         return HashSetCapacity(count) * sizeof(TypeObject *);
     return 0;
 }
 
 static void
 GetScriptMemoryStats(JSScript *script, JSCompartment::TypeInferenceMemoryStats *stats)
 {
-    if (!script->types.typeArray)
+    if (!script->types)
         return;
 
-    unsigned count = script->types.numTypeSets();
-    stats->scriptMain += count * sizeof(TypeSet);
+    unsigned count = TypeScript::NumTypeSets(script);
+    stats->scriptMain += sizeof(TypeScript) + count * sizeof(TypeSet);
+
+    TypeSet *typeArray = script->types->typeArray();
     for (unsigned i = 0; i < count; i++)
-        stats->scriptSets += script->types.typeArray[i].dynamicSize();
-
-    TypeResult *result = script->types.dynamicList;
+        stats->scriptSets += typeArray[i].dynamicSize();
+
+    TypeResult *result = script->types->dynamicList;
     while (result) {
         stats->scriptMain += sizeof(TypeResult);
         result = result->next;
     }
 }
 
 void
 JSCompartment::getTypeInferenceMemoryStats(JSContext *cx, TypeInferenceMemoryStats *stats)
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -46,16 +46,19 @@
 #include "jsarena.h"
 #include "jscell.h"
 #include "jstl.h"
 #include "jsprvtd.h"
 #include "jsvalue.h"
 
 namespace js {
     class CallArgs;
+    namespace analyze {
+        class ScriptAnalysis;
+    }
 }
 
 namespace js {
 namespace types {
 
 /* Forward declarations. */
 class TypeSet;
 struct TypeCallsite;
@@ -875,87 +878,79 @@ struct TypeCallsite
 
     inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
                         bool isNew, unsigned argumentCount);
 };
 
 /* Persistent type information for a script, retained across GCs. */
 struct TypeScript
 {
-    inline JSScript *script();
+    /* Analysis information for the script, cleared on each GC. */
+    analyze::ScriptAnalysis *analysis;
 
-    /* Lazily constructed types of variables and JOF_TYPESET ops in this script. */
-    TypeSet *typeArray;
-    inline unsigned numTypeSets();
+    /* Array of type type sets for variables and JOF_TYPESET ops. */
+    TypeSet *typeArray() { return (TypeSet *) (jsuword(this) + sizeof(TypeScript)); }
 
-    /* Any type objects associated with this script, including initializer objects. */
-    TypeObject *typeObjects;
+    static inline unsigned NumTypeSets(JSScript *script);
 
     /* Dynamic types generated at points within this script. */
     TypeResult *dynamicList;
 
-    /* Make sure there the type array has been constructed. */
-    inline bool ensureTypeArray(JSContext *cx);
-
-    inline TypeSet *bytecodeTypes(const jsbytecode *pc);
-    inline TypeSet *returnTypes();
-    inline TypeSet *thisTypes();
-    inline TypeSet *argTypes(unsigned i);
-    inline TypeSet *localTypes(unsigned i);
-    inline TypeSet *upvarTypes(unsigned i);
+    static inline TypeSet *ReturnTypes(JSScript *script);
+    static inline TypeSet *ThisTypes(JSScript *script);
+    static inline TypeSet *ArgTypes(JSScript *script, unsigned i);
+    static inline TypeSet *LocalTypes(JSScript *script, unsigned i);
+    static inline TypeSet *UpvarTypes(JSScript *script, unsigned i);
 
     /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
-    inline TypeSet *slotTypes(unsigned slot);
-
-  private:
-    bool makeTypeArray(JSContext *cx);
-  public:
+    static inline TypeSet *SlotTypes(JSScript *script, unsigned slot);
 
 #ifdef DEBUG
     /* Check that correct types were inferred for the values pushed by this bytecode. */
-    void checkBytecode(JSContext *cx, jsbytecode *pc, const js::Value *sp);
+    static void CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp);
 #endif
 
     /* Get the default 'new' object for a given standard class, per the script's global. */
-    inline TypeObject *standardType(JSContext *cx, JSProtoKey kind);
+    static inline TypeObject *StandardType(JSContext *cx, JSScript *script, JSProtoKey kind);
 
     /* Get a type object for an allocation site in this script. */
-    inline TypeObject *initObject(JSContext *cx, const jsbytecode *pc, JSProtoKey kind);
+    static inline TypeObject *InitObject(JSContext *cx, JSScript *script, const jsbytecode *pc, JSProtoKey kind);
 
     /*
      * Monitor a bytecode pushing a value which is not accounted for by the
      * inference type constraints, such as integer overflow.
      */
-    inline void monitorOverflow(JSContext *cx, jsbytecode *pc);
-    inline void monitorString(JSContext *cx, jsbytecode *pc);
-    inline void monitorUnknown(JSContext *cx, jsbytecode *pc);
+    static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
+    static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
+    static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
 
     /*
      * Monitor a bytecode pushing any value. This must be called for any opcode
      * which is JOF_TYPESET, and where either the script has not been analyzed
      * by type inference or where the pc has type barriers. For simplicity, we
      * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
      * and only look at barriers when generating JIT code for the script.
      */
-    inline void monitor(JSContext *cx, jsbytecode *pc, const js::Value &val);
+    static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
+                               const js::Value &val);
 
     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
-    inline void monitorAssign(JSContext *cx, jsbytecode *pc,
-                              JSObject *obj, jsid id, const js::Value &val);
+    static inline void MonitorAssign(JSContext *cx, JSScript *script, jsbytecode *pc,
+                                     JSObject *obj, jsid id, const js::Value &val);
 
-    /* Add a type for a variable in this script. */
-    inline void setThis(JSContext *cx, Type type);
-    inline void setThis(JSContext *cx, const js::Value &value);
-    inline void setLocal(JSContext *cx, unsigned local, Type type);
-    inline void setLocal(JSContext *cx, unsigned local, const js::Value &value);
-    inline void setArgument(JSContext *cx, unsigned arg, Type type);
-    inline void setArgument(JSContext *cx, unsigned arg, const js::Value &value);
-    inline void setUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
+    /* Add a type for a variable in a script. */
+    static inline void SetThis(JSContext *cx, JSScript *script, Type type);
+    static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
+    static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type);
+    static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
+    static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
+    static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
+    static inline void SetUpvar(JSContext *cx, JSScript *script, unsigned upvar, const js::Value &value);
 
-    void sweep(JSContext *cx);
+    static void Sweep(JSContext *cx, JSScript *script);
     void destroy();
 };
 
 struct ArrayTableKey;
 typedef HashMap<ArrayTableKey,TypeObject*,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
 
 struct ObjectTableKey;
 struct ObjectTableEntry;
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -285,17 +285,17 @@ GetTypeNewObject(JSContext *cx, JSProtoK
 /* Get a type object for the immediate allocation site within a native. */
 inline TypeObject *
 GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
 {
     if (cx->typeInferenceEnabled()) {
         jsbytecode *pc;
         JSScript *script = cx->stack.currentScript(&pc);
         if (script && script->compartment == cx->compartment)
-            return script->types.initObject(cx, pc, key);
+            return TypeScript::InitObject(cx, script, pc, key);
     }
     return GetTypeNewObject(cx, key);
 }
 
 /*
  * When using a custom iterator within the initialization of a 'for in' loop,
  * mark the iterator values as unknown.
  */
@@ -454,113 +454,73 @@ UseNewTypeAtEntry(JSContext *cx, StackFr
            fp->prev() && fp->prev()->isScriptFrame() &&
            UseNewType(cx, fp->prev()->script(), fp->prev()->pcQuadratic(cx->stack, fp));
 }
 
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
-inline JSScript *
-TypeScript::script()
+/* static */ inline unsigned
+TypeScript::NumTypeSets(JSScript *script)
 {
-    /*
-     * Each TypeScript is embedded as the 'types' field of a JSScript. They
-     * have the same lifetime, the distinction is made for code separation.
-     * Obtain the base pointer of the outer JSScript.
-     */
-    return (JSScript *)((char *)this - offsetof(JSScript, types));
-}
-
-inline unsigned
-TypeScript::numTypeSets()
-{
-    return script()->nTypeSets + analyze::TotalSlots(script()) + script()->bindings.countUpvars();
-}
-
-inline bool
-TypeScript::ensureTypeArray(JSContext *cx)
-{
-    if (typeArray)
-        return true;
-    return makeTypeArray(cx);
+    return script->nTypeSets + analyze::TotalSlots(script) + script->bindings.countUpvars();
 }
 
-inline TypeSet *
-TypeScript::bytecodeTypes(const jsbytecode *pc)
+/* static */ inline TypeSet *
+TypeScript::ReturnTypes(JSScript *script)
 {
-    JS_ASSERT(typeArray);
-
-    JSOp op = JSOp(*pc);
-    JS_ASSERT(op != JSOP_TRAP);
-    JS_ASSERT(js_CodeSpec[op].format & JOF_TYPESET);
-
-    /* All bytecodes with type sets are JOF_ATOM, except JSOP_{GET,CALL}ELEM */
-    const jsbytecode *npc = (op == JSOP_GETELEM || op == JSOP_CALLELEM) ? pc : pc + 2;
-    JS_ASSERT(npc - pc + 3 == js_CodeSpec[op].length);
-
-    uint16 index = GET_UINT16(npc);
-    JS_ASSERT(index < script()->nTypeSets);
-
-    return &typeArray[index];
+    return script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
 }
 
-inline TypeSet *
-TypeScript::returnTypes()
+/* static */ inline TypeSet *
+TypeScript::ThisTypes(JSScript *script)
 {
-    JS_ASSERT(typeArray);
-    return &typeArray[script()->nTypeSets + js::analyze::CalleeSlot()];
-}
-
-inline TypeSet *
-TypeScript::thisTypes()
-{
-    JS_ASSERT(typeArray);
-    return &typeArray[script()->nTypeSets + js::analyze::ThisSlot()];
+    return script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
 }
 
 /*
  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
  * only the initial type of the variable (e.g. passed values for argTypes,
  * or undefined for localTypes) and not types from subsequent assignments.
  */
 
-inline TypeSet *
-TypeScript::argTypes(unsigned i)
+/* static */ inline TypeSet *
+TypeScript::ArgTypes(JSScript *script, unsigned i)
 {
-    JS_ASSERT(typeArray && script()->fun && i < script()->fun->nargs);
-    return &typeArray[script()->nTypeSets + js::analyze::ArgSlot(i)];
+    JS_ASSERT(i < script->function()->nargs);
+    return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
 }
 
-inline TypeSet *
-TypeScript::localTypes(unsigned i)
+/* static */ inline TypeSet *
+TypeScript::LocalTypes(JSScript *script, unsigned i)
 {
-    JS_ASSERT(typeArray && i < script()->nfixed);
-    return &typeArray[script()->nTypeSets + js::analyze::LocalSlot(script(), i)];
+    JS_ASSERT(i < script->nfixed);
+    return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
 }
 
-inline TypeSet *
-TypeScript::upvarTypes(unsigned i)
+/* static */ inline TypeSet *
+TypeScript::UpvarTypes(JSScript *script, unsigned i)
 {
-    JS_ASSERT(typeArray && i < script()->bindings.countUpvars());
-    return &typeArray[script()->nTypeSets + js::analyze::TotalSlots(script()) + i];
+    JS_ASSERT(i < script->bindings.countUpvars());
+    return script->types->typeArray() + script->nTypeSets + js::analyze::TotalSlots(script) + i;
 }
 
-inline TypeSet *
-TypeScript::slotTypes(unsigned slot)
+/* static */ inline TypeSet *
+TypeScript::SlotTypes(JSScript *script, unsigned slot)
 {
-    JS_ASSERT(typeArray && slot < js::analyze::TotalSlots(script()));
-    return &typeArray[script()->nTypeSets + slot];
+    JS_ASSERT(slot < js::analyze::TotalSlots(script));
+    return script->types->typeArray() + script->nTypeSets + slot;
 }
 
-inline TypeObject *
-TypeScript::standardType(JSContext *cx, JSProtoKey key)
+/* static */ inline TypeObject *
+TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
 {
     JSObject *proto;
-    if (!js_GetClassPrototype(cx, script()->global(), key, &proto, NULL))
+    if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
         return NULL;
     return proto->getNewType(cx);
 }
 
 struct AllocationSiteKey {
     JSScript *script;
     uint32 offset : 23;
     JSProtoKey kind : 8;
@@ -576,174 +536,173 @@ struct AllocationSiteKey {
         return (uint32) size_t(key.script->code + key.offset) ^ key.kind;
     }
 
     static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
         return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
     }
 };
 
-inline TypeObject *
-TypeScript::initObject(JSContext *cx, const jsbytecode *pc, JSProtoKey kind)
+/* static */ inline TypeObject *
+TypeScript::InitObject(JSContext *cx, JSScript *script, const jsbytecode *pc, JSProtoKey kind)
 {
     /* :XXX: Limit script->length so we don't need to check the offset up front? */
-    uint32 offset = pc - script()->code;
+    uint32 offset = pc - script->code;
 
-    if (!cx->typeInferenceEnabled() || !script()->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT)
+    if (!cx->typeInferenceEnabled() || !script->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT)
         return GetTypeNewObject(cx, kind);
 
     AllocationSiteKey key;
-    key.script = script();
+    key.script = script;
     key.offset = offset;
-    key.uncached = script()->isUncachedEval;
+    key.uncached = script->isUncachedEval;
     key.kind = kind;
 
     if (!cx->compartment->types.allocationSiteTable)
         return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
 
     AllocationSiteTable::Ptr p = cx->compartment->types.allocationSiteTable->lookup(key);
 
     if (p)
         return p->value;
     return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
 }
 
-inline void
-TypeScript::monitor(JSContext *cx, jsbytecode *pc, const js::Value &rval)
+/* static */ inline void
+TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
 {
     if (cx->typeInferenceEnabled())
-        TypeMonitorResult(cx, script(), pc, rval);
+        TypeMonitorResult(cx, script, pc, rval);
 }
 
-inline void
-TypeScript::monitorOverflow(JSContext *cx, jsbytecode *pc)
+/* static */ inline void
+TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
-        TypeDynamicResult(cx, script(), pc, Type::DoubleType());
+        TypeDynamicResult(cx, script, pc, Type::DoubleType());
 }
 
-inline void
-TypeScript::monitorString(JSContext *cx, jsbytecode *pc)
+/* static */ inline void
+TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
-        TypeDynamicResult(cx, script(), pc, Type::StringType());
+        TypeDynamicResult(cx, script, pc, Type::StringType());
 }
 
-inline void
-TypeScript::monitorUnknown(JSContext *cx, jsbytecode *pc)
+/* static */ inline void
+TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
-        TypeDynamicResult(cx, script(), pc, Type::UnknownType());
+        TypeDynamicResult(cx, script, pc, Type::UnknownType());
 }
 
-inline void
-TypeScript::monitorAssign(JSContext *cx, jsbytecode *pc,
+/* static */ inline void
+TypeScript::MonitorAssign(JSContext *cx, JSScript *script, jsbytecode *pc,
                           JSObject *obj, jsid id, const js::Value &rval)
 {
     if (cx->typeInferenceEnabled() && !obj->hasLazyType()) {
         /*
          * Mark as unknown any object which has had dynamic assignments to
          * non-integer properties at SETELEM opcodes. This avoids making large
          * numbers of type properties for hashmap-style objects. :FIXME: this
          * is too aggressive for things like prototype library initialization.
          */
         uint32 i;
         if (js_IdIsIndex(id, &i))
             return;
         MarkTypeObjectUnknownProperties(cx, obj->type());
     }
 }
 
-inline void
-TypeScript::setThis(JSContext *cx, Type type)
+/* static */ inline void
+TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
 {
-    JS_ASSERT(cx->typeInferenceEnabled());
-    if (!ensureTypeArray(cx))
+    if (!cx->typeInferenceEnabled() || !script->ensureHasTypes(cx))
         return;
 
     /* Analyze the script regardless if -a was used. */
-    bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && !script()->isUncachedEval;
+    bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && !script->isUncachedEval;
 
-    if (!thisTypes()->hasType(type) || analyze) {
+    if (!ThisTypes(script)->hasType(type) || analyze) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setThis #%u: %s",
-                  script()->id(), TypeString(type));
-        thisTypes()->addType(cx, type);
+                  script->id(), TypeString(type));
+        ThisTypes(script)->addType(cx, type);
 
         if (analyze)
-            script()->ensureRanInference(cx);
+            script->ensureRanInference(cx);
     }
 }
 
-inline void
-TypeScript::setThis(JSContext *cx, const js::Value &value)
+/* static */ inline void
+TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
 {
     if (cx->typeInferenceEnabled())
-        setThis(cx, GetValueType(cx, value));
+        SetThis(cx, script, GetValueType(cx, value));
 }
 
-inline void
-TypeScript::setLocal(JSContext *cx, unsigned local, Type type)
+/* static */ inline void
+TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
 {
-    if (!cx->typeInferenceEnabled() || !ensureTypeArray(cx))
+    if (!cx->typeInferenceEnabled() || !script->ensureHasTypes(cx))
         return;
-    if (!localTypes(local)->hasType(type)) {
+    if (!LocalTypes(script, local)->hasType(type)) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
-                  script()->id(), local, TypeString(type));
-        localTypes(local)->addType(cx, type);
+                  script->id(), local, TypeString(type));
+        LocalTypes(script, local)->addType(cx, type);
     }
 }
 
-inline void
-TypeScript::setLocal(JSContext *cx, unsigned local, const js::Value &value)
+/* static */ inline void
+TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         Type type = GetValueType(cx, value);
-        setLocal(cx, local, type);
+        SetLocal(cx, script, local, type);
     }
 }
 
-inline void
-TypeScript::setArgument(JSContext *cx, unsigned arg, Type type)
+/* static */ inline void
+TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
 {
-    if (!cx->typeInferenceEnabled() || !ensureTypeArray(cx))
+    if (!cx->typeInferenceEnabled() || !script->ensureHasTypes(cx))
         return;
-    if (!argTypes(arg)->hasType(type)) {
+    if (!ArgTypes(script, arg)->hasType(type)) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
-                  script()->id(), arg, TypeString(type));
-        argTypes(arg)->addType(cx, type);
+                  script->id(), arg, TypeString(type));
+        ArgTypes(script, arg)->addType(cx, type);
     }
 }
 
-inline void
-TypeScript::setArgument(JSContext *cx, unsigned arg, const js::Value &value)
+/* static */ inline void
+TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         Type type = GetValueType(cx, value);
-        setArgument(cx, arg, type);
+        SetArgument(cx, script, arg, type);
     }
 }
 
-inline void
-TypeScript::setUpvar(JSContext *cx, unsigned upvar, const js::Value &value)
+/* static */ inline void
+TypeScript::SetUpvar(JSContext *cx, JSScript *script, unsigned upvar, const js::Value &value)
 {
-    if (!cx->typeInferenceEnabled() || !ensureTypeArray(cx))
+    if (!cx->typeInferenceEnabled() || !script->ensureHasTypes(cx))
         return;
     Type type = GetValueType(cx, value);
-    if (!upvarTypes(upvar)->hasType(type)) {
+    if (!UpvarTypes(script, upvar)->hasType(type)) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setUpvar #%u %u: %s",
-                  script()->id(), upvar, TypeString(type));
-        upvarTypes(upvar)->addType(cx, type);
+                  script->id(), upvar, TypeString(type));
+        UpvarTypes(script, upvar)->addType(cx, type);
     }
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 inline JSCompartment *
@@ -1330,28 +1289,61 @@ class AutoTypeRooter : private AutoGCRoo
 
 } } /* namespace js::types */
 
 inline bool
 JSScript::isAboutToBeFinalized(JSContext *cx)
 {
     return isCachedEval ||
         (u.object && IsAboutToBeFinalized(cx, u.object)) ||
-        (fun && IsAboutToBeFinalized(cx, fun));
+        (hasFunction && IsAboutToBeFinalized(cx, function()));
+}
+
+inline bool
+JSScript::ensureHasTypes(JSContext *cx)
+{
+    return types || makeTypes(cx);
+}
+
+inline bool
+JSScript::ensureRanBytecode(JSContext *cx)
+{
+    if (!ensureHasTypes(cx))
+        return false;
+    if (!hasAnalysis()) {
+        if (!makeAnalysis(cx))
+            return false;
+    }
+    JS_ASSERT(analysis()->ranBytecode());
+    return true;
 }
 
 inline bool
 JSScript::ensureRanInference(JSContext *cx)
 {
-    js::analyze::ScriptAnalysis *analysis = this->analysis(cx);
-    if (analysis && !analysis->ranInference()) {
+    if (!ensureRanBytecode(cx))
+        return false;
+    if (!analysis()->ranInference()) {
         js::types::AutoEnterTypeInference enter(cx);
-        analysis->analyzeTypes(cx);
+        analysis()->analyzeTypes(cx);
     }
-    return analysis && !analysis->OOM();
+    return !analysis()->OOM();
+}
+
+inline bool
+JSScript::hasAnalysis()
+{
+    return types && types->analysis;
+}
+
+inline js::analyze::ScriptAnalysis *
+JSScript::analysis()
+{
+    JS_ASSERT(hasAnalysis());
+    return types->analysis;
 }
 
 inline void
 js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32 offset, uint32 which,
                                            js::types::Type type)
 {
     js::types::TypeSet *pushed = pushedTypes(offset, which);
     pushed->addType(cx, type);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -529,17 +529,17 @@ js_OnUnknownMethod(JSContext *cx, Value 
 {
     JS_ASSERT(!vp[1].isPrimitive());
 
     JSObject *obj = &vp[1].toObject();
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
     AutoValueRooter tvr(cx);
     if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr()))
         return false;
-    cx->fp()->script()->types.monitorUnknown(cx, cx->regs().pc);
+    TypeScript::MonitorUnknown(cx, cx->fp()->script(), cx->regs().pc);
 
     if (tvr.value().isPrimitive()) {
         vp[0] = tvr.value();
     } else {
 #if JS_HAS_XML_SUPPORT
         /* Extract the function name from function::name qname. */
         if (vp[0].isObject()) {
             obj = &vp[0].toObject();
@@ -751,19 +751,19 @@ InvokeSessionGuard::start(JSContext *cx,
         if (!stack.pushInvokeFrame(cx, args_, INITIAL_NONE, &ifg_))
             return false;
 
         /*
          * Update the 'this' type of the callee according to the value given,
          * along with the types of any missing arguments. These will be the
          * same across all calls.
          */
-        script_->types.setThis(cx, thisv);
+        TypeScript::SetThis(cx, script_, thisv);
         for (unsigned i = argc; i < fun->nargs; i++)
-            script_->types.setArgument(cx, i, types::Type::UndefinedType());
+            TypeScript::SetArgument(cx, script_, i, types::Type::UndefinedType());
 
         StackFrame *fp = ifg_.fp();
 #ifdef JS_METHODJIT
         /* Hoist dynamic checks from RunScript. */
         mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp, mjit::CompileRequest_JIT);
         if (status == mjit::Compile_Error)
             return false;
         if (status != mjit::Compile_Okay)
@@ -925,17 +925,17 @@ Execute(JSContext *cx, JSScript *script,
 
 #if JS_HAS_SHARP_VARS
     if (script->hasSharps && !InitSharpSlots(cx, fp))
         return false;
 #endif
 
     Probes::startExecution(cx, script);
 
-    script->types.setThis(cx, fp->thisValue());
+    TypeScript::SetThis(cx, script, fp->thisValue());
 
     AutoPreserveEnumerators preserve(cx);
     JSBool ok = RunScript(cx, script, fp);
     if (result && ok)
         *result = fp->returnValue();
 
     Probes::stopExecution(cx, script);
 
@@ -1702,17 +1702,17 @@ IteratorNext(JSContext *cx, JSObject *it
  */
 static inline void
 TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRegs &regs)
 {
 #ifdef DEBUG
     if (cx->typeInferenceEnabled() &&
         *regs.pc != JSOP_TRAP &&
         n == analyze::GetBytecodeLength(regs.pc)) {
-        script->types.checkBytecode(cx, regs.pc, regs.sp);
+        TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
     }
 #endif
 }
 
 namespace js {
 
 JS_REQUIRES_STACK JS_NEVER_INLINE bool
 Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
@@ -2078,20 +2078,16 @@ Interpret(JSContext *cx, StackFrame *ent
     } else if (TRACE_RECORDER(cx)) {
         AbortRecording(cx, "attempt to reenter interpreter while recording");
     }
 
     if (regs.fp()->hasImacropc())
         atoms = rt->atomState.commonAtomsStart();
 #endif
 
-    /* Any script we interpret needs to have its type sets filled in. */
-    if (cx->typeInferenceEnabled() && !script->types.ensureTypeArray(cx))
-        goto error;
-
     /* Don't call the script prologue if executing between Method and Trace JIT. */
     if (interpMode == JSINTERP_NORMAL) {
         StackFrame *fp = regs.fp();
         JS_ASSERT_IF(!fp->isGeneratorFrame(), regs.pc == script->code);
         if (!ScriptPrologueOrGeneratorResume(cx, fp, UseNewTypeAtEntry(cx, fp)))
             goto error;
     }
 
@@ -2428,17 +2424,17 @@ BEGIN_CASE(JSOP_STOP)
         RESTORE_INTERP_VARS();
 
         /* Resume execution in the calling frame. */
         RESET_USE_METHODJIT();
         if (JS_LIKELY(interpReturnOK)) {
             JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length
                       == JSOP_CALL_LENGTH);
             TRACE_0(LeaveFrame);
-            script->types.monitor(cx, regs.pc, regs.sp[-1]);
+            TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 
             op = JSOp(*regs.pc);
             len = JSOP_CALL_LENGTH;
 
             if (shiftResult) {
                 regs.sp[-2] = regs.sp[-1];
                 regs.sp--;
             }
@@ -3035,43 +3031,43 @@ BEGIN_CASE(JSOP_URSH)
     int32_t j;
     if (!ValueToECMAInt32(cx, regs.sp[-1], &j))
         goto error;
 
     u >>= (j & 31);
 
     regs.sp--;
     if (!regs.sp[-1].setNumber(uint32(u)))
-        script->types.monitorOverflow(cx, regs.pc);
+        TypeScript::MonitorOverflow(cx, script, regs.pc);
 }
 END_CASE(JSOP_URSH)
 
 BEGIN_CASE(JSOP_ADD)
 {
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
 
     if (lval.isInt32() && rval.isInt32()) {
         int32_t l = lval.toInt32(), r = rval.toInt32();
         int32_t sum = l + r;
         if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
             regs.sp[-2].setDouble(double(l) + double(r));
-            script->types.monitorOverflow(cx, regs.pc);
+            TypeScript::MonitorOverflow(cx, script, regs.pc);
         } else {
             regs.sp[-2].setInt32(sum);
         }
         regs.sp--;
     } else
 #if JS_HAS_XML_SUPPORT
     if (IsXML(lval) && IsXML(rval)) {
         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
             goto error;
         regs.sp[-2] = rval;
         regs.sp--;
-        script->types.monitorUnknown(cx, regs.pc);
+        TypeScript::MonitorUnknown(cx, script, regs.pc);
     } else
 #endif
     {
         /*
          * If either operand is an object, any non-integer result must be
          * reported to inference.
          */
         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
@@ -3098,27 +3094,27 @@ BEGIN_CASE(JSOP_ADD)
                 if (!rstr)
                     goto error;
                 regs.sp[-1].setString(rstr);
             }
             JSString *str = js_ConcatStrings(cx, lstr, rstr);
             if (!str)
                 goto error;
             if (lIsObject || rIsObject)
-                script->types.monitorString(cx, regs.pc);
+                TypeScript::MonitorString(cx, script, regs.pc);
             regs.sp[-2].setString(str);
             regs.sp--;
         } else {
             double l, r;
             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
                 goto error;
             l += r;
             if (!regs.sp[-2].setNumber(l) &&
                 (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
-                script->types.monitorOverflow(cx, regs.pc);
+                TypeScript::MonitorOverflow(cx, script, regs.pc);
             }
             regs.sp--;
         }
     }
 }
 END_CASE(JSOP_ADD)
 
 #define BINARY_OP(OP)                                                         \
@@ -3127,17 +3123,17 @@ END_CASE(JSOP_ADD)
         Value lval = regs.sp[-2];                                             \
         double d1, d2;                                                        \
         if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2))             \
             goto error;                                                       \
         double d = d1 OP d2;                                                  \
         regs.sp--;                                                            \
         if (!regs.sp[-1].setNumber(d) &&                                      \
             !(lval.isDouble() || rval.isDouble())) {                          \
-            script->types.monitorOverflow(cx, regs.pc);                         \
+            TypeScript::MonitorOverflow(cx, script, regs.pc);                 \
         }                                                                     \
     JS_END_MACRO
 
 BEGIN_CASE(JSOP_SUB)
     BINARY_OP(-);
 END_CASE(JSOP_SUB)
 
 BEGIN_CASE(JSOP_MUL)
@@ -3164,22 +3160,22 @@ BEGIN_CASE(JSOP_DIV)
 #endif
         if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
             vp = &rt->NaNValue;
         else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
             vp = &rt->negativeInfinityValue;
         else
             vp = &rt->positiveInfinityValue;
         regs.sp[-1] = *vp;
-        script->types.monitorOverflow(cx, regs.pc);
+        TypeScript::MonitorOverflow(cx, script, regs.pc);
     } else {
         d1 /= d2;
         if (!regs.sp[-1].setNumber(d1) &&
             !(lval.isDouble() || rval.isDouble())) {
-            script->types.monitorOverflow(cx, regs.pc);
+            TypeScript::MonitorOverflow(cx, script, regs.pc);
         }
     }
 }
 END_CASE(JSOP_DIV)
 
 BEGIN_CASE(JSOP_MOD)
 {
     Value &lref = regs.sp[-2];
@@ -3196,17 +3192,17 @@ BEGIN_CASE(JSOP_MOD)
             goto error;
         regs.sp--;
         if (d2 == 0) {
             regs.sp[-1].setDouble(js_NaN);
         } else {
             d1 = js_fmod(d1, d2);
             regs.sp[-1].setDouble(d1);
         }
-        script->types.monitorOverflow(cx, regs.pc);
+        TypeScript::MonitorOverflow(cx, script, regs.pc);
     }
 }
 END_CASE(JSOP_MOD)
 
 BEGIN_CASE(JSOP_NOT)
 {
     Value *_;
     bool cond;
@@ -3238,26 +3234,26 @@ BEGIN_CASE(JSOP_NEG)
         i = -i;
         regs.sp[-1].setInt32(i);
     } else {
         double d;
         if (!ToNumber(cx, regs.sp[-1], &d))
             goto error;
         d = -d;
         if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
-            script->types.monitorOverflow(cx, regs.pc);
+            TypeScript::MonitorOverflow(cx, script, regs.pc);
     }
 }
 END_CASE(JSOP_NEG)
 
 BEGIN_CASE(JSOP_POS)
     if (!ToNumber(cx, &regs.sp[-1]))
         goto error;
     if (!regs.sp[-1].isInt32())
-        script->types.monitorOverflow(cx, regs.pc);
+        TypeScript::MonitorOverflow(cx, script, regs.pc);
 END_CASE(JSOP_POS)
 
 BEGIN_CASE(JSOP_DELNAME)
 {
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj, *obj2;
@@ -3320,17 +3316,17 @@ BEGIN_CASE(JSOP_TOID)
      */
     JSObject *obj;
     FETCH_OBJECT(cx, -2, obj);
 
     jsid id;
     FETCH_ELEMENT_ID(obj, -1, id);
 
     if (!regs.sp[-1].isInt32())
-        script->types.monitorUnknown(cx, regs.pc);
+        TypeScript::MonitorUnknown(cx, script, regs.pc);
 }
 END_CASE(JSOP_TOID)
 
 BEGIN_CASE(JSOP_TYPEOFEXPR)
 BEGIN_CASE(JSOP_TYPEOF)
 {
     const Value &ref = regs.sp[-1];
     JSType type = JS_TypeOfValue(cx, Jsvalify(ref));
@@ -3557,17 +3553,17 @@ BEGIN_CASE(JSOP_LOCALINC)
         vp->getInt32Ref() = tmp + incr;
         JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length);
         SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0);
         PUSH_INT32(tmp + incr2);
     } else {
         PUSH_COPY(*vp);
         if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
             goto error;
-        script->types.monitorOverflow(cx, regs.pc);
+        TypeScript::MonitorOverflow(cx, script, regs.pc);
     }
     len = JSOP_INCARG_LENGTH;
     JS_ASSERT(len == js_CodeSpec[op].length);
     DO_NEXT_OP(len);
 }
 
 BEGIN_CASE(JSOP_THIS)
     if (!ComputeThis(cx, regs.fp()))
@@ -3670,17 +3666,17 @@ BEGIN_CASE(JSOP_LENGTH)
                                     ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                                     : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
                                     &rval)
             : !obj->getProperty(cx, id, &rval)) {
             goto error;
         }
     } while (0);
 
-    script->types.monitor(cx, regs.pc, rval);
+    TypeScript::Monitor(cx, script, regs.pc, rval);
 
     regs.sp[-1] = rval;
     assertSameCompartment(cx, regs.sp[-1]);
 }
 END_CASE(JSOP_GETPROP)
 
 BEGIN_CASE(JSOP_CALLPROP)
 {
@@ -3765,17 +3761,17 @@ BEGIN_CASE(JSOP_CALLPROP)
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         LOAD_ATOM(0, atom);
         regs.sp[-2].setString(atom);
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             goto error;
     }
 #endif
-    script->types.monitor(cx, regs.pc, rval);
+    TypeScript::Monitor(cx, script, regs.pc, rval);
 }
 END_CASE(JSOP_CALLPROP)
 
 BEGIN_CASE(JSOP_UNBRAND)
     JS_ASSERT(regs.sp - regs.fp()->slots() >= 1);
     regs.sp[-1].toObject().unbrand(cx);
 END_CASE(JSOP_UNBRAND)
 
@@ -3943,27 +3939,27 @@ BEGIN_CASE(JSOP_GETELEM)
         JSString *str = lref.toString();
         int32_t i = rref.toInt32();
         if (size_t(i) < str->length()) {
             str = JSAtom::getUnitStringForElement(cx, str, size_t(i));
             if (!str)
                 goto error;
             regs.sp--;
             regs.sp[-1].setString(str);
-            script->types.monitor(cx, regs.pc, regs.sp[-1]);
+            TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
             len = JSOP_GETELEM_LENGTH;
             DO_NEXT_OP(len);
         }
     }
 
     if (lref.isMagic(JS_LAZY_ARGUMENTS)) {
         if (rref.isInt32() && size_t(rref.toInt32()) < regs.fp()->numActualArgs()) {
             regs.sp--;
             regs.sp[-1] = regs.fp()->canonicalActualArg(rref.toInt32());
-            script->types.monitor(cx, regs.pc, regs.sp[-1]);
+            TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
             len = JSOP_GETELEM_LENGTH;
             DO_NEXT_OP(len);
         }
         MarkArgumentsCreated(cx, script);
         JS_ASSERT(!lref.isMagic(JS_LAZY_ARGUMENTS));
     }
 
     JSObject *obj;
@@ -4009,23 +4005,23 @@ BEGIN_CASE(JSOP_GETELEM)
         }
     }
 
     if (!obj->getProperty(cx, id, &rval))
         goto error;
     copyFrom = &rval;
 
     if (!JSID_IS_INT(id))
-        script->types.monitorUnknown(cx, regs.pc);
+        TypeScript::MonitorUnknown(cx, script, regs.pc);
 
   end_getelem:
     regs.sp--;
     regs.sp[-1] = *copyFrom;
     assertSameCompartment(cx, regs.sp[-1]);
-    script->types.monitor(cx, regs.pc, regs.sp[-1]);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 }
 END_CASE(JSOP_GETELEM)
 
 BEGIN_CASE(JSOP_CALLELEM)
 {
     /* Find the object on which to look for |this|'s properties. */
     Value thisv = regs.sp[-2];
     JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2);
@@ -4049,30 +4045,30 @@ BEGIN_CASE(JSOP_CALLELEM)
             goto error;
     } else
 #endif
     {
         regs.sp[-1] = thisv;
     }
 
     if (!JSID_IS_INT(id))
-        script->types.monitorUnknown(cx, regs.pc);
-    script->types.monitor(cx, regs.pc, regs.sp[-2]);
+        TypeScript::MonitorUnknown(cx, script, regs.pc);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-2]);
 }
 END_CASE(JSOP_CALLELEM)
 
 BEGIN_CASE(JSOP_SETELEM)
 BEGIN_CASE(JSOP_SETHOLE)
 {
     JSObject *obj;
     FETCH_OBJECT(cx, -3, obj);
     jsid id;
     FETCH_ELEMENT_ID(obj, -2, id);
     Value rval;
-    script->types.monitorAssign(cx, regs.pc, obj, id, regs.sp[-1]);
+    TypeScript::MonitorAssign(cx, script, regs.pc, obj, id, regs.sp[-1]);
     do {
         if (obj->isDenseArray() && JSID_IS_INT(id)) {
             jsuint length = obj->getDenseArrayInitializedLength();
             jsint i = JSID_TO_INT(id);
             if ((jsuint)i < length) {
                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
                     if (js_PrototypeHasIndexedProperties(cx, obj))
                         break;
@@ -4115,17 +4111,17 @@ BEGIN_CASE(JSOP_EVAL)
         if (!DirectEval(cx, args))
             goto error;
     } else {
         if (!Invoke(cx, args))
             goto error;
     }
     CHECK_INTERRUPT_HANDLER();
     regs.sp = args.spAfterCall();
-    script->types.monitor(cx, regs.pc, regs.sp[-1]);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 BEGIN_CASE(JSOP_NEW)
 BEGIN_CASE(JSOP_CALL)
 BEGIN_CASE(JSOP_FUNCALL)
 BEGIN_CASE(JSOP_FUNAPPLY)
 {
@@ -4142,17 +4138,17 @@ BEGIN_CASE(JSOP_FUNAPPLY)
         if (construct) {
             if (!InvokeConstructor(cx, args))
                 goto error;
         } else {
             if (!Invoke(cx, args))
                 goto error;
         }
         regs.sp = args.spAfterCall();
-        script->types.monitor(cx, regs.pc, regs.sp[-1]);
+        TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
         CHECK_INTERRUPT_HANDLER();
         TRACE_0(NativeCallComplete);
         len = JSOP_CALL_LENGTH;
         DO_NEXT_OP(len);
     }
 
     TypeMonitorCall(cx, args, construct);
 
@@ -4243,17 +4239,17 @@ BEGIN_CASE(JSOP_CALLNAME)
             PUSH_COPY(obj2->nativeGetSlot(slot));
         } else {
             JS_ASSERT(entry->vword.isShape());
             shape = entry->vword.toShape();
             NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval);
             PUSH_COPY(rval);
         }
 
-        script->types.monitor(cx, regs.pc, regs.sp[-1]);
+        TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 
         JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj));
         if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
             PUSH_IMPLICIT_THIS(cx, obj, regs.sp[-1]);
         len = JSOP_NAME_LENGTH;
         DO_NEXT_OP(len);
     }
 
@@ -4261,17 +4257,17 @@ BEGIN_CASE(JSOP_CALLNAME)
     JSProperty *prop;
     if (!js_FindPropertyHelper(cx, id, true, global, &obj, &obj2, &prop))
         goto error;
     if (!prop) {
         /* Kludge to allow (typeof foo == "undefined") tests. */
         JSOp op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH);
         if (op2 == JSOP_TYPEOF) {
             PUSH_UNDEFINED();
-            script->types.monitor(cx, regs.pc, regs.sp[-1]);
+            TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
             len = JSOP_NAME_LENGTH;
             DO_NEXT_OP(len);
         }
         atomNotDefined = atom;
         goto atom_not_defined;
     }
 
     /* Take the slow path if prop was not found in a native object. */
@@ -4282,17 +4278,17 @@ BEGIN_CASE(JSOP_CALLNAME)
         shape = (Shape *)prop;
         JSObject *normalized = obj;
         if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, normalized);
         NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval);
     }
 
     PUSH_COPY(rval);
-    script->types.monitor(cx, regs.pc, rval);
+    TypeScript::Monitor(cx, script, regs.pc, rval);
 
     /* obj must be on the scope chain, thus not a function. */
     if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
         PUSH_IMPLICIT_THIS(cx, obj, rval);
 }
 END_CASE(JSOP_NAME)
 
 BEGIN_CASE(JSOP_UINT16)
@@ -4692,17 +4688,17 @@ END_CASE(JSOP_GETFCSLOT)
 BEGIN_CASE(JSOP_GETGLOBAL)
 BEGIN_CASE(JSOP_CALLGLOBAL)
 {
     uint32 slot = GET_SLOTNO(regs.pc);
     slot = script->getGlobalSlot(slot);
     JSObject *obj = regs.fp()->scopeChain().getGlobal();
     JS_ASSERT(obj->containsSlot(slot));
     PUSH_COPY(obj->getSlot(slot));
-    script->types.monitor(cx, regs.pc, regs.sp[-1]);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
     if (op == JSOP_CALLGLOBAL)
         PUSH_UNDEFINED();
 }
 END_CASE(JSOP_GETGLOBAL)
 
 BEGIN_CASE(JSOP_DEFCONST)
 BEGIN_CASE(JSOP_DEFVAR)
 {
@@ -5198,17 +5194,17 @@ BEGIN_CASE(JSOP_NEWINIT)
     } else {
         gc::FinalizeKind kind = GuessObjectGCKind(0, false);
         obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
     }
 
     if (!obj)
         goto error;
 
-    TypeObject *type = script->types.initObject(cx, regs.pc, (JSProtoKey) i);
+    TypeObject *type = TypeScript::InitObject(cx, script, regs.pc, (JSProtoKey) i);
     if (!type)
         goto error;
     if (i == JSProto_Array) {
         obj->setType(type);
     } else {
         if (!obj->setTypeAndEmptyShape(cx, type))
             goto error;
     }
@@ -5220,32 +5216,32 @@ END_CASE(JSOP_NEWINIT)
 
 BEGIN_CASE(JSOP_NEWARRAY)
 {
     unsigned count = GET_UINT24(regs.pc);
     JSObject *obj = NewDenseAllocatedArray(cx, count);
     if (!obj)
         goto error;
 
-    TypeObject *type = script->types.initObject(cx, regs.pc, JSProto_Array);
+    TypeObject *type = TypeScript::InitObject(cx, script, regs.pc, JSProto_Array);
     if (!type)
         goto error;
     obj->setType(type);
 
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWARRAY)
 
 BEGIN_CASE(JSOP_NEWOBJECT)
 {
     JSObject *baseobj;
     LOAD_OBJECT(0, baseobj);
 
-    TypeObject *type = script->types.initObject(cx, regs.pc, JSProto_Object);
+    TypeObject *type = TypeScript::InitObject(cx, script, regs.pc, JSProto_Object);
     if (!type)
         goto error;
 
     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
     if (!obj)
         goto error;
 
     PUSH_OBJECT(*obj);
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -127,17 +127,17 @@ InvokeSessionGuard::invoke(JSContext *cx
     if (!optimized())
         return Invoke(cx, args_);
 
     /*
      * Update the types of each argument. The 'this' type and missing argument
      * types were handled when the invoke session was created.
      */
     for (unsigned i = 0; i < Min(argc(), nformals_); i++)
-        script_->types.setArgument(cx, i, (*this)[i]);
+        types::TypeScript::SetArgument(cx, script_, i, (*this)[i]);
 
 #ifdef JS_METHODJIT
     mjit::JITScript *jit = script_->getJIT(false /* !constructing */);
     if (!jit) {
         /* Watch in case the code was thrown away due a recompile. */
         mjit::CompileStatus status = mjit::TryCompile(cx, ifg_.fp());
         if (status == mjit::Compile_Error)
             return false;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2937,17 +2937,17 @@ js_CreateThisForFunctionWithProto(JSCont
             return NULL;
         res = CreateThisForFunctionWithType(cx, type, callee->getParent());
     } else {
         gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
         res = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), kind);
     }
 
     if (res && cx->typeInferenceEnabled())
-        calleeScript->types.setThis(cx, types::Type::ObjectType(res));
+        TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(res));
 
     return res;
 }
 
 JSObject *
 js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType)
 {
     Value protov;
@@ -2968,17 +2968,17 @@ js_CreateThisForFunction(JSContext *cx, 
          * Reshape the object and give it a (lazily instantiated) singleton
          * type before passing it as the 'this' value for the call.
          */
         obj->clear(cx);
         if (!obj->setSingletonType(cx))
             return NULL;
 
         JSScript *calleeScript = callee->getFunctionPrivate()->script();
-        calleeScript->types.setThis(cx, types::Type::ObjectType(obj));
+        TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(obj));
     }
 
     return obj;
 }
 
 #ifdef JS_TRACER
 
 JSObject* FASTCALL
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -137,18 +137,17 @@ typedef enum JSOp {
                                      besides the slots opcode uses */
 #define JOF_TMPSLOT_SHIFT 22
 #define JOF_TMPSLOT_MASK  (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT)
 
 #define JOF_SHARPSLOT    (1U<<24) /* first immediate is uint16 stack slot no.
                                      that needs fixup when in global code (see
                                      Compiler::compileScript) */
 #define JOF_GNAME        (1U<<25) /* predicted global name */
-#define JOF_TYPESET      (1U<<26) /* has a trailing 2 byte immediate indexing
-                                     the set of observed types */
+#define JOF_TYPESET      (1U<<26) /* has an entry in a script's type sets */
 #define JOF_DECOMPOSE    (1U<<27) /* followed by an equivalent decomposed
                                    * version of the opcode */
 
 /* Shorthands for type from format and type from opcode. */
 #define JOF_TYPE(fmt)   ((fmt) & JOF_TYPEMASK)
 #define JOF_OPTYPE(op)  JOF_TYPE(js_CodeSpec[op].format)
 
 /* Shorthands for mode from format and mode from opcode. */
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -167,23 +167,23 @@ OPDEF(JSOP_DECPROP,   45, "decprop",    
 OPDEF(JSOP_DECELEM,   46, "decelem",    NULL,         2,  2,  1, 15,  JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_TMPSLOT2|JOF_DECOMPOSE)
 OPDEF(JSOP_NAMEINC,   47, "nameinc",    NULL,         4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_PROPINC,   48, "propinc",    NULL,         4,  1,  1, 15,  JOF_ATOM|JOF_PROP|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_ELEMINC,   49, "eleminc",    NULL,         2,  2,  1, 15,  JOF_BYTE |JOF_ELEM|JOF_INC|JOF_POST|JOF_TMPSLOT2|JOF_DECOMPOSE)
 OPDEF(JSOP_NAMEDEC,   50, "namedec",    NULL,         4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_PROPDEC,   51, "propdec",    NULL,         4,  1,  1, 15,  JOF_ATOM|JOF_PROP|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_ELEMDEC,   52, "elemdec",    NULL,         2,  2,  1, 15,  JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_POST|JOF_TMPSLOT2|JOF_DECOMPOSE)
 
-OPDEF(JSOP_GETPROP,   53, "getprop",    NULL,         5,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
+OPDEF(JSOP_GETPROP,   53, "getprop",    NULL,         3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
 OPDEF(JSOP_SETPROP,   54, "setprop",    NULL,         3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_GETELEM,   55, "getelem",    NULL,         3,  2,  1, 18,  JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC)
+OPDEF(JSOP_GETELEM,   55, "getelem",    NULL,         1,  2,  1, 18,  JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC)
 OPDEF(JSOP_SETELEM,   56, "setelem",    NULL,         1,  3,  1,  3,  JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_CALLNAME,  57, "callname",   NULL,         5,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_CALLOP)
-OPDEF(JSOP_CALL,      58, "call",       NULL,         5, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
-OPDEF(JSOP_NAME,      59, "name",       NULL,         5,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET)
+OPDEF(JSOP_CALLNAME,  57, "callname",   NULL,         3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_CALLOP)
+OPDEF(JSOP_CALL,      58, "call",       NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
+OPDEF(JSOP_NAME,      59, "name",       NULL,         3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET)
 OPDEF(JSOP_DOUBLE,    60, "double",     NULL,         3,  0,  1, 16,  JOF_ATOM)
 OPDEF(JSOP_STRING,    61, "string",     NULL,         3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_ZERO,      62, "zero",       "0",          1,  0,  1, 16,  JOF_BYTE)
 OPDEF(JSOP_ONE,       63, "one",        "1",          1,  0,  1, 16,  JOF_BYTE)
 OPDEF(JSOP_NULL,      64, js_null_str,  js_null_str,  1,  0,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_THIS,      65, js_this_str,  js_this_str,  1,  0,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_FALSE,     66, js_false_str, js_false_str, 1,  0,  1, 19,  JOF_BYTE)
 OPDEF(JSOP_TRUE,      67, js_true_str,  js_true_str,  1,  0,  1, 19,  JOF_BYTE)
@@ -216,26 +216,26 @@ OPDEF(JSOP_SETCALL,   74, "setcall",    
  * JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator
  * for temporary GC rooting.
  */
 OPDEF(JSOP_ITER,      75, "iter",       NULL,         2,  1,  1,  0,  JOF_UINT8)
 OPDEF(JSOP_MOREITER,  76, "moreiter",   NULL,         1,  1,  2,  0,  JOF_BYTE)
 OPDEF(JSOP_ITERNEXT,  77, "iternext",   "<next>",     2,  0,  1,  0,  JOF_UINT8)
 OPDEF(JSOP_ENDITER,   78, "enditer",    NULL,         1,  1,  0,  0,  JOF_BYTE)
 
-OPDEF(JSOP_FUNAPPLY,  79, "funapply",   NULL,         5, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
+OPDEF(JSOP_FUNAPPLY,  79, "funapply",   NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 /* Push object literal: either an XML object or initialiser object. */
 OPDEF(JSOP_OBJECT,    80, "object",     NULL,         3,  0,  1, 19,  JOF_OBJECT)
 
 /* Pop value and discard it. */
 OPDEF(JSOP_POP,       81, "pop",        NULL,         1,  1,  0,  2,  JOF_BYTE)
 
 /* Call a function as a constructor; operand is argc. */
-OPDEF(JSOP_NEW,       82, js_new_str,   NULL,         5, -1,  1, 17,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
+OPDEF(JSOP_NEW,       82, js_new_str,   NULL,         3, -1,  1, 17,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 /* Trap into debugger for breakpoint, etc. */
 OPDEF(JSOP_TRAP,      83, "trap",       NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /* Fast get/set ops for function arguments and local variables. */
 OPDEF(JSOP_GETARG,    84, "getarg",     NULL,         3,  0,  1, 19,  JOF_QARG |JOF_NAME)
 OPDEF(JSOP_SETARG,    85, "setarg",     NULL,         3,  1,  1,  3,  JOF_QARG |JOF_NAME|JOF_SET)
 OPDEF(JSOP_GETLOCAL,  86,"getlocal",    NULL,         3,  0,  1, 19,  JOF_LOCAL|JOF_NAME)
@@ -270,21 +270,21 @@ OPDEF(JSOP_ARGDEC,   100, "argdec",     
 OPDEF(JSOP_INCLOCAL,  101,"inclocal",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_INC|JOF_TMPSLOT3)
 OPDEF(JSOP_DECLOCAL,  102,"declocal",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT3)
 OPDEF(JSOP_LOCALINC,  103,"localinc",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3)
 OPDEF(JSOP_LOCALDEC,  104,"localdec",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3)
 
 OPDEF(JSOP_IMACOP,    105,"imacop",     NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /* Static binding for globals. */
-OPDEF(JSOP_GETGLOBAL, 106,"getglobal",  NULL,         5,  0,  1, 19,  JOF_GLOBAL|JOF_NAME|JOF_TYPESET)
-OPDEF(JSOP_CALLGLOBAL,107,"callglobal", NULL,         5,  0,  2, 19,  JOF_GLOBAL|JOF_NAME|JOF_TYPESET|JOF_CALLOP)
+OPDEF(JSOP_GETGLOBAL, 106,"getglobal",  NULL,         3,  0,  1, 19,  JOF_GLOBAL|JOF_NAME|JOF_TYPESET)
+OPDEF(JSOP_CALLGLOBAL,107,"callglobal", NULL,         3,  0,  2, 19,  JOF_GLOBAL|JOF_NAME|JOF_TYPESET|JOF_CALLOP)
 
 /* Like JSOP_FUNAPPLY but for f.call instead of f.apply. */
-OPDEF(JSOP_FUNCALL,   108,"funcall",    NULL,         5, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
+OPDEF(JSOP_FUNCALL,   108,"funcall",    NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 /* This opcode stores an index that is unique to the given loop. */
 OPDEF(JSOP_TRACE,     109,"trace",      NULL,         3,  0,  0,  0,  JOF_UINT16)
 
 /* ECMA-compliant assignment ops. */
 OPDEF(JSOP_BINDNAME,  110,"bindname",   NULL,         3,  0,  1,  0,  JOF_ATOM|JOF_NAME|JOF_SET)
 OPDEF(JSOP_SETNAME,   111,"setname",    NULL,         3,  2,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING)
 
@@ -315,17 +315,17 @@ OPDEF(JSOP_LINENO,    119,"lineno",     
  */
 OPDEF(JSOP_CONDSWITCH,120,"condswitch", NULL,         1,  0,  0,  0,  JOF_BYTE|JOF_PARENHEAD)
 OPDEF(JSOP_CASE,      121,"case",       NULL,         3,  2,  1,  0,  JOF_JUMP|JOF_TMPSLOT2)
 OPDEF(JSOP_DEFAULT,   122,"default",    NULL,         3,  1,  0,  0,  JOF_JUMP)
 
 /*
  * ECMA-compliant call to eval op
  */
-OPDEF(JSOP_EVAL,      123,"eval",       NULL,         5, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
+OPDEF(JSOP_EVAL,      123,"eval",       NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 /*
  * ECMA-compliant helper for 'for (x[i] in o)' loops.
  */
 OPDEF(JSOP_ENUMELEM,  124,"enumelem",   NULL,         1,  3,  0,  3,  JOF_BYTE |JOF_SET|JOF_TMPSLOT)
 
 /*
  * Getter and setter prefix bytecodes.  These modify the next bytecode, either
@@ -407,17 +407,17 @@ OPDEF(JSOP_BACKPATCH_POP, 152,"backpatch
 /* Set pending exception from the stack, to trigger rethrow. */
 OPDEF(JSOP_THROWING,      153,"throwing", NULL,       1,  1,  0,  0,  JOF_BYTE)
 
 /* Set and get return value pseudo-register in stack frame. */
 OPDEF(JSOP_SETRVAL,       154,"setrval",  NULL,       1,  1,  0,  2,  JOF_BYTE)
 OPDEF(JSOP_RETRVAL,       155,"retrval",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 
 /* Free variable references that must either be found on the global or a ReferenceError */
-OPDEF(JSOP_GETGNAME,      156,"getgname",  NULL,       5,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME)
+OPDEF(JSOP_GETGNAME,      156,"getgname",  NULL,       3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME)
 OPDEF(JSOP_SETGNAME,      157,"setgname",  NULL,       3,  2,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME)
 OPDEF(JSOP_INCGNAME,      158,"incgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 OPDEF(JSOP_DECGNAME,      159,"decgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 OPDEF(JSOP_GNAMEINC,      160,"gnameinc",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 OPDEF(JSOP_GNAMEDEC,      161,"gnamedec",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 
 /* Regular expression literal requiring special "fork on exec" handling. */
 OPDEF(JSOP_REGEXP,        162,"regexp",   NULL,       3,  0,  1, 19,  JOF_REGEXP)
@@ -443,17 +443,17 @@ OPDEF(JSOP_TOXMLLIST,     179,"toxmllist
 OPDEF(JSOP_XMLTAGEXPR,    180,"xmltagexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_XMLELTEXPR,    181,"xmleltexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_NOTRACE,       182,"notrace",    NULL,     3,  0,  0,  0,  JOF_UINT16)
 OPDEF(JSOP_XMLCDATA,      183,"xmlcdata",   NULL,     3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_XMLCOMMENT,    184,"xmlcomment", NULL,     3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_XMLPI,         185,"xmlpi",      NULL,     3,  1,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_DELDESC,       186,"deldesc",    NULL,     1,  2,  1, 15,  JOF_BYTE|JOF_ELEM|JOF_DEL)
 
-OPDEF(JSOP_CALLPROP,      187,"callprop",   NULL,     5,  1,  2, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_CALLOP|JOF_TMPSLOT3)
+OPDEF(JSOP_CALLPROP,      187,"callprop",   NULL,     3,  1,  2, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_CALLOP|JOF_TMPSLOT3)
 
 /*
  * These opcodes contain a reference to the current blockChain object.
  * They are emitted directly after instructions, such as DEFFUN, that need fast access to
  * the blockChain. The special NULLBLOCKCHAIN is needed because the JOF_OBJECT
  * does not permit NULL object references, since it stores an index into a table of
  * objects.
  */
@@ -476,29 +476,29 @@ OPDEF(JSOP_RESETBASE,     192,"resetbase
 OPDEF(JSOP_RESETBASE0,    193,"resetbase0", NULL,     1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Opcodes to help the decompiler deal with XML.
  */
 OPDEF(JSOP_STARTXML,      194,"startxml",    NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_STARTXMLEXPR,  195,"startxmlexpr",NULL,    1,  0,  0,  0,  JOF_BYTE)
 
-OPDEF(JSOP_CALLELEM,      196, "callelem",   NULL,    3,  2,  2, 18,  JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC|JOF_CALLOP)
+OPDEF(JSOP_CALLELEM,      196, "callelem",   NULL,    1,  2,  2, 18,  JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC|JOF_CALLOP)
 
 /*
  * Stop interpretation, emitted at end of script to save the threaded bytecode
  * interpreter an extra branch test on every DO_NEXT_OP (see jsinterp.c).
  */
 OPDEF(JSOP_STOP,          197,"stop",        NULL,    1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Get an extant property value, throwing ReferenceError if the identified
  * property does not exist.
  */
-OPDEF(JSOP_GETXPROP,      198,"getxprop",    NULL,    5,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
+OPDEF(JSOP_GETXPROP,      198,"getxprop",    NULL,    3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
 
 OPDEF(JSOP_CALLXMLNAME,   199, "callxmlname",  NULL,  1,  1,  2, 19,  JOF_BYTE|JOF_CALLOP)
 
 /*
  * Specialized JSOP_TYPEOF to avoid reporting undefined for typeof(0, undef).
  */
 OPDEF(JSOP_TYPEOFEXPR,    200,"typeofexpr",  NULL,    1,  1,  1, 15,  JOF_BYTE|JOF_DETECTING)
 
@@ -540,31 +540,31 @@ OPDEF(JSOP_LEAVEBLOCKEXPR,210,"leavebloc
 /*
  * Optimize atom segments 1-3.  These must be followed by JSOP_RESETBASE0 after
  * the opcode that they prefix.
  */
 OPDEF(JSOP_INDEXBASE1,    211,"indexbase1",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 OPDEF(JSOP_INDEXBASE2,    212,"indexbase2",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 OPDEF(JSOP_INDEXBASE3,    213,"indexbase3",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 
-OPDEF(JSOP_CALLGNAME,     214, "callgname",    NULL,  5,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_CALLOP|JOF_GNAME)
+OPDEF(JSOP_CALLGNAME,     214, "callgname",    NULL,  3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_CALLOP|JOF_GNAME)
 OPDEF(JSOP_CALLLOCAL,     215, "calllocal",    NULL,  3,  0,  2, 19,  JOF_LOCAL|JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLARG,       216, "callarg",      NULL,  3,  0,  2, 19,  JOF_QARG |JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_BINDGNAME,     217, "bindgname",    NULL,  3,  0,  1,  0,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME)
 
 /*
  * Opcodes to hold 8-bit and 32-bit immediate integer operands.
  */
 OPDEF(JSOP_INT8,          218, "int8",         NULL,  2,  0,  1, 16,  JOF_INT8)
 OPDEF(JSOP_INT32,         219, "int32",        NULL,  5,  0,  1, 16,  JOF_INT32)
 
 /*
  * Get the value of the 'length' property from a stacked object.
  */
-OPDEF(JSOP_LENGTH,        220, "length",       NULL,  5,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
+OPDEF(JSOP_LENGTH,        220, "length",       NULL,  3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
 
 /*
  * Push a JSVAL_HOLE value onto the stack, representing an omitted property in
  * an array literal (e.g. property 0 in the array [, 1]).  This opcode is used
  * with the JSOP_NEWARRAY opcode.
  */
 OPDEF(JSOP_HOLE,          221, "hole",         NULL,  1,  0,  1,  0,  JOF_BYTE)
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1121,17 +1121,17 @@ JSScript::NewScriptFromCG(JSContext *cx,
     uint16 nClosedVars = uint16(cg->closedVars.length());
     JS_ASSERT(nClosedVars == cg->closedVars.length());
     size_t upvarIndexCount = cg->upvarIndices.hasMap() ? cg->upvarIndices->count() : 0;
     script = NewScript(cx, prologLength + mainLength, nsrcnotes,
                        cg->atomIndices->count(), cg->objectList.length,
                        upvarIndexCount, cg->regexpList.length,
                        cg->ntrynotes, cg->constList.length(),
                        cg->globalUses.length(), nClosedArgs, nClosedVars,
-                       cg->typesetIndex, cg->version());
+                       cg->typesetCount, cg->version());
     if (!script)
         return NULL;
 
     cg->bindings.makeImmutable();
     AutoShapeRooter shapeRoot(cx, cg->bindings.lastShape());
 
     /* Now that we have script, error control flow must go to label bad. */
     script->main += prologLength;
@@ -1193,19 +1193,19 @@ JSScript::NewScriptFromCG(JSContext *cx,
         cg->upvarIndices->clear();
         cg->upvarMap.clear();
     }
 
     /* Set global for compileAndGo scripts. */
     if (script->compileAndGo) {
         GlobalScope *globalScope = cg->compiler()->globalScope;
         if (globalScope->globalObj && globalScope->globalObj->isGlobal())
-            script->global_ = globalScope->globalObj->asGlobal();
+            script->where.global = globalScope->globalObj->asGlobal();
         else if (cx->globalObject->isGlobal())
-            script->global_ = cx->globalObject->asGlobal();
+            script->where.global = cx->globalObject->asGlobal();
     }
 
     if (cg->globalUses.length()) {
         memcpy(script->globals()->vector, &cg->globalUses[0],
                cg->globalUses.length() * sizeof(GlobalSlotArray::Entry));
     }
 
     if (script->nClosedArgs)
@@ -1390,19 +1390,20 @@ DestroyScript(JSContext *cx, JSScript *s
 #endif
     }
 
 #ifdef JS_TRACER
     if (script->compartment->hasTraceMonitor())
         PurgeScriptFragments(script->compartment->traceMonitor(), script);
 #endif
 
-    JS_ASSERT(!script->hasAnalysis());
-
-    script->types.destroy();
+    if (script->types) {
+        script->types->destroy();
+        Foreground::free_(script->types);
+    }
 
 #ifdef JS_METHODJIT
     mjit::ReleaseScriptCode(cx, script, true);
     mjit::ReleaseScriptCode(cx, script, false);
 #endif
 
     JS_REMOVE_LINK(&script->links);
 
@@ -1476,18 +1477,18 @@ js_TraceScript(JSTracer *trc, JSScript *
 
     /*
      * Mark the object keeping this script alive. The script can be traced
      * separately if, e.g. we are GC'ing while type inference code is active,
      * and we need to make sure both the script and the object survive the GC.
      */
     if (!script->isCachedEval && !script->isUncachedEval && script->u.object)
         MarkObject(trc, *script->u.object, "object");
-    if (script->fun)
-        MarkObject(trc, *script->fun, "script_fun");
+    if (script->hasFunction)
+        MarkObject(trc, *script->function(), "script_fun");
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 
     script->bindings.trace(trc);
 
 #ifdef JS_METHODJIT
     if (script->jitNormal)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -488,16 +488,17 @@ struct JSScript {
     bool            usesArguments:1;  /* script uses arguments */
     bool            warnedAboutTwoArgumentEval:1; /* have warned about use of
                                                      obsolete eval(s, o) in
                                                      this script */
     bool            warnedAboutUndefinedProp:1; /* have warned about uses of
                                                    undefined properties in this
                                                    script */
     bool            hasSingletons:1;  /* script has singleton objects */
+    bool            hasFunction:1;    /* function is active in 'where' union */
     bool            isActiveEval:1;   /* script came from eval(), and is still active */
     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     bool            isUncachedEval:1; /* script came from EvaluateScript */
     bool            usedLazyArgs:1;   /* script has used lazy arguments at some point */
     bool            createdArgs:1;    /* script has had arguments objects created */
     bool            uninlineable:1;   /* script is considered uninlineable by analysis */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
@@ -546,69 +547,70 @@ struct JSScript {
 
     /* array of execution counters for every JSOp in the script, by runmode */
     JSPCCounters    pcCounters;
 
     uint32          cookie2;
 
   public:
 
-    /* Function this script is the body for, if there is one. */
-    JSFunction *fun;
+    union {
+        /* Function this script is the body for, if there is one. */
+        JSFunction *fun;
+
+        /* Global object for this script, if compileAndGo. */
+        js::GlobalObject *global;
+    } where;
+
+    inline JSFunction *function() const {
+        JS_ASSERT(hasFunction);
+        return where.fun;
+    }
 
     /*
      * Associates this script with a specific function, constructing a new type
      * object for the function.
      */
     bool typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton = false);
 
-    /* Global object for this script, if compileAndGo. */
-    js::GlobalObject *global_;
     inline bool hasGlobal() const;
     inline js::GlobalObject *global() const;
 
     inline bool hasClearedGlobal() const;
 
 #ifdef DEBUG
     /*
      * Unique identifier within the compartment for this script, used for
      * printing analysis information.
      */
     unsigned id_;
     unsigned id() { return id_; }
 #else
     unsigned id() { return 0; }
 #endif
 
-    /*
-     * Bytecode analysis and type inference results for this script. Destroyed
-     * on every GC.
-     */
-  private:
-    js::analyze::ScriptAnalysis *analysis_;
-    void makeAnalysis(JSContext *cx);
-  public:
+    /* Persistent type information retained across GCs. */
+    js::types::TypeScript *types;
 
-    bool hasAnalysis() { return analysis_ != NULL; }
-    void clearAnalysis() { analysis_ = NULL; }
-
-    js::analyze::ScriptAnalysis *analysis(JSContext *cx) {
-        if (!analysis_)
-            makeAnalysis(cx);
-        return analysis_;
-    }
-
-    /* Ensure the script has current type inference results. */
+    /* Ensure the script has types, bytecode and/or type inference results. */
+    inline bool ensureHasTypes(JSContext *cx);
+    inline bool ensureRanBytecode(JSContext *cx);
     inline bool ensureRanInference(JSContext *cx);
 
-    /* Persistent type information retained across GCs. */
-    js::types::TypeScript types;
+    /* Filled in by one of the above. */
+    inline bool hasAnalysis();
+    inline js::analyze::ScriptAnalysis *analysis();
 
     inline bool isAboutToBeFinalized(JSContext *cx);
 
+  private:
+    bool makeTypes(JSContext *cx);
+    bool makeAnalysis(JSContext *cx);
+  public:
+
 #ifdef JS_METHODJIT
     // Fast-cached pointers to make calls faster. These are also used to
     // quickly test whether there is JIT code; a NULL value means no
     // compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means
     // compilation failed. Any value is the arity-check entry point.
     void *jitArityCheckNormal;
     void *jitArityCheckCtor;
 
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -165,25 +165,31 @@ JSScript::isEmpty() const
 inline bool
 JSScript::hasGlobal() const
 {
     /*
      * Make sure that we don't try to query information about global objects
      * which have had their scopes cleared. compileAndGo code should not run
      * anymore against such globals.
      */
-    return global_ && !global_->isCleared();
+    if (!compileAndGo)
+        return false;
+    js::GlobalObject *obj = hasFunction ? function()->getGlobal() : where.global;
+    return obj && !obj->isCleared();
 }
 
 inline js::GlobalObject *
 JSScript::global() const
 {
     JS_ASSERT(hasGlobal());
-    return global_;
+    return hasFunction ? function()->getGlobal() : where.global;
 }
 
 inline bool
 JSScript::hasClearedGlobal() const
 {
-    return global_ && global_->isCleared();
+    if (!compileAndGo)
+        return false;
+    js::GlobalObject *obj = hasFunction ? function()->getGlobal() : where.global;
+    return obj && obj->isCleared();
 }
 
 #endif /* jsscriptinlines_h___ */
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -163,37 +163,35 @@ mjit::Compiler::compile()
         // just need a pointer so the VM can quickly decide whether this
         // method can be JIT'd or not. Global scripts cannot be IC'd, since
         // they have no functions, so there is no danger.
         *checkAddr = (*jit)->arityCheckEntry
                      ? (*jit)->arityCheckEntry
                      : (*jit)->invokeEntry;
     } else if (status != Compile_Retry) {
         *checkAddr = JS_UNJITTABLE_SCRIPT;
-        if (outerScript->fun) {
+        if (outerScript->hasFunction) {
             outerScript->uninlineable = true;
-            types::MarkTypeObjectFlags(cx, outerScript->fun,
+            types::MarkTypeObjectFlags(cx, outerScript->function(),
                                        types::OBJECT_FLAG_UNINLINEABLE);
         }
     }
 
     return status;
 }
 
 CompileStatus
 mjit::Compiler::checkAnalysis(JSScript *script)
 {
-    ScriptAnalysis *analysis = script->analysis(cx);
-    if (analysis && !analysis->ranBytecode())
-        analysis->analyzeBytecode(cx);
-
+    if (!script->ensureRanBytecode(cx))
+        return Compile_Error;
     if (cx->typeInferenceEnabled() && !script->ensureRanInference(cx))
         return Compile_Error;
-    if (!analysis || analysis->OOM())
-        return Compile_Error;
+
+    ScriptAnalysis *analysis = script->analysis();
     if (analysis->failed()) {
         JaegerSpew(JSpew_Abort, "couldn't analyze bytecode; probably switchX or OOM\n");
         return Compile_Abort;
     }
 
     return Compile_Okay;
 }
 
@@ -222,23 +220,23 @@ mjit::Compiler::scanInlineCalls(uint32 i
 
     JS_ASSERT(inlining() && globalObj);
 
     /* Not inlining yet from 'new' scripts. */
     if (isConstructing)
         return Compile_Okay;
 
     JSScript *script = ssa.getFrame(index).script;
-    ScriptAnalysis *analysis = script->analysis(cx);
+    ScriptAnalysis *analysis = script->analysis();
 
     /* Don't inline from functions which could have a non-global scope object. */
     if (!script->hasGlobal() ||
         script->global() != globalObj ||
-        (script->fun && script->fun->getParent() != globalObj) ||
-        (script->fun && script->fun->isHeavyweight()) ||
+        (script->hasFunction && script->function()->getParent() != globalObj) ||
+        (script->hasFunction && script->function()->isHeavyweight()) ||
         script->isActiveEval) {
         return Compile_Okay;
     }
 
     uint32 nextOffset = 0;
     while (nextOffset < script->length) {
         uint32 offset = nextOffset;
         jsbytecode *pc = script->code + offset;
@@ -332,35 +330,35 @@ mjit::Compiler::scanInlineCalls(uint32 i
                 okay = false;
                 break;
             }
 
             CompileStatus status = checkAnalysis(script);
             if (status != Compile_Okay)
                 return status;
 
-            if (!script->analysis(cx)->inlineable(argc)) {
+            if (!script->analysis()->inlineable(argc)) {
                 okay = false;
                 break;
             }
 
             if (types::TypeSet::HasObjectFlags(cx, fun->getType(cx),
                                                types::OBJECT_FLAG_UNINLINEABLE)) {
                 okay = false;
                 break;
             }
 
             /*
              * Don't inline scripts which use 'this' if it is possible they
              * could be called with a 'this' value requiring wrapping. During
              * inlining we do not want to modify frame entries belonging to the
              * caller.
              */
-            if (script->analysis(cx)->usesThisValue() &&
-                script->types.thisTypes()->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT) {
+            if (script->analysis()->usesThisValue() &&
+                types::TypeScript::ThisTypes(script)->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT) {
                 okay = false;
                 break;
             }
         }
         if (!okay)
             continue;
 
         calleeTypes->addFreeze(cx);
@@ -402,21 +400,21 @@ mjit::Compiler::pushActiveFrame(JSScript
         newa->inlineIndex = uint32(inlineFrames.length());
         inlineFrames.append(newa);
     } else {
         newa->inlineIndex = CrossScriptSSA::OUTER_FRAME;
         outer = newa;
     }
     JS_ASSERT(ssa.getFrame(newa->inlineIndex).script == script);
 
-    ScriptAnalysis *newAnalysis = script->analysis(cx);
+    ScriptAnalysis *newAnalysis = script->analysis();
 
 #ifdef JS_METHODJIT_SPEW
     if (cx->typeInferenceEnabled() && IsJaegerSpewChannelActive(JSpew_Regalloc)) {
-        unsigned nargs = script->fun ? script->fun->nargs : 0;
+        unsigned nargs = script->hasFunction ? script->function()->nargs : 0;
         for (unsigned i = 0; i < nargs; i++) {
             uint32 slot = ArgSlot(i);
             if (!newAnalysis->slotEscapes(slot)) {
                 JaegerSpew(JSpew_Regalloc, "Argument %u:", i);
                 newAnalysis->liveness(slot).print();
             }
         }
         for (unsigned i = 0; i < script->nfixed; i++) {
@@ -460,17 +458,17 @@ mjit::Compiler::pushActiveFrame(JSScript
 
 void
 mjit::Compiler::popActiveFrame()
 {
     JS_ASSERT(a->parent);
     this->PC = a->parentPC;
     this->a = a->parent;
     this->script = a->script;
-    this->analysis = this->script->analysis(cx);
+    this->analysis = this->script->analysis();
 
     frame.popActiveFrame();
 }
 
 #define CHECK_STATUS(expr)                                           \
     JS_BEGIN_MACRO                                                   \
         CompileStatus status_ = (expr);                              \
         if (status_ != Compile_Okay) {                               \
@@ -585,17 +583,17 @@ mjit::Compiler::prepareInferenceTypes(JS
 
     a->varTypes = (VarType *)
         cx->calloc_(TotalSlots(script) * sizeof(VarType));
     if (!a->varTypes)
         return Compile_Error;
 
     for (uint32 slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
         VarType &vt = a->varTypes[slot];
-        vt.types = script->types.slotTypes(slot);
+        vt.types = types::TypeScript::SlotTypes(script, slot);
         vt.type = vt.types->getKnownTypeTag(cx);
     }
 
     return Compile_Okay;
 }
 
 CompileStatus JS_NEVER_INLINE
 mjit::TryCompile(JSContext *cx, StackFrame *fp)
@@ -648,62 +646,62 @@ CompileStatus
 mjit::Compiler::generatePrologue()
 {
     invokeLabel = masm.label();
 
     /*
      * If there is no function, then this can only be called via JaegerShot(),
      * which expects an existing frame to be initialized like the interpreter.
      */
-    if (script->fun) {
+    if (script->hasFunction) {
         Jump j = masm.jump();
 
         /*
          * Entry point #2: The caller has partially constructed a frame, and
          * either argc >= nargs or the arity check has corrected the frame.
          */
         invokeLabel = masm.label();
 
         Label fastPath = masm.label();
 
         /* Store this early on so slow paths can access it. */
-        masm.storePtr(ImmPtr(script->fun), Address(JSFrameReg, StackFrame::offsetOfExec()));
+        masm.storePtr(ImmPtr(script->function()), Address(JSFrameReg, StackFrame::offsetOfExec()));
 
         {
             /*
              * Entry point #3: The caller has partially constructed a frame,
              * but argc might be != nargs, so an arity check might be called.
              *
              * This loops back to entry point #2.
              */
             arityLabel = stubcc.masm.label();
 
             Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc,
-                                                 Imm32(script->fun->nargs));
+                                                 Imm32(script->function()->nargs));
 
             if (JSParamReg_Argc != Registers::ArgReg1)
                 stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
 
             /* Slow path - call the arity check function. Returns new fp. */
-            stubcc.masm.storePtr(ImmPtr(script->fun),
+            stubcc.masm.storePtr(ImmPtr(script->function()),
                                  Address(JSFrameReg, StackFrame::offsetOfExec()));
             OOL_STUBCALL(stubs::FixupArity, REJOIN_NONE);
             stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
             argMatch.linkTo(stubcc.masm.label(), &stubcc.masm);
 
             argsCheckLabel = stubcc.masm.label();
 
             /* Type check the arguments as well. */
             if (cx->typeInferenceEnabled()) {
 #ifdef JS_MONOIC
                 this->argsCheckJump = stubcc.masm.jump();
                 this->argsCheckStub = stubcc.masm.label();
                 this->argsCheckJump.linkTo(this->argsCheckStub, &stubcc.masm);
 #endif
-                stubcc.masm.storePtr(ImmPtr(script->fun), Address(JSFrameReg, StackFrame::offsetOfExec()));
+                stubcc.masm.storePtr(ImmPtr(script->function()), Address(JSFrameReg, StackFrame::offsetOfExec()));
                 OOL_STUBCALL(stubs::CheckArgumentTypes, REJOIN_CHECK_ARGUMENTS);
 #ifdef JS_MONOIC
                 this->argsCheckFallthrough = stubcc.masm.label();
 #endif
             }
 
             stubcc.crossJump(stubcc.masm.jump(), fastPath);
         }
@@ -733,81 +731,81 @@ mjit::Compiler::generatePrologue()
         for (uint32 i = 0; i < script->nfixed; i++) {
             if (analysis->localHasUseBeforeDef(i) || addTraceHints) {
                 Address local(JSFrameReg, sizeof(StackFrame) + i * sizeof(Value));
                 masm.storeValue(UndefinedValue(), local);
             }
         }
 
         /* Create the call object. */
-        if (script->fun->isHeavyweight()) {
+        if (script->function()->isHeavyweight()) {
             prepareStubCall(Uses(0));
             INLINE_STUBCALL(stubs::CreateFunCallObject, REJOIN_CREATE_CALL_OBJECT);
         }
 
         j.linkTo(masm.label(), &masm);
 
-        if (analysis->usesScopeChain() && !script->fun->isHeavyweight()) {
+        if (analysis->usesScopeChain() && !script->function()->isHeavyweight()) {
             /*
              * Load the scope chain into the frame if necessary.  The scope chain
              * is always set for global and eval frames, and will have been set by
              * CreateFunCallObject for heavyweight function frames.
              */
             RegisterID t0 = Registers::ReturnReg;
             Jump hasScope = masm.branchTest32(Assembler::NonZero,
                                               FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN));
-            masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->fun)), t0);
+            masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->function())), t0);
             masm.loadPtr(Address(t0, offsetof(JSObject, parent)), t0);
             masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain()));
             hasScope.linkTo(masm.label(), &masm);
         }
 
-        if (outerScript->usesArguments && !script->fun->isHeavyweight()) {
+        if (outerScript->usesArguments && !script->function()->isHeavyweight()) {
             /*
              * Make sure that fp->args.nactual is always coherent. This may be
              * inspected directly by JIT code, and is not guaranteed to be
              * correct if the UNDERFLOW and OVERFLOW flags are not set.
              */
             Jump hasArgs = masm.branchTest32(Assembler::NonZero, FrameFlagsAddress(),
                                              Imm32(StackFrame::OVERRIDE_ARGS |
                                                    StackFrame::UNDERFLOW_ARGS |
                                                    StackFrame::OVERFLOW_ARGS |
                                                    StackFrame::HAS_ARGS_OBJ));
-            masm.storePtr(ImmPtr((void *) script->fun->nargs),
+            masm.storePtr(ImmPtr((void *) script->function()->nargs),
                           Address(JSFrameReg, StackFrame::offsetOfArgs()));
             hasArgs.linkTo(masm.label(), &masm);
         }
     }
 
     if (isConstructing)
         constructThis();
 
     if (debugMode())
         INLINE_STUBCALL(stubs::ScriptDebugPrologue, REJOIN_RESUME);
     else if (Probes::callTrackingActive(cx))
         INLINE_STUBCALL(stubs::ScriptProbeOnlyPrologue, REJOIN_RESUME);
 
     if (cx->typeInferenceEnabled()) {
 #ifdef DEBUG
-        if (script->fun)
+        if (script->hasFunction)
             INLINE_STUBCALL(stubs::AssertArgumentTypes, REJOIN_NONE);
 #endif
         ensureDoubleArguments();
     }
 
     recompileCheckHelper();
 
     return Compile_Okay;
 }
 
 void
 mjit::Compiler::ensureDoubleArguments()
 {
     /* Convert integer arguments which were inferred as (int|double) to doubles. */
-    for (uint32 i = 0; script->fun && i < script->fun->nargs; i++) {
+    for (uint32 i = 0; script->hasFunction && i < script->function()->nargs; i++) {
         uint32 slot = ArgSlot(i);
         if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
             frame.ensureDouble(frame.getArg(i));
     }
 }
 
 CompileStatus
 mjit::Compiler::generateEpilogue()
@@ -899,17 +897,17 @@ mjit::Compiler::finishThisUp(JITScript *
     cursor += sizeof(JITScript);
 
     JS_ASSERT(outerScript == script);
 
     jit->script = script;
     jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
     jit->invokeEntry = result;
     jit->singleStepMode = script->singleStepMode;
-    if (script->fun) {
+    if (script->hasFunction) {
         jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
         jit->argsCheckEntry = stubCode.locationOf(argsCheckLabel).executableAddress();
         jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
     }
 
     /* 
      * WARNING: mics(), callICs() et al depend on the ordering of these
      * variable-length sections.  See JITScript's declaration for details.
@@ -960,17 +958,17 @@ mjit::Compiler::finishThisUp(JITScript *
     for (size_t i = 0; i < jit->nInlineFrames; i++) {
         InlineFrame &to = jitInlineFrames[i];
         ActiveFrame *from = inlineFrames[i];
         if (from->parent != outer)
             to.parent = &jitInlineFrames[from->parent->inlineIndex];
         else
             to.parent = NULL;
         to.parentpc = from->parentPC;
-        to.fun = from->script->fun;
+        to.fun = from->script->function();
         to.depth = ssa.getFrame(from->inlineIndex).depth;
     }
 
     /* Build the table of call sites. */
     CallSite *jitCallSites = (CallSite *)cursor;
     jit->nCallSites = callSites.length();
     cursor += sizeof(CallSite) * jit->nCallSites;
     for (size_t i = 0; i < jit->nCallSites; i++) {
@@ -1002,17 +1000,17 @@ mjit::Compiler::finishThisUp(JITScript *
          */
         if (from.loopPatch.hasPatch)
             stubCode.patch(from.loopPatch.codePatch, result + codeOffset);
     }
 
 #if defined JS_MONOIC
     JS_INIT_CLIST(&jit->callers);
 
-    if (script->fun && cx->typeInferenceEnabled()) {
+    if (script->hasFunction && cx->typeInferenceEnabled()) {
         jit->argsCheckStub = stubCode.locationOf(argsCheckStub);
         jit->argsCheckFallthrough = stubCode.locationOf(argsCheckFallthrough);
         jit->argsCheckJump = stubCode.locationOf(argsCheckJump);
         jit->argsCheckPool = NULL;
     }
 
     ic::GetGlobalNameIC *getGlobalNames_ = (ic::GetGlobalNameIC *)cursor;
     jit->nGetGlobalNames = getGlobalNames.length();
@@ -1632,17 +1630,17 @@ mjit::Compiler::generateMethod()
                  * Check for interrupts at the JSOP_ARGUMENTS when using
                  * apply tricks, see inlineCallHelper().
                  */
                 interruptCheckHelper();
 
                 applyTricks = LazyArgsObj;
                 pushSyncedEntry(0);
             } else if (cx->typeInferenceEnabled() && !script->strictModeCode &&
-                       !script->fun->getType(cx)->hasAnyFlags(types::OBJECT_FLAG_CREATED_ARGUMENTS)) {
+                       !script->function()->getType(cx)->hasAnyFlags(types::OBJECT_FLAG_CREATED_ARGUMENTS)) {
                 frame.push(MagicValue(JS_LAZY_ARGUMENTS));
             } else {
                 jsop_arguments(REJOIN_FALLTHROUGH);
                 pushSyncedEntry(0);
             }
           END_CASE(JSOP_ARGUMENTS)
 
           BEGIN_CASE(JSOP_ITERNEXT)
@@ -1859,17 +1857,17 @@ mjit::Compiler::generateMethod()
                 double d;
                 JS_ALWAYS_TRUE(ToNumber(cx, top->getValue(), &d));
                 d = -d;
                 Value v = NumberValue(d);
 
                 /* Watch for overflow in constant propagation. */
                 types::TypeSet *pushed = pushedTypeSet(0);
                 if (!v.isInt32() && pushed && !pushed->hasType(types::Type::DoubleType())) {
-                    script->types.monitorOverflow(cx, PC);
+                    types::TypeScript::MonitorOverflow(cx, script, PC);
                     return Compile_Retry;
                 }
 
                 frame.pop();
                 frame.push(v);
             } else {
                 jsop_neg();
             }
@@ -2838,17 +2836,17 @@ mjit::Compiler::loadReturnValue(Assemble
 // loaded out of the frame. Otherwise, the explicitly returned object is kept.
 //
 void
 mjit::Compiler::fixPrimitiveReturn(Assembler *masm, FrameEntry *fe)
 {
     JS_ASSERT(isConstructing);
 
     bool ool = (masm != &this->masm);
-    Address thisv(JSFrameReg, StackFrame::offsetOfThis(script->fun));
+    Address thisv(JSFrameReg, StackFrame::offsetOfThis(script->function()));
 
     // We can just load |thisv| if either of the following is true:
     //  (1) There is no explicit return value, AND fp->rval is not used.
     //  (2) There is an explicit return value, and it's known to be primitive.
     if ((!fe && !analysis->usesReturnValue()) ||
         (fe && fe->isTypeKnown() && fe->getKnownType() != JSVAL_TYPE_OBJECT))
     {
         if (ool)
@@ -2947,17 +2945,17 @@ mjit::Compiler::emitInlineReturnValue(Fr
     a->returnSet = true;
     if (a->exitState)
         a->exitState->setUnassigned(a->returnRegister);
 }
 
 void
 mjit::Compiler::emitReturn(FrameEntry *fe)
 {
-    JS_ASSERT_IF(!script->fun, JSOp(*PC) == JSOP_STOP);
+    JS_ASSERT_IF(!script->hasFunction, JSOp(*PC) == JSOP_STOP);
 
     /* Only the top of the stack can be returned. */
     JS_ASSERT_IF(fe, fe == frame.peek(-1));
 
     if (debugMode() || Probes::callTrackingActive(cx)) {
         prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::ScriptDebugEpilogue, REJOIN_RESUME);
     }
@@ -3003,17 +3001,17 @@ mjit::Compiler::emitReturn(FrameEntry *f
      * members. For JSOP_RETURN, the interpreter only calls popInlineFrame if
      * fp != entryFrame since the VM protocol is that Invoke/Execute are
      * responsible for pushing/popping the initial frame. The mjit does not
      * perform this branch (by instead using a trampoline at the return address
      * to handle exiting mjit code) and thus always puts activation objects,
      * even on the entry frame. To avoid double-putting, EnterMethodJIT clears
      * out the entry frame's activation objects.
      */
-    if (script->fun && script->fun->isHeavyweight()) {
+    if (script->hasFunction && script->function()->isHeavyweight()) {
         /* There will always be a call object. */
         prepareStubCall(Uses(fe ? 1 : 0));
         INLINE_STUBCALL(stubs::PutActivationObjects, REJOIN_NONE);
     } else {
         /* if (hasCallObj() || hasArgsObj()) */
         Jump putObjs = masm.branchTest32(Assembler::NonZero,
                                          Address(JSFrameReg, StackFrame::offsetOfFlags()),
                                          Imm32(StackFrame::HAS_CALL_OBJ | StackFrame::HAS_ARGS_OBJ));
@@ -3723,17 +3721,17 @@ mjit::Compiler::inlineScriptedFunction(u
 
     /* We already know which frames we are inlining at each PC, so scan the list of inline frames. */
     bool calleeMultipleReturns = false;
     Vector<JSScript *> inlineCallees(CompilerAllocPolicy(cx, *this));
     for (unsigned i = 0; i < ssa.numFrames(); i++) {
         if (ssa.iterFrame(i).parent == a->inlineIndex && ssa.iterFrame(i).parentpc == PC) {
             JSScript *script = ssa.iterFrame(i).script;
             inlineCallees.append(script);
-            if (script->analysis(cx)->numReturnSites() > 1)
+            if (script->analysis()->numReturnSites() > 1)
                 calleeMultipleReturns = true;
         }
     }
 
     if (inlineCallees.empty())
         return Compile_InlineAbort;
 
     JS_ASSERT(!monitored(PC));
@@ -3802,17 +3800,17 @@ mjit::Compiler::inlineScriptedFunction(u
         if (calleePrevious.isSet()) {
             calleePrevious.get().linkTo(masm.label(), &masm);
             calleePrevious = MaybeJump();
         }
 
         if (i + 1 != inlineCallees.length()) {
             /* Guard on the callee, except when this object must be the callee. */
             JS_ASSERT(calleeReg.isSet());
-            calleePrevious = masm.branchPtr(Assembler::NotEqual, calleeReg.reg(), ImmPtr(script->fun));
+            calleePrevious = masm.branchPtr(Assembler::NotEqual, calleeReg.reg(), ImmPtr(script->function()));
         }
 
         a->returnJumps = &returnJumps;
         a->needReturnValue = needReturnValue;
         a->syncReturnValue = syncReturnValue;
         a->returnValueDouble = returnType == JSVAL_TYPE_DOUBLE;
         if (returnSet) {
             a->returnSet = true;
@@ -3826,17 +3824,17 @@ mjit::Compiler::inlineScriptedFunction(u
         ensureDoubleArguments();
 
         status = generateMethod();
         if (status != Compile_Okay) {
             popActiveFrame();
             if (status == Compile_Abort) {
                 /* The callee is uncompileable, mark it as uninlineable and retry. */
                 script->uninlineable = true;
-                types::MarkTypeObjectFlags(cx, script->fun,
+                types::MarkTypeObjectFlags(cx, script->function(),
                                            types::OBJECT_FLAG_UNINLINEABLE);
                 return Compile_Retry;
             }
             return status;
         }
 
         if (needReturnValue && !returnSet) {
             if (a->returnSet) {
@@ -5320,28 +5318,28 @@ mjit::Compiler::jsop_this()
 {
     frame.pushThis();
 
     /* 
      * In strict mode code, we don't wrap 'this'.
      * In direct-call eval code, we wrapped 'this' before entering the eval.
      * In global code, 'this' is always an object.
      */
-    if (script->fun && !script->strictModeCode) {
+    if (script->hasFunction && !script->strictModeCode) {
         FrameEntry *thisFe = frame.peek(-1);
 
         /*
          * We don't inline calls to scripts which use 'this' but might require
          * 'this' to be wrapped.
          */
         JS_ASSERT(!thisFe->isNotType(JSVAL_TYPE_OBJECT));
 
         if (!thisFe->isType(JSVAL_TYPE_OBJECT)) {
             JSValueType type = cx->typeInferenceEnabled()
-                ? script->types.thisTypes()->getKnownTypeTag(cx)
+                ? types::TypeScript::ThisTypes(script)->getKnownTypeTag(cx)
                 : JSVAL_TYPE_UNKNOWN;
             if (type != JSVAL_TYPE_OBJECT) {
                 Jump notObj = frame.testObject(Assembler::NotEqual, thisFe);
                 stubcc.linkExit(notObj, Uses(1));
                 stubcc.leave();
                 OOL_STUBCALL(stubs::This, REJOIN_FALLTHROUGH);
                 stubcc.rejoin(Changes(1));
             }
@@ -6141,17 +6139,18 @@ mjit::Compiler::jsop_newinit()
         return false;
     }
 
     prepareStubCall(Uses(0));
 
     /* Don't bake in types for non-compileAndGo scripts. */
     types::TypeObject *type = NULL;
     if (globalObj) {
-        type = script->types.initObject(cx, PC, isArray ? JSProto_Array : JSProto_Object);
+        type = types::TypeScript::InitObject(cx, script, PC,
+                                             isArray ? JSProto_Array : JSProto_Object);
         if (!type)
             return false;
     }
     masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
 
     if (isArray) {
         masm.move(Imm32(count), Registers::ArgReg1);
         INLINE_STUBCALL(stubs::NewInitArray, REJOIN_PUSH_OBJECT);
@@ -7067,17 +7066,17 @@ mjit::Compiler::testBarrier(RegisterID t
 {
     BarrierState state;
     state.typeReg = typeReg;
     state.dataReg = dataReg;
 
     if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET))
         return state;
 
-    types::TypeSet *types = script->types.bytecodeTypes(PC);
+    types::TypeSet *types = analysis->bytecodeTypes(PC);
     if (types->unknown()) {
         /*
          * If the result of this opcode is already unknown, there is no way for
          * a type barrier to fail.
          */
         return state;
     }
 
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -198,17 +198,17 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
     Value v;
     if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
         if (!v.isInt32() && typeSet && !typeSet->hasType(types::Type::DoubleType())) {
             /*
              * OK to ignore failure here, we aren't performing the operation
              * itself. Note that monitorOverflow will propagate the type as
              * necessary if a *INC operation overflowed.
              */
-            script->types.monitorOverflow(cx, PC);
+            types::TypeScript::MonitorOverflow(cx, script, PC);
             return false;
         }
         frame.popn(2);
         frame.push(v);
         return true;
     }
 
     /*
@@ -942,17 +942,17 @@ mjit::Compiler::jsop_mod()
     JSValueType type = knownPushedType(0);
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
         types::TypeSet *pushed = pushedTypeSet(0);
         if (!v.isInt32() && pushed && !pushed->hasType(types::Type::DoubleType())) {
-            script->types.monitorOverflow(cx, PC);
+            types::TypeScript::MonitorOverflow(cx, script, PC);
             return false;
         }
         frame.popn(2);
         frame.push(v);
         return true;
     }
 
     if ((lhs->isConstant() && rhs->isConstant()) ||
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1822,17 +1822,17 @@ mjit::Compiler::jsop_getelem_args()
         stubcc.linkExit(rangeGuard.get(), Uses(2));
     }
 
     RegisterID actualsReg;
     if (actualsFe) {
         actualsReg = frame.tempRegForData(actualsFe);
     } else {
         actualsReg = dataReg;
-        masm.loadFrameActuals(outerScript->fun, actualsReg);
+        masm.loadFrameActuals(outerScript->function(), actualsReg);
     }
 
     if (key.isConstant()) {
         Address arg(actualsReg, key.index() * sizeof(Value));
         masm.loadValueAsComponents(arg, typeReg, dataReg);
     } else {
         JS_ASSERT(key.reg() != dataReg);
         BaseIndex arg(actualsReg, key.reg(), masm.JSVAL_SCALE);
@@ -1977,17 +1977,17 @@ mjit::Compiler::jsop_getelem(bool isCall
             jsop_getelem_slow();
         return true;
     }
 
     // If the object is definitely an arguments object, a dense array or a typed array
     // we can generate code directly without using an inline cache.
     if (cx->typeInferenceEnabled() && id->mightBeType(JSVAL_TYPE_INT32) && !isCall) {
         types::TypeSet *types = analysis->poppedTypes(PC, 1);
-        if (types->isLazyArguments(cx) && !outerScript->analysis(cx)->modifiesArguments()) {
+        if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
             // Inline arguments path.
             jsop_getelem_args();
             return true;
         }
 
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
             !arrayPrototypeHasIndexedProperty()) {
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -992,21 +992,21 @@ FrameState::frameOffset(const FrameEntry
      * reserved stack space.
      */
     JS_STATIC_ASSERT(StackSpace::STACK_JIT_EXTRA >= TEMPORARY_LIMIT);
     JS_ASSERT(fe >= a->callee_ && fe < a->sp);
 
     if (fe >= a->locals)
         return StackFrame::offsetOfFixed(uint32(fe - a->locals));
     if (fe >= a->args)
-        return StackFrame::offsetOfFormalArg(a->script->fun, uint32(fe - a->args));
+        return StackFrame::offsetOfFormalArg(a->script->function(), uint32(fe - a->args));
     if (fe == a->this_)
-        return StackFrame::offsetOfThis(a->script->fun);
+        return StackFrame::offsetOfThis(a->script->hasFunction ? a->script->function() : NULL);
     if (fe == a->callee_)
-        return StackFrame::offsetOfCallee(a->script->fun);
+        return StackFrame::offsetOfCallee(a->script->function());
     JS_NOT_REACHED("Bad fe");
     return 0;
 }
 
 inline JSC::MacroAssembler::Address
 FrameState::addressOf(const FrameEntry *fe) const
 {
     if (isTemporary(fe)) {
@@ -1156,17 +1156,17 @@ FrameState::getLocal(uint32 slot)
 {
     JS_ASSERT(slot < a->script->nslots);
     return getOrTrack(uint32(a->locals + slot - entries));
 }
 
 inline FrameEntry *
 FrameState::getArg(uint32 slot)
 {
-    JS_ASSERT(a->script->fun && slot < a->script->fun->nargs);
+    JS_ASSERT(slot < a->script->function()->nargs);
     return getOrTrack(uint32(a->args + slot - entries));
 }
 
 inline FrameEntry *
 FrameState::getThis()
 {
     return getOrTrack(uint32(a->this_ - entries));
 }
@@ -1177,17 +1177,17 @@ FrameState::getSlotEntry(uint32 slot)
     JS_ASSERT(slot < analyze::TotalSlots(a->script));
     return getOrTrack(uint32(a->callee_ + slot - entries));
 }
 
 inline FrameEntry *
 FrameState::getCallee()
 {
     // Callee can only be used in function code, and it's always an object.
-    JS_ASSERT(a->script->fun);
+    JS_ASSERT(a->script->hasFunction);
     FrameEntry *fe = a->callee_;
     if (!fe->isTracked()) {
         addToTracker(fe);
         fe->resetSynced();
         fe->setType(JSVAL_TYPE_OBJECT);
     }
     return fe;
 }
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -56,17 +56,17 @@ FrameState::FrameState(JSContext *cx, mj
     loop(NULL), inTryBlock(false)
 {
 }
 
 FrameState::~FrameState()
 {
     while (a) {
         ActiveFrame *parent = a->parent;
-        a->script->analysis(cx)->clearAllocations();
+        a->script->analysis()->clearAllocations();
         cx->free_(a);
         a = parent;
     }
     cx->free_(entries);
 }
 
 void
 FrameState::pruneDeadEntries()
@@ -113,28 +113,28 @@ FrameState::pushActiveFrame(JSScript *sc
         if (!reifier.init(cx, *this, nentries))
             return false;
 #endif
 
         this->temporaries = this->temporariesTop = this->entries + nentries - TEMPORARY_LIMIT;
     }
 
     /* We should have already checked that argc == nargs */
-    JS_ASSERT_IF(a, argc == script->fun->nargs);
+    JS_ASSERT_IF(a, argc == script->function()->nargs);
 
     ActiveFrame *newa = cx->new_<ActiveFrame>();
     if (!newa)
         return false;
 
     newa->parent = a;
     newa->depth = a ? (totalDepth() + VALUES_PER_STACK_FRAME) : 0;
 
     newa->script = script;
     newa->PC = script->code;
-    newa->analysis = script->analysis(cx);
+    newa->analysis = script->analysis();
 
     /*
      * The callee/this/args in the new frame reuse the same entries as are on
      * the stack in the old frame.
      */
     FrameEntry *entriesStart = a ? a->sp - (argc + 2) : entries;
     newa->callee_ = entriesStart + analyze::CalleeSlot();
     newa->this_   = entriesStart + analyze::ThisSlot();
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -1018,17 +1018,17 @@ class FrameState
     inline bool binaryEntryLive(FrameEntry *fe) const;
     void relocateReg(AnyRegisterID reg, RegisterAllocation *alloc, Uses uses);
 
     bool isThis(const FrameEntry *fe) const {
         return fe == a->this_;
     }
 
     bool isArg(const FrameEntry *fe) const {
-        return a->script->fun && fe >= a->args && fe - a->args < a->script->fun->nargs;
+        return a->script->hasFunction && fe >= a->args && fe - a->args < a->script->function()->nargs;
     }
 
     bool isLocal(const FrameEntry *fe) const {
         return fe >= a->locals && fe - a->locals < a->script->nfixed;
     }
 
     bool isTemporary(const FrameEntry *fe) const {
         JS_ASSERT_IF(fe >= temporaries, fe < temporariesTop);
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -182,27 +182,27 @@ InlineReturn(VMFrame &f)
 
 void JS_FASTCALL
 stubs::SlowCall(VMFrame &f, uint32 argc)
 {
     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
     if (!Invoke(f.cx, args))
         THROW();
 
-    f.script()->types.monitor(f.cx, f.pc(), args.rval());
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 }
 
 void JS_FASTCALL
 stubs::SlowNew(VMFrame &f, uint32 argc)
 {
     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
     if (!InvokeConstructor(f.cx, args))
         THROW();
 
-    f.script()->types.monitor(f.cx, f.pc(), args.rval());
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 }
 
 static inline bool
 CheckStackQuota(VMFrame &f)
 {
     JS_ASSERT(f.regs.sp == f.fp()->base());
 
     f.stackLimit = f.cx->stack.space().getStackLimit(f.cx, DONT_REPORT_ERROR);
@@ -370,17 +370,17 @@ UncachedInlineCall(VMFrame &f, InitialFr
         JS_ASSERT(!f.regs.inlined());
         regs.fp()->resetInlinePrev(f.fp(), f.regs.pc);
     }
 
     bool ok = !!Interpret(cx, cx->fp());
     f.cx->stack.popInlineFrame(regs);
 
     if (ok)
-        f.script()->types.monitor(cx, f.pc(), args.rval());
+        types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 
     *pret = NULL;
     return ok;
 }
 
 void * JS_FASTCALL
 stubs::UncachedNew(VMFrame &f, uint32 argc)
 {
@@ -399,17 +399,17 @@ stubs::UncachedNewHelper(VMFrame &f, uin
     /* Try to do a fast inline call before the general Invoke path. */
     if (IsFunctionObject(args.calleev(), &ucr->fun) && ucr->fun->isInterpretedConstructor()) {
         ucr->callee = &args.callee();
         if (!UncachedInlineCall(f, INITIAL_CONSTRUCT, &ucr->codeAddr, &ucr->unjittable, argc))
             THROW();
     } else {
         if (!InvokeConstructor(cx, args))
             THROW();
-        f.script()->types.monitor(cx, f.pc(), args.rval());
+        types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
     }
 }
 
 void * JS_FASTCALL
 stubs::UncachedCall(VMFrame &f, uint32 argc)
 {
     UncachedCallResult ucr;
     UncachedCallHelper(f, argc, false, &ucr);
@@ -428,25 +428,25 @@ void JS_FASTCALL
 stubs::Eval(VMFrame &f, uint32 argc)
 {
     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
 
     if (!IsBuiltinEvalForScope(&f.fp()->scopeChain(), args.calleev())) {
         if (!Invoke(f.cx, args))
             THROW();
 
-        f.script()->types.monitor(f.cx, f.pc(), args.rval());
+        types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         return;
     }
 
     JS_ASSERT(f.fp() == f.cx->fp());
     if (!DirectEval(f.cx, args))
         THROW();
 
-    f.script()->types.monitor(f.cx, f.pc(), args.rval());
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 }
 
 void
 stubs::UncachedCallHelper(VMFrame &f, uint32 argc, bool lowered, UncachedCallResult *ucr)
 {
     ucr->init();
 
     JSContext *cx = f.cx;
@@ -461,25 +461,25 @@ stubs::UncachedCallHelper(VMFrame &f, ui
             if (!UncachedInlineCall(f, initial, &ucr->codeAddr, &ucr->unjittable, argc))
                 THROW();
             return;
         }
 
         if (ucr->fun->isNative()) {
             if (!CallJSNative(cx, ucr->fun->u.n.native, args))
                 THROW();
-            f.script()->types.monitor(cx, f.pc(), args.rval());
+            types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
             return;
         }
     }
 
     if (!Invoke(f.cx, args))
         THROW();
 
-    f.script()->types.monitor(cx, f.pc(), args.rval());
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
     return;
 }
 
 void JS_FASTCALL
 stubs::PutActivationObjects(VMFrame &f)
 {
     JS_ASSERT(f.fp()->hasCallObj() || f.fp()->hasArgsObj());
     f.fp()->putActivationObjects();
@@ -608,27 +608,25 @@ js_InternalThrow(VMFrame &f)
         /*
          * Expanding inline frames will ensure that prevpc values are filled in
          * for all frames on this VMFrame, without needing to walk the entire
          * stack: downFramesExpanded() on a StackFrame also means the prevpc()
          * values are also filled in.
          */
         ExpandInlineFrames(cx->compartment, true);
 
-        analyze::AutoEnterAnalysis enter(cx);
-        analyze::ScriptAnalysis *analysis = script->analysis(cx);
-        if (analysis && !analysis->ranBytecode())
-            analysis->analyzeBytecode(cx);
-        if (!analysis || analysis->OOM()) {
+        if (!script->ensureRanBytecode(cx)) {
             js_ReportOutOfMemory(cx);
             return NULL;
         }
 
+        analyze::AutoEnterAnalysis enter(cx);
+
         cx->regs().pc = pc;
-        cx->regs().sp = fp->base() + analysis->getCode(pc).stackDepth;
+        cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth;
 
         /*
          * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
          * back into the interpreter with a pending exception. This will cause
          * it to immediately rethrow.
          */
         if (cx->isExceptionPending()) {
             JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK);
@@ -1210,17 +1208,17 @@ FinishVarIncOp(VMFrame &f, RejoinState r
 
     unsigned i = GET_SLOTNO(f.pc());
     Value *var = (JOF_TYPE(cs->format) == JOF_LOCAL) ? f.fp()->slots() + i : &f.fp()->formalArg(i);
 
     if (rejoin == REJOIN_POS) {
         double d = ov.toNumber();
         double N = (cs->format & JOF_INC) ? 1 : -1;
         if (!nv.setNumber(d + N))
-            f.script()->types.monitorOverflow(cx, f.pc());
+            types::TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     }
 
     *var = nv;
     *vp = (cs->format & JOF_POST) ? ov : nv;
 }
 
 extern "C" void *
 js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VMFrame &f)
@@ -1242,26 +1240,24 @@ js_InternalInterpret(void *returnData, v
     JSScript *script = fp->script();
 
     jsbytecode *pc = f.regs.pc;
     analyze::UntrapOpcode untrap(cx, script, pc);
 
     JSOp op = JSOp(*pc);
     const JSCodeSpec *cs = &js_CodeSpec[op];
 
-    analyze::AutoEnterAnalysis enter(cx);
-
-    analyze::ScriptAnalysis *analysis = script->analysis(cx);
-    if (analysis && !analysis->ranBytecode())
-        analysis->analyzeBytecode(cx);
-    if (!analysis || analysis->OOM()) {
+    if (!script->ensureRanBytecode(cx)) {
         js_ReportOutOfMemory(cx);
         return js_InternalThrow(f);
     }
 
+    analyze::AutoEnterAnalysis enter(cx);
+    analyze::ScriptAnalysis *analysis = script->analysis();
+
     /*
      * f.regs.sp is not normally maintained by stubs (except for call prologues
      * where it indicates the new frame), so is not expected to be coherent
      * here. Update it to its value at the start of the opcode.
      */
     Value *oldsp = f.regs.sp;
     f.regs.sp = fp->base() + analysis->getCode(pc).stackDepth;
 
@@ -1314,17 +1310,17 @@ js_InternalInterpret(void *returnData, v
 #error "Unknown boxing format"
 #endif
         nextsp[-1].setRawBits(rvalBits);
 
         /*
          * When making a scripted call at monitored sites, it is the caller's
          * responsibility to update the pushed type set.
          */
-        script->types.monitor(cx, pc, nextsp[-1]);
+        types::TypeScript::Monitor(cx, script, pc, nextsp[-1]);
         f.regs.pc = nextpc;
         break;
       }
 
       case REJOIN_NONE:
         JS_NOT_REACHED("Unpossible rejoin!");
         break;
 
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -77,17 +77,17 @@ SafeMul(int32 one, int32 two, int32 *res
         return true;
     JaegerSpew(JSpew_Analysis, "Overflow computing %d * %d\n", one, two);
     return false;
 }
 
 LoopState::LoopState(JSContext *cx, analyze::CrossScriptSSA *ssa,
                      mjit::Compiler *cc, FrameState *frame)
     : cx(cx), ssa(ssa),
-      outerScript(ssa->outerScript()), outerAnalysis(outerScript->analysis(cx)),
+      outerScript(ssa->outerScript()), outerAnalysis(outerScript->analysis()),
       cc(*cc), frame(*frame),
       lifetime(NULL), alloc(NULL), reachedEntryPoint(false), loopRegs(0), skipAnalysis(false),
       loopJoins(CompilerAllocPolicy(cx, *cc)),
       loopPatches(CompilerAllocPolicy(cx, *cc)),
       restoreInvariantCalls(CompilerAllocPolicy(cx, *cc)),
       invariantEntries(CompilerAllocPolicy(cx, *cc)),
       outer(NULL), temporariesStart(0),
       testLHS(UNASSIGNED), testRHS(UNASSIGNED),
@@ -161,18 +161,18 @@ LoopState::init(jsbytecode *head, Jump e
 
     this->alloc = alloc;
     this->loopRegs = Registers::AvailAnyRegs;
 
     /*
      * Don't hoist bounds checks or loop invariant code in scripts that have
      * had indirect modification of their arguments.
      */
-    if (outerScript->fun) {
-        if (TypeSet::HasObjectFlags(cx, outerScript->fun->getType(cx), OBJECT_FLAG_UNINLINEABLE))
+    if (outerScript->hasFunction) {
+        if (TypeSet::HasObjectFlags(cx, outerScript->function()->getType(cx), OBJECT_FLAG_UNINLINEABLE))
             this->skipAnalysis = true;
     }
 
     /*
      * Don't hoist bounds checks or loop invariant code in loops with safe
      * points in the middle, which the interpreter can join at directly without
      * performing hoisted bounds checks or doing initial computation of loop
      * invariant terms.
@@ -975,17 +975,17 @@ LoopState::cannotIntegerOverflow(const C
 
     /*
      * Compute a slot and constant such that the result of the binary op is
      * 'slot + constant', where slot is expressed in terms of its value at
      * the head of the loop.
      */
     JS_ASSERT(pushed.v.kind() == SSAValue::PUSHED);
     jsbytecode *PC = ssa->getFrame(pushed.frame).script->code + pushed.v.pushedOffset();
-    ScriptAnalysis *analysis = ssa->getFrame(pushed.frame).script->analysis(cx);
+    ScriptAnalysis *analysis = ssa->getFrame(pushed.frame).script->analysis();
 
     uint32 baseSlot = UNASSIGNED;
     int32 baseConstant = 0;
     JSOp op = JSOp(*PC);
     switch (op) {
 
       case JSOP_INCLOCAL:
       case JSOP_LOCALINC:
@@ -1419,17 +1419,17 @@ LoopState::restoreInvariants(jsbytecode 
                 masm.loadPtr(Address(T0, js::TypedArray::dataOffset()), T0);
                 masm.storePtr(T0, address);
             }
             break;
           }
 
           case InvariantEntry::INVARIANT_ARGS_BASE: {
             Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary));
-            masm.loadFrameActuals(outerScript->fun, T0);
+            masm.loadFrameActuals(outerScript->function(), T0);
             masm.storePtr(T0, address);
             break;
           }
 
           case InvariantEntry::INVARIANT_ARGS_LENGTH: {
             Address address = frame.addressOf(frame.getTemporary(entry.u.array.temporary));
             masm.load32(Address(JSFrameReg, StackFrame::offsetOfArgs()), T0);
             masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), T0, address);
@@ -1753,17 +1753,17 @@ void
 LoopState::analyzeLoopBody(unsigned frame)
 {
     if (cc.debugMode()) {
         skipAnalysis = true;
         return;
     }
 
     JSScript *script = ssa->getFrame(frame).script;
-    analyze::ScriptAnalysis *analysis = script->analysis(cx);
+    analyze::ScriptAnalysis *analysis = script->analysis();
     JS_ASSERT(analysis && !analysis->failed() && analysis->ranInference());
 
     /*
      * The temporaries need to be positioned after all values in the deepest
      * inlined frame plus another stack frame pushed by, e.g. ic::Call.
      * This new frame will have been partially initialized by the call, and
      * we don't want to scribble on that frame when restoring invariants.
      */
@@ -2084,17 +2084,17 @@ LoopState::adjustConstantForIncrement(js
 }
 
 bool
 LoopState::getEntryValue(const CrossSSAValue &iv, uint32 *pslot, int32 *pconstant)
 {
     CrossSSAValue cv = ssa->foldValue(iv);
 
     JSScript *script = ssa->getFrame(cv.frame).script;
-    ScriptAnalysis *analysis = script->analysis(cx);
+    ScriptAnalysis *analysis = script->analysis();
     const SSAValue &v = cv.v;
 
     /*
      * For a stack value popped by the bytecode at offset, try to get an
      * expression 'slot + constant' with the same value as the stack value
      * and expressed in terms of the state at loop entry.
      */
 
@@ -2194,17 +2194,17 @@ LoopState::getEntryValue(const CrossSSAV
         return false;
     }
 }
 
 bool
 LoopState::computeInterval(const CrossSSAValue &cv, int32 *pmin, int32 *pmax)
 {
     JSScript *script = ssa->getFrame(cv.frame).script;
-    ScriptAnalysis *analysis = script->analysis(cx);
+    ScriptAnalysis *analysis = script->analysis();
     const SSAValue &v = cv.v;
 
     if (v.kind() == SSAValue::VAR && !v.varInitial()) {
         jsbytecode *pc = script->code + v.varOffset();
         switch (JSOp(*pc)) {
           case JSOP_SETLOCAL:
           case JSOP_SETARG: {
             CrossSSAValue ncv(cv.frame, analysis->poppedValue(pc, 0));
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -839,17 +839,17 @@ class CallCompiler : public BaseCompiler
         if (callingNew)
             args.thisv().setMagicWithObjectOrNullPayload(NULL);
 
         RecompilationMonitor monitor(cx);
 
         if (!CallJSNative(cx, fun->u.n.native, args))
             THROWV(true);
 
-        f.script()->types.monitor(f.cx, f.pc(), args.rval());
+        types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 
         /* Don't touch the IC if the call triggered a recompilation. */
         if (monitor.recompiled())
             return true;
 
         /* Right now, take slow-path for IC misses or multiple stubs. */
         if (ic.fastGuardedNative || ic.hasJsFunCheck)
             return true;
@@ -974,26 +974,28 @@ class CallCompiler : public BaseCompiler
         /* Reload fp, which may have been clobbered by restoreStackBase(). */
         masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
 
         Jump hasException = masm.branchTest32(Assembler::Zero, Registers::ReturnReg,
                                               Registers::ReturnReg);
 
         Vector<Jump> mismatches(f.cx);
         if (cx->typeInferenceEnabled()) {
+            types::AutoEnterTypeInference enter(f.cx);
+
             /*
              * Test the result of this native against the known result type
              * set for the call. We don't assume knowledge about the types that
              * natives can return, except when generating specialized paths in
              * FastBuiltins. We don't need to record dependencies on the result
              * type set, as the compiler will already have done so when making
              * the call IC.
              */
             Address address(JSFrameReg, vpOffset);
-            types::TypeSet *types = f.script()->types.bytecodeTypes(f.pc());
+            types::TypeSet *types = f.script()->analysis()->bytecodeTypes(f.pc());
             if (!masm.generateTypeCheck(f.cx, address, types, &mismatches))
                 THROWV(true);
 
             /*
              * Can no longer trigger recompilation in this stub, clear the stub
              * rejoin on the VMFrame.
              */
             masm.storePtr(ImmPtr(NULL), FrameAddress(offsetof(VMFrame, stubRejoin)));
@@ -1299,24 +1301,26 @@ ic::GenerateArgumentCheckStub(VMFrame &f
 
     if (jit->argsCheckPool)
         jit->resetArgsCheck();
 
     Assembler masm;
     Vector<Jump> mismatches(f.cx);
 
     if (!f.fp()->isConstructing()) {
+        types::TypeSet *types = types::TypeScript::ThisTypes(script);
         Address address(JSFrameReg, StackFrame::offsetOfThis(fun));
-        if (!masm.generateTypeCheck(f.cx, address, script->types.thisTypes(), &mismatches))
+        if (!masm.generateTypeCheck(f.cx, address, types, &mismatches))
             return;
     }
 
     for (unsigned i = 0; i < fun->nargs; i++) {
+        types::TypeSet *types = types::TypeScript::ArgTypes(script, i);
         Address address(JSFrameReg, StackFrame::offsetOfFormalArg(fun, i));
-        if (!masm.generateTypeCheck(f.cx, address, script->types.argTypes(i), &mismatches))
+        if (!masm.generateTypeCheck(f.cx, address, types, &mismatches))
             return;
     }
 
     Jump done = masm.jump();
 
     LinkerHelper linker(masm);
     JSC::ExecutablePool *ep = linker.init(f.cx);
     if (!ep)
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -663,24 +663,24 @@ class SetPropCompiler : public PICStubCo
                  * script. We also depend on the fact that the scope chains hit
                  * at the same bytecode are all isomorphic: the same scripts,
                  * in the same order (though the properties on their call
                  * objects may differ due to eval(), DEFFUN, etc.).
                  */
                 RecompilationMonitor monitor(cx);
                 JSScript *script = obj->getCallObjCalleeFunction()->script();
                 uint16 slot = uint16(shape->shortid);
-                if (!script->types.ensureTypeArray(cx))
+                if (!script->ensureHasTypes(cx))
                     return error();
                 {
                     types::AutoEnterTypeInference enter(cx);
                     if (shape->setterOp() == SetCallArg)
-                        pic.rhsTypes->addSubset(cx, script->types.argTypes(slot));
+                        pic.rhsTypes->addSubset(cx, types::TypeScript::ArgTypes(script, slot));
                     else
-                        pic.rhsTypes->addSubset(cx, script->types.localTypes(slot));
+                        pic.rhsTypes->addSubset(cx, types::TypeScript::LocalTypes(script, slot));
                 }
                 if (monitor.recompiled())
                     return Lookup_Uncacheable;
             }
         }
 
         JS_ASSERT(obj == holder);
         if (!pic.inlinePathPatched &&
@@ -1759,21 +1759,21 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
     if (atom == f.cx->runtime->atomState.lengthAtom) {
         if (f.regs.sp[-1].isString()) {
             GetPropCompiler cc(f, script, NULL, *pic, NULL, DisabledGetPropIC);
             LookupStatus status = cc.generateStringLengthStub();
             if (status == Lookup_Error)
                 THROW();
             JSString *str = f.regs.sp[-1].toString();
             f.regs.sp[-1].setInt32(str->length());
-            f.script()->types.monitor(f.cx, f.pc(), f.regs.sp[-1]);
+            types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-1]);
             return;
         } else if (f.regs.sp[-1].isMagic(JS_LAZY_ARGUMENTS)) {
             f.regs.sp[-1].setInt32(f.regs.fp()->numActualArgs());
-            f.script()->types.monitor(f.cx, f.pc(), f.regs.sp[-1]);
+            types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-1]);
             return;
         } else if (!f.regs.sp[-1].isPrimitive()) {
             JSObject *obj = &f.regs.sp[-1].toObject();
             if (obj->isArray() ||
                 (obj->isArguments() && !obj->asArguments()->hasOverriddenLength()) ||
                 obj->isString()) {
                 GetPropCompiler cc(f, script, obj, *pic, NULL, DisabledGetPropIC);
                 if (obj->isArray()) {
@@ -1788,17 +1788,17 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
                     f.regs.sp[-1].setInt32(int32_t(obj->asArguments()->initialLength()));
                 } else if (obj->isString()) {
                     LookupStatus status = cc.generateStringObjLengthStub();
                     if (status == Lookup_Error)
                         THROW();
                     JSString *str = obj->getPrimitiveThis().toString();
                     f.regs.sp[-1].setInt32(str->length());
                 }
-                f.script()->types.monitor(f.cx, f.pc(), f.regs.sp[-1]);
+                types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-1]);
                 return;
             }
         }
         atom = f.cx->runtime->atomState.lengthAtom;
     }
 
     bool usePropCache = pic->usePropCache;
 
@@ -1831,17 +1831,17 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
     /*
      * Ignore undefined reads for the 'prototype' property in constructors,
      * which will be at the start of the script and are never holes due to fun_resolve.
      * Any undefined value was explicitly stored here, and is known by inference.
      * :FIXME: looking under the usePropCache abstraction, which is only unset for
      * reads of the prototype.
      */
     if (usePropCache)
-        f.script()->types.monitor(f.cx, f.pc(), v);
+        types::TypeScript::Monitor(f.cx, f.script(), f.pc(), v);
 
     f.regs.sp[-1] = v;
 }
 
 void JS_FASTCALL
 ic::GetPropNoCache(VMFrame &f, ic::PICInfo *pic)
 {
     /*
@@ -1997,17 +1997,17 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         regs.sp[-2].setString(JSID_TO_STRING(id));
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     }
 #endif
 
-    f.script()->types.monitor(cx, f.pc(), regs.sp[-2]);
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), regs.sp[-2]);
 
     if (monitor.recompiled())
         return;
 
     GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, DisabledCallPropIC);
     if (lval.isObject()) {
         if (pic->shouldUpdate(cx)) {
             LookupStatus status = cc.update();
@@ -2049,17 +2049,17 @@ ic::XName(VMFrame &f, ic::PICInfo *pic)
     if (status == Lookup_Error)
         THROW();
 
     Value rval;
     if (!cc.retrieve(&rval, NULL))
         THROW();
     f.regs.sp[-1] = rval;
 
-    f.script()->types.monitor(f.cx, f.pc(), rval);
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), rval);
 }
 
 void JS_FASTCALL
 ic::Name(VMFrame &f, ic::PICInfo *pic)
 {
     JSScript *script = f.fp()->script();
 
     ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, DisabledNameIC);
@@ -2068,17 +2068,17 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
     if (status == Lookup_Error)
         THROW();
 
     Value rval;
     if (!cc.retrieve(&rval, NULL))
         THROW();
     f.regs.sp[0] = rval;
 
-    f.script()->types.monitor(f.cx, f.pc(), rval);
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), rval);
 }
 
 static void JS_FASTCALL
 DisabledCallNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::CallName(f);
 }
 
@@ -2095,17 +2095,17 @@ ic::CallName(VMFrame &f, ic::PICInfo *pi
 
     Value rval, thisval;
     if (!cc.retrieve(&rval, &thisval))
         THROW();
 
     f.regs.sp[0] = rval;
     f.regs.sp[1] = thisval;
 
-    f.script()->types.monitor(f.cx, f.pc(), rval);
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), rval);
 }
 
 static void JS_FASTCALL
 DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::BindName(f);
 }
 
@@ -2546,18 +2546,18 @@ ic::CallElement(VMFrame &f, ic::GetEleme
         if (status != Lookup_Uncacheable) {
             if (status == Lookup_Error)
                 THROW();
 
             // If the result can be cached, the value was already retrieved.
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             f.regs.sp[-1].setObject(*thisObj);
             if (!JSID_IS_INT(id))
-                f.script()->types.monitorUnknown(cx, f.pc());
-            f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
+                types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
+            types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]);
             return;
         }
     }
 
     /* Get or set the element. */
     if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, &f.regs.sp[-2]))
         THROW();
 
@@ -2568,18 +2568,18 @@ ic::CallElement(VMFrame &f, ic::GetEleme
         if (!js_OnUnknownMethod(cx, f.regs.sp - 2))
             THROW();
     } else
 #endif
     {
         f.regs.sp[-1] = thisv;
     }
     if (!JSID_IS_INT(id))
-        f.script()->types.monitorUnknown(cx, f.pc());
-    f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
+        types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]);
 }
 
 void JS_FASTCALL
 ic::GetElement(VMFrame &f, ic::GetElementIC *ic)
 {
     JSContext *cx = f.cx;
 
     // Right now, we don't optimize for strings or lazy arguments.
@@ -2612,27 +2612,27 @@ ic::GetElement(VMFrame &f, ic::GetElemen
         LookupStatus status = ic->update(f, cx, obj, idval, id, &f.regs.sp[-2]);
         if (status != Lookup_Uncacheable) {
             if (status == Lookup_Error)
                 THROW();
 
             // If the result can be cached, the value was already retrieved.
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             if (!JSID_IS_INT(id))
-                f.script()->types.monitorUnknown(cx, f.pc());
-            f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
+                types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
+            types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]);
             return;
         }
     }
 
     if (!obj->getProperty(cx, id, &f.regs.sp[-2]))
         THROW();
     if (!JSID_IS_INT(id))
-        f.script()->types.monitorUnknown(cx, f.pc());
-    f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
+        types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
+    types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]);
 }
 
 #define APPLY_STRICTNESS(f, s)                          \
     (FunctionTemplateConditional(s, f<true>, f<false>))
 
 LookupStatus
 SetElementIC::disable(JSContext *cx, const char *reason)
 {
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -369,17 +369,17 @@ NameOp(VMFrame &f, JSObject *obj, bool c
         if (!js_FindPropertyHelper(cx, id, true, global, &obj, &obj2, &prop))
             return NULL;
         if (!prop) {
             /* Kludge to allow (typeof foo == "undefined") tests. */
             JSOp op2 = js_GetOpcode(cx, f.script(), f.pc() + JSOP_NAME_LENGTH);
             if (op2 == JSOP_TYPEOF) {
                 f.regs.sp++;
                 f.regs.sp[-1].setUndefined();
-                f.script()->types.monitor(cx, f.pc(), f.regs.sp[-1]);
+                TypeScript::Monitor(cx, f.script(), f.pc(), f.regs.sp[-1]);
                 return obj;
             }
             ReportAtomNotDefined(cx, atom);
             return NULL;
         }
 
         /* Take the slow path if prop was not found in a native object. */
         if (!obj->isNative() || !obj2->isNative()) {
@@ -396,17 +396,17 @@ NameOp(VMFrame &f, JSObject *obj, bool c
         /*
          * If this is an incop, update the property's types themselves,
          * to capture the type effect on the intermediate value.
          */
         if (rval.isUndefined() && (js_CodeSpec[*f.pc()].format & (JOF_INC|JOF_DEC)))
             AddTypePropertyId(cx, obj, id, Type::UndefinedType());
     }
 
-    f.script()->types.monitor(cx, f.pc(), rval);
+    TypeScript::Monitor(cx, f.script(), f.pc(), rval);
 
     *f.regs.sp++ = rval;
 
     if (callname)
         PushImplicitThis(f, obj, rval);
 
     return obj;
 }
@@ -437,25 +437,25 @@ stubs::GetElem(VMFrame &f)
     if (lref.isString() && rref.isInt32()) {
         JSString *str = lref.toString();
         int32_t i = rref.toInt32();
         if ((size_t)i < str->length()) {
             str = JSAtom::getUnitStringForElement(cx, str, (size_t)i);
             if (!str)
                 THROW();
             f.regs.sp[-2].setString(str);
-            f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
+            TypeScript::Monitor(cx, f.script(), f.pc(), f.regs.sp[-2]);
             return;
         }
     }
 
     if (lref.isMagic(JS_LAZY_ARGUMENTS)) {
         if (rref.isInt32() && size_t(rref.toInt32()) < regs.fp()->numActualArgs()) {
             regs.sp[-2] = regs.fp()->canonicalActualArg(rref.toInt32());
-            f.script()->types.monitor(cx, f.pc(), regs.sp[-2]);
+            TypeScript::Monitor(cx, f.script(), f.pc(), regs.sp[-2]);
             return;
         }
         MarkArgumentsCreated(cx, f.script());
         JS_ASSERT(!lref.isMagic(JS_LAZY_ARGUMENTS));
     }
 
     JSObject *obj = ValueToObject(cx, &lref);
     if (!obj)
@@ -503,21 +503,21 @@ stubs::GetElem(VMFrame &f)
         }
     }
 
     if (!obj->getProperty(cx, id, &rval))
         THROW();
     copyFrom = &rval;
 
     if (!JSID_IS_INT(id))
-        f.script()->types.monitorUnknown(cx, f.pc());
+        TypeScript::MonitorUnknown(cx, f.script(), f.pc());
 
   end_getelem:
     f.regs.sp[-2] = *copyFrom;
-    f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
+    TypeScript::Monitor(cx, f.script(), f.pc(), f.regs.sp[-2]);
 }
 
 static inline bool
 FetchElementId(VMFrame &f, JSObject *obj, const Value &idval, jsid &id, Value *vp)
 {
     int32_t i_;
     if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
         id = INT_TO_JSID(i_);
@@ -554,18 +554,18 @@ stubs::CallElem(VMFrame &f)
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     } else
 #endif
     {
         regs.sp[-1] = thisv;
     }
     if (!JSID_IS_INT(id))
-        f.script()->types.monitorUnknown(cx, f.pc());
-    f.script()->types.monitor(cx, f.pc(), regs.sp[-2]);
+        TypeScript::MonitorUnknown(cx, f.script(), f.pc());
+    TypeScript::Monitor(cx, f.script(), f.pc(), regs.sp[-2]);
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::SetElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
@@ -579,17 +579,17 @@ stubs::SetElem(VMFrame &f)
 
     obj = ValueToObject(cx, &objval);
     if (!obj)
         THROW();
 
     if (!FetchElementId(f, obj, idval, id, &regs.sp[-2]))
         THROW();
 
-    f.script()->types.monitorAssign(cx, f.pc(), obj, id, rval);
+    TypeScript::MonitorAssign(cx, f.script(), f.pc(), obj, id, rval);
 
     do {
         if (obj->isDenseArray() && JSID_IS_INT(id)) {
             jsuint length = obj->getDenseArrayInitializedLength();
             jsint i = JSID_TO_INT(id);
             if ((jsuint)i < length) {
                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
                     if (js_PrototypeHasIndexedProperties(cx, obj))
@@ -634,17 +634,17 @@ stubs::ToId(VMFrame &f)
     if (!obj)
         THROW();
 
     jsid id;
     if (!FetchElementId(f, obj, idval, id, &idval))
         THROW();
 
     if (!idval.isInt32())
-        f.script()->types.monitorUnknown(f.cx, f.pc());
+        TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
 stubs::CallName(VMFrame &f)
 {
     JSObject *obj = NameOp(f, &f.fp()->scopeChain(), true);
     if (!obj)
         THROW();
@@ -743,17 +743,17 @@ stubs::Ursh(VMFrame &f)
         THROW();
     int32_t j;
     if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j))
         THROW();
 
     u >>= (j & 31);
 
 	if (!f.regs.sp[-2].setNumber(uint32(u)))
-        f.script()->types.monitorOverflow(f.cx, f.pc());
+        TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DefFun(VMFrame &f, JSFunction *fun)
 {
     JSObject *obj2;
 
@@ -1059,17 +1059,17 @@ stubs::Add(VMFrame &f)
     } else
 #if JS_HAS_XML_SUPPORT
     if (lval.isObject() && lval.toObject().isXML() &&
         rval.isObject() && rval.toObject().isXML()) {
         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
             THROW();
         regs.sp[-2] = rval;
         regs.sp--;
-        f.script()->types.monitorUnknown(cx, f.pc());
+        TypeScript::MonitorUnknown(cx, f.script(), f.pc());
     } else
 #endif
     {
         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
         if (!ToPrimitive(f.cx, &lval))
             THROW();
         if (!ToPrimitive(f.cx, &rval))
             THROW();
@@ -1086,27 +1086,27 @@ stubs::Add(VMFrame &f)
                 rstr = rval.toString();
             } else {
                 rstr = js_ValueToString(cx, rval);
                 if (!rstr)
                     THROW();
                 regs.sp[-1].setString(rstr);
             }
             if (lIsObject || rIsObject)
-                f.script()->types.monitorString(cx, f.pc());
+                TypeScript::MonitorString(cx, f.script(), f.pc());
             goto string_concat;
 
         } else {
             double l, r;
             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
                 THROW();
             l += r;
             if (!regs.sp[-2].setNumber(l) &&
                 (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
-                f.script()->types.monitorOverflow(cx, f.pc());
+                TypeScript::MonitorOverflow(cx, f.script(), f.pc());
             }
         }
     }
     return;
 
   string_concat:
     JSString *str = js_ConcatStrings(cx, lstr, rstr);
     if (!str)
@@ -1121,30 +1121,30 @@ stubs::Sub(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
     double d1, d2;
     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
         THROW();
     double d = d1 - d2;
     if (!regs.sp[-2].setNumber(d))
-        f.script()->types.monitorOverflow(cx, f.pc());
+        TypeScript::MonitorOverflow(cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
 stubs::Mul(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
     double d1, d2;
     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
         THROW();
     double d = d1 * d2;
     if (!regs.sp[-2].setNumber(d))
-        f.script()->types.monitorOverflow(cx, f.pc());
+        TypeScript::MonitorOverflow(cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
 stubs::Div(VMFrame &f)
 {
     JSContext *cx = f.cx;
     JSRuntime *rt = cx->runtime;
     FrameRegs &regs = f.regs;
@@ -1162,21 +1162,21 @@ stubs::Div(VMFrame &f)
 #endif
         if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
             vp = &rt->NaNValue;
         else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
             vp = &rt->negativeInfinityValue;
         else
             vp = &rt->positiveInfinityValue;
         regs.sp[-2] = *vp;
-        f.script()->types.monitorOverflow(cx, f.pc());
+        TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     } else {
         d1 /= d2;
         if (!regs.sp[-2].setNumber(d1))
-            f.script()->types.monitorOverflow(cx, f.pc());
+            TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     }
 }
 
 void JS_FASTCALL
 stubs::Mod(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
@@ -1193,17 +1193,17 @@ stubs::Mod(VMFrame &f)
         if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
             THROW();
         if (d2 == 0) {
             regs.sp[-2].setDouble(js_NaN);
         } else {
             d1 = js_fmod(d1, d2);
             regs.sp[-2].setDouble(d1);
         }
-        f.script()->types.monitorOverflow(cx, f.pc());
+        TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     }
 }
 
 void JS_FASTCALL
 stubs::Debugger(VMFrame &f, jsbytecode *pc)
 {
     JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler;
     if (handler) {
@@ -1294,33 +1294,33 @@ void JS_FASTCALL
 stubs::This(VMFrame &f)
 {
     /*
      * We can't yet inline scripts which need to compute their 'this' object
      * from a primitive; the frame we are computing 'this' for does not exist yet.
      */
     if (f.regs.inlined()) {
         f.script()->uninlineable = true;
-        MarkTypeObjectFlags(f.cx, f.script()->fun, OBJECT_FLAG_UNINLINEABLE);
+        MarkTypeObjectFlags(f.cx, &f.fp()->callee(), OBJECT_FLAG_UNINLINEABLE);
     }
 
     if (!ComputeThis(f.cx, f.fp()))
         THROW();
     f.regs.sp[-1] = f.fp()->thisValue();
 }
 
 void JS_FASTCALL
 stubs::Neg(VMFrame &f)
 {
     double d;
     if (!ToNumber(f.cx, f.regs.sp[-1], &d))
         THROW();
     d = -d;
     if (!f.regs.sp[-1].setNumber(d))
-        f.script()->types.monitorOverflow(f.cx, f.pc());
+        TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 JSObject * JS_FASTCALL
 stubs::NewInitArray(VMFrame &f, uint32 count)
 {
     JSObject *obj = NewDenseAllocatedArray(f.cx, count);
     if (!obj)
         THROWV(NULL);
@@ -1572,17 +1572,17 @@ InlineGetProp(VMFrame &f)
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
     Value *vp = &f.regs.sp[-1];
 
     if (vp->isMagic(JS_LAZY_ARGUMENTS)) {
         JS_ASSERT(js_GetOpcode(cx, f.script(), f.pc()) == JSOP_LENGTH);
         regs.sp[-1] = Int32Value(regs.fp()->numActualArgs());
-        f.script()->types.monitor(cx, f.pc(), regs.sp[-1]);
+        TypeScript::Monitor(cx, f.script(), f.pc(), regs.sp[-1]);
         return true;
     }
 
     JSObject *obj = ValueToObject(f.cx, vp);
     if (!obj)
         return false;
 
     Value rval;
@@ -1621,17 +1621,17 @@ InlineGetProp(VMFrame &f)
                     ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                     : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
                     &rval)
                 : !obj->getProperty(cx, id, &rval)) {
             return false;
         }
     } while(0);
 
-    f.script()->types.monitor(cx, f.pc(), rval);
+    TypeScript::Monitor(cx, f.script(), f.pc(), rval);
 
     regs.sp[-1] = rval;
     return true;
 }
 
 void JS_FASTCALL
 stubs::GetProp(VMFrame &f)
 {
@@ -1741,17 +1741,17 @@ stubs::CallProp(VMFrame &f, JSAtom *orig
     }
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         regs.sp[-2].setString(origAtom);
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     }
 #endif
-    f.script()->types.monitor(cx, f.pc(), rval);
+    TypeScript::Monitor(cx, f.script(), f.pc(), rval);
 }
 
 void JS_FASTCALL
 stubs::Iter(VMFrame &f, uint32 flags)
 {
     if (!js_ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
         THROW();
     JS_ASSERT(!f.regs.sp[-1].isPrimitive());
@@ -2193,17 +2193,17 @@ stubs::Unbrand(VMFrame &f)
 }
 
 void JS_FASTCALL
 stubs::Pos(VMFrame &f)
 {
     if (!ToNumber(f.cx, &f.regs.sp[-1]))
         THROW();
     if (!f.regs.sp[-1].isInt32())
-        f.script()->types.monitorOverflow(f.cx, f.pc());
+        TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
 stubs::ArgSub(VMFrame &f, uint32 n)
 {
     jsid id = INT_TO_JSID(n);
     Value rval;
     if (!js_GetArgsProperty(f.cx, f.fp(), id, &rval))
@@ -2368,39 +2368,39 @@ stubs::TypeBarrierHelper(VMFrame &f, uin
     result = f.regs.sp[0];
 
     /*
      * Break type barriers at this bytecode if we have added many objects to
      * the target already. This isn't needed if inference results for the
      * script have been destroyed, as we will reanalyze and prune type barriers
      * as they are regenerated.
      */
-    if (f.script()->hasAnalysis() && f.script()->analysis(f.cx)->ranInference()) {
+    if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
         AutoEnterTypeInference enter(f.cx);
-        f.script()->analysis(f.cx)->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
+        f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
     }
 
-    f.script()->types.monitor(f.cx, f.pc(), result);
+    TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
 }
 
 /*
  * Variant of TypeBarrierHelper for checking types after making a native call.
  * The stack is already correct, and no fixup should be performed.
  */
 void JS_FASTCALL
 stubs::TypeBarrierReturn(VMFrame &f, Value *vp)
 {
-    f.script()->types.monitor(f.cx, f.pc(), vp[0]);
+    TypeScript::Monitor(f.cx, f.script(), f.pc(), vp[0]);
 }
 
 void JS_FASTCALL
 stubs::NegZeroHelper(VMFrame &f)
 {
     f.regs.sp[-1].setDouble(-0.0);
-    f.script()->types.monitorOverflow(f.cx, f.pc());
+    TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
 stubs::CallPropSwap(VMFrame &f)
 {
     /*
      * CALLPROP operations on strings are implemented in terms of GETPROP.
      * If we rejoin from such a GETPROP, we come here at the end of the
@@ -2425,19 +2425,19 @@ stubs::CheckArgumentTypes(VMFrame &f)
     JSScript *script = fun->script();
     RecompilationMonitor monitor(f.cx);
 
     {
         /* Postpone recompilations until all args have been updated. */
         types::AutoEnterTypeInference enter(f.cx);
 
         if (!f.fp()->isConstructing())
-            script->types.setThis(f.cx, fp->thisValue());
+            TypeScript::SetThis(f.cx, script, fp->thisValue());
         for (unsigned i = 0; i < fun->nargs; i++)
-            script->types.setArgument(f.cx, i, fp->formalArg(i));
+            TypeScript::SetArgument(f.cx, script, i, fp->formalArg(i));
     }
 
     if (monitor.recompiled())
         return;
 
 #ifdef JS_MONOIC
     ic::GenerateArgumentCheckStub(f);
 #endif
@@ -2447,22 +2447,22 @@ stubs::CheckArgumentTypes(VMFrame &f)
 void JS_FASTCALL
 stubs::AssertArgumentTypes(VMFrame &f)
 {
     StackFrame *fp = f.fp();
     JSFunction *fun = fp->fun();
     JSScript *script = fun->script();
 
     Type type = GetValueType(f.cx, fp->thisValue());
-    if (!script->types.thisTypes()->hasType(type))
+    if (!TypeScript::ThisTypes(script)->hasType(type))
         TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
 
     for (unsigned i = 0; i < fun->nargs; i++) {
         type = GetValueType(f.cx, fp->formalArg(i));
-        if (!script->types.argTypes(i)->hasType(type))
+        if (!TypeScript::ArgTypes(script, i)->hasType(type))
             TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
     }
 }
 #endif
 
 /*
  * These two are never actually called, they just give us a place to rejoin if
  * there is an invariant failure when initially entering a loop.