[INFER] Fixes for jstests, bug 620599, part 2.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 21 Dec 2010 18:26:09 -0800
changeset 74683 2d2bc8417871d24c3981e2142f41eeb9bfc8e518
parent 74682 a6438d91ca4d309bf5356eed2dc799608379f924
child 74684 955c4fbfbd09cf1ab6458cbe24cd411c3f2ec5f3
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs620599
milestone2.0b8pre
[INFER] Fixes for jstests, bug 620599, part 2.
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsarray.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsregexp.cpp
js/src/jsscript.cpp
js/src/jstypedarray.cpp
js/src/jswrapper.cpp
js/src/shell/js.cpp
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -77,16 +77,23 @@ TypeCompartment::~TypeCompartment()
 
 types::TypeObject *
 TypeCompartment::newTypeObject(JSContext *cx, analyze::Script *script, const char *name,
                                bool isFunction, JSObject *proto)
 {
     JSArenaPool &pool = script ? script->pool : this->pool;
 
 #ifdef DEBUG
+#if 1 /* Define to get unique printed names, including when there are multiple globals. */
+    static unsigned nameCount = 0;
+    unsigned len = strlen(name) + 15;
+    char *newName = (char *) alloca(len);
+    JS_snprintf(newName, len, "%u:%s", ++nameCount, name);
+    name = newName;
+#endif
     jsid id = ATOM_TO_JSID(js_Atomize(cx, name, strlen(name), ATOM_PINNED));
 #else
     jsid id = JSID_VOID;
 #endif
 
     TypeObject *object;
     if (isFunction)
         object = ArenaNew<TypeFunction>(pool, &pool, id, proto);
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -207,32 +207,26 @@ class Script
     void destroy();
 
     /*
      * For analysis scripts allocated on the stack.  Scripts don't have constructors,
      * and must be zeroed out before being used.
      */
     ~Script() { destroy(); }
 
-    /* Whether we ran out of memory during analysis. */
     bool OOM() { return outOfMemory; }
-
-    /* Whether the script was analyzed successfully. */
     bool failed() { return hadFailure; }
 
     /* 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; }
 
-    /* Whether the script has been analyzed. */
     bool hasAnalyzed() const { return !!codeArray; }
-
-    /* Script/function being analyzed. */
     JSScript *getScript() const { return script; }
 
     /* Accessors for bytecode information. */
 
     Bytecode& getCode(uint32 offset) {
         JS_ASSERT(offset < script->length);
         JS_ASSERT(codeArray[offset]);
         return *codeArray[offset];
@@ -317,16 +311,19 @@ class Script
   public:
 
     /* Unique identifier within the compartment. */
     unsigned id;
 
     /* Function this script is the body for, if there is one. */
     JSFunction *fun;
 
+    /* Global object for this script, if compileAndGo. */
+    JSObject *global;
+
     /* List of objects associated with this script. */
     types::TypeObject *objects;
 
     /*
      * Location where the definition of this script occurs, representing any
      * nesting for scope lookups.  NULL for global scripts.
      */
     JSScript *parent;
@@ -342,25 +339,25 @@ class Script
     /* Types of the 'this' variable in this script. */
     types::TypeSet thisTypes;
 
     /* Array of local variable names, computed by js_GetLocalNameArray. */
     jsuword *localNames;
 
     void setFunction(JSContext *cx, JSFunction *fun);
 
-    /* Whether this is eval code. */
     bool isEval() { return parent && !fun; }
-
-    /* Whether this is global code, including from a global-scope eval(). */
     bool isGlobal() { return !parent || (!fun && !parent->analysis->parent); }
 
     unsigned argCount() { return fun ? fun->nargs : 0; }
     types::TypeFunction *function() { return fun->getType()->asFunction(); }
 
+    inline JSObject *getGlobal();
+    inline types::TypeObject *getGlobalType();
+
     /*
      * Get the non-eval script which this one is nested in, returning this script
      * if it was not produced as the result of an eval.
      */
     inline Script *evalParent();
 
     /* Bytecode where this script is nested. */
     inline Bytecode *parentCode();
@@ -461,34 +458,31 @@ class Script
                 }
             }
         }
     };
 
     /* Analyzes a bytecode, generating type constraints describing its behavior. */
     void analyzeTypes(JSContext *cx, Bytecode *code, AnalyzeState &state);
 
-    /* Get the name to use for the local with specified index. */
+    /* Get the default 'new' object for a given standard class, per the script's global. */
+    inline js::types::TypeObject *getTypeNewObject(JSContext *cx, JSProtoKey key);
+
     inline jsid getLocalId(unsigned index, Bytecode *code);
-
-    /* Get the name to use for the argument with the specified index. */
     inline jsid getArgumentId(unsigned index);
 
-    /* Get or make type information for the specified local/argument variable. */
     inline types::TypeSet *getVariable(JSContext *cx, jsid id);
 
     /* Get the type set to use for a stack slot at a fixed stack depth. */
     inline types::TypeSet *getStackTypes(unsigned index, Bytecode *code);
 
-    /* Get any known type tag for an argument or local variable. */
     inline JSValueType knownArgumentTypeTag(JSContext *cx, JSScript *script, unsigned arg);
     inline JSValueType knownLocalTypeTag(JSContext *cx, JSScript *script, unsigned local);
 
