Merge mozilla-central to tracemonkey.
authorRobert Sayre <sayrer@gmail.com>
Sat, 26 Feb 2011 19:36:09 -0800
changeset 63150 41218b2d043a
parent 63115 f9e075d85552 (current diff)
parent 63149 8323a963fd6c (diff)
child 63151 04e69fadcbcd
child 63233 672a84576ca6
push id19043
push userrsayre@mozilla.com
push dateSun, 27 Feb 2011 15:29:23 +0000
treeherdermozilla-central@04e69fadcbcd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b13pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to tracemonkey.
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -290,17 +290,17 @@ def run_tests(tests, test_dir, lib_dir):
         print('PASSED ALL' + ('' if complete else ' (partial run -- interrupted by user %s)'%doing))
         return True
 
 def parse_jitflags():
     jitflags = [ [ '-' + flag for flag in flags ] 
                  for flags in OPTIONS.jitflags.split(',') ]
     for flags in jitflags:
         for flag in flags:
-            if flag not in ('-j', '-m', '-p', '-d'):
+            if flag not in ('-j', '-m', '-a', '-p', '-d'):
                 print('Invalid jit flag: "%s"'%flag)
                 sys.exit(1)
     return jitflags
 
 def platform_might_be_android():
     try:
         # The python package for SL4A provides an |android| module.
         # If that module is present, we're likely in SL4A-python on
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug635417.js
@@ -0,0 +1,2 @@
+assertEq(/^@(A*)x(B)*/.test("@xB"), true);
+
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -66,17 +66,17 @@ JSCompartment::JSCompartment(JSRuntime *
     gcBytes(0),
     gcTriggerBytes(0),
     gcLastBytes(0),
     data(NULL),
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
 #endif
-    propertyTree(this),
+    propertyTree(thisForCtor()),
     debugMode(rt->debugMode),
 #if ENABLE_YARR_JIT
     regExpAllocator(NULL),
 #endif
     mathCache(NULL),
     marked(false)
 {
     JS_INIT_CLIST(&scripts);
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -484,16 +484,17 @@ struct JS_FRIEND_API(JSCompartment) {
     
     typedef js::HashMap<jsbytecode*,
                         size_t,
                         js::DefaultHasher<jsbytecode*>,
                         js::SystemAllocPolicy> BackEdgeMap;
 
     BackEdgeMap                  backEdgeTable;
 
+    JSCompartment *thisForCtor() { return this; }
   public:
     js::MathCache *getMathCache(JSContext *cx) {
         return mathCache ? mathCache : allocMathCache(cx);
     }
 
     bool isMarked() { return marked; }
     void clearMark() { marked = false; }
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -712,16 +712,21 @@ Exception(JSContext *cx, uintN argc, Val
      * NewNativeClassInstance to find the class prototype, we must get the
      * class prototype ourselves.
      */
     JSObject &callee = vp[0].toObject();
     Value protov;
     if (!callee.getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov))
         return JS_FALSE;
 
+    if (!protov.isObject()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
+        return JS_FALSE;
+    }
+
     JSObject *errProto = &protov.toObject();
     JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
     if (!obj)
         return JS_FALSE;
 
     /*
      * If it's a new object of class Exception, then null out the private
      * data so that the finalizer doesn't attempt to free it.
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -128,72 +128,66 @@ ArrayBuffer::class_finalize(JSContext *c
 }
 
 /*
  * new ArrayBuffer(byteLength)
  */
 JSBool
 ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp)
 {
-    return create(cx, argc, JS_ARGV(cx, vp), vp);
+    int32 nbytes = 0;
+    if (argc > 0 && !ValueToECMAInt32(cx, vp[2], &nbytes))
+        return false;
+
+    JSObject *bufobj = create(cx, nbytes);
+    if (!bufobj)
+        return false;
+    vp->setObject(*bufobj);
+    return true;
 }
 
-bool
-ArrayBuffer::create(JSContext *cx, uintN argc, Value *argv, Value *rval)
+JSObject *
+ArrayBuffer::create(JSContext *cx, int32 nbytes)
 {
-    /* N.B. there may not be an argv[-2]/argv[-1]. */
-
     JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
     if (!obj)
-        return false;
-
-    int32_t nbytes = 0;
-    if (argc > 0) {
-        if (!ValueToECMAInt32(cx, argv[0], &nbytes))
-            return false;
-    }
+        return NULL;
 
     if (nbytes < 0) {
         /*
          * We're just not going to support arrays that are bigger than what will fit
          * as an integer value; if someone actually ever complains (validly), then we
          * can fix.
          */
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                             JSMSG_BAD_ARRAY_LENGTH);
-        return false;
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
+        return NULL;
     }
 
     ArrayBuffer *abuf = cx->create<ArrayBuffer>();
-    if (!abuf) {
-        JS_ReportOutOfMemory(cx);
-        return false;
-    }
+    if (!abuf)
+        return NULL;
 
     if (!abuf->allocateStorage(cx, nbytes)) {
         cx->destroy<ArrayBuffer>(abuf);
-        return false;
+        return NULL;
     }
 
     obj->setPrivate(abuf);
-    rval->setObject(*obj);
-    return true;
+    return obj;
 }
 
 bool
 ArrayBuffer::allocateStorage(JSContext *cx, uint32 nbytes)
 {
     JS_ASSERT(data == 0);
 
     if (nbytes) {
         data = cx->calloc(nbytes);
-        if (!data) {
-            JS_ReportOutOfMemory(cx);
+        if (!data)
             return false;
-        }
     }
 
     byteLength = nbytes;
     return true;
 }
 
 void
 ArrayBuffer::freeStorage(JSContext *cx)
@@ -721,100 +715,121 @@ class TypedArrayTemplate
     }
 
     static JSType
     obj_typeOf(JSContext *cx, JSObject *obj)
     {
         return JSTYPE_OBJECT;
     }
 
