Bug 578700 - Numeric types implementation. r=nmatsakis
authorNikhil Marathe <nsm.nikhil@gmail.com>
Thu, 25 Jul 2013 17:58:50 -0700
changeset 140051 2aa4435cd79882c98217991bad72c65633269430
parent 140050 5dd7854c9474f0a997233430072f7a6b239677a7
child 140052 8253f5b39cbd23c09ee7485489d5daee520555a9
push id31583
push usernsm.nikhil@gmail.com
push dateFri, 26 Jul 2013 01:00:52 +0000
treeherdermozilla-inbound@13b28328f010 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnmatsakis
bugs578700
milestone25.0a1
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
Bug 578700 - Numeric types implementation. r=nmatsakis
js/src/builtin/BinaryData.cpp
js/src/builtin/BinaryData.h
js/src/jsapi.cpp
js/src/tests/ecma_6/BinaryData/architecture.js
js/src/tests/ecma_6/BinaryData/numerictypes.js
js/src/vm/CommonPropertyNames.h
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/BinaryData.cpp
+++ b/js/src/builtin/BinaryData.cpp
@@ -1,201 +1,382 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/BinaryData.h"
 
+#include "mozilla/FloatingPoint.h"
+
 #include "jscompartment.h"
 #include "jsobj.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/GlobalObject.h"
+#include "vm/TypedArrayObject.h"
 
 using namespace js;
 
 JSBool TypeThrowError(JSContext *cx, unsigned argc, Value *vp)
 {
     return ReportIsNotFunction(cx, *vp);
 }
 
 JSBool DataThrowError(JSContext *cx, unsigned argc, Value *vp)
 {
     return ReportIsNotFunction(cx, *vp);
 }
 
-// FIXME will actually require knowing function name
-JSBool createNumericBlock(JSContext *cx, unsigned argc, jsval *vp)
+static void
+ReportTypeError(JSContext *cx, Value fromValue, const char *toType)
+{
+    char *valueStr = JS_EncodeString(cx, JS_ValueToString(cx, fromValue));
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
+                         valueStr, toType);
+    JS_free(cx, (void *) valueStr);
+}
+
+static void
+ReportTypeError(JSContext *cx, Value fromValue, JSString *toType)
+{
+    const char *fnName = JS_EncodeString(cx, toType);
+    ReportTypeError(cx, fromValue, fnName);
+    JS_free(cx, (void *) fnName);
+}
+
+static inline bool
+IsNumericType(JSObject *type)
+{
+    return type && &NumericTypeClasses[NUMERICTYPE_UINT8] <= type->getClass() &&
+                   type->getClass() <= &NumericTypeClasses[NUMERICTYPE_FLOAT64];
+}
+
+template <typename Domain, typename Input>
+bool
+InRange(Input x)
 {
-    return false;
+    return std::numeric_limits<Domain>::min() <= x &&
+           x <= std::numeric_limits<Domain>::max();
+}
+
+template <>
+bool
+InRange<float, int>(int x)
+{
+    return -std::numeric_limits<float>::max() <= x &&
+           x <= std::numeric_limits<float>::max();
+}
+
+template <>
+bool
+InRange<double, int>(int x)
+{
+    return -std::numeric_limits<double>::max() <= x &&
+           x <= std::numeric_limits<double>::max();
+}
+
+template <>
+bool
+InRange<float, double>(double x)
+{
+    return -std::numeric_limits<float>::max() <= x &&
+           x <= std::numeric_limits<float>::max();
+}
+
+template <>
+bool
+InRange<double, double>(double x)
+{
+    return -std::numeric_limits<double>::max() <= x &&
+           x <= std::numeric_limits<double>::max();
+}
+
+template <typename T>
+Class *
+js::NumericType<T>::typeToClass()
+{
+    JS_ASSERT(0);
+    return NULL;
 }
 
-JSBool createArrayType(JSContext *cx, unsigned argc, jsval *vp)
-{
-    return false;
+#define BINARYDATA_TYPE_TO_CLASS(constant_, type_)\
+    template <>\
+    Class *\
+    NumericType<type_##_t>::typeToClass()\
+    {\
+        return &NumericTypeClasses[constant_];\
+    }
+
+/**
+ * This namespace declaration is required because of a weird 'specialization in
+ * different namespace' error that happens in gcc, only on type specialized
+ * template functions.
+ */
+namespace js {
+    BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_TYPE_TO_CLASS);
 }
 
-JSBool createStructType(JSContext *cx, unsigned argc, jsval *vp)
+template <typename T>
+bool
+NumericType<T>::convert(JSContext *cx, HandleValue val, T* converted)
 {
-    return false;
+    if (val.isInt32()) {
+        *converted = T(val.toInt32());
+        return true;
+    }
+
+    double d;
+    if (!ToDoubleForTypedArray(cx, val, &d)) {
+        Class *typeClass = typeToClass();
+        ReportTypeError(cx, val, typeClass->name);
+        return false;
+    }
+
+    if (TypeIsFloatingPoint<T>()) {
+        *converted = T(d);
+    } else if (TypeIsUnsigned<T>()) {
+        uint32_t n = ToUint32(d);
+        *converted = T(n);
+    } else {
+        int32_t n = ToInt32(d);
+        *converted = T(n);
+    }
+
+    return true;
 }
 
-JSBool DataInstanceUpdate(JSContext *cx, unsigned argc, jsval *vp)
+template <typename T>
+JSBool
+NumericType<T>::call(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() < 1) {
+        char *fnName = JS_EncodeString(cx, args.callee().as<JSFunction>().atom());
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
+                             fnName, "0", "s");
+        JS_free(cx, (void *) fnName);
+        return false;
+    }
+
+    RootedValue arg(cx, args[0]);
+    T answer;
+    if (!convert(cx, arg, &answer))
+        return false; // convert() raises TypeError.
+
+    // TODO Once reify is implemented (in a later patch) this will be replaced
+    // by a call to reify.
+    args.rval().set(NumberValue(answer));
+    return true;
+}
+
+template<unsigned int N>
+JSBool
+NumericTypeToString(JSContext *cx, unsigned int argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(NUMERICTYPE_UINT8 <= N && N <= NUMERICTYPE_FLOAT64);
+    JSString *s = JS_NewStringCopyZ(cx, NumericTypeClasses[N].name);
+    args.rval().set(StringValue(s));
+    return true;
+}
+
+JSBool
+createArrayType(JSContext *cx, unsigned argc, Value *vp)
 {
     return false;
 }
 
 JSBool
-ArrayTypeObject::repeat(JSContext *cx, unsigned int argc, jsval *vp)
+createStructType(JSContext *cx, unsigned argc, Value *vp)
+{
+    return false;
+}
+
+JSBool
+DataInstanceUpdate(JSContext *cx, unsigned argc, Value *vp)
+{
+    return false;
+}
+
+JSBool
+ArrayTypeObject::repeat(JSContext *cx, unsigned int argc, Value *vp)
 {
     return false;
 }
 
 bool
 GlobalObject::initDataObject(JSContext *cx, Handle<GlobalObject *> global)
 {
     RootedObject DataProto(cx);
-    DataProto = NewObjectWithGivenProto(cx, &DataClass, global->getOrCreateObjectPrototype(cx), global, SingletonObject);
+    DataProto = NewObjectWithGivenProto(cx, &DataClass,
+                                        global->getOrCreateObjectPrototype(cx),
+                                        global, SingletonObject);
     if (!DataProto)
         return false;
 
     RootedAtom DataName(cx, ClassName(JSProto_Data, cx));
-    RootedFunction DataCtor(cx, global->createConstructor(cx, DataThrowError, DataName, 1, JSFunction::ExtendedFinalizeKind));
+    RootedFunction DataCtor(cx,
+            global->createConstructor(cx, DataThrowError, DataName,
+                                      1, JSFunction::ExtendedFinalizeKind));
+
     if (!DataCtor)
         return false;
 
     if (!JS_DefineFunction(cx, DataProto, "update", DataInstanceUpdate, 1, 0))
         return false;
 
     if (!LinkConstructorAndPrototype(cx, DataCtor, DataProto))
         return false;
 
-    if (!DefineConstructorAndPrototype(cx, global, JSProto_Data, DataCtor, DataProto))
+    if (!DefineConstructorAndPrototype(cx, global, JSProto_Data,
+                                       DataCtor, DataProto))
         return false;
 
     global->setReservedSlot(JSProto_Data, ObjectValue(*DataCtor));
     return true;
 }
 
 bool
 GlobalObject::initTypeObject(JSContext *cx, Handle<GlobalObject *> global)
 {
     RootedObject TypeProto(cx, global->getOrCreateDataObject(cx));
     if (!TypeProto)
         return false;
 
     RootedAtom TypeName(cx, ClassName(JSProto_Type, cx));
-    RootedFunction TypeCtor(cx, global->createConstructor(cx, TypeThrowError, TypeName, 1, JSFunction::ExtendedFinalizeKind));
+    RootedFunction TypeCtor(cx,
+            global->createConstructor(cx, TypeThrowError, TypeName,
+                                      1, JSFunction::ExtendedFinalizeKind));
     if (!TypeCtor)
         return false;
 
     if (!LinkConstructorAndPrototype(cx, TypeCtor, TypeProto))
         return false;
 
-    if (!DefineConstructorAndPrototype(cx, global, JSProto_Type, TypeCtor, TypeProto))
+    if (!DefineConstructorAndPrototype(cx, global, JSProto_Type,
+                                       TypeCtor, TypeProto))
         return false;
 
     global->setReservedSlot(JSProto_Type, ObjectValue(*TypeCtor));
     return true;
 }
 
 static JSObject *
-SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject *> global, HandleObject complexObject)
+SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject *> global,
+                      HandleObject complexObject)
 {
     // get the 'Type' constructor
     RootedObject TypeObject(cx, global->getOrCreateTypeObject(cx));
     if (!TypeObject)
         return NULL;
 
     // Set complexObject.__proto__ = Type
     if (!JS_SetPrototype(cx, complexObject, TypeObject))
         return NULL;
 
     RootedObject DataObject(cx, global->getOrCreateDataObject(cx));
     if (!DataObject)
         return NULL;
 
     RootedValue DataProtoVal(cx);
-    if (!JSObject::getProperty(cx, DataObject, DataObject, cx->names().classPrototype, &DataProtoVal))
+    if (!JSObject::getProperty(cx, DataObject, DataObject,
+                               cx->names().classPrototype, &DataProtoVal))
         return NULL;
 
     RootedObject DataProto(cx, DataProtoVal.toObjectOrNull());
     if (!DataProto)
         return NULL;
 
     // Set complexObject.prototype.__proto__ = Data
     RootedObject prototypeObj(cx, JS_NewObject(cx, NULL, NULL, global));
     if (!LinkConstructorAndPrototype(cx, complexObject, prototypeObj))
         return NULL;
 
     if (!JS_SetPrototype(cx, prototypeObj, DataObject))
         return NULL;
 
     // Set complexObject.prototype.prototype.__proto__ = Data.prototype
-    // TODO does this have to actually be a Class so we can set accessor properties etc?
-    RootedObject prototypePrototypeObj(cx, JS_NewObject(cx, NULL, NULL, global));
-    if (!LinkConstructorAndPrototype(cx, prototypeObj, prototypePrototypeObj))
+    RootedObject prototypePrototypeObj(cx, JS_NewObject(cx, NULL, NULL,
+                                       global));
+
+    if (!LinkConstructorAndPrototype(cx, prototypeObj,
+                                     prototypePrototypeObj))
         return NULL;
 
     if (!JS_SetPrototype(cx, prototypePrototypeObj, DataProto))
         return NULL;
 
     return complexObject;
 }
 
 static JSObject *
 InitComplexClasses(JSContext *cx, Handle<GlobalObject *> global)
 {
-    // TODO FIXME use DefineConstructorAndPrototype and other
-    // utilities
-    RootedFunction ArrayTypeFun(cx, JS_DefineFunction(cx, global, "ArrayType", createArrayType, 1, 0));
+    RootedFunction ArrayTypeFun(cx,
+            JS_DefineFunction(cx, global, "ArrayType", createArrayType, 1, 0));
+
     if (!ArrayTypeFun)
         return NULL;
 
     if (!SetupComplexHeirarchy(cx, global, ArrayTypeFun))
         return NULL;
 
     // ArrayType.prototype.repeat
     RootedValue ArrayTypePrototypeVal(cx);
-    if (!JSObject::getProperty(cx, ArrayTypeFun, ArrayTypeFun, cx->names().classPrototype, &ArrayTypePrototypeVal))
+    if (!JSObject::getProperty(cx, ArrayTypeFun, ArrayTypeFun,
+                               cx->names().classPrototype, &ArrayTypePrototypeVal))
         return NULL;
 
-    if (!JS_DefineFunction(cx, ArrayTypePrototypeVal.toObjectOrNull(), "repeat", ArrayTypeObject::repeat, 1, 0))
+    if (!JS_DefineFunction(cx, ArrayTypePrototypeVal.toObjectOrNull(), "repeat",
+                           ArrayTypeObject::repeat, 1, 0))
         return NULL;
 
-    RootedFunction StructTypeFun(cx, JS_DefineFunction(cx, global, "StructType", createStructType, 1, 0));
+    RootedFunction StructTypeFun(cx,
+        JS_DefineFunction(cx, global, "StructType", createStructType, 1, 0));
+
     if (!StructTypeFun)
         return NULL;
 
     if (!SetupComplexHeirarchy(cx, global, StructTypeFun))
         return NULL;
 
     return global;
 }
 
 JSObject *
 js_InitBinaryDataClasses(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->is<GlobalObject>());
     Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
 
