[JAEGER] Merge from tracemonkey.
authorDavid Mandelin <dmandelin@mozilla.com>
Mon, 23 Aug 2010 11:35:14 -0700
changeset 53478 7f7a0154ed13db8875576cd11614fd25a6ceafad
parent 53477 0850c92fccfd7061586bd800f58794ad1524e2fc (current diff)
parent 51445 7e5cdd50de1045bb07e929e83f91c7b7b00250e4 (diff)
child 53480 d6eafa87676406c55f04fc4d9a22e9ebff92d498
push idunknown
push userunknown
push dateunknown
milestone2.0b5pre
[JAEGER] Merge from tracemonkey.
js/src/assembler/wtf/Assertions.cpp
js/src/jsapi.cpp
js/src/jscntxtinlines.h
js/src/jsexn.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsobj.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jstracer.cpp
js/src/jsxdrapi.cpp
js/src/tests/js1_5/extensions/jstests.list
--- a/js/src/assembler/wtf/Assertions.cpp
+++ b/js/src/assembler/wtf/Assertions.cpp
@@ -59,17 +59,17 @@ static void printf_stderr_common(const c
     va_list args;
     va_start(args, format);
     vprintf_stderr_common(format, args);
     va_end(args);
 }
 
 static void printCallSite(const char* file, int line, const char* function)
 {
-#if WTF_PLATFORM_WIN && !WTF_PLATFORM_WINCE && defined _DEBUG
+#if WTF_COMPILER_MSVC && !WTF_PLATFORM_WINCE && defined _DEBUG
     _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
 #else
     printf_stderr_common("(%s:%d %s)\n", file, line, function);
 #endif
 }
 
 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
 {
--- a/js/src/jsapi-tests/testContexts.cpp
+++ b/js/src/jsapi-tests/testContexts.cpp
@@ -63,16 +63,18 @@ BEGIN_TEST(testContexts_bug561444)
         ThreadData *d = (ThreadData *) arg;
 
         JSContext *cx = JS_NewContext(d->rt, 8192);
         if (!cx)
             return;
         JS_BeginRequest(cx);
         {
             jsvalRoot v(cx);
+            JSAutoCrossCompartmentCall crossCall;
+            crossCall.enter(cx, d->obj);            
             if (!JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__, v.addr()))
                 return;
         }
         JS_DestroyContext(cx);
         d->ok = true;
     }
 END_TEST(testContexts_bug561444)
 #endif
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4409,16 +4409,20 @@ JS_CompileUCScriptForPrincipals(JSContex
                                 const char *filename, uintN lineno)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
 
     uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
     JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
                                                chars, length, NULL, filename, lineno);
+    if (script && !js_NewScriptObject(cx, script)) {
+        js_DestroyScript(cx, script);
+        script = NULL;
+    }
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
                    const char *filename, uintN lineno)
 {
@@ -4504,87 +4508,99 @@ JS_CompileFile(JSContext *cx, JSObject *
         fp = fopen(filename, "r");
         if (!fp) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
                                  filename, "No such file or directory");
             return NULL;
         }
     }
 
-    tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
+    tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
     script = Compiler::compileScript(cx, obj, NULL, NULL, tcflags,
                                      NULL, 0, fp, filename, 1);
     if (fp != stdin)
         fclose(fp);
+    if (script && !js_NewScriptObject(cx, script)) {
+        js_DestroyScript(cx, script);
+        script = NULL;
+    }
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
                                   JSPrincipals *principals)
 {
     uint32 tcflags;
     JSScript *script;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
-    tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
+    tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
     script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
                                      NULL, 0, file, filename, 1);