+    static JSObject *
+    createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len)
+    {
+        JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
+        if (!obj)
+            return NULL;
+
+        ThisTypeArray *tarray = cx->create<ThisTypeArray>(bufobj, byteOffset, len);
+        if (!tarray)
+            return NULL;
+
+        JS_ASSERT(obj->getClass() == slowClass());
+        obj->setSharedNonNativeMap();
+        obj->clasp = fastClass();
+        obj->setPrivate(tarray);
+
+        // FIXME Bug 599008: make it ok to call preventExtensions here.
+        obj->flags |= JSObject::NOT_EXTENSIBLE;
+
+        return obj;
+    }
+
     /*
      * new [Type]Array(length)
      * new [Type]Array(otherTypedArray)
      * new [Type]Array(JSArray)
      * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
      */
     static JSBool
     class_constructor(JSContext *cx, uintN argc, Value *vp)
     {
         /* N.B. this is a constructor for slowClass, not fastClass! */
-        return create(cx, argc, JS_ARGV(cx, vp), vp);
+        JSObject *obj = create(cx, argc, JS_ARGV(cx, vp));
+        if (!obj)
+            return false;
+        vp->setObject(*obj);
+        return true;
     }
 
-    static JSBool
-    create(JSContext *cx, uintN argc, Value *argv, Value *rval)
+    static JSObject *
+    create(JSContext *cx, uintN argc, Value *argv)
     {
         /* N.B. there may not be an argv[-2]/argv[-1]. */
 
-        JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
-        if (!obj)
-            return false;
-
-        ThisTypeArray *tarray = 0;
+        /* () or (number) */
+        jsuint len = 0;
+        if (argc == 0 || ValueIsLength(cx, argv[0], &len)) {
+            JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
+            if (!bufobj)
+                return NULL;
 
-        // figure out the type of the first argument;
-        // no args is treated like an int arg of 0.
-        jsuint len = 0;
-        bool hasLen = true;
-        if (argc > 0)
-            hasLen = ValueIsLength(cx, argv[0], &len);
+            return createTypedArray(cx, bufobj, 0, len);
+        }
+
+        /* (not an object) */
+        if (!argv[0].isObject()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                 JSMSG_TYPED_ARRAY_BAD_ARGS);
+            return NULL;
+        }
+
+        JSObject *dataObj = &argv[0].toObject();
 