-    /* Helpers */
-
+  private:
     void addVariable(JSContext *cx, jsid id, types::Variable *&var);
 
 #endif /* JS_TYPE_INFERENCE */
 };
 
 static inline unsigned
 GetBytecodeLength(jsbytecode *pc)
 {
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2494,48 +2494,49 @@ array_splice(JSContext *cx, uintN argc, 
  * Python-esque sequence operations.
  */
 static JSBool
 array_concat(JSContext *cx, uintN argc, Value *vp)
 {
     /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
     Value *p = JS_ARGV(cx, vp) - 1;
 
+    /* Get the type object to use for the result. */
+    TypeObject *ntype = cx->getTypeCallerInitObject(true);
+    if (!ntype)
+        return JS_FALSE;
+    if (cx->isTypeCallerMonitored())
+        cx->markTypeObjectUnknownProperties(ntype);
+
     /* Create a new Array object and root it using *vp. */
     JSObject *aobj = ComputeThisFromVp(cx, vp);
     JSObject *nobj;
     jsuint length;
     if (aobj->isDenseArray()) {
         length = aobj->getArrayLength();
         jsuint initlen = aobj->getDenseArrayInitializedLength();
         nobj = NewDenseCopiedArray(cx, initlen, aobj->getDenseArrayElements());
         if (!nobj)
             return JS_FALSE;
         nobj->setArrayLength(cx, length);
+        nobj->setType(ntype);
         vp->setObject(*nobj);
         if (argc == 0)
             return JS_TRUE;
         argc--;
         p++;
     } else {
         nobj = NewDenseEmptyArray(cx);
         if (!nobj)
             return JS_FALSE;
+        nobj->setType(ntype);
         vp->setObject(*nobj);
         length = 0;
     }
 
-    /* Get the type object to use for the result. */
-    TypeObject *ntype = cx->getTypeCallerInitObject(true);
-    if (!ntype)
-        return JS_FALSE;
-    nobj->setType(ntype);
-    if (cx->isTypeCallerMonitored())
-        cx->markTypeObjectUnknownProperties(ntype);
-
     if (aobj->isDenseArray() && !aobj->isPackedDenseArray())
         nobj->setDenseArrayNotPacked(cx);
 
     AutoValueRooter tvr(cx);
 
     /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
     for (uintN i = 0; i <= argc; i++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
@@ -3035,19 +3036,18 @@ static void array_TypeSort(JSContext *cx
     }
 
     if (site->argumentCount == 0)
         return;
 
     TypeSet *funTypes = site->argumentTypes[0];
 
     /* Make a callsite for the calls to the sorting function this will perform. */
-    jstype globalType = (jstype) cx->globalTypeObject();
     TypeCallsite *sortSite = ArenaNew<TypeCallsite>(site->pool(), site->code, false, 2);
-    sortSite->thisType = globalType;
+    sortSite->thisType = TYPE_UNDEFINED;
 
     /* Both arguments to the argument function are array elements. */
     TypeSet *argTypes = sortSite->argumentTypes[0] = sortSite->argumentTypes[1] =
         TypeSet::make(cx, site->pool(), "ArraySort");
     site->thisTypes->addGetProperty(cx, site->code, argTypes, JSID_VOID);
 
     funTypes->addCall(cx, sortSite);
 #endif
@@ -3173,17 +3173,17 @@ static void array_TypeExtra(JSContext *c
 
     /* Make the call site to use for the higher order function. */
     TypeCallsite *extraSite = ArenaNew<TypeCallsite>(pool, code, false, REDUCE_MODE(mode) ? 4 : 3);
 
     /* Figure out the 'this' type passed to the higher order function. */
     if (site->argumentCount > 1 && !REDUCE_MODE(mode))
         extraSite->thisTypes = site->argumentTypes[1];
     else
-        extraSite->thisType = (jstype) cx->globalTypeObject();
+        extraSite->thisType = TYPE_UNDEFINED;
 
     switch (mode) {
 
       case FOREACH:
         site->returnTypes->addType(cx, TYPE_UNDEFINED);
         break;
 
       case REDUCE: {
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -2304,23 +2304,26 @@ IsJITBrokenHere()
         computedIsBroken = true;
     }
     return isBroken;
 }
 
 void
 JSContext::updateJITEnabled()
 {
+    /* :FIXME: Don't enable the trace JIT if inference is on, they are not compatible yet. */
+#ifndef JS_TYPE_INFERENCE
 #ifdef JS_TRACER
     traceJitEnabled = ((options & JSOPTION_JIT) &&
                        !IsJITBrokenHere() &&
                        (debugHooks == &js_NullDebugHooks ||
                         (debugHooks == &runtime->globalDebugHooks &&
                          !runtime->debuggerInhibitsJIT())));
 #endif
+#endif
 #ifdef JS_METHODJIT
     methodJitEnabled = (options & JSOPTION_METHODJIT) &&
                        !IsJITBrokenHere()
 # if defined JS_CPU_X86 || defined JS_CPU_X64
                        && JSC::MacroAssemblerX86Common::getSSEState() >=
                           JSC::MacroAssemblerX86Common::HasSSE2
 # endif
                         ;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -2408,27 +2408,22 @@ public:
 
     /* Make a type function or object with the specified name. */
     js::types::TypeFunction *newTypeFunction(const char *name, JSObject *proto);
     js::types::TypeObject   *newTypeObject(const char *name, JSObject *proto);
 
     /* Make a type object whose name is that of base followed by postfix. */
     js::types::TypeObject *newTypeObject(const char *base, const char *postfix, JSObject *proto);
 
-    /* Get the default 'new' object for a given standard class. */
+    /*
+     * Get the default 'new' object for a given standard class, per the currently
+     * active global.
+     */
     inline js::types::TypeObject *getTypeNewObject(JSProtoKey key);
 
-    /*
-     * Get the type of the global object to use. :XXX: This function is probably
-     * totally broken when analyzing code involved with multiple global objects.
-     * It uses cx->globalObject even if that's not the global object attached to the
-     * COMPILE_N_GO script being analyzed.
-     */
-    inline js::types::TypeObject *globalTypeObject();
-
     /* Get a singleton type object to use for objects with no prototype. */
     inline js::types::TypeObject *emptyTypeObject();
 
     /* Set the type information for fun to the specified script. */
     inline void setTypeFunctionScript(JSFunction *fun, JSScript *script);
 
     /* Get a type object for the immediate allocation site in this context. */
     inline js::types::TypeObject *
@@ -2451,16 +2446,17 @@ public:
     inline void typeMonitorEntry(JSScript *script);
     inline void typeMonitorEntry(JSScript *script, const js::Value &thisv);
 
     /* Add a possible value for the named property of obj. */
     inline void addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type);
     inline void addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
     inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
     inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
+    inline void markTypePropertyUnknown(js::types::TypeObject *obj, jsid id);
 
     /* Get the type to add for properties which can be scripted getters/setters. */
     inline js::types::TypeObject *getTypeGetSet();
 
     /* Alias two properties in the type information for obj. */
     inline void aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second);
 
     /* Mark an array type as being not packed and, possibly, not dense. */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1549,42 +1549,51 @@ fun_getProperty(JSContext *cx, JSObject 
     /* Find fun's top-most activation record. */
     JSStackFrame *fp;
     for (fp = js_GetTopStackFrame(cx);
          fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
          fp = fp->prev()) {
         continue;
     }
 
+    JSAtom *atom;
+
     switch (slot) {
       case FUN_ARGUMENTS:
         /* Warn if strict about f.arguments or equivalent unqualified uses. */
         if (!JS_ReportErrorFlagsAndNumber(cx,
                                           JSREPORT_WARNING | JSREPORT_STRICT,
                                           js_GetErrorMessage, NULL,
                                           JSMSG_DEPRECATED_USAGE,
                                           js_arguments_str)) {
             return false;
         }
         if (fp) {
             if (!js_GetArgsValue(cx, fp, vp))
                 return false;
         } else {
             vp->setNull();
         }
+        atom = cx->runtime->atomState.argumentsAtom;
         break;
 
       case FUN_LENGTH:
+        vp->setInt32(fun->nargs);
+        atom = cx->runtime->atomState.lengthAtom;
+        break;
+
       case FUN_ARITY:
         vp->setInt32(fun->nargs);
+        atom = cx->runtime->atomState.arityAtom;
         break;
 
       case FUN_NAME:
         vp->setString(fun->atom ? ATOM_TO_STRING(fun->atom)
                                 : cx->runtime->emptyString);
+        atom = cx->runtime->atomState.nameAtom;
         break;
 
       case FUN_CALLER:
         vp->setNull();
         if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp))
             return false;
 
         if (vp->isObject()) {
@@ -1594,26 +1603,30 @@ fun_getProperty(JSContext *cx, JSObject 
             if (caller.getCompartment() != cx->compartment) {
                 vp->setNull();
             } else if (caller.isFunction() && caller.getFunctionPrivate()->inStrictMode()) {
                 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                              JSMSG_CALLER_IS_STRICT);
                 return false;
             }
         }
+        atom = cx->runtime->atomState.callerAtom;
         break;
 
       default:
         /* XXX fun[0] and fun.arguments[0] are equivalent. */
         if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
             *vp = fp->formalArg(slot);
+        atom = NULL;
         break;
     }
 
-    cx->addTypePropertyId(obj->getType(), id, *vp);
+    jsid nameid = atom ? ATOM_TO_JSID(atom) : JSID_VOID;
+    cx->addTypePropertyId(obj->getType(), nameid, *vp);
+
     return true;
 }
 
 struct LazyFunctionDataProp {
     uint16      atomOffset;
     int8        tinyid;
     uint8       attrs;
 };
@@ -2710,17 +2723,17 @@ Function(JSContext *cx, uintN argc, Valu
     }
 
     size_t length = str->length();
     const jschar *chars = str->getChars(cx);
     if (!chars)
         return JS_FALSE;
     JSBool res = Compiler::compileFunctionBody(cx, fun, principals, chars, length,
                                                filename, lineno);
-    if (res)
+    if (res && fun->u.i.script->compileAndGo)
         fun->u.i.script->setTypeNesting(caller->script(), caller->pc(cx));
     return res;
 }
 
 static JSBool
 ThrowTypeError(JSContext *cx, uintN argc, Value *vp)
 {
     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -585,42 +585,36 @@ void
 TypeConstraintSubset::newType(JSContext *cx, TypeSet *source, jstype type)
 {
     /* Basic subset constraint, move all types to the target. */
     target->addType(cx, type);
 }
 
 /* Get the object to use for a property access on type. */
 static inline TypeObject *
-GetPropertyObject(JSContext *cx, jstype type)
+GetPropertyObject(JSContext *cx, analyze::Script *script, jstype type)
 {
     if (TypeIsObject(type))
         return (TypeObject*) type;
 
     /*
      * Handle properties attached to primitive types, treating this access as a
      * read on the primitive's new object.
      */
     switch (type) {
 
       case TYPE_INT32:
       case TYPE_DOUBLE:
-        if (!cx->globalObject->getReservedSlot(JSProto_Number).isObject())
-            js_InitNumberClass(cx, cx->globalObject);
-        return cx->getTypeNewObject(JSProto_Number);
+        return script->getTypeNewObject(cx, JSProto_Number);
 
       case TYPE_BOOLEAN:
-        if (!cx->globalObject->getReservedSlot(JSProto_Boolean).isObject())
-            js_InitBooleanClass(cx, cx->globalObject);
-        return cx->getTypeNewObject(JSProto_Boolean);
+        return script->getTypeNewObject(cx, JSProto_Boolean);
 
       case TYPE_STRING:
-        if (!cx->globalObject->getReservedSlot(JSProto_String).isObject())
-            js_InitStringClass(cx, cx->globalObject);
-        return cx->getTypeNewObject(JSProto_String);
+        return script->getTypeNewObject(cx, JSProto_String);
 
       default:
         /* undefined and null do not have properties. */
         return NULL;
     }
 }
 
 /*
@@ -688,17 +682,17 @@ TypeConstraintProp::newType(JSContext *c
          */
         if (assign)
             cx->compartment->types.monitorBytecode(cx, code);
         else
             target->addType(cx, TYPE_UNKNOWN);
         return;
     }
 
-    TypeObject *object = GetPropertyObject(cx, type);
+    TypeObject *object = GetPropertyObject(cx, code->script, type);
     if (object)
         PropertyAccess(cx, code, object, assign, target, id);
 }
 
 void
 TypeConstraintElem::newType(JSContext *cx, TypeSet *source, jstype type)
 {
     switch (type) {
@@ -745,17 +739,17 @@ TypeConstraintNewObject::newType(JSConte
     } else if (!fun->script) {
         /*
          * This constraint should only be used for native constructors with
          * immutable non-primitive prototypes. Disregard primitives here.
          */
     } else if (!fun->script->compileAndGo) {
         target->addType(cx, TYPE_UNKNOWN);
     } else {
-        target->addType(cx, (jstype) cx->getTypeNewObject(JSProto_Object));
+        target->addType(cx, (jstype) fun->script->analysis->getTypeNewObject(cx, JSProto_Object));
     }
 }
 
 void
 TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
 {
     if (type == TYPE_UNKNOWN) {
         /* Monitor calls on unknown functions. */
@@ -834,18 +828,20 @@ TypeConstraintCall::newType(JSContext *c
              * which is monitored.
              */
         }
     }
 
     /* Add void type for any formals in the callee not supplied at the call site. */
     for (unsigned i = callsite->argumentCount; i < script->argCount(); i++) {
         jsid id = script->getArgumentId(i);
-        TypeSet *types = script->getVariable(cx, id);
-        types->addType(cx, TYPE_UNDEFINED);
+        if (!JSID_IS_VOID(id)) {
+            TypeSet *types = script->getVariable(cx, id);
+            types->addType(cx, TYPE_UNDEFINED);
+        }
     }
 
     /* Add a binding for the receiver object of the call. */
     if (callsite->isNew) {
         /* The receiver object is the 'new' object for the function's prototype. */
         if (function->unknownProperties) {
             script->thisTypes.addType(cx, TYPE_UNKNOWN);
         } else {
@@ -936,42 +932,41 @@ TypeConstraintArith::newType(JSContext *
             break;
         }
     }
 }
 
 void
 TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, jstype type)
 {
-    if (type == TYPE_UNKNOWN || TypeIsObject(type)) {
+    if (type == TYPE_UNKNOWN || TypeIsObject(type) || code->script->getScript()->strictModeCode) {
         target->addType(cx, type);
         return;
     }
 
     if (!code->script->getScript()->compileAndGo) {
         target->addType(cx, TYPE_UNKNOWN);
         return;
     }
 
-    /* TODO: handle strict mode code correctly. */
     TypeObject *object = NULL;
     switch (type) {
       case TYPE_NULL:
       case TYPE_UNDEFINED:
-        object = cx->globalTypeObject();
+        object = code->script->getGlobalType();
         break;
       case TYPE_INT32:
       case TYPE_DOUBLE:
-        object = cx->getTypeNewObject(JSProto_Number);
+        object = code->script->getTypeNewObject(cx, JSProto_Number);
         break;
       case TYPE_BOOLEAN:
-        object = cx->getTypeNewObject(JSProto_Boolean);
+        object = code->script->getTypeNewObject(cx, JSProto_Boolean);
         break;
       case TYPE_STRING:
-        object = cx->getTypeNewObject(JSProto_String);
+        object = code->script->getTypeNewObject(cx, JSProto_String);
         break;
       default:
         JS_NOT_REACHED("Bad type");
     }
 
     target->addType(cx, (jstype) object);
 }
 
@@ -1011,20 +1006,22 @@ TypeConstraintGenerator::newType(JSConte
         return;
 
     /*
      * Watch for 'for in' loops which could produce values other than strings.
      * This includes loops on Iterator and Generator objects, and objects with
      * a custom __iterator__ property that is marked as typeGetSet (see GetCustomIterator).
      */
     TypeObject *object = (TypeObject *) type;
-    if (object == cx->compartment->types.typeGetSet ||
-        object->proto->getClass() == &js_IteratorClass ||
-        object->proto->getClass() == &js_GeneratorClass) {
+    if (object == cx->compartment->types.typeGetSet)
         target->addType(cx, TYPE_UNKNOWN);
+    if (object->proto) {
+        Class *clasp = object->proto->getClass();
+        if (clasp == &js_IteratorClass || clasp == &js_GeneratorClass)
+            target->addType(cx, TYPE_UNKNOWN);
     }
 }
 
 /* Constraint marking incoming arrays as possibly packed. */
 class TypeConstraintPossiblyPacked : public TypeConstraint
 {
 public:
     TypeConstraintPossiblyPacked() : TypeConstraint("possiblyPacked") {}
@@ -1532,17 +1529,16 @@ TypeCompartment::monitorBytecode(JSConte
       case JSOP_DECELEM:
       case JSOP_ELEMINC:
       case JSOP_ELEMDEC:
       case JSOP_INCPROP:
       case JSOP_DECPROP:
       case JSOP_PROPINC:
       case JSOP_PROPDEC:
       case JSOP_CALL:
-      case JSOP_SETCALL:
       case JSOP_EVAL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
       case JSOP_NEW:
         code->setFixed(cx, 0, TYPE_UNKNOWN);
         break;
       default:
         TypeFailure(cx, "Monitoring unknown bytecode: %s", js_CodeNameTwo[op]);
@@ -1832,17 +1828,17 @@ JSScript::typeCheckBytecode(JSContext *c
 
     if (!useCount)
         return;
 
     js::types::TypeStack *stack = code.inStack->group();
     for (int i = 0; i < useCount; i++) {
         const js::Value &val = sp[-1 - i];
         js::types::TypeSet *types = &stack->types;
-        bool ignore = val.isMagic(JS_ARRAY_HOLE) || stack->ignoreTypeTag || IgnorePopped(op, i);
+        bool ignore = val.isMagic() || stack->ignoreTypeTag || IgnorePopped(op, i);
 
         stack = stack->innerStack ? stack->innerStack->group() : NULL;
 
         if (ignore)
             continue;
 
         js::types::jstype type = js::types::GetValueType(cx, val);
 
@@ -1896,17 +1892,17 @@ Script::addVariable(JSContext *cx, jsid 
 {
     JS_ASSERT(!var);
     var = ArenaNew<types::Variable>(pool, &pool, id);
 
     /* Augment with builtin types for the 'arguments' variable. */
     if (fun && id == id_arguments(cx)) {
         TypeSet *types = &var->types;
         if (script->compileAndGo)
-            types->addType(cx, (jstype) cx->getTypeNewObject(JSProto_Object));
+            types->addType(cx, (jstype) getTypeNewObject(cx, JSProto_Object));
         else
             types->addType(cx, TYPE_UNKNOWN);
     }
 
     InferSpew(ISpewOps, "addVariable: #%lu %s T%u",
               this->id, TypeIdString(id), var->types.id());
 }
 
@@ -1943,18 +1939,23 @@ Script::setFunction(JSContext *cx, JSFun
      * will be merged with any declaration in the context the eval occurred in,
      * and definitions information will be cleared for any scripts that could use
      * the declared variable.
      */
     if (fun->hasLocalNames())
         localNames = fun->getLocalNameArray(cx, &pool);
 
     /* Make a local variable for the function. */
-    if (fun->atom)
-        getVariable(cx, ATOM_TO_JSID(fun->atom))->addType(cx, (jstype) fun->getType());
+    if (fun->atom) {
+        TypeSet *var = getVariable(cx, ATOM_TO_JSID(fun->atom));
+        if (script->compileAndGo)
+            var->addType(cx, (jstype) function());
+        else
+            var->addType(cx, TYPE_UNKNOWN);
+    }
 }
 
 static inline ptrdiff_t
 GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
 {
     uint32 type = JOF_OPTYPE(*pc);
     if (JOF_TYPE_IS_EXTENDED_JUMP(type))
         return GET_JUMPX_OFFSET(pc2);
@@ -1987,17 +1988,17 @@ BytecodeNoFallThrough(JSOp op)
       default:
         return false;
     }
 }
 
 /*
  * Get the variable set which declares id, either the local variables of a script
  * or the properties of the global object.  NULL if the scope is ambiguous due
- * to a 'with', SCOPE_GLOBAL if the scope is definitely global.
+ * to a 'with' or non-compileAndGo code, SCOPE_GLOBAL if the scope is definitely global.
  */
 static Script * const SCOPE_GLOBAL = (Script *) 0x1;
 static Script *
 SearchScope(JSContext *cx, Script *script, TypeStack *stack, jsid id)
 {
     /* Search up until we find a local variable with the specified name. */
     while (true) {
         /* Search the stack for any 'with' objects or 'let' variables. */
@@ -2024,17 +2025,17 @@ SearchScope(JSContext *cx, Script *scrip
 
         if (!script->parent)
             break;
 
         /* Function scripts have 'arguments' local variables. */
         if (id == id_arguments(cx) && script->fun) {
             TypeSet *types = script->getVariable(cx, id);
             if (script->getScript()->compileAndGo)
-                types->addType(cx, (jstype) cx->getTypeNewObject(JSProto_Object));
+                types->addType(cx, (jstype) script->getTypeNewObject(cx, JSProto_Object));
             else
                 types->addType(cx, TYPE_UNKNOWN);
             return script;
         }
 
         /* Function scripts with names have local variables of that name. */
         if (script->fun && id == ATOM_TO_JSID(script->fun->atom)) {
             TypeSet *types = script->getVariable(cx, id);
@@ -2053,34 +2054,37 @@ SearchScope(JSContext *cx, Script *scrip
             if (id == script->getLocalId(i, NULL))
                 return script;
         }
 
         stack = script->parentCode()->inStack;
         script = script->parent->analysis;
     }
 
-    return SCOPE_GLOBAL;
+    JS_ASSERT(script);
+    return script->getScript()->compileAndGo ? SCOPE_GLOBAL : NULL;
 }
 
 /* Mark the specified variable as undefined in any scope it could refer to. */
 void
 TrashScope(JSContext *cx, Script *script, jsid id)
 {
     while (true) {
         if (!script->isEval()) {
             TypeSet *types = script->getVariable(cx, id);
             types->addType(cx, TYPE_UNKNOWN);
         }
         if (!script->parent)
             break;
         script = script->parent->analysis;
     }
-    TypeSet *types = cx->globalTypeObject()->getProperty(cx, id, true);
-    types->addType(cx, TYPE_UNKNOWN);
+    if (script->getScript()->compileAndGo) {
+        TypeSet *types = script->getGlobalType()->getProperty(cx, id, true);
+        types->addType(cx, TYPE_UNKNOWN);
+    }
 }
 
 static inline jsid
 GetAtomId(JSContext *cx, Script *script, const jsbytecode *pc, unsigned offset)
 {
     unsigned index = js_GetIndexFromBytecode(cx, script->getScript(), (jsbytecode*) pc, offset);
     return MakeTypeId(cx, ATOM_TO_JSID(script->getScript()->getAtom(index)));
 }
@@ -2256,18 +2260,18 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_INDEXBASE1:
       case JSOP_INDEXBASE2:
       case JSOP_INDEXBASE3:
       case JSOP_RESETBASE:
       case JSOP_RESETBASE0:
       case JSOP_BLOCKCHAIN:
       case JSOP_NULLBLOCKCHAIN:
       case JSOP_POPV:
-      case JSOP_FORELEM:
       case JSOP_DEBUGGER:
+      case JSOP_SETCALL:
         break;
 
         /* Bytecodes pushing values of known type. */
       case JSOP_VOID:
       case JSOP_PUSH:
         code->setFixed(cx, 0, TYPE_UNDEFINED);
         break;
       case JSOP_ZERO:
@@ -2316,17 +2320,17 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_XMLELTEXPR:
         code->setFixed(cx, 0, TYPE_STRING);
         break;
       case JSOP_NULL:
         code->setFixed(cx, 0, TYPE_NULL);
         break;
       case JSOP_REGEXP:
         if (script->compileAndGo)
-            code->setFixed(cx, 0, (jstype) cx->getTypeNewObject(JSProto_RegExp));
+            code->setFixed(cx, 0, (jstype) getTypeNewObject(cx, JSProto_RegExp));
         else
             code->setFixed(cx, 0, TYPE_UNKNOWN);
         break;
 
       case JSOP_STOP:
         /* If a stop is reachable then the return type may be void. */
         if (fun)
             function()->returnTypes.addType(cx, TYPE_UNDEFINED);
@@ -2365,39 +2369,39 @@ Script::analyzeTypes(JSContext *cx, Byte
         switch (op) {
           case JSOP_GETGLOBAL:
           case JSOP_CALLGLOBAL:
             id = GetGlobalId(cx, this, pc);
             scope = SCOPE_GLOBAL;
             break;
           default:
             /*
-             * Search the scope to mirror the interpreter's behavior, and to workaround
-             * cases where GNAME is broken, :FIXME: bug 605200.
+             * Search the scope for GNAME to mirror the interpreter's behavior,
+             * and to workaround cases where GNAME is broken, :FIXME: bug 605200.
              */
             id = GetAtomId(cx, this, pc, 0);
             scope = SearchScope(cx, this, code->inStack, id);
             break;
         }
 
         if (scope == SCOPE_GLOBAL) {
             /*
              * This might be a lazily loaded property of the global object.
              * Resolve it now. Subtract this from the total analysis time.
              */
             uint64_t startTime = cx->compartment->types.currentTime();
             JSObject *obj;
             JSProperty *prop;
-            js_LookupPropertyWithFlags(cx, cx->globalObject, id,
+            js_LookupPropertyWithFlags(cx, getGlobal(), id,
                                        JSRESOLVE_QUALIFIED, &obj, &prop);
             uint64_t endTime = cx->compartment->types.currentTime();
             cx->compartment->types.analysisTime -= (endTime - startTime);
 
             /* Handle as a property access. */
-            PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
+            PropertyAccess(cx, code, getGlobalType(), false, code->pushed(0), id);
         } else if (scope) {
             /* Definitely a local variable. */
             TypeSet *types = scope->getVariable(cx, id);
             types->addSubset(cx, scope->pool, code->pushed(0));
         } else {
             /* Ambiguous access, unknown result. */
             code->setFixed(cx, 0, TYPE_UNKNOWN);
         }
@@ -2414,34 +2418,34 @@ Script::analyzeTypes(JSContext *cx, Byte
         break;
 
       case JSOP_SETGNAME:
       case JSOP_SETNAME: {
         jsid id = GetAtomId(cx, this, pc, 0);
 
         const AnalyzeStateStack &stack = state.popped(1);
         if (stack.scope == SCOPE_GLOBAL) {
-            PropertyAccess(cx, code, cx->globalTypeObject(), true, code->popped(0), id);
+            PropertyAccess(cx, code, getGlobalType(), true, code->popped(0), id);
         } else if (stack.scope) {
             TypeSet *types = stack.scope->getVariable(cx, id);
             code->popped(0)->addSubset(cx, pool, types);
         } else {
             cx->compartment->types.monitorBytecode(cx, code);
         }
 
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
       }
 
       case JSOP_GETXPROP: {
         jsid id = GetAtomId(cx, this, pc, 0);
 
         const AnalyzeStateStack &stack = state.popped(0);
         if (stack.scope == SCOPE_GLOBAL) {
-            PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
+            PropertyAccess(cx, code, getGlobalType(), false, code->pushed(0), id);
         } else if (stack.scope) {
             TypeSet *types = stack.scope->getVariable(cx, id);
             types->addSubset(cx, stack.scope->pool, code->pushed(0));
         } else {
             code->setFixed(cx, 0, TYPE_UNKNOWN);
         }
 
         break;
@@ -2455,18 +2459,18 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_DECNAME:
       case JSOP_NAMEINC:
       case JSOP_NAMEDEC: {
         /* Same issue for searching scope as JSOP_GNAME/CALLGNAME. :FIXME: bug 605200 */
         jsid id = GetAtomId(cx, this, pc, 0);
 
         Script *scope = SearchScope(cx, this, code->inStack, id);
         if (scope == SCOPE_GLOBAL) {
-            PropertyAccess(cx, code, cx->globalTypeObject(), true, NULL, id);
-            PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
+            PropertyAccess(cx, code, getGlobalType(), true, NULL, id);
+            PropertyAccess(cx, code, getGlobalType(), false, code->pushed(0), id);
         } else if (scope) {
             TypeSet *types = scope->getVariable(cx, id);
             types->addSubset(cx, scope->pool, code->pushed(0));
             types->addArith(cx, scope->pool, code, types);
             if (code->hasIncDecOverflow)
                 types->addType(cx, TYPE_DOUBLE);
         } else {
             cx->compartment->types.monitorBytecode(cx, code);
@@ -2480,28 +2484,28 @@ Script::analyzeTypes(JSContext *cx, Byte
         /*
          * Even though they are on the global object, GLOBAL accesses do not run into
          * the issues which require monitoring that other property accesses do:
          * __proto__ is still emitted as a SETGNAME even if there is a 'var __proto__',
          * and there will be no getter/setter in a prototype, and 'constructor',
          * 'prototype' and 'caller' do not have special meaning on the global object.
          */
         jsid id = (op == JSOP_SETGLOBAL) ? GetGlobalId(cx, this, pc) : GetAtomId(cx, this, pc, 0);
-        TypeSet *types = cx->globalTypeObject()->getProperty(cx, id, true);
+        TypeSet *types = getGlobalType()->getProperty(cx, id, true);
         code->popped(0)->addSubset(cx, pool, types);
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
       }
 
       case JSOP_INCGLOBAL:
       case JSOP_DECGLOBAL:
       case JSOP_GLOBALINC:
       case JSOP_GLOBALDEC: {
         jsid id = GetGlobalId(cx, this, pc);
-        TypeSet *types = cx->globalTypeObject()->getProperty(cx, id, true);
+        TypeSet *types = getGlobalType()->getProperty(cx, id, true);
         types->addArith(cx, cx->compartment->types.pool, code, types);
         MergePushed(cx, cx->compartment->types.pool, code, 0, types);
         if (code->hasIncDecOverflow)
             types->addType(cx, TYPE_DOUBLE);
         break;
       }
 
       case JSOP_GETUPVAR:
@@ -2681,16 +2685,22 @@ Script::analyzeTypes(JSContext *cx, Byte
         CheckNextTest(cx, code, pc);
         break;
       }
 
       case JSOP_GETLOCALPROP: {
         jsid id = getLocalId(GET_SLOTNO(pc), code);
         TypeSet *types = evalParent()->getVariable(cx, id);
 
+        if (this != evalParent()) {
+            TypeSet *newTypes = TypeSet::make(cx, pool, "localprop");
+            types->addSubset(cx, evalParent()->pool, newTypes);
+            types = newTypes;
+        }
+
         jsid propid = GetAtomId(cx, this, pc, SLOTNO_LEN);
         types->addGetProperty(cx, code, code->pushed(0), propid);
 
         CheckNextTest(cx, code, pc);
         break;
       }
 
       case JSOP_GETELEM:
@@ -2730,20 +2740,16 @@ Script::analyzeTypes(JSContext *cx, Byte
 
       case JSOP_LENGTH:
         /* Treat this as an access to the length property. */
         code->popped(0)->addGetProperty(cx, code, code->pushed(0), id_length(cx));
         break;
 
       case JSOP_THIS:
         thisTypes.addTransformThis(cx, code, code->pushed(0));
-
-        /* 'this' refers to the parent global/scope object in non-function scripts. */
-        if (!fun)
-            code->setFixed(cx, 0, (jstype) cx->globalTypeObject());
         break;
 
       case JSOP_RETURN:
       case JSOP_SETRVAL:
         if (fun)
             code->popped(0)->addSubset(cx, pool, &function()->returnTypes);
         break;
 
@@ -2789,19 +2795,19 @@ Script::analyzeTypes(JSContext *cx, Byte
             res = code->pushed(0);
         } else if (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) {
             jsid id = getLocalId(GET_SLOTNO(pc), code);
             res = evalParent()->getVariable(cx, id);
         } else {
             JSAtom *atom = obj->getFunctionPrivate()->atom;
             JS_ASSERT(atom);
             jsid id = ATOM_TO_JSID(atom);
-            if (isGlobal()) {
+            if (isGlobal() && script->compileAndGo) {
                 /* Defined function at global scope. */
-                res = cx->globalTypeObject()->getProperty(cx, id, true);
+                res = getGlobalType()->getProperty(cx, id, true);
             } else {
                 /* Defined function in a function eval() or ambiguous function scope. */
                 TrashScope(cx, this, id);
                 break;
             }
         }
 
         if (res) {
@@ -2811,17 +2817,16 @@ Script::analyzeTypes(JSContext *cx, Byte
                 res->addType(cx, TYPE_UNKNOWN);
         } else {
             cx->compartment->types.monitorBytecode(cx, code);
         }
         break;
       }
 
       case JSOP_CALL:
-      case JSOP_SETCALL:
       case JSOP_EVAL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
       case JSOP_NEW: {
         /* Construct the base call information about this site. */
         unsigned argCount = GetUseCount(script, offset) - 2;
         TypeCallsite *callsite = ArenaNew<TypeCallsite>(pool, code, op == JSOP_NEW, argCount);
         callsite->thisTypes = code->popped(argCount);
@@ -2931,17 +2936,17 @@ Script::analyzeTypes(JSContext *cx, Byte
         code->pushedArray[0].group()->boundWith = true;
         break;
 
       case JSOP_ENTERBLOCK: {
         JSObject *obj = GetScriptObject(cx, script, pc, 0);
         unsigned defCount = GetDefCount(script, offset);
 
         const Shape *shape = obj->lastProperty();
-        for (unsigned i = 0; i < defCount; i++) {
+        for (unsigned i = defCount - 1; i < defCount; i--) {
             code->pushedArray[i].group()->letVariable = shape->id;
             shape = shape->previous();
         }
         break;
       }
 
       case JSOP_ITER:
         /*
@@ -2960,27 +2965,27 @@ Script::analyzeTypes(JSContext *cx, Byte
         code->setFixed(cx, 1, TYPE_BOOLEAN);
         break;
 
       case JSOP_FORNAME: {
         jsid id = GetAtomId(cx, this, pc, 0);
         Script *scope = SearchScope(cx, this, code->inStack, id);
 
         if (scope == SCOPE_GLOBAL)
-            SetForTypes(cx, state, code, cx->globalTypeObject()->getProperty(cx, id, true));
+            SetForTypes(cx, state, code, getGlobalType()->getProperty(cx, id, true));
         else if (scope)
             SetForTypes(cx, state, code, scope->getVariable(cx, id));
         else
             cx->compartment->types.monitorBytecode(cx, code);
         break;
       }
 
       case JSOP_FORGLOBAL: {
         jsid id = GetGlobalId(cx, this, pc);
-        SetForTypes(cx, state, code, cx->globalTypeObject()->getProperty(cx, id, true));
+        SetForTypes(cx, state, code, getGlobalType()->getProperty(cx, id, true));
         break;
       }
 
       case JSOP_FORLOCAL: {
         jsid id = getLocalId(GET_SLOTNO(pc), code);
         JS_ASSERT(!JSID_IS_VOID(id));
 
         SetForTypes(cx, state, code, evalParent()->getVariable(cx, id)); 
@@ -2990,16 +2995,21 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_FORARG: {
         jsid id = getArgumentId(GET_ARGNO(pc));
         JS_ASSERT(!JSID_IS_VOID(id));
 
         SetForTypes(cx, state, code, getVariable(cx, id));
         break;
       }
 
+      case JSOP_FORELEM:
+        MergePushed(cx, pool, code, 0, code->popped(0));
+        code->setFixed(cx, 1, TYPE_UNKNOWN);
+        break;
+
       case JSOP_FORPROP:
       case JSOP_ENUMELEM:
         cx->compartment->types.monitorBytecode(cx, code);
         break;
 
       case JSOP_ARRAYPUSH: {
         TypeSet *types = getStackTypes(GET_SLOTNO(pc), code);
         types->addSetProperty(cx, code, code->popped(0), JSID_VOID);
@@ -3046,17 +3056,17 @@ Script::analyzeTypes(JSContext *cx, Byte
 
       case JSOP_UNBRAND:
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
 
       case JSOP_GENERATOR:
         if (fun) {
             if (script->compileAndGo) {
-                TypeObject *object = cx->getTypeNewObject(JSProto_Generator);
+                TypeObject *object = getTypeNewObject(cx, JSProto_Generator);
                 function()->returnTypes.addType(cx, (jstype) object);
             } else {
                 function()->returnTypes.addType(cx, TYPE_UNKNOWN);
             }
         }
         break;
 
       case JSOP_YIELD:
@@ -3410,17 +3420,19 @@ Script::finish(JSContext *cx)
     /* Print out points where variables became unconditionally defined. */
     printf("defines:");
     for (unsigned i = 0; i < localCount(); i++) {
         if (locals[i] != LOCAL_USE_BEFORE_DEF && locals[i] != LOCAL_CONDITIONALLY_DEFINED)
             printf(" %s@%u", TypeIdString(getLocalId(i, NULL)), locals[i]);
     }
     printf("\n");
 
-    printf("locals:");
+    printf("locals:\n");
+    printf("    this:");
+    thisTypes.print(cx);
 
     if (variableCount >= 2) {
         unsigned capacity = HashSetCapacity(variableCount);
         for (unsigned i = 0; i < capacity; i++) {
             Variable *var = variableSet[i];
             if (var) {
                 printf("\n    %s:", TypeIdString(var->id));
                 var->types.print(cx);
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -149,22 +149,16 @@ JSContext::getTypeNewObject(JSProtoKey k
 {
     JSObject *proto;
     if (!js_GetClassPrototype(this, NULL, key, &proto, NULL))
         return NULL;
     return proto->getNewType(this);
 }
 
 inline js::types::TypeObject *
-JSContext::globalTypeObject()
-{
-    return globalObject->getType();
-}
-
-inline js::types::TypeObject *
 JSContext::emptyTypeObject()
 {
     return &compartment->types.emptyObject;
 }
 
 inline void
 JSContext::setTypeFunctionScript(JSFunction *fun, JSScript *script)
 {
@@ -173,48 +167,50 @@ JSContext::setTypeFunctionScript(JSFunct
 
     typeFun->script = script;
     fun->type = typeFun;
 
     script->analysis->setFunction(this, fun);
 #endif
 }
 
+/*
+ * :FIXME: bug 619693 the following TypeCaller functions may produce wrong behavior
+ * when natives call other natives.
+ */
+
 inline js::types::TypeObject *
 JSContext::getTypeCallerInitObject(bool isArray)
 {
 #ifdef JS_TYPE_INFERENCE
-    /* :FIXME: this code is broken when a native reenters JS by calling Call/New. */
     JSStackFrame *caller = js_GetScriptedCaller(this, NULL);
     if (caller)
         return caller->script()->getTypeInitObject(this, caller->pc(this), isArray);
 #endif
     return getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
 }
 
 inline bool
 JSContext::isTypeCallerMonitored()
 {
 #ifdef JS_TYPE_INFERENCE
-    /* :FIXME: this code is broken when a native reenters JS by calling Call/New. */
     JSStackFrame *caller = js_GetScriptedCaller(this, NULL);
     if (!caller)
         return true;
     js::analyze::Script *analysis = caller->script()->analysis;
     return analysis->failed() || analysis->getCode(caller->pc(this)).monitorNeeded;
 #else
     return false;
 #endif
 }
 
 inline void
 JSContext::markTypeCallerUnexpected(js::types::jstype type)
 {
 #ifdef JS_TYPE_INFERENCE
-    /* :FIXME: this code is broken when a native reenters JS by calling Call/New. */
     JSStackFrame *caller = js_GetScriptedCaller(this, NULL);
     if (!caller)
         return;
     caller->script()->typeMonitorResult(this, caller->pc(this), 0, type);
 #endif
 }
 
 inline void
@@ -275,16 +271,38 @@ JSContext::addTypePropertyId(js::types::
 inline void
 JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value)
 {
 #ifdef JS_TYPE_INFERENCE
     addTypePropertyId(obj, id, js::types::GetValueType(this, value));
 #endif
 }
 
+inline void
+JSContext::markTypePropertyUnknown(js::types::TypeObject *obj, jsid id)
+{
+#ifdef JS_TYPE_INFERENCE
+    /* Convert string index properties into the common index property. */
+    id = js::types::MakeTypeId(this, id);
+
+    js::types::TypeSet *types = obj->getProperty(this, id, true);
+
+    if (types->unknown())
+        return;
+
+    if (compartment->types.interpreting) {
+        js::types::InferSpew(js::types::ISpewDynamic, "AddUnknown: %s %s",
+                             obj->name(), js::types::TypeIdString(id));
+        compartment->types.addDynamicType(this, types, js::types::TYPE_UNKNOWN);
+    } else {
+        types->addType(this, js::types::TYPE_UNKNOWN);
+    }
+#endif
+}
+
 inline js::types::TypeObject *
 JSContext::getTypeGetSet()
 {
     if (!compartment->types.typeGetSet)
         compartment->types.typeGetSet = newTypeObject("GetSet", NULL);
     return compartment->types.typeGetSet;
 }
 
@@ -482,19 +500,17 @@ JSScript::setTypeNesting(JSScript *paren
     analysis->parentpc = pc;
 #endif
 }
 
 inline js::types::TypeObject *
 JSScript::getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray)
 {
 #ifdef JS_TYPE_INFERENCE
-    /* :FIXME: */
-    JS_ASSERT(!analysis->failed());
-    if (!compileAndGo)
+    if (!compileAndGo || analysis->failed())
         return cx->getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
     return analysis->getCode(pc).getInitObject(cx, isArray);
 #else
     return cx->getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
 #endif
 }
 
 inline void
@@ -607,41 +623,79 @@ inline void
 Bytecode::setFixed(JSContext *cx, unsigned num, types::jstype type)
 {
     pushed(num)->addType(cx, type);
 }
 
 inline types::TypeObject *
 Bytecode::getInitObject(JSContext *cx, bool isArray)
 {
-    JS_ASSERT(script->script->compileAndGo);
 #ifdef JS_TYPE_INFERENCE
     types::TypeObject *&object = isArray ? initArray : initObject;
     if (!object) {
         char *name = NULL;
 #ifdef DEBUG
         name = (char *) alloca(32);
         JS_snprintf(name, 32, "#%u:%u:%s", script->id, offset, isArray ? "Array" : "Object");
 #endif
         JSObject *proto;
-        if (!js_GetClassPrototype(cx, NULL, isArray ? JSProto_Array : JSProto_Object, &proto, NULL))
+        JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
+        if (!js_GetClassPrototype(cx, script->getGlobal(), key, &proto, NULL))
             return NULL;
         object = cx->compartment->types.newTypeObject(cx, script, name, false, proto);
     }
     return object;
 #else
     JS_NOT_REACHED("Call to Bytecode::getInitObject");
     return NULL;
 #endif
 }
 
 /////////////////////////////////////////////////////////////////////
 // analyze::Script
 /////////////////////////////////////////////////////////////////////
 
+inline JSObject *
+Script::getGlobal()
+{
+    JS_ASSERT(script->compileAndGo);
+    if (global)
+        return global;
+
+    /*
+     * Nesting parents of this script must also be compileAndGo for the same global.
+     * The parser must have set the global object for the analysis at the root
+     * global script.
+     */
+    JSScript *nested = parent;
+    while (true) {
+        if (nested->analysis->global) {
+            global = nested->analysis->global;
+            return global;
+        }
+        nested = nested->analysis->parent;
+    }
+    return NULL;
+}
+
+inline types::TypeObject *
+Script::getGlobalType()
+{
+    return getGlobal()->getType();
+}
+
+inline types::TypeObject *
+Script::getTypeNewObject(JSContext *cx, JSProtoKey key)
+{
+    JSObject *proto;
+    if (!js_GetClassPrototype(cx, getGlobal(), key, &proto, NULL))
+        return NULL;
+    return proto->getNewType(cx);
+}
+
 inline jsid
 Script::getLocalId(unsigned index, Bytecode *code)
 {
     if (index >= script->nfixed) {
         /*
          * This is an access on a let variable, we need the stack to figure out
          * the name of the accessed variable.  If multiple let variables have
          * the same name, we flatten their types together.
@@ -1172,18 +1226,18 @@ inline TypeObject::TypeObject(JSArenaPoo
             unknownProperties = true;
         } else if (proto->isArray()) {
             /*
              * Note: this check is insufficient for determining whether new objects
              * are dense arrays, as they may not themselves be arrays but simply
              * have an array or Array.prototype as their prototype. We can't use
              * a clasp here as type does not determine the clasp of an object, so we
              * intercept at the places where a non-Array can have an Array as its
-             * prototype --- scripted 'new', reassignments to __proto__, Object.create
-             * and through the API.
+             * prototype --- scripted 'new', reassignments to __proto__, particular
+             * natives and through the API.
              */
             isDenseArray = isPackedArray = true;
         }
         instanceNext = prototype->instanceList;
         prototype->instanceList = this;
     }
 }
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -594,19 +594,18 @@ js_OnUnknownMethod(JSContext *cx, Value 
          * stillborn instance that needs no finalization, which is sound:
          * NoSuchMethod helper objects own no manually allocated resources.
          */
         obj->map = NULL;
         obj->init(cx, &js_NoSuchMethodClass, cx->emptyTypeObject(), NULL, NULL, false);
         obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
         obj->setSlot(JSSLOT_SAVED_ID, vp[0]);
         vp[0].setObject(*obj);
-
-        cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, 0, *vp);
-    }
+    }
+    cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, 0, *vp);
     return true;
 }
 
 static JS_REQUIRES_STACK JSBool
 NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags)
 {
     InvokeArgsGuard args;
     if (!cx->stack().pushInvokeArgs(cx, 2, &args))
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1519,17 +1519,17 @@ js_InitIteratorClasses(JSContext *cx, JS
     JSObject *proto, *stop;
 
     /* Idempotency required: we initialize several things, possibly lazily. */
     if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop))
         return NULL;
     if (stop)
         return stop;
 
-    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2, JS_TypeHandlerNew,
+    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2, JS_TypeHandlerDynamic,
                          NULL, iterator_methods, NULL, NULL);
     if (!proto)
         return NULL;
 
 #if JS_HAS_GENERATORS
     /* Initialize the generator internals if configured. */
     if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0, NULL,
                       NULL, generator_methods, NULL, NULL)) {
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1130,16 +1130,20 @@ NewProxyObject(JSContext *cx, JSProxyHan
     obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
     obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
     if (fun) {
         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
         if (construct) {
             obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
         }
     }
+
+    /* Don't track types of properties of proxies. */
+    cx->markTypeObjectUnknownProperties(obj->getType());
+
     return obj;
 }
 
 static JSObject *
 NonNullObject(JSContext *cx, const Value &v)
 {
     if (v.isPrimitive()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -2874,35 +2874,35 @@ reflect_parse(JSContext *cx, uint32 argc
         return JS_FALSE;
     }
 
     JS_SET_RVAL(cx, vp, Jsvalify(val));
     return JS_TRUE;
 }
 
 static JSFunctionSpec static_methods[] = {
-    JS_FN("parse", reflect_parse, 1, 0),
+    JS_FN_TYPE("parse", reflect_parse, 1, 0, JS_TypeHandlerDynamic),
     JS_FS_END
 };
 
 
 JSObject *
 js_InitReflectClass(JSContext *cx, JSObject *obj)
 {
     JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj);
     if (!Reflect)
         return NULL;
 
     types::TypeObject *type = cx->newTypeObject(js_ReflectClass.name, Reflect->getProto());
     if (!type)
         return NULL;
     Reflect->setType(type);
 
-    if (!JS_DefineProperty(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
-                           JS_PropertyStub, JS_PropertyStub, 0)) {
+    if (!JS_DefinePropertyWithType(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
+                                   JS_PropertyStub, JS_PropertyStub, 0)) {
         return NULL;
     }
 
-    if (!JS_DefineFunctions(cx, Reflect, static_methods))
+    if (!JS_DefineFunctionsWithPrefix(cx, Reflect, static_methods, "Reflect"))
         return NULL;
 
     return Reflect;
 }
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -353,29 +353,16 @@ regexp_resolve(JSContext *cx, JSObject *
                                      JSPROP_PERMANENT | JSPROP_SHARED,
                                      0, 0, NULL)) {
             return false;
         }
         *objp = obj;
         return true;
     }
 
-    static const struct LazyProp {
-        const char *name;
-        uint16 atomOffset;
-        PropertyOp getter;
-        jstype type;
-    } lazyRegExpProps[] = {
-        { js_source_str,     ATOM_OFFSET(source),     source_getter, TYPE_STRING },
-        { js_global_str,     ATOM_OFFSET(global),     global_getter, TYPE_BOOLEAN },
-        { js_ignoreCase_str, ATOM_OFFSET(ignoreCase), ignoreCase_getter, TYPE_BOOLEAN },
-        { js_multiline_str,  ATOM_OFFSET(multiline),  multiline_getter, TYPE_BOOLEAN },
-        { js_sticky_str,     ATOM_OFFSET(sticky),     sticky_getter, TYPE_BOOLEAN }
-    };
-
     for (size_t i = 0; i < JS_ARRAY_LENGTH(lazyRegExpProps); i++) {
         const LazyProp &lazy = lazyRegExpProps[i];
         JSAtom *atom = OFFSET_TO_ATOM(cx->runtime, lazy.atomOffset);
         if (id == ATOM_TO_JSID(atom)) {
             if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(),
                                          lazy.getter, NULL,
                                          JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY,
                                          0, 0, NULL)) {
@@ -931,12 +918,13 @@ js_InitRegExpClass(JSContext *cx, JSObje
 
     TypeObject *regexpType = proto->getNewType(cx);
     JS_ASSERT(regexpType);
 
     cx->addTypeProperty(regexpType, "source", TYPE_STRING);
     cx->addTypeProperty(regexpType, "global", TYPE_BOOLEAN);
     cx->addTypeProperty(regexpType, "ignoreCase", TYPE_BOOLEAN);
     cx->addTypeProperty(regexpType, "multiline", TYPE_BOOLEAN);
+    cx->addTypeProperty(regexpType, "sticky", TYPE_BOOLEAN);
     cx->addTypeProperty(regexpType, "lastIndex", TYPE_INT32);
 
     return proto;
 }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1127,16 +1127,22 @@ JSScript::NewScriptFromCG(JSContext *cx,
         cg->upvarList.clear();
         cx->free(cg->upvarMap.vector);
         cg->upvarMap.vector = NULL;
     }
 
 #ifdef JS_TYPE_INFERENCE
     /* Make empty type information for the script. */
     script->makeAnalysis(cx);
+
+    /* Set global for compileAndGo scripts. */
+    if (script->compileAndGo) {
+        GlobalScope *globalScope = cg->compiler()->globalScope;
+        script->analysis->global = globalScope->globalObj;
+    }
 #endif
 
     if (cg->globalUses.length()) {
         memcpy(script->globals()->vector, &cg->globalUses[0],
                cg->globalUses.length() * sizeof(GlobalSlotArray::Entry));
     }
 
     if (script->nClosedArgs)
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1430,17 +1430,18 @@ Class ArrayBuffer::jsclass = {
     ResolveStub,
     ConvertStub,
     ArrayBuffer::class_finalize,
 };
 
 JSPropertySpec ArrayBuffer::jsprops[] = {
     { "byteLength",
       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
-      Jsvalify(ArrayBuffer::prop_getByteLength), Jsvalify(ArrayBuffer::prop_getByteLength) },
+      Jsvalify(ArrayBuffer::prop_getByteLength), Jsvalify(ArrayBuffer::prop_getByteLength),
+      JS_TypeHandlerInt },
     {0,0,0,0,0}
 };
 
 /*
  * shared TypedArray
  */
 
 JSPropertySpec TypedArray::jsprops[] = {
@@ -1533,16 +1534,18 @@ do {                                    
                          _typedArray::jsprops,                                 \
                          _typedArray::jsfuncs,                                 \
                          NULL, NULL);                                          \
     if (!proto)                                                                \
         return NULL;                                                           \
     cx->addTypeProperty(proto->getType(), NULL, types::TYPE_INT32);            \
     if (_typedArray::ArrayElementTypeMayBeDouble())                            \
         cx->addTypeProperty(proto->getType(), NULL, types::TYPE_DOUBLE);       \
+    cx->addTypeProperty(proto->getType(), "buffer",                            \
+                        (types::jstype) bufferType);                           \
     JSObject *ctor = JS_GetConstructor(cx, proto);                             \
     if (!ctor ||                                                               \
         !JS_DefinePropertyWithType(cx, ctor, "BYTES_PER_ELEMENT",              \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
                            JS_PropertyStub, JS_PropertyStub,                   \
                            JSPROP_PERMANENT | JSPROP_READONLY) ||              \
         !JS_DefinePropertyWithType(cx, proto, "BYTES_PER_ELEMENT",             \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
@@ -1595,32 +1598,34 @@ js_InitTypedArrayClasses(JSContext *cx, 
     JSObject *stop;
     if (!js_GetClassObject(cx, obj, JSProto_ArrayBuffer, &stop))
         return NULL;
     if (stop)
         return stop;
 
     JSObject *proto;
 
+    proto = js_InitClass(cx, obj, NULL, &ArrayBuffer::jsclass,
+                         ArrayBuffer::class_constructor, 1, JS_TypeHandlerNew,
+                         ArrayBuffer::jsprops, NULL, NULL, NULL);
+    if (!proto)
+        return NULL;
+
+    TypeObject *bufferType = proto->getNewType(cx);
+
     INIT_TYPED_ARRAY_CLASS(Int8Array,TYPE_INT8);
     INIT_TYPED_ARRAY_CLASS(Uint8Array,TYPE_UINT8);
     INIT_TYPED_ARRAY_CLASS(Int16Array,TYPE_INT16);
     INIT_TYPED_ARRAY_CLASS(Uint16Array,TYPE_UINT16);
     INIT_TYPED_ARRAY_CLASS(Int32Array,TYPE_INT32);
     INIT_TYPED_ARRAY_CLASS(Uint32Array,TYPE_UINT32);
     INIT_TYPED_ARRAY_CLASS(Float32Array,TYPE_FLOAT32);
     INIT_TYPED_ARRAY_CLASS(Float64Array,TYPE_FLOAT64);
     INIT_TYPED_ARRAY_CLASS(Uint8ClampedArray,TYPE_UINT8_CLAMPED);
 
-    proto = js_InitClass(cx, obj, NULL, &ArrayBuffer::jsclass,
-                         ArrayBuffer::class_constructor, 1, JS_TypeHandlerNew,
-                         ArrayBuffer::jsprops, NULL, NULL, NULL);
-    if (!proto)
-        return NULL;
-
     proto->setPrivate(NULL);
     return proto;
 }
 
 JS_FRIEND_API(JSBool)
 js_IsArrayBuffer(JSObject *obj)
 {
     JS_ASSERT(obj);
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -205,16 +205,18 @@ bool
 JSWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
 {
     GET(wrappedObject(wrapper)->getProperty(cx, receiver, id, vp));
 }
 
 bool
 JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
 {
+    cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, *vp);
+
     // FIXME (bug 596351): Need deal with strict mode.
     SET(wrappedObject(wrapper)->setProperty(cx, id, vp, false));
 }
 
 bool
 JSWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
     const jsid id = JSID_VOID;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2462,16 +2462,17 @@ DumpHeap(JSContext *cx, uintN argc, jsva
             return JS_FALSE;
         }
     }
 
     ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
                      maxDepth, thingToIgnore);
     if (dumpFile != stdout)
         fclose(dumpFile);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return ok;
 
   not_traceable_arg:
     JS_ReportError(cx, "argument '%s' is not null or a heap-allocated thing",
                    badTraceArg);
     return JS_FALSE;
 }
 
@@ -3003,16 +3004,18 @@ ResolveClass(JSContext *cx, JSObject *ob
     return JS_TRUE;
 }
 
 static JSBool
 split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
 {
     ComplexObject *cpx;
 
+    cx->markTypePropertyUnknown(obj->getType(), id);
+
     if (JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "isInner")) {
         *objp = obj;
         return JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, NULL, NULL, JSPROP_SHARED);
     }
 
     cpx = split_get_private(cx, obj);
     if (!cpx)
         return JS_TRUE;