Bug 952890 part 1. Make WebIDL sequence JS to C++ conversions use for-of iteration, not length/index gets. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 14 Feb 2014 10:46:09 -0500
changeset 171500 d0b0dca8f79266b3c759e69d807f1c7913df2e05
parent 171499 b87877dfeb496b3839685ca8016069a293c38cf3
child 171501 584e7a00ac79c9506a1e031fb237f0cb93aef272
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerspeterv
bugs952890
milestone30.0a1
Bug 952890 part 1. Make WebIDL sequence JS to C++ conversions use for-of iteration, not length/index gets. r=peterv
dom/bindings/Codegen.py
dom/contacts/tests/test_contacts_basics2.html
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3100,41 +3100,45 @@ def getJSToNativeConversionInfo(type, de
         sequenceType = typeName.define()
         if nullable:
             typeName = CGTemplatedType("Nullable", typeName)
             arrayRef = "${declName}.SetValue()"
         else:
             arrayRef = "${declName}"
 
         # NOTE: Keep this in sync with variadic conversions as needed
-        templateBody = ("""JS::Rooted<JSObject*> seq(cx, &${val}.toObject());\n
-if (!IsArrayLike(cx, seq)) {
+        templateBody = ("""JS::ForOfIterator iter(cx);
+if (!iter.init(${val}, JS::ForOfIterator::AllowNonIterable)) {
 %s
 }
-uint32_t length;
-// JS_GetArrayLength actually works on all objects
-if (!JS_GetArrayLength(cx, seq, &length)) {
+if (!iter.valueIsIterable()) {
 %s
 }
 %s &arr = %s;
-if (!arr.SetCapacity(length)) {
-  JS_ReportOutOfMemory(cx);
-%s
-}
-for (uint32_t i = 0; i < length; ++i) {
-  JS::Rooted<JS::Value> temp(cx);
-  if (!JS_GetElement(cx, seq, i, &temp)) {
+JS::Rooted<JS::Value> temp(cx);
+while (true) {
+  bool done;
+  if (!iter.next(&temp, &done)) {
 %s
   }
-  %s& slot = *arr.AppendElement();
-""" % (CGIndenter(CGGeneric(notSequence)).define(),
-       exceptionCodeIndented.define(),
+  if (done) {
+    break;
+  }
+  %s* slotPtr = arr.AppendElement();
+  if (!slotPtr) {
+    JS_ReportOutOfMemory(cx);
+%s
+  }
+  %s& slot = *slotPtr;
+""" % (exceptionCodeIndented.define(),
+       CGIndenter(CGGeneric(notSequence)).define(),
        sequenceType,
        arrayRef,
-       exceptionCodeIndented.define(),
+       CGIndenter(exceptionCodeIndented).define(),
+       elementInfo.declType.define(),
        CGIndenter(exceptionCodeIndented).define(),
        elementInfo.declType.define()))
 
         templateBody += CGIndenter(CGGeneric(
                 string.Template(elementInfo.template).substitute(
                     {
                         "val": "temp",
                         "mutableVal": "&temp",
@@ -3191,22 +3195,17 @@ for (uint32_t i = 0; i < length; ++i) {
                 interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext" % (unionArgumentObj, name)))
                 names.append(name)
             interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True)
         else:
             interfaceObject = None
 
         arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
         if len(arrayObjectMemberTypes) > 0:
-            assert len(arrayObjectMemberTypes) == 1
-            memberType = arrayObjectMemberTypes[0]
-            name = memberType.name
-            arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
-            arrayObject = CGIfWrapper(arrayObject, "IsArrayLike(cx, argObj)")
-            names.append(name)
+            raise TypeError("Bug 767924: We don't support sequences in unions yet")
         else:
             arrayObject = None
 
         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
         if len(dateObjectMemberTypes) > 0:
             assert len(dateObjectMemberTypes) == 1
             memberType = dateObjectMemberTypes[0]
             name = memberType.name
--- a/dom/contacts/tests/test_contacts_basics2.html
+++ b/dom/contacts/tests/test_contacts_basics2.html
@@ -676,22 +676,25 @@ var steps = [
     req = mozContacts.clear()
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
     req.onerror = onFailure;
   },
   function() {
-    ok(true, "Test setting array properties to scalar values")
+    ok(true, "Test that after setting array properties to scalar values the property os not a non-array")
     const FIELDS = ["email","url","adr","tel","impp"];
     createResult1 = new mozContact();
     for (var prop of FIELDS) {
-      createResult1[prop] = {type: ["foo"]};
-      ok(Array.isArray(createResult1[prop]), prop + " is array");
+      try {
+        createResult1[prop] = {type: ["foo"]};
+      } catch (e) {}
+      ok(createResult1[prop] === null ||
+         Array.isArray(createResult1[prop]), prop + " is array");
     }
     next();
   },
   function() {
     ok(true, "Undefined properties of fields should be treated correctly");
     var c = new mozContact({
       adr: [{streetAddress: undefined}],
       email: [{value: undefined}],