-        if (hasLen) {
-            tarray = cx->create<ThisTypeArray>();
-            if (!tarray) {
-                JS_ReportOutOfMemory(cx);
-                return false;
-            }
+        /* (typedArray) */
+        if (js_IsTypedArray(dataObj)) {
+            TypedArray *otherTypedArray = TypedArray::fromJSObject(dataObj);
+            JS_ASSERT(otherTypedArray);
+
+            uint32 len = otherTypedArray->length;
+            JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
+            if (!bufobj)
+                return NULL;
 
-            if (!tarray->init(cx, len)) {
-                cx->destroy<ThisTypeArray>(tarray);
-                return false;
-            }
-        } else if (argc > 0 && argv[0].isObject()) {
-            int32_t byteOffset = -1;
-            int32_t length = -1;
+            JSObject *obj = createTypedArray(cx, bufobj, 0, len);
+            if (!obj || !copyFrom(cx, obj, otherTypedArray, 0))
+                return NULL;
+            return obj;
+        }
 
-            if (argc > 1) {
-                if (!ValueToInt32(cx, argv[1], &byteOffset))
-                    return false;
-                if (byteOffset < 0) {
-                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                         JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
-                    return false;
-                }
+        /* (obj, byteOffset, length). */
+        int32_t byteOffset = -1;
+        int32_t length = -1;
+
+        if (argc > 1) {
+            if (!ValueToInt32(cx, argv[1], &byteOffset))
+                return NULL;
+            if (byteOffset < 0) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                     JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
+                return NULL;
             }
 
             if (argc > 2) {
                 if (!ValueToInt32(cx, argv[2], &length))
-                    return false;
+                    return NULL;
                 if (length < 0) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
-                    return false;
+                    return NULL;
                 }
             }
-
-            tarray = cx->create<ThisTypeArray>();
-            if (!tarray) {
-                JS_ReportOutOfMemory(cx);
-                return false;
-            }
-
-            if (!tarray->init(cx, &argv[0].toObject(), byteOffset, length)) {
-                cx->destroy<ThisTypeArray>(tarray);
-                return false;
-            }
-        } else {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_TYPED_ARRAY_BAD_ARGS);
-            return false;
         }
 
-        rval->setObject(*obj);
-        return makeFastWithPrivate(cx, obj, tarray);
+        /* (obj, byteOffset, length) */
+        return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
     }
 
     static void
     class_finalize(JSContext *cx, JSObject *obj)
     {
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         if (tarray)
             cx->destroy<ThisTypeArray>(tarray);
@@ -870,35 +885,21 @@ class TypedArrayTemplate
                     end = length;
                 }
             }
         }
 
         if (begin > end)
             begin = end;
 
-        ThisTypeArray *ntarray = tarray->subarray(cx, begin, end);
-        if (!ntarray) {
-            // this should rarely ever happen
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_TYPED_ARRAY_BAD_ARGS);
+        JSObject *nobj = createSubarray(cx, tarray, begin, end);
+        if (!nobj)
             return false;
-        }
-
-        // note the usage of NewObject here -- we don't want the
-        // constructor to be called!
-        JS_ASSERT(slowClass() != &js_FunctionClass);
-        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, slowClass(), NULL, NULL);
-        if (!nobj) {
-            cx->destroy<ThisTypeArray>(ntarray);
-            return false;
-        }
-
         vp->setObject(*nobj);
-        return makeFastWithPrivate(cx, nobj, ntarray);
+        return true;
     }
 
     /* set(array[, offset]) */
     static JSBool
     fun_set(JSContext *cx, uintN argc, Value *vp)
     {
         JSObject *obj = ToObject(cx, &vp[1]);
         if (!obj)
@@ -915,31 +916,33 @@ class TypedArrayTemplate
             return false;
         }
 
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         if (!tarray)
             return true;
 
         // these are the default values