+    if (script && !js_NewScriptObject(cx, script)) {
+        js_DestroyScript(cx, script);
+        script = NULL;
+    }
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
 {
     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewScriptObject(JSContext *cx, JSScript *script)
 {
-    JSObject *obj;
-
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, script);
     if (!script)
         return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
 
-    JS_ASSERT(!script->u.object);
-
-    {
-        AutoScriptRooter root(cx, script);
-
-        obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
-        if (obj) {
-            obj->setPrivate(script);
-            script->u.object = obj;
-#ifdef CHECK_SCRIPT_OWNER
-            script->owner = NULL;
-#endif
-        }
-    }
-
-    return obj;
+    /*
+     * This function should only ever be applied to JSScripts that had
+     * script objects allocated for them when they were created, as
+     * described in the comment for JSScript::u.object.
+     */
+    JS_ASSERT(script->u.object);
+    return script->u.object;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetScriptObject(JSScript *script)
 {
+    /*
+     * This function should only ever be applied to JSScripts that had
+     * script objects allocated for them when they were created, as
+     * described in the comment for JSScript::u.object.
+     */
+    JS_ASSERT(script->u.object);
     return script->u.object;
 }
 
 JS_PUBLIC_API(void)
 JS_DestroyScript(JSContext *cx, JSScript *script)
 {
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, script);
-    js_DestroyScript(cx, script);
+
+    /*
+     * Originally, JSScript lifetimes were managed explicitly, and this function
+     * was used to free a JSScript. Now, this function does nothing, and the
+     * garbage collector manages JSScripts; you must root the JSScript's script
+     * object (obtained via JS_GetScriptObject) to keep it alive.
+     *
+     * However, since the script objects have taken over this responsibility, it
+     * follows that every script passed here must have a script object.
+     */
+    JS_ASSERT(script->u.object);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
                                   JSPrincipals *principals, const char *name,
                                   uintN nargs, const char **argnames,
                                   const jschar *chars, size_t length,
                                   const char *filename, uintN lineno)
