Bug 1165053 - Part 6: Refactor TypedArrayObjectTemplate::fromArray. r=lth
☠☠ backed out by e1bbed330deb ☠ ☠
authorTooru Fujisawa <arai_a@mac.com>
Sun, 20 Dec 2015 19:15:54 +0900
changeset 290600 27189d8e678de79cb4b8e00ec6230cd82442e831
parent 290599 71ef5f8009ec19ad4bfdbf009bfc0b11ffd788d2
child 290601 51249df95c69025fc997ef74a38be9ee7a89dfcd
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1165053
milestone48.0a1
Bug 1165053 - Part 6: Refactor TypedArrayObjectTemplate::fromArray. r=lth
js/src/vm/TypedArrayCommon.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -835,33 +835,19 @@ class TypedArrayMethods
             if (!setFromNonTypedArray(cx, target, arg0, len, offset))
                 return false;
         }
 
         args.rval().setUndefined();
         return true;
     }
 
-    static bool
-    setFromArrayLike(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source, uint32_t len,
-                     uint32_t offset = 0)
-    {
-        MOZ_ASSERT(offset <= target->length());
-        MOZ_ASSERT(len <= target->length() - offset);
-
-        if (source->is<TypedArrayObject>())
-            return setFromTypedArray(cx, target, source, offset);
-
-        return setFromNonTypedArray(cx, target, source, len, offset);
-    }
-
-  private:
      static bool
      setFromTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
-                       uint32_t offset)
+                       uint32_t offset = 0)
      {
          MOZ_ASSERT(source->is<TypedArrayObject>(), "use setFromNonTypedArray");
 
          bool isShared = target->isSharedMemory() || source->as<TypedArrayObject>().isSharedMemory();
 
          switch (target->type()) {
            case Scalar::Int8:
              if (isShared)
@@ -905,17 +891,17 @@ class TypedArrayMethods
              break;
          }
 
          MOZ_CRASH("nonsense target element type");
      }
 
     static bool
     setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
-                         uint32_t len, uint32_t offset)
+                         uint32_t len, uint32_t offset = 0)
     {
         MOZ_ASSERT(!source->is<TypedArrayObject>(), "use setFromTypedArray");
 
         bool isShared = target->isSharedMemory();
 
         switch (target->type()) {
           case Scalar::Int8:
             if (isShared)
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -671,16 +671,22 @@ class TypedArrayObjectTemplate : public 
             return nullptr;
 
         return makeInstance(cx, buffer, 0, nelements, proto);
     }
 
     static JSObject*
     fromArray(JSContext* cx, HandleObject other, HandleObject newTarget = nullptr);
 
+    static JSObject*
+    fromTypedArray(JSContext* cx, HandleObject other, HandleObject newTarget);
+
+    static JSObject*
+    fromObject(JSContext* cx, HandleObject other, HandleObject newTarget);
+
     static const NativeType
     getIndex(JSObject* obj, uint32_t index)
     {
         TypedArrayObject& tarray = obj->as<TypedArrayObject>();
         MOZ_ASSERT(index < tarray.length());
         return jit::AtomicOperations::loadSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>() + index);
     }
 
@@ -714,41 +720,89 @@ struct TypedArrayObject::OfType
 
 template<typename T>
 /* static */ JSObject*
 TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
                                        HandleObject newTarget /* = nullptr */)
 {
     // Allow nullptr newTarget for FriendAPI methods, which don't care about
     // subclassing.
-    RootedObject proto(cx);
+    if (other->is<TypedArrayObject>())
+        return fromTypedArray(cx, other, newTarget);
+
+    return fromObject(cx, other, newTarget);
+}
 
-    uint32_t len;
-    if (other->is<TypedArrayObject>()) {
-        if (!GetPrototypeForInstance(cx, newTarget, &proto))
-            return nullptr;
+// ES 2016 draft Mar 25, 2016 22.2.4.3.
+template<typename T>
+/* static */ JSObject*
+TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other,
+                                            HandleObject newTarget)
+{
+    // Step 1.
+    MOZ_ASSERT(other->is<TypedArrayObject>());
 
-        if (other->as<TypedArrayObject>().hasDetachedBuffer()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-            return nullptr;
-        }
-        len = other->as<TypedArrayObject>().length();
-    } else {
-        if (!GetLengthProperty(cx, other, &len))
-            return nullptr;
-        if (!GetPrototypeForInstance(cx, newTarget, &proto))
-            return nullptr;
+    // Step 2 (done in caller).
+
+    // Step 4 (partially).
+    RootedObject proto(cx);
+    if (!GetPrototypeForInstance(cx, newTarget, &proto))
+        return nullptr;
+
+    // Step 5.
+    Rooted<TypedArrayObject*> srcArray(cx, &other->as<TypedArrayObject>());
+
+    // Steps 6-7.
+    if (srcArray->hasDetachedBuffer()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+        return nullptr;
     }
 
+    // Steps 10.
+    uint32_t elementLength = srcArray->length();
+
+    // Steps 8-9, 11-18.
     Rooted<ArrayBufferObject*> buffer(cx);
+    if (!maybeCreateArrayBuffer(cx, elementLength, &buffer))
+        return nullptr;
+
+    // Steps 3, 4 (remaining part), 19-23.
+    Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, elementLength, proto));
+    if (!obj)
+        return nullptr;
+
+    // Step 18.d-g or 24.1.1.4 step 11.
+    if (!TypedArrayMethods<TypedArrayObject>::setFromTypedArray(cx, obj, srcArray))
+        return nullptr;
+
+    return obj;
+}
+
+// FIXME: This is not compatible with TypedArrayFrom in the spec
+// (ES 2016 draft Mar 25, 2016 22.2.4.4 and 22.2.2.1.1)
+// We should handle iterator protocol (bug 1232266).
+template<typename T>
+/* static */ JSObject*
+TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, HandleObject newTarget)
+{
+    RootedObject proto(cx);
+    Rooted<ArrayBufferObject*> buffer(cx);
+    uint32_t len;
+    if (!GetLengthProperty(cx, other, &len))
+        return nullptr;
+    if (!GetPrototypeForInstance(cx, newTarget, &proto))
+        return nullptr;
     if (!maybeCreateArrayBuffer(cx, len, &buffer))
         return nullptr;
 
     Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
-    if (!obj || !TypedArrayMethods<TypedArrayObject>::setFromArrayLike(cx, obj, other, len))
+    if (!obj)
+        return nullptr;
+
+    if (!TypedArrayMethods<TypedArrayObject>::setFromNonTypedArray(cx, obj, other, len))
         return nullptr;
     return obj;
 }
 
 bool
 TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
 {
     JS_ReportError(cx, "%%TypedArray%% calling/constructing not implemented yet");