-        int32_t offset = 0;
+        int32_t off = 0;
 
         Value *argv = JS_ARGV(cx, vp);
         if (argc > 1) {
-            if (!ValueToInt32(cx, argv[1], &offset))
+            if (!ValueToInt32(cx, argv[1], &off))
                 return false;
 
-            if (offset < 0 || uint32_t(offset) > tarray->length) {
+            if (off < 0 || uint32_t(off) > tarray->length) {
                 // the given offset is bogus
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
         }
 
+        uint32 offset(off);
+
         // first arg must be either a typed array or a JS array
         if (argc == 0 || !argv[0].isObject()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
         JSObject *arg0 = argv[0].toObjectOrNull();
@@ -948,174 +951,168 @@ class TypedArrayTemplate
             if (!src ||
                 src->length > tarray->length - offset)
             {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
-            if (!tarray->copyFrom(cx, src, offset))
+            if (!copyFrom(cx, obj, src, offset))
                 return false;
         } else {
             jsuint len;
             if (!js_GetLengthProperty(cx, arg0, &len))
                 return false;
 
             // avoid overflow; we know that offset <= length
             if (len > tarray->length - offset) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
-            if (!tarray->copyFrom(cx, arg0, len, offset))
+            if (!copyFrom(cx, obj, arg0, len, offset))
                 return false;
         }
 
         vp->setUndefined();
         return true;
     }
 
     static ThisTypeArray *
     fromJSObject(JSObject *obj)
     {
         JS_ASSERT(obj->getClass() == fastClass());
         return reinterpret_cast<ThisTypeArray*>(obj->getPrivate());
     }
 
-    // helper used by both the constructor and Subarray()
-    static bool
-    makeFastWithPrivate(JSContext *cx, JSObject *obj, ThisTypeArray *tarray)
+  public:
+    TypedArrayTemplate(JSObject *bufobj, uint32 byteOffset, uint32 len)
     {
-        JS_ASSERT(obj->getClass() == slowClass());
-        obj->setSharedNonNativeMap();
-        obj->clasp = fastClass();
-        obj->setPrivate(tarray);
-        
-        // FIXME bug 599008. make it ok to call preventExtensions here.
-        // Keeping the boolean signature of this method for now.
-        obj->flags |= JSObject::NOT_EXTENSIBLE;
-        return true;
+        JS_ASSERT(bufobj->getClass() == &ArrayBuffer::jsclass);
+
+        type = ArrayTypeID();
+        bufferJS = bufobj;
+        buffer = ArrayBuffer::fromJSObject(bufobj);
+
+        this->byteOffset = byteOffset;
+
+        JS_ASSERT(byteOffset <= buffer->byteLength);
+        this->data = buffer->offsetData(byteOffset);
+        JS_ASSERT(buffer->data <= this->data);
+        JS_ASSERT(this->data <= buffer->offsetData(buffer->byteLength));
+
+        this->byteLength = len * sizeof(NativeType);
+        JS_ASSERT(buffer->byteLength - byteOffset >= this->byteLength);
+
+        this->length = len;
     }
 
-  public:
-    TypedArrayTemplate() { }
-
-    bool
-    init(JSContext *cx, uint32 len)
-    {
-        type = ArrayTypeID();
-        return createBufferWithSizeAndCount(cx, sizeof(NativeType), len);
-    }
-
-    bool
-    init(JSContext *cx, JSObject *other, int32 byteOffsetInt = -1, int32 lengthInt = -1)
+    static JSObject *
+    createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
+                                     int32 byteOffsetInt, int32 lengthInt)
     {
-        type = ArrayTypeID();
-        ArrayBuffer *abuf;
+        JS_ASSERT(!js_IsTypedArray(other));
 
-        if (js_IsTypedArray(other)) {
-            TypedArray *tarray = TypedArray::fromJSObject(other);
-            JS_ASSERT(tarray);
-
-            if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), tarray->length))
-                return false;
-            if (!copyFrom(cx, tarray))
-                return false;
-        } else if (other->getClass() == &ArrayBuffer::jsclass &&
+        /* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
+        ArrayBuffer *abuf;
+        if (other->getClass() == &ArrayBuffer::jsclass &&
                    ((abuf = ArrayBuffer::fromJSObject(other)) != NULL)) {
             uint32 boffset = (byteOffsetInt < 0) ? 0 : uint32(byteOffsetInt);
 
             if (boffset > abuf->byteLength || boffset % sizeof(NativeType) != 0) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
-                return false; // invalid byteOffset
+                return NULL; // invalid byteOffset
             }
 
             uint32 len;
             if (lengthInt < 0) {
                 len = (abuf->byteLength - boffset) / sizeof(NativeType);
                 if (len * sizeof(NativeType) != (abuf->byteLength - boffset)) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_TYPED_ARRAY_BAD_ARGS);
-                    return false; // given byte array doesn't map exactly to sizeof(NativeType)*N
+                    return NULL; // given byte array doesn't map exactly to sizeof(NativeType)*N
                 }
             } else {
                 len = (uint32) lengthInt;
             }
 
             // Go slowly and check for overflow.
             uint32 arrayByteLength = len*sizeof(NativeType);
             if (uint32(len) >= INT32_MAX / sizeof(NativeType) ||
                 uint32(boffset) >= INT32_MAX - arrayByteLength)
             {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
-                return false; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
+                return NULL; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
             }
 
             if (arrayByteLength + boffset > abuf->byteLength) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
-                return false; // boffset+len is too big for the arraybuffer
+                return NULL; // boffset+len is too big for the arraybuffer
             }
 
-            buffer = abuf;
-            bufferJS = other;
-            byteOffset = boffset;
-            byteLength = arrayByteLength;
-            length = len;
-            data = abuf->offsetData(boffset);
-        } else {
-            jsuint len;
-            if (!js_GetLengthProperty(cx, other, &len))
-                return false;
-            if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), len))
-                return false;
-            if (!copyFrom(cx, other, len))
-                return false;
+            return createTypedArray(cx, other, boffset, len);
         }
 
-        return true;
+        /*
+         * Otherwise create a new typed array and copy len properties from the
+         * object.
+         */
+        jsuint len;
+        if (!js_GetLengthProperty(cx, other, &len))
+            return NULL;
+
+        JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
+        if (!bufobj)
+            return NULL;
+
+        JSObject *obj = createTypedArray(cx, bufobj, 0, len);
+        if (!obj || !copyFrom(cx, obj, other, len))
+            return NULL;
+        return obj;
     }
 
     const NativeType
     getIndex(uint32 index) const
     {
         return *(static_cast<const NativeType*>(data) + index);
     }
 
     void
     setIndex(uint32 index, NativeType val)
     {
         *(static_cast<NativeType*>(data) + index) = val;
     }
 
     inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp);
 