@@ -4736,16 +4752,18 @@ JS_DecompileFunctionBody(JSContext *cx, 
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
 {
     JSBool ok;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, script);
+    /* This should receive only scripts handed out via the JSAPI. */
+    JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
     ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
     LAST_FRAME_CHECKS(cx, ok);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
                                  JSPrincipals *principals,
@@ -4763,17 +4781,17 @@ JS_EvaluateUCScriptForPrincipals(JSConte
                                      : TCF_COMPILE_N_GO,
                                      chars, length, NULL, filename, lineno);
     if (!script) {
         LAST_FRAME_CHECKS(cx, script);
         return JS_FALSE;
     }
     ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
     LAST_FRAME_CHECKS(cx, ok);
-    JS_DestroyScript(cx, script);
+    js_DestroyScript(cx, script);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
                     const char *filename, uintN lineno, jsval *rval)
 {
     return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -379,18 +379,20 @@ StackSpace::popInlineFrame(JSContext *cx
 #endif
     cx->setCurrentFrame(down);
 }
 
 JS_REQUIRES_STACK inline
 FrameRegsIter::FrameRegsIter(JSContext *cx)
 {
     curseg = cx->getCurrentSegment();
-    if (JS_UNLIKELY(!curseg || !curseg->isActive()))
+    if (JS_UNLIKELY(!curseg || !curseg->isActive())) {
         initSlow();
+        return;
+    }
     JS_ASSERT(cx->fp);
     curfp = cx->fp;
     cursp = cx->regs->sp;
     curpc = cx->regs->pc;
     return;
 }
 
 inline Value *
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -288,17 +288,17 @@ InitExnPrivate(JSContext *cx, JSObject *
                   : NULL;
     older = JS_SetErrorReporter(cx, NULL);
     state = JS_SaveExceptionState(cx);
 
     callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
     stackDepth = 0;
     valueCount = 0;
     for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
-        if (fp->hasFunction() && fp->argv) {
+        if (fp->hasFunction() && fp->argv && !fp->isEvalFrame()) {
             Value v = NullValue();
             if (checkAccess &&
                 !checkAccess(cx, fp->callee(), callerid, JSACC_READ, &v)) {
                 break;
             }
             valueCount += fp->numActualArgs();
         }
         ++stackDepth;
@@ -329,17 +329,17 @@ InitExnPrivate(JSContext *cx, JSObject *
     priv->message = message;
     priv->filename = filename;
     priv->lineno = lineno;
     priv->stackDepth = stackDepth;
 
     values = GetStackTraceValueBuffer(priv);
     elem = priv->stackElems;
     for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) {
-        if (!fp->hasFunction()) {
+        if (!fp->hasFunction() || fp->isEvalFrame()) {
             elem->funName = NULL;
             elem->argc = 0;
         } else {
             elem->funName = fp->getFunction()->atom
                             ? ATOM_TO_STRING(fp->getFunction()->atom)
                             : cx->runtime->emptyString;
             elem->argc = fp->numActualArgs();
             memcpy(values, fp->argv, elem->argc * sizeof(jsval));
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -869,22 +869,23 @@ Execute(JSContext *cx, JSObject *chain, 
         }
     }
 #endif
 
     /* Initialize frame. */
     JSObject *initialVarObj;
     if (down) {
         /* Propagate arg state for eval and the debugger API. */
+        JS_ASSERT_IF(down->hasFunction(), down->hasCallObj());
         fp->setCallObj(down->maybeCallObj());
         fp->setArgsObj(NULL);
         fp->setFunction((script->staticLevel > 0) ? down->maybeFunction() : NULL);
         fp->setThisValue(down->getThisValue());
         fp->flags = flags;
-        fp->setNumActualArgs(down->numActualArgs());
+        fp->setNumActualArgs(0);
         fp->argv = down->argv;
         fp->setAnnotation(down->maybeAnnotation());
         fp->setScopeChain(chain);
 
         /*
          * We want to call |down->varobj()|, but this requires knowing the
          * CallStackSegment of |down|. If |down == cx->fp|, the callstack is
          * simply the context's active callstack, so we can use
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -180,16 +180,17 @@ struct JSStackFrame
     /* Arguments object accessors */
 
     bool hasArgsObj() const {
         return argsobj != NULL;
     }
 
     JSObject* getArgsObj() const {
         JS_ASSERT(hasArgsObj());
+        JS_ASSERT(!isEvalFrame());
         return argsobj;
     }
 
     JSObject* maybeArgsObj() const {
         return argsobj;
     }
 
     void setArgsObj(JSObject *obj) {
@@ -404,16 +405,17 @@ struct JSStackFrame
         return fun;
     }
 
     JSFunction* maybeFunction() const {
         return fun;
     }
 
     size_t numFormalArgs() const {
+        JS_ASSERT(!isEvalFrame());
         return getFunction()->nargs;
     }
 
     void setFunction(JSFunction *f) {
         fun = f;
     }
 
     /* This-value accessors */
@@ -450,16 +452,17 @@ struct JSStackFrame
 
     static size_t offsetReturnValue() {
         return offsetof(JSStackFrame, rval);
     }
 
     /* Argument count accessors */
 
     size_t numActualArgs() const {
+        JS_ASSERT(!isEvalFrame());
         return argc;
     }
 
     void setNumActualArgs(size_t n) {
         argc = n;
     }
 
     static size_t offsetNumActualArgs() {
@@ -523,16 +526,17 @@ struct JSStackFrame
 
     bool isGenerator() const { return !!(flags & JSFRAME_GENERATOR); }
     bool isFloatingGenerator() const {
         JS_ASSERT_IF(flags & JSFRAME_FLOATING_GENERATOR, isGenerator());
         return !!(flags & JSFRAME_FLOATING_GENERATOR);
     }
 
     bool isDummyFrame() const { return !!(flags & JSFRAME_DUMMY); }
+    bool isEvalFrame() const { return !!(flags & JSFRAME_EVAL); }
 
   private:
     JSObject *computeThisObject(JSContext *cx);
 	
     /* Contains static assertions for member alignment, don't call. */
     inline void staticAsserts();
 };
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -6077,18 +6077,21 @@ JSObject::getCompartment(JSContext *cx)
             return cx->runtime->defaultCompartment;
 
         // The magic function namespace object is runtime-wide.
         if (clasp == &js_NamespaceClass &&
             obj->getNameURI() == ATOM_TO_JSVAL(cx->runtime->atomState.lazy.functionNamespaceURIAtom)) {
             return cx->runtime->defaultCompartment;
         }
 
-        // Compile-time Function, Block, and RegExp objects are not parented.
-        if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass) {
+        /* 
+         * Script objects and compile-time Function, Block, RegExp objects
+         * are not parented.
+         */
+        if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass || clasp == &js_ScriptClass) {
             // This is a bogus answer, but it'll do for now.
             return cx->runtime->defaultCompartment;
         }
         JS_NOT_REACHED("non-global object at end of scope chain");
     }
     const Value &v = obj->getReservedSlot(JSRESERVED_GLOBAL_COMPARTMENT);
     return (JSCompartment *)v.toPrivate();
 }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1317,16 +1317,43 @@ js_TraceScript(JSTracer *trc, JSScript *
         JS_SET_TRACING_NAME(trc, "object");
         Mark(trc, script->u.object, JSTRACE_OBJECT);
     }
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 }
 
+JSBool
+js_NewScriptObject(JSContext *cx, JSScript *script)
+{
+    AutoScriptRooter root(cx, script);
+
+    JS_ASSERT(!script->u.object);
+    JS_ASSERT(script != JSScript::emptyScript());
+
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
+    if (!obj)
+        return JS_FALSE;
+    obj->setPrivate(script);
+    script->u.object = obj;
+
+    /*
+     * Clear the object's proto, to avoid entraining stuff. Once we no longer use the parent
+     * for security checks, then we can clear the parent, too.
+     */
+    obj->clearProto();
+
+#ifdef CHECK_SCRIPT_OWNER
+    script->owner = NULL;
+#endif
+
+    return JS_TRUE;
+}
+
 typedef struct GSNCacheEntry {
     JSDHashEntryHdr     hdr;
     jsbytecode          *pc;
     jssrcnote           *sn;
 } GSNCacheEntry;
 
 #define GSN_CACHE_THRESHOLD     100
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -222,17 +222,33 @@ struct JSScript {
     jsbytecode      *main;      /* main entry point, after predef'ing prolog */
     JSAtomMap       atomMap;    /* maps immediate index to literal struct */
     const char      *filename;  /* source filename or null */
     uint32          lineno;     /* base line number of script */
     uint16          nslots;     /* vars plus maximum stack depth */
     uint16          staticLevel;/* static level for display maintenance */
     JSPrincipals    *principals;/* principals for this script */
     union {
-        JSObject    *object;    /* optional Script-class object wrapper */
+        /*
+         * A script object of class js_ScriptClass, to ensure the script is GC'd.
+         * - All scripts returned by JSAPI functions (JS_CompileScript,
+         *   JS_CompileFile, etc.) have these objects.
+         * - Function scripts never have script objects; such scripts are owned
+         *   by their function objects.
+         * - Temporary scripts created by obj_eval, JS_EvaluateScript, and 
+         *   similar functions never have these objects; such scripts are
+         *   explicitly destroyed by the code that created them.
+         * Debugging API functions (JSDebugHooks::newScriptHook;
+         * JS_GetFunctionScript) may reveal sans-script-object Function and
+         * temporary scripts to clients, but clients must never call
+         * JS_NewScriptObject on such scripts: doing so would double-free them,
+         * once from the explicit call to js_DestroyScript, and once when the
+         * script object is garbage collected.
+         */
+        JSObject    *object;
         JSScript    *nextToGC;  /* next to GC in rt->scriptsToGC list */
     } u;
 #ifdef CHECK_SCRIPT_OWNER
     JSThread        *owner;     /* for thread-safe life-cycle assertions */
 #endif
 #ifdef JS_METHODJIT
     // Note: the other pointers in this group may be non-NULL only if 
     // |execPool| is non-NULL.
@@ -474,16 +490,19 @@ extern JS_FRIEND_API(void)
 js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
 
 extern void
 js_DestroyScript(JSContext *cx, JSScript *script);
 
 extern void
 js_TraceScript(JSTracer *trc, JSScript *script);
 
+extern JSBool
+js_NewScriptObject(JSContext *cx, JSScript *script);
+
 /*
  * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
  * cache without adding an explicit cx parameter.  Thus js_GetSrcNote becomes
  * a macro that uses cx from its calls' lexical environments.
  */
 #define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc)
 
 extern jssrcnote *
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1090,17 +1090,23 @@ Tracker::set(const void* v, LIns* i)
     if (!p)
         p = addTrackerPage(v);
     p->map[getTrackerPageOffset(v)] = i;
 }
 
 static inline jsuint
 argSlots(JSStackFrame* fp)
 {
-    return JS_MAX(fp->numActualArgs(), fp->numFormalArgs());
+    return fp->isEvalFrame() ? 0 : JS_MAX(fp->numActualArgs(), fp->numFormalArgs());
+}
+
+static inline jsuint
+numEntryFrameArgs(JSStackFrame* fp)
+{
+    return fp->isEvalFrame() ? 0 : fp->numActualArgs();
 }
 
 static inline bool
 hasInt32Repr(const Value &v)
 {
     if (!v.isNumber())
         return false;
     if (v.isInt32())
@@ -6099,17 +6105,17 @@ AttemptToExtendTree(JSContext* cx, VMSid
             stackSlots = fullMap.length();
             ngslots = BuildGlobalTypeMapFromInnerTree(fullMap, e2);
             JS_ASSERT(ngslots >= e1->numGlobalSlots); // inner tree must have all globals
             JS_ASSERT(ngslots == fullMap.length() - stackSlots);
             typeMap = fullMap.data();
         }
         JS_ASSERT(ngslots >= anchor->numGlobalSlots);
         bool rv = TraceRecorder::startRecorder(cx, anchor, c, stackSlots, ngslots, typeMap,
-                                               exitedFrom, outer, cx->fp->numActualArgs(),
+                                               exitedFrom, outer, numEntryFrameArgs(cx->fp),
                                                Record_Branch, hits < maxHits);
 #ifdef MOZ_TRACEVIS
         if (!rv && tvso)
             tvso->r = R_FAIL_EXTEND_START;
 #endif
         return rv;
     }
 #ifdef MOZ_TRACEVIS
@@ -6148,17 +6154,17 @@ TraceRecorder::recordLoopEdge(JSContext*
     if (tm->needFlush) {
         ResetJIT(cx, FR_DEEP_BAIL);
         return MONITOR_NOT_RECORDING;
     }
 
     JS_ASSERT(r->fragment && !r->fragment->lastIns);
     TreeFragment* root = r->fragment->root;
     TreeFragment* first = LookupOrAddLoop(tm, cx->regs->pc, root->globalObj,
-                                          root->globalShape, cx->fp->numActualArgs());
+                                          root->globalShape, numEntryFrameArgs(cx->fp));
 
     /*
      * Make sure the shape of the global object still matches (this might flush
      * the JIT cache).
      */
     JSObject* globalObj = cx->fp->getScopeChain()->getGlobal();
     uint32 globalShape = -1;
     SlotList* globalSlots = NULL;
@@ -6176,17 +6182,17 @@ TraceRecorder::recordLoopEdge(JSContext*
     // Find a matching inner tree. If none can be found, compile one.
     TreeFragment* f = r->findNestedCompatiblePeer(first);
     if (!f || !f->code()) {
         AUDIT(noCompatInnerTrees);
 
         TreeFragment* outerFragment = root;
         jsbytecode* outer = (jsbytecode*) outerFragment->ip;
         uint32 outerArgc = outerFragment->argc;
-        JS_ASSERT(cx->fp->numActualArgs() == first->argc);
+        JS_ASSERT(numEntryFrameArgs(cx->fp) == first->argc);
         AbortRecording(cx, "No compatible inner tree");
 
         return RecordingIfTrue(RecordTree(cx, first, outer, outerArgc, globalSlots, Record_Branch));
     }
 
     AbortableRecordingStatus status = r->attemptTreeCall(f, inlineCallCount);
     if (status == ARECORD_CONTINUE)
         return MONITOR_RECORDING;
@@ -7200,17 +7206,17 @@ MonitorLoopEdge(JSContext* cx, uintN& in
     if (JS_THREAD_DATA(cx)->interruptFlags) {
 #ifdef MOZ_TRACEVIS
         tvso.r = R_CALLBACK_PENDING;
 #endif
         return MONITOR_NOT_RECORDING;
     }
 
     jsbytecode* pc = cx->regs->pc;
-    uint32 argc = cx->fp->numActualArgs();
+    uint32 argc = numEntryFrameArgs(cx->fp);
 
     TreeFragment* f = LookupOrAddLoop(tm, pc, globalObj, globalShape, argc);
 
     /*
      * If we have no code in the anchor and no peers, we definitively won't be
      * able to activate any trees, so start compiling.
      */
     if (!f->code() && !f->peer) {
@@ -8242,29 +8248,26 @@ TraceRecorder::callProp(JSObject* obj, J
     JSOp op = JSOp(*cx->regs->pc);
     uint32 setflags = (js_CodeSpec[op].format & (JOF_SET | JOF_INCDEC | JOF_FOR));
     if (setflags && !sprop->writable())
         RETURN_STOP("writing to a read-only property");
 
     uintN slot = uint16(sprop->shortid);
 
     vp = NULL;
-    uintN upvar_slot = SPROP_INVALID_SLOT;
     JSStackFrame* cfp = (JSStackFrame*) obj->getPrivate();
     if (cfp) {
         if (sprop->getterOp() == js_GetCallArg) {
             JS_ASSERT(slot < cfp->numFormalArgs());
             vp = &cfp->argv[slot];
-            upvar_slot = slot;
             nr.v = *vp;
         } else if (sprop->getterOp() == js_GetCallVar ||
                    sprop->getterOp() == js_GetCallVarChecked) {
             JS_ASSERT(slot < cfp->getSlotCount());
             vp = &cfp->slots()[slot];
-            upvar_slot = cx->fp->numFormalArgs() + slot;
             nr.v = *vp;
         } else {
             RETURN_STOP("dynamic property of Call object");
         }
 
         // Now assert that our use of sprop->shortid was in fact kosher.
         JS_ASSERT(sprop->hasShortID());
 
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -666,18 +666,27 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **ato
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
 {
     if (!js_XDRScript(xdr, scriptp, true, NULL))
         return JS_FALSE;
-    if (xdr->mode == JSXDR_DECODE)
+
+    if (xdr->mode == JSXDR_DECODE) {
         js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
+        if (*scriptp != JSScript::emptyScript() &&
+            !js_NewScriptObject(xdr->cx, *scriptp)) {
+            js_DestroyScript(xdr->cx, *scriptp);
+            *scriptp = NULL;
+            return JS_FALSE;
+        }
+    }
+
     return JS_TRUE;
 }
 
 #define CLASS_REGISTRY_MIN      8
 #define CLASS_INDEX_TO_ID(i)    ((i)+1)
 #define CLASS_ID_TO_INDEX(id)   ((id)-1)
 
 typedef struct JSRegHashEntry {
--- a/js/src/tests/js1_5/extensions/jstests.list
+++ b/js/src/tests/js1_5/extensions/jstests.list
@@ -44,17 +44,17 @@ script regress-327608.js
 script regress-328443.js
 script regress-328556.js
 skip script regress-330569.js # Yarr doesn't bail on complex regexps.
 script regress-333541.js
 skip script regress-335700.js # bug xxx - reftest hang, BigO
 skip-if(!xulRuntime.shell) script regress-336409-1.js # no results reported.
 skip-if(!xulRuntime.shell&&xulRuntime.XPCOMABI.match(/x86_64/)) script regress-336409-2.js # fails on 64 bit systems for some reason
 skip-if(!xulRuntime.shell) script regress-336410-1.js # slow
-skip-if(!xulRuntime.shell&&xulRuntime.XPCOMABI.match(/x86_64/)) script regress-336410-2.js # fails on 64 bit systems for some reason
+skip-if(!xulRuntime.shell&&(xulRuntime.XPCOMABI.match(/x86_64/)||xulRuntime.OS=="WINNT")) script regress-336410-2.js # fails in browser on 64 bit systems or Windows.
 script regress-338804-01.js
 script regress-338804-02.js
 script regress-338804-03.js
 script regress-339685.js
 script regress-340199.js
 script regress-341956-01.js
 script regress-341956-02.js
 script regress-341956-03.js