# HG changeset patch # Parent a354cc019f074faa85f0db9d1b0e60ad064fab33 # User Nikhil Marathe Bug 578700 - Numeric Type implementation. diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1783,18 +1783,18 @@ static const JSStdName standard_class_at #endif {js_InitProxyClass, EAGER_CLASS_ATOM(Proxy), &js::ObjectProxyClass}, #if ENABLE_INTL_API {js_InitIntlClass, EAGER_ATOM_AND_CLASP(Intl)}, #endif #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} }; diff --git a/js/src/builtin/BinaryData.cpp b/js/src/builtin/BinaryData.cpp --- a/js/src/builtin/BinaryData.cpp +++ b/js/src/builtin/BinaryData.cpp @@ -1,16 +1,18 @@ /* -*- 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" @@ -21,181 +23,391 @@ JSBool TypeThrowError(JSContext *cx, uns 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 +bool +InRange(Input x) +{ + return std::numeric_limits::min() <= x && + x <= std::numeric_limits::max(); +} + +template <> +bool +InRange(int x) +{ + return -std::numeric_limits::max() <= x && + x <= std::numeric_limits::max(); +} + +template <> +bool +InRange(int x) +{ + return -std::numeric_limits::max() <= x && + x <= std::numeric_limits::max(); +} + +template <> +bool +InRange(double x) +{ + return -std::numeric_limits::max() <= x && + x <= std::numeric_limits::max(); +} + +template <> +bool +InRange(double x) +{ + return -std::numeric_limits::max() <= x && + x <= std::numeric_limits::max(); +} + +template +Class * +js::NumericType::typeToClass() +{ + JS_ASSERT(0); + return NULL; +} + +#define BINARYDATA_TYPE_TO_CLASS(constant_, type_)\ + template <>\ + Class *\ + NumericType::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 +bool +NumericType::convert(JSContext *cx, HandleValue val, T* converted) +{ + if (val.isBoolean()) { + *converted = val.toBoolean() ? 1 : 0; + return true; + } + + if (val.isNumber()) { + if (val.isInt32()) { + int num = val.toInt32(); + *converted = T(num); + } else { + double num = val.toDouble(); + if (mozilla::IsInfinite(num) || mozilla::IsNaN(num)) { + *converted = 0; + } else { + *converted = T(num); + } + } + return true; + } + + Class *typeClass = typeToClass(); + ReportTypeError(cx, val, typeClass->name); return false; } -JSBool createArrayType(JSContext *cx, unsigned argc, jsval *vp) +template +bool +NumericType::cast(JSContext *cx, HandleValue val, T *casted) { + if (convert(cx, val, casted)) { + return true; + } else { + // Clear the exception since we want to try more things. + JS_ASSERT(cx->isExceptionPending()); + cx->clearPendingException(); + } + + if (val.isString()) { + // always returns true in this case, so no check + double d; + JS_ValueToNumber(cx, val, &d); + + if (!mozilla::IsNaN(d)) { + // [[CCast]] + *casted = (T) (d); + return true; + } + + // If the string is non-numeric, execution continues to the type error + // below. + } + + Class *typeClass = typeToClass(); + ReportTypeError(cx, val, typeClass->name); return false; } -JSBool createStructType(JSContext *cx, unsigned argc, jsval *vp) +template +JSBool +NumericType::call(JSContext *cx, unsigned argc, Value *vp) { - return false; + CallArgs args = CallArgsFromVp(argc, vp); + if (args.length() < 1) { + char *fnName = JS_EncodeString(cx, args.callee().as().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 (!cast(cx, arg, &answer)) + return false; // cast() 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; } -JSBool DataInstanceUpdate(JSContext *cx, unsigned argc, jsval *vp) +template +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 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 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 global, HandleObject complexObject) +SetupComplexHeirarchy(JSContext *cx, Handle 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 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()); Rooted global(cx, &obj->as()); -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, 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; } diff --git a/js/src/builtin/BinaryData.h b/js/src/builtin/BinaryData.h --- 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,88 @@ static Class TypeClass = { JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; +template +class NumericType +{ + private: + static bool cast(JSContext *cx, HandleValue val, T *casted); + 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 +JS_ALWAYS_INLINE +bool NumericType::reify(JSContext *cx, void *mem, MutableHandleValue vp) +{ + vp.setInt32(* ((T*)mem) ); + return true; +} + +template <> +JS_ALWAYS_INLINE +bool NumericType::reify(JSContext *cx, void *mem, MutableHandleValue vp) +{ + vp.setNumber(* ((float32_t*)mem) ); + return true; +} + +template <> +JS_ALWAYS_INLINE +bool NumericType::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::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, diff --git a/js/src/tests/ecma_6/BinaryData/architecture.js b/js/src/tests/ecma_6/BinaryData/architecture.js --- a/js/src/tests/ecma_6/BinaryData/architecture.js +++ b/js/src/tests/ecma_6/BinaryData/architecture.js @@ -8,16 +8,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); @@ -25,16 +36,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); diff --git a/js/src/tests/ecma_6/BinaryData/numerictypes.js b/js/src/tests/ecma_6/BinaryData/numerictypes.js new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/BinaryData/numerictypes.js @@ -0,0 +1,170 @@ +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, float32, float64]; + var strings = ["uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "float32", "float64"]; + 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]); + + checkThrows(function() new type()); + checkThrows(function() type(null)); + checkThrows(function() type(undefined)); + checkThrows(function() type([])); + checkThrows(function() type({})); + checkThrows(function() type(/abcd/)); + } + + ///// 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); + checkThrows(function() uint8("-0xff") == 1); + + /// 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); + checkThrows(function() uint16("-0xffff") == 1); // FIXME + check(function() uint16("0xffffff") == 0xffff); + + // wrong types + check(function() uint16(3.14) == 3); // c-like casts in explicit conversion + + checkThrows(function() uint16([1, 2, 3])); + checkThrows(function() uint16({})); + checkThrows(function() uint16("not a number")); + + print("done"); + + reportCompare(0, TestFailCount, "BinaryData numeric type tests"); +} + +if (getBuildConfiguration()['binary-data']) + runTests(); +else + reportCompare(true, true); diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h --- 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") \