Bug 578700 - Numeric types implementation. r=nmatsakis

--HG--
extra : amend_source : 16bd14404c2e30589101f5b965c016b7304b7773
This commit is contained in:
Nikhil Marathe 2013-07-25 17:58:50 -07:00
parent 84314cdddb
commit cf4fae0864
8 changed files with 525 additions and 74 deletions

View File

@ -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

View File

@ -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",

View File

@ -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)},

View File

@ -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);

View 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();

View File

@ -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") \

View File

@ -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

View File

@ -590,6 +590,8 @@ ClampIntForUint8Array(int32_t x)
return x;
}
bool ToDoubleForTypedArray(JSContext *cx, JS::HandleValue vp, double *d);
} // namespace js
template <>