-    ThisTypeArray *
-    subarray(JSContext *cx, uint32 begin, uint32 end)
+    static JSObject *
+    createSubarray(JSContext *cx, ThisTypeArray *tarray, uint32 begin, uint32 end)
     {
-        if (begin > length || end > length)
-            return NULL;
+        JS_ASSERT(tarray);
 
-        ThisTypeArray *tarray = cx->create<ThisTypeArray>();
-        if (!tarray)
-            return NULL;
+        JS_ASSERT(0 <= begin);
+        JS_ASSERT(begin <= tarray->length);
+        JS_ASSERT(0 <= end);
+        JS_ASSERT(end <= tarray->length);
 
-        tarray->buffer = buffer;
-        tarray->bufferJS = bufferJS;
-        tarray->byteOffset = byteOffset + begin * sizeof(NativeType);
-        tarray->byteLength = (end - begin) * sizeof(NativeType);
-        tarray->length = end - begin;
-        tarray->type = type;
-        tarray->data = buffer->offsetData(tarray->byteOffset);
+        JSObject *bufobj = tarray->bufferJS;
+        JS_ASSERT(bufobj);
 
-        return tarray;
+        JS_ASSERT(begin <= end);
+        uint32 length = end - begin;
+
+        JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
+        uint32 byteOffset = begin * sizeof(NativeType);
+
+        return createTypedArray(cx, bufobj, byteOffset, length);
     }
 
   protected:
     static NativeType
     nativeFromValue(JSContext *cx, const Value &v)
     {
         if (v.isInt32())
             return NativeType(v.toInt32());
@@ -1134,22 +1131,26 @@ class TypedArrayTemplate
         }
 
         if (ArrayTypeIsFloatingPoint())
             return NativeType(js_NaN);
 
         return NativeType(int32(0));
     }
     
-    bool
-    copyFrom(JSContext *cx, JSObject *ar, jsuint len, jsuint offset = 0)
+    static bool
+    copyFrom(JSContext *cx, JSObject *thisTypedArrayObj,
+             JSObject *ar, jsuint len, jsuint offset = 0)
     {
-        JS_ASSERT(offset <= length);
-        JS_ASSERT(len <= length - offset);
-        NativeType *dest = static_cast<NativeType*>(data) + offset;
+        ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
+        JS_ASSERT(thisTypedArray);
+
+        JS_ASSERT(offset <= thisTypedArray->length);
+        JS_ASSERT(len <= thisTypedArray->length - offset);
+        NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
 
         if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
             JS_ASSERT(ar->getArrayLength() == len);
 
             Value *src = ar->getDenseArrayElements();
 
             for (uintN i = 0; i < len; ++i)
                 *dest++ = nativeFromValue(cx, *src++);
@@ -1162,27 +1163,30 @@ class TypedArrayTemplate
                     return false;
                 *dest++ = nativeFromValue(cx, v);
             }
         }
 
         return true;
     }
 