-typedef float_t float32_t;
-typedef double_t float64_t;
-#define BINARYDATA_NUMERIC_DEFINE(type_)\
+    JSObject *funProto = JS_GetFunctionPrototype(cx, global);
+#define BINARYDATA_NUMERIC_DEFINE(constant_, type_)\
     do {\
-        JSFunction *numFun = JS_DefineFunction(cx, obj, #type_, createNumericBlock, 1, 0);\
+        RootedObject numFun(cx, JS_DefineObject(cx, global, #type_,\
+                    (JSClass *) &NumericTypeClasses[constant_], funProto, 0));\
+\
         if (!numFun)\
             return NULL;\
 \
-        if (!JS_DefineProperty(cx, numFun, "bytes", INT_TO_JSVAL(sizeof(type_##_t)), JS_PropertyStub, JS_StrictPropertyStub, 0))\
-        return NULL;\
+        numFun->setFixedSlot(SLOT_DATATYPE, Int32Value(constant_));\
+\
+        RootedValue sizeVal(cx, NumberValue(sizeof(type_##_t)));\
+        if (!JSObject::defineProperty(cx, numFun, cx->names().bytes,\
+                                      sizeVal,\
+                                      NULL, NULL,\
+                                      JSPROP_READONLY | JSPROP_PERMANENT))\
+            return NULL;\
+\
+        if (!JS_DefineFunction(cx, numFun, "toString",\
+                               NumericTypeToString<constant_>, 0, 0))\
+            return NULL;\
     } while(0);
     BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_DEFINE)
 #undef BINARYDATA_NUMERIC_DEFINE
 
     if (!InitComplexClasses(cx, global))
         return NULL;
     return global;
 }
--- a/js/src/builtin/BinaryData.h
+++ b/js/src/builtin/BinaryData.h
@@ -12,16 +12,44 @@
 #include "jsfriendapi.h"
 #include "gc/Heap.h"
 
 namespace js {
 class Block : public gc::Cell
 {
 };
 
+typedef float float32_t;
+typedef double float64_t;
+
+enum {
+    NUMERICTYPE_UINT8 = 0,
+    NUMERICTYPE_UINT16,
+    NUMERICTYPE_UINT32,
+    NUMERICTYPE_UINT64,
+    NUMERICTYPE_INT8,
+    NUMERICTYPE_INT16,
+    NUMERICTYPE_INT32,
+    NUMERICTYPE_INT64,
+    NUMERICTYPE_FLOAT32,
+    NUMERICTYPE_FLOAT64,
+    NUMERICTYPES
+};
+
+enum TypeCommonSlots {
+    SLOT_MEMSIZE = 0,
+    SLOT_ALIGN,
+    TYPE_RESERVED_SLOTS
+};
+
+enum BlockCommonSlots {
+    SLOT_DATATYPE = 0,
+    BLOCK_RESERVED_SLOTS
+};
+
 static Class DataClass = {
     "Data",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Data),
     JS_PropertyStub,
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
@@ -36,44 +64,87 @@ static Class TypeClass = {
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
+template <typename T>
+class NumericType
+{
+    private:
+        static Class * typeToClass();
+    public:
+        static bool convert(JSContext *cx, HandleValue val, T *converted);
+        static bool reify(JSContext *cx, void *mem, MutableHandleValue vp);
+        static JSBool call(JSContext *cx, unsigned argc, Value *vp);
+};
+
+template <typename T>
+JS_ALWAYS_INLINE
+bool NumericType<T>::reify(JSContext *cx, void *mem, MutableHandleValue vp)
+{
+    vp.setInt32(* ((T*)mem) );
+    return true;
+}
+
+template <>
+JS_ALWAYS_INLINE
+bool NumericType<float32_t>::reify(JSContext *cx, void *mem, MutableHandleValue vp)
+{
+    vp.setNumber(* ((float32_t*)mem) );
+    return true;
+}
+
+template <>
+JS_ALWAYS_INLINE
+bool NumericType<float64_t>::reify(JSContext *cx, void *mem, MutableHandleValue vp)
+{
+    vp.setNumber(* ((float64_t*)mem) );
+    return true;
+}
 
 #define BINARYDATA_FOR_EACH_NUMERIC_TYPES(macro_)\
-    macro_(uint8)\
-    macro_(uint16)\
-    macro_(uint32)\
-    macro_(uint64)\
-    macro_(int8)\
-    macro_(int16)\
-    macro_(int32)\
-    macro_(int64)\
-    macro_(float32)\
-    macro_(float64)
+    macro_(NUMERICTYPE_UINT8,    uint8)\
+    macro_(NUMERICTYPE_UINT16,   uint16)\
+    macro_(NUMERICTYPE_UINT32,   uint32)\
+    macro_(NUMERICTYPE_UINT64,   uint64)\
+    macro_(NUMERICTYPE_INT8,     int8)\
+    macro_(NUMERICTYPE_INT16,    int16)\
+    macro_(NUMERICTYPE_INT32,    int32)\
+    macro_(NUMERICTYPE_INT64,    int64)\
+    macro_(NUMERICTYPE_FLOAT32,  float32)\
+    macro_(NUMERICTYPE_FLOAT64,  float64)
 
-#define BINARYDATA_NUMERIC_CLASSES(type_)\
-static Class type_##BlockClass = {\
+#define BINARYDATA_NUMERIC_CLASSES(constant_, type_)\
+{\
     #type_,\
+    JSCLASS_HAS_RESERVED_SLOTS(1) |\
     JSCLASS_HAS_CACHED_PROTO(JSProto_##type_),\
     JS_PropertyStub,       /* addProperty */\
     JS_DeletePropertyStub, /* delProperty */\
     JS_PropertyStub,       /* getProperty */\
     JS_StrictPropertyStub, /* setProperty */\
     JS_EnumerateStub,\
     JS_ResolveStub,\
-    JS_ConvertStub\
+    JS_ConvertStub,\
+    NULL,\
+    NULL,\
+    NumericType<type_##_t>::call,\
+    NULL,\
+    NULL,\
+    NULL\
+},
+
+static Class NumericTypeClasses[NUMERICTYPES] = {
+    BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_CLASSES)
 };
 
-BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_CLASSES)
-
 static Class ArrayTypeClass = {
     "ArrayType",
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayType),
     JS_PropertyStub,
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1909,18 +1909,18 @@ static const JSStdName standard_class_na
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8ClampedArray),
                                 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(DataView),     &DataViewObject::class_},
 
     /* Binary Data */
 #ifdef ENABLE_BINARYDATA
     {js_InitBinaryDataClasses,          EAGER_ATOM_AND_CLASP(Type)},
     {js_InitBinaryDataClasses,          EAGER_ATOM_AND_CLASP(Data)},
-#define BINARYDATA_NUMERIC_NAMES(type_)\
-    {js_InitBinaryDataClasses,          EAGER_CLASS_ATOM(type_),      CLASP(type_##Block)},
+#define BINARYDATA_NUMERIC_NAMES(constant_, type_)\
+    {js_InitBinaryDataClasses,          EAGER_CLASS_ATOM(type_),      &NumericTypeClasses[constant_]},
     BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_NAMES)
 #undef BINARYDATA_NUMERIC_NAMES
     {js_InitBinaryDataClasses,          EAGER_ATOM_AND_CLASP(ArrayType)},
     {js_InitBinaryDataClasses,          EAGER_ATOM_AND_CLASP(StructType)},
 #endif
     {NULL,                      0, NULL}
 };
 
--- a/js/src/tests/ecma_6/BinaryData/architecture.js
+++ b/js/src/tests/ecma_6/BinaryData/architecture.js
@@ -9,16 +9,27 @@ function assertNotEq(a, b) {
     } catch(exc) {
         ok = true;
     }
   
     if (!ok)
         throw new TypeError("Assertion failed: assertNotEq(" + a + " " + b + ")");
 }
 
+function assertThrows(f) {
+    var ok = false;
+    try {
+        f();
+    } catch (exc) {
+        ok = true;
+    }
+    if (!ok)
+        throw new TypeError("Assertion failed: " + f + " did not throw as expected");
+}
+
 function runTests() {
     print(BUGNUMBER + ": " + summary);
   
     assertEq(Data.__proto__, Function.prototype);
     assertEq(Data.prototype.__proto__, Object.prototype);
     assertEq(Data.prototype.constructor, Data);
     assertEq(typeof Data.prototype.update === "function", true);
   
@@ -26,16 +37,17 @@ function runTests() {
     assertEq(Type.prototype, Data);
   
     var sizes = [1, 2, 4, 8, 1, 2, 4, 8, 4, 8];
     [ uint8, uint16, uint32,
       uint64, int8, int16,
       int32, int64, float32, float64 ].forEach(function(numType, i) {
         assertEq(numType.__proto__, Function.prototype);
         assertEq(numType.bytes, sizes[i]);
+        assertThrows(function() new numType());
     });
   
     assertEq(ArrayType.__proto__, Type);
     assertEq(ArrayType.prototype.__proto__, Type.prototype);
     assertEq(typeof ArrayType.prototype.repeat === "function", true);
   
     assertEq(ArrayType.prototype.prototype.__proto__, Data.prototype);
   
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/BinaryData/numerictypes.js
@@ -0,0 +1,184 @@
+// |reftest| skip-if(!this.hasOwnProperty("Type"))
+var BUGNUMBER = 578700;
+var summary = 'BinaryData numeric types';
+var actual = '';
+var expect = '';
+
+function runTests()
+{
+    printBugNumber(BUGNUMBER);
+    printStatus(summary);
+
+    var TestPassCount = 0;
+    var TestFailCount = 0;
+    var TestTodoCount = 0;
+
+    var TODO = 1;
+
+    function check(fun, todo) {
+        var thrown = null;
+        var success = false;
+        try {
+            success = fun();
+        } catch (x) {
+            thrown = x;
+        }
+
+        if (thrown)
+            success = false;
+
+        if (todo) {
+            TestTodoCount++;
+
+            if (success) {
+                var ex = new Error;
+                print ("=== TODO but PASSED? ===");
+                print (ex.stack);
+                print ("========================");
+            }
+
+            return;
+        }
+
+        if (success) {
+            TestPassCount++;
+        } else {
+            TestFailCount++;
+
+            var ex = new Error;
+            print ("=== FAILED ===");
+            print (ex.stack);
+            if (thrown) {
+                print ("    threw exception:");
+                print (thrown);
+            }
+            print ("==============");
+        }
+    }
+
+    function checkThrows(fun, todo) {
+        var thrown = false;
+        try {
+            fun();
+        } catch (x) {
+            thrown = true;
+        }
+
+        check(function() thrown, todo);
+    }
+
+    var types = [uint8, uint16, uint32, uint64, int8, int16, int32, int64];
+    var strings = ["uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64"];
+    for (var i = 0; i < types.length; i++) {
+        var type = types[i];
+
+        check(function() type(true) === 1);
+        check(function() type(false) === 0);
+        check(function() type(+Infinity) === 0);
+        check(function() type(-Infinity) === 0);
+        check(function() type(NaN) === 0);
+        check(function() type.toString() === strings[i]);
+        check(function() type(null) == 0);
+        check(function() type(undefined) == 0);
+        check(function() type([]) == 0);
+        check(function() type({}) == 0);
+        check(function() type(/abcd/) == 0);
+
+        checkThrows(function() new type());
+    }
+
+    var floatTypes = [float32, float64];
+    var floatStrings = ["float32", "float64"];
+    for (var i = 0; i < floatTypes.length; i++) {
+        var type = floatTypes[i];
+
+        check(function() type(true) === 1);
+        check(function() type(false) === 0);
+        check(function() type(+Infinity) === Infinity);
+        check(function() type(-Infinity) === -Infinity);
+        check(function() Number.isNaN(type(NaN)));
+        check(function() type.toString() === floatStrings[i]);
+        check(function() type(null) == 0);
+        check(function() Number.isNaN(type(undefined)));
+        check(function() Number.isNaN(type([])));
+        check(function() Number.isNaN(type({})));
+        check(function() Number.isNaN(type(/abcd/)));
+
+        checkThrows(function() new type());
+    }
+
+    ///// test ranges and creation
+    /// uint8
+    // valid
+    check(function() uint8(0) == 0);
+    check(function() uint8(-0) == 0);
+    check(function() uint8(129) == 129);
+    check(function() uint8(255) == 255);
+
+    if (typeof ctypes != "undefined") {
+        check(function() uint8(ctypes.Uint64(99)) == 99);
+        check(function() uint8(ctypes.Int64(99)) == 99);
+    }
+
+    // overflow is allowed for explicit conversions
+    check(function() uint8(-1) == 255);
+    check(function() uint8(-255) == 1);
+    check(function() uint8(256) == 0);
+    check(function() uint8(2345678) == 206);
+    check(function() uint8(3.14) == 3);
+    check(function() uint8(342.56) == 86);
+    check(function() uint8(-342.56) == 170);
+
+    if (typeof ctypes != "undefined") {
+        checkThrows(function() uint8(ctypes.Uint64("18446744073709551615")) == 255);
+        checkThrows(function() uint8(ctypes.Int64("0xcafebabe")) == 190);
+    }
+
+    // strings
+    check(function() uint8("0") == 0);
+    check(function() uint8("255") == 255);
+    check(function() uint8("256") == 0);
+    check(function() uint8("0x0f") == 15);
+    check(function() uint8("0x00") == 0);
+    check(function() uint8("0xff") == 255);
+    check(function() uint8("0x1ff") == 255);
+    // in JS, string literals with leading zeroes are interpreted as decimal
+    check(function() uint8("-0777") == 247);
+    check(function() uint8("-0xff") == 0);
+
+    /// uint16
+    // valid
+    check(function() uint16(65535) == 65535);
+
+    if (typeof ctypes != "undefined") {
+        check(function() uint16(ctypes.Uint64("0xb00")) == 2816);
+        check(function() uint16(ctypes.Int64("0xb00")) == 2816);
+    }
+
+    // overflow is allowed for explicit conversions
+    check(function() uint16(-1) == 65535);
+    check(function() uint16(-65535) == 1);
+    check(function() uint16(-65536) == 0);
+    check(function() uint16(65536) == 0);
+
+    if (typeof ctypes != "undefined") {
+        check(function() uint16(ctypes.Uint64("18446744073709551615")) == 65535);
+        check(function() uint16(ctypes.Int64("0xcafebabe")) == 47806);
+    }
+
+    // strings
+    check(function() uint16("0x1234") == 0x1234);
+    check(function() uint16("0x00") == 0);
+    check(function() uint16("0xffff") == 65535);
+    check(function() uint16("-0xffff") == 0);
+    check(function() uint16("0xffffff") == 0xffff);
+
+    // wrong types
+    check(function() uint16(3.14) == 3); // c-like casts in explicit conversion
+
+    print("done");
+
+    reportCompare(0, TestFailCount, "BinaryData numeric type tests");
+}
+
+runTests();
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -15,16 +15,17 @@
 #define FOR_EACH_COMMON_PROPERTYNAME(macro) \
     macro(anonymous, anonymous, "anonymous") \
     macro(apply, apply, "apply") \
     macro(arguments, arguments, "arguments") \
     macro(buffer, buffer, "buffer") \
     macro(builder, builder, "builder") \
     macro(byteLength, byteLength, "byteLength") \
     macro(byteOffset, byteOffset, "byteOffset") \
+    macro(bytes, bytes, "bytes") \
     macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
     macro(call, call, "call") \
     macro(callee, callee, "callee") \
     macro(caller, caller, "caller") \
     macro(callFunction, callFunction, "callFunction") \
     macro(caseFirst, caseFirst, "caseFirst") \
     macro(classPrototype, classPrototype, "prototype") \
     macro(Collator, Collator, "Collator") \
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1326,16 +1326,41 @@ js::ClampDoubleToUint8(const double x)
          * want.
          */
         return (y & ~1);
     }
 
     return y;
 }
 
+bool
+js::ToDoubleForTypedArray(JSContext *cx, JS::HandleValue vp, double *d)
+{
+    if (vp.isDouble()) {
+        *d = vp.toDouble();
+    } else if (vp.isNull()) {
+        *d = 0.0;
+    } else if (vp.isPrimitive()) {
+        JS_ASSERT(vp.isString() || vp.isUndefined() || vp.isBoolean());
+        if (vp.isString()) {
+            if (!ToNumber(cx, vp, d))
+                return false;
+        } else if (vp.isUndefined()) {
+            *d = js_NaN;
+        } else {
+            *d = double(vp.toBoolean());
+        }
+    } else {
+        // non-primitive assignments become NaN or 0 (for float/int arrays)
+        *d = js_NaN;
+    }
+
+    return true;
+}
+
 /*
  * This method is used to trace TypedArrayObjects and DataViewObjects. We need
  * a custom tracer because some of an ArrayBufferViewObject's reserved slots
  * are weak references, and some need to be updated specially during moving
  * GCs.
  */
 /* static */ void
 ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
@@ -1497,54 +1522,29 @@ class TypedArrayObjectTemplate : public 
             vp.setUndefined();
             return true;
         }
 
         return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present);
     }
 
     static bool
-    toDoubleForTypedArray(JSContext *cx, HandleValue vp, double *d)
-    {
-        if (vp.isDouble()) {
-            *d = vp.toDouble();
-        } else if (vp.isNull()) {
-            *d = 0.0;
-        } else if (vp.isPrimitive()) {
-            JS_ASSERT(vp.isString() || vp.isUndefined() || vp.isBoolean());
-            if (vp.isString()) {
-                if (!ToNumber(cx, vp, d))
-                    return false;
-            } else if (vp.isUndefined()) {
-                *d = js_NaN;
-            } else {
-                *d = double(vp.toBoolean());
-            }
-        } else {
-            // non-primitive assignments become NaN or 0 (for float/int arrays)
-            *d = js_NaN;
-        }
-
-        return true;
-    }
-
-    static bool
     setElementTail(JSContext *cx, HandleObject tarray, uint32_t index,
                    MutableHandleValue vp, JSBool strict)
     {
         JS_ASSERT(tarray);
         JS_ASSERT(index < tarray->as<TypedArrayObject>().length());
 
         if (vp.isInt32()) {
             setIndex(tarray, index, NativeType(vp.toInt32()));
             return true;
         }
 
         double d;
-        if (!toDoubleForTypedArray(cx, vp, &d))
+        if (!ToDoubleForTypedArray(cx, vp, &d))
             return false;
 
         // If the array is an integer array, we only handle up to
         // 32-bit ints from this point on.  if we want to handle
         // 64-bit ints, we'll need some changes.
 
         // Assign based on characteristics of the destination type
         if (ArrayTypeIsFloatingPoint()) {
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -585,16 +585,18 @@ ClampIntForUint8Array(int32_t x)
 {
     if (x < 0)
         return 0;
     if (x > 255)
         return 255;
     return x;
 }
 
+bool ToDoubleForTypedArray(JSContext *cx, JS::HandleValue vp, double *d);
+
 } // namespace js
 
 template <>
 inline bool
 JSObject::is<js::TypedArrayObject>() const
 {
     return js::IsTypedArrayClass(getClass());
 }