mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Bug 578700 - Numeric types implementation. r=nmatsakis
--HG-- extra : amend_source : 16bd14404c2e30589101f5b965c016b7304b7773
This commit is contained in:
parent
44bc6b526e
commit
9fe0a85392
@ -6,6 +6,8 @@
|
||||
|
||||
#include "builtin/BinaryData.h"
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include "jscompartment.h"
|
||||
#include "jsobj.h"
|
||||
|
||||
@ -13,6 +15,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
@ -26,29 +29,179 @@ 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)
|
||||
{
|
||||
return false;
|
||||
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);
|
||||
}
|
||||
|
||||
JSBool createArrayType(JSContext *cx, unsigned argc, jsval *vp)
|
||||
static void
|
||||
ReportTypeError(JSContext *cx, Value fromValue, JSString *toType)
|
||||
{
|
||||
return false;
|
||||
const char *fnName = JS_EncodeString(cx, toType);
|
||||
ReportTypeError(cx, fromValue, fnName);
|
||||
JS_free(cx, (void *) fnName);
|
||||
}
|
||||
|
||||
JSBool createStructType(JSContext *cx, unsigned argc, jsval *vp)
|
||||
static inline bool
|
||||
IsNumericType(JSObject *type)
|
||||
{
|
||||
return false;
|
||||
return type && &NumericTypeClasses[NUMERICTYPE_UINT8] <= type->getClass() &&
|
||||
type->getClass() <= &NumericTypeClasses[NUMERICTYPE_FLOAT64];
|
||||
}
|
||||
|
||||
JSBool DataInstanceUpdate(JSContext *cx, unsigned argc, jsval *vp)
|
||||
template <typename Domain, typename Input>
|
||||
bool
|
||||
InRange(Input x)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
NumericType<T>::convert(JSContext *cx, HandleValue val, T* converted)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -57,12 +210,17 @@ 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;
|
||||
|
||||
@ -72,7 +230,8 @@ GlobalObject::initDataObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
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));
|
||||
@ -87,14 +246,17 @@ GlobalObject::initTypeObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
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));
|
||||
@ -102,7 +264,8 @@ GlobalObject::initTypeObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
}
|
||||
|
||||
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));
|
||||
@ -118,7 +281,8 @@ SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject *> global, HandleObject
|
||||
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());
|
||||
@ -134,9 +298,11 @@ SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject *> global, HandleObject
|
||||
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))
|
||||
@ -148,9 +314,9 @@ SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject *> global, HandleObject
|
||||
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;
|
||||
|
||||
@ -159,13 +325,17 @@ InitComplexClasses(JSContext *cx, Handle<GlobalObject *> global)
|
||||
|
||||
// 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;
|
||||
|
||||
@ -181,16 +351,27 @@ 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
|
||||
|
@ -17,6 +17,34 @@ 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),
|
||||
@ -41,22 +69,57 @@ static Class TypeClass = {
|
||||
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 */\
|
||||
@ -64,10 +127,18 @@ static Class type_##BlockClass = {\
|
||||
JS_StrictPropertyStub, /* setProperty */\
|
||||
JS_EnumerateStub,\
|
||||
JS_ResolveStub,\
|
||||
JS_ConvertStub\
|
||||
};
|
||||
JS_ConvertStub,\
|
||||
NULL,\
|
||||
NULL,\
|
||||
NumericType<type_##_t>::call,\
|
||||
NULL,\
|
||||
NULL,\
|
||||
NULL\
|
||||
},
|
||||
|
||||
BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_CLASSES)
|
||||
static Class NumericTypeClasses[NUMERICTYPES] = {
|
||||
BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_CLASSES)
|
||||
};
|
||||
|
||||
static Class ArrayTypeClass = {
|
||||
"ArrayType",
|
||||
|
@ -1914,8 +1914,8 @@ static const JSStdName standard_class_names[] = {
|
||||
#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)},
|
||||
|
@ -14,6 +14,17 @@ function assertNotEq(a, b) {
|
||||
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);
|
||||
|
||||
@ -31,6 +42,7 @@ function runTests() {
|
||||
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);
|
||||
|
184
js/src/tests/ecma_6/BinaryData/numerictypes.js
Normal file
184
js/src/tests/ecma_6/BinaryData/numerictypes.js
Normal file
@ -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();
|
@ -20,6 +20,7 @@
|
||||
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") \
|
||||
|
@ -1331,6 +1331,31 @@ js::ClampDoubleToUint8(const double x)
|
||||
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
|
||||
@ -1501,31 +1526,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
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)
|
||||
@ -1539,7 +1539,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -590,6 +590,8 @@ ClampIntForUint8Array(int32_t x)
|
||||
return x;
|
||||
}
|
||||
|
||||
bool ToDoubleForTypedArray(JSContext *cx, JS::HandleValue vp, double *d);
|
||||
|
||||
} // namespace js
|
||||
|
||||
template <>
|
||||
|
Loading…
Reference in New Issue
Block a user