-    bool
-    copyFrom(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
+    static bool
+    copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, TypedArray *tarray, jsuint offset)
     {
-        JS_ASSERT(offset <= length);
-        JS_ASSERT(tarray->length <= length - offset);
-        if (tarray->buffer == buffer)
-            return copyFromWithOverlap(cx, tarray, offset);
+        ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
+        JS_ASSERT(thisTypedArray);
 
-        NativeType *dest = static_cast<NativeType*>(data) + offset;
+        JS_ASSERT(offset <= thisTypedArray->length);
+        JS_ASSERT(tarray->length <= thisTypedArray->length - offset);
+        if (tarray->buffer == thisTypedArray->buffer)
+            return thisTypedArray->copyFromWithOverlap(cx, tarray, offset);
 
-        if (tarray->type == type) {
+        NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
+
+        if (tarray->type == thisTypedArray->type) {
             memcpy(dest, tarray->data, tarray->byteLength);
             return true;
         }
 
         uintN srclen = tarray->length;
         switch (tarray->type) {
           case TypedArray::TYPE_INT8: {
             int8 *src = static_cast<int8*>(tarray->data);
@@ -1237,34 +1241,32 @@ class TypedArrayTemplate
             JS_NOT_REACHED("copyFrom with a TypedArray of unknown type");
             break;
         }
 
         return true;
     }
 
     bool
-    copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset = 0)
+    copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset)
     {
         JS_ASSERT(offset <= length);
 
         NativeType *dest = static_cast<NativeType*>(data) + offset;
 
         if (tarray->type == type) {
             memmove(dest, tarray->data, tarray->byteLength);
             return true;
         }
 
         // We have to make a copy of the source array here, since
         // there's overlap, and we have to convert types.
-        void *srcbuf = js_malloc(tarray->byteLength);
-        if (!srcbuf) {
-            js_ReportOutOfMemory(cx);
+        void *srcbuf = cx->malloc(tarray->byteLength);
+        if (!srcbuf)
             return false;
-        }
         memcpy(srcbuf, tarray->data, tarray->byteLength);
 
         switch (tarray->type) {
           case TypedArray::TYPE_INT8: {
             int8 *src = (int8*) srcbuf;
             for (uintN i = 0; i < tarray->length; ++i)
                 *dest++ = NativeType(*src++);
             break;
@@ -1316,52 +1318,28 @@ class TypedArrayTemplate
             JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type");
             break;
         }
 
         js_free(srcbuf);
         return true;
     }
 
-    bool
-    createBufferWithSizeAndCount(JSContext *cx, uint32 size, uint32 count)
+    static JSObject *
+    createBufferWithSizeAndCount(JSContext *cx, uint32 count)
     {
-        JS_ASSERT(size != 0);
-
+        size_t size = sizeof(NativeType);
         if (size != 0 && count >= INT32_MAX / size) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_NEED_DIET, "size and count");
             return false;
         }
 
         int32 bytelen = size * count;
-        if (!createBufferWithByteLength(cx, bytelen))
-            return false;
-
-        length = count;
-        return true;
-    }
-
-    bool
-    createBufferWithByteLength(JSContext *cx, int32 bytes)
-    {
-        Value arg = Int32Value(bytes), rval;
-        if (!ArrayBuffer::create(cx, 1, &arg, &rval))
-            return false;
-
-        JSObject *obj = &rval.toObject();
-
-        bufferJS = obj;
-        buffer = ArrayBuffer::fromJSObject(obj);
-
-        byteOffset = 0;
-        byteLength = bytes;
-        data = buffer->data;
-
-        return true;
+        return ArrayBuffer::create(cx, bytelen);
     }
 };
 
 // this default implementation is only valid for integer types
 // less than 32-bits in size.
 template<typename NativeType>
 void
 TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
@@ -1645,120 +1623,99 @@ js_IsTypedArray(JSObject *obj)
     Class *clasp = obj->getClass();
     return clasp >= &TypedArray::fastClasses[0] &&
            clasp <  &TypedArray::fastClasses[TypedArray::TYPE_MAX];
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateArrayBuffer(JSContext *cx, jsuint nbytes)
 {
-    Value arg = NumberValue(nbytes), rval;
-    if (!ArrayBuffer::create(cx, 1, &arg, &rval))
-        return NULL;
-    return &rval.toObject();
+    return ArrayBuffer::create(cx, nbytes);
 }
 
-static inline JSBool
-TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv, Value *rv)
+static inline JSObject *
+TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv)
 {
     switch (atype) {
       case TypedArray::TYPE_INT8:
-        return Int8Array::create(cx, argc, argv, rv);
+        return Int8Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_UINT8:
-        return Uint8Array::create(cx, argc, argv, rv);
+        return Uint8Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_INT16:
-        return Int16Array::create(cx, argc, argv, rv);
+        return Int16Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_UINT16:
-        return Uint16Array::create(cx, argc, argv, rv);
+        return Uint16Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_INT32:
-        return Int32Array::create(cx, argc, argv, rv);
+        return Int32Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_UINT32:
-        return Uint32Array::create(cx, argc, argv, rv);
+        return Uint32Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_FLOAT32:
-        return Float32Array::create(cx, argc, argv, rv);
+        return Float32Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_FLOAT64:
-        return Float64Array::create(cx, argc, argv, rv);
+        return Float64Array::create(cx, argc, argv);
 
       case TypedArray::TYPE_UINT8_CLAMPED:
-        return Uint8ClampedArray::create(cx, argc, argv, rv);
+        return Uint8ClampedArray::create(cx, argc, argv);
 
       default:
         JS_NOT_REACHED("shouldn't have gotten here");
         return false;
     }
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
 
-    Value vals[2];
-    vals[0].setInt32(nelements);
-    vals[1].setUndefined();
-
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
-    if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
-        return NULL;
-
-    return &vals[1].toObject();
+    Value nelems = Int32Value(nelements);
+    return TypedArrayConstruct(cx, atype, 1, &nelems);
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
 
-    Value vals[2];
-    vals[0].setObject(*arrayArg);
-    vals[1].setUndefined();
-
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
-    if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
-        return NULL;
-
-    return &vals[1].toObject();
+    Value arrval = ObjectValue(*arrayArg);
+    return TypedArrayConstruct(cx, atype, 1, &arrval);
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg,
                               jsint byteoffset, jsint length)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
     JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg));
     JS_ASSERT_IF(byteoffset < 0, length < 0);
 
     Value vals[4];
 
     int argc = 1;
     vals[0].setObject(*bufArg);
-    vals[3].setUndefined();
 
     if (byteoffset >= 0) {
         vals[argc].setInt32(byteoffset);
         argc++;
     }
 
     if (length >= 0) {
         vals[argc].setInt32(length);
         argc++;
     }
 
     AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
-    if (!TypedArrayConstruct(cx, atype, argc, &vals[0], &vals[3]))
-        return NULL;
-
-    return &vals[3].toObject();
+    return TypedArrayConstruct(cx, atype, argc, &vals[0]);
 }
 
 JS_FRIEND_API(JSBool)
 js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope)
 {
     JS_ASSERT(obj);
 
     scope = JS_GetGlobalForObject(cx, scope);
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -59,17 +59,17 @@ struct JS_FRIEND_API(ArrayBuffer) {
     static Class jsclass;
     static JSPropertySpec jsprops[];
 
     static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static void class_finalize(JSContext *cx, JSObject *obj);
 
     static JSBool class_constructor(JSContext *cx, uintN argc, Value *vp);
 
-    static bool create(JSContext *cx, uintN argc, Value *argv, Value *rval);
+    static JSObject *create(JSContext *cx, int32 nbytes);
 
     static ArrayBuffer *fromJSObject(JSObject *obj);
 
     ArrayBuffer()
         : data(0), byteLength()
     {
     }
 
--- a/js/src/yarr/pcre/pcre_exec.cpp
+++ b/js/src/yarr/pcre/pcre_exec.cpp
@@ -420,27 +420,16 @@ struct MatchStack {
             js_delete(oldFrame);
         size--;
     }
 
     void popAllFrames() {
         while (size)
             popCurrentFrame();
     }
-
-    /* Return true iff the instruction pointer is currently at an optional bracket,
-     i.e., a bracket that may be matched zero times. */
-    bool atOptionalBracket() const {
-        /* We don't need to include OP_BRAMINZERO: we try to match the group within
-         the BRAMINZERO only if we have already failed to match the rest of the 
-         regular expression. Thus, we will not be able to complete a successful
-         match by matching the group against the empty string anyway. */
-        unsigned char prevOp = currentFrame->args.instructionPtr[-1];
-        return prevOp == OP_BRAZERO;
-    }
 };
 
 static int matchError(int errorCode, MatchStack& stack)
 {
     stack.popAllFrames();
     return errorCode;
 }
 
@@ -471,27 +460,49 @@ static inline void repeatInformationFrom
     JS_ASSERT(instructionOffset >= 0);
     JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR));
 
     minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2
     minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset];
     maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset];
 }
 
+/* Helper class for passing a flag value from one op to the next that runs.
+ This allows us to set the flag in certain ops. When the flag is read, it
+ will be true only if the previous op set the flag, otherwise it is false. */
+class LinearFlag {
+public:
+    LinearFlag() : flag(false) {}
+    
+    bool readAndClear() {
+        bool rv = flag;
+        flag = false;
+        return rv;
+    }
+
+    void set() {
+        flag = true;
+    }
+
+private:
+    bool flag;
+};
+
 static int
 match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md)
 {
     bool isMatch = false;
     int min;
     bool minimize = false; /* Initialization not really needed, but some compilers think so. */
     unsigned remainingMatchCount = matchLimit;
     int othercase; /* Declare here to avoid errors during jumps */
     bool minSatisfied;
     
     MatchStack stack(regExpPool);
+    LinearFlag minSatNextBracket;
 
     /* The opcode jump table. */
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
 #define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode)
     static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
 #undef EMIT_JUMP_TABLE_ENTRY
 #endif
     
@@ -547,18 +558,17 @@ RECURSE:
             BEGIN_OPCODE(BRA):
             NON_CAPTURING_BRACKET:
                 DPRINTF(("start non-capturing bracket\n"));
                 stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr);
                 /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested
                  bracket data. */
                 stack.currentFrame->locals.skipBytes = 3;
                 /* We must compute this value at the top, before we move the instruction pointer. */
-                stack.currentFrame->locals.minSatisfied = instructionPtr != stack.currentFrame->args.instructionPtr &&
-                                                          stack.atOptionalBracket();
+                stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear();
                 do {
                     /* We need to extract this into a variable so we can correctly pass it by value
                      through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */
                     minSatisfied = stack.currentFrame->locals.minSatisfied;
                     RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied);
                     if (isMatch) {
                         DPRINTF(("non-capturing bracket succeeded\n"));
                         RRETURN;
@@ -653,16 +663,17 @@ RECURSE:
              i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
              repeat limits are compiled as a number of copies, with the optional ones
              preceded by BRAZERO or BRAMINZERO. */
                 
             BEGIN_OPCODE(BRAZERO): {
                 stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
                 stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1);
                 stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
+                minSatNextBracket.set();
                 RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true);
                 if (isMatch)
                     RRETURN;
                 stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
                 advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
                 stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE;
                 NEXT_OPCODE;
             }
@@ -761,21 +772,23 @@ RECURSE:
                 if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) {
                     stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
                     RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                     if (isMatch)
                         RRETURN;
                     else
                         stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
                     DPRINTF(("recursively matching lazy group\n"));
+                    minSatNextBracket.set();
                     RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true);
                 } else { /* OP_KETRMAX */
                     stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
                     stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
                     DPRINTF(("recursively matching greedy group\n"));
+                    minSatNextBracket.set();
                     RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true);
                     if (isMatch)
                         RRETURN;
                     else
                         stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd);
                     RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                 }
                 RRETURN;
@@ -1854,17 +1867,17 @@ RECURSE:
                 
                 if (stack.currentFrame->locals.offset < md.offsetMax) {
                     stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
                     DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject));
                     md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject;
                     stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */
                     
                     /* We must compute this value at the top, before we move the instruction pointer. */
-                    stack.currentFrame->locals.minSatisfied = stack.atOptionalBracket();
+                    stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear();
                     do {
                         /* We need to extract this into a variable so we can correctly pass it by value
                          through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */
                         minSatisfied = stack.currentFrame->locals.minSatisfied;
                         RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied);
                         if (isMatch)
                             RRETURN;
                         stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -105,30 +105,34 @@
             return Components.interfaces.nsIAccessibleProvider.XULCombobox;
           ]]>
         </getter>
       </property>
 
       <!-- =================== nsIAutoCompleteInput =================== -->
 
       <field name="popup"><![CDATA[
-        var popup = null;
-        var popupId = this.getAttribute("autocompletepopup");
-        if (popupId)
-          popup = document.getElementById(popupId);
-        if (!popup) {
-          popup = document.createElement("panel");
-          popup.setAttribute("type", "autocomplete");
-          popup.setAttribute("noautofocus", "true");
-
-          var popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
-          popupset.appendChild(popup);
-        }
-        popup.mInput = this;
-        popup;
+        // Wrap in an anonymous function so that the var statements don't
+        // create properties on 'this'.
+        (function (that) {
+          var popup = null;
+          var popupId = that.getAttribute("autocompletepopup");
+          if (popupId)
+            popup = document.getElementById(popupId);
+          if (!popup) {
+            popup = document.createElement("panel");
+            popup.setAttribute("type", "autocomplete");
+            popup.setAttribute("noautofocus", "true");
+  
+            var popupset = document.getAnonymousElementByAttribute(that, "anonid", "popupset");
+            popupset.appendChild(popup);
+          }
+          popup.mInput = that;
+          return popup;
+        })(this);
       ]]></field>
 
       <property name="controller" onget="return this.mController;" readonly="true"/>
 
       <property name="popupOpen"
                 onget="return this.popup.popupOpen;"
                 onset="if (val) this.openPopup(); else this.closePopup();"/>