-- v3: jscript: Implement 'set' for Typed Arrays. jscript: Implement 'subarray' for Typed Arrays. jscript: Implement Typed Array construction from objects. jscript: Implement ArrayBuffer.isView. jscript: Implement Typed Array construction on ArrayBuffers. jscript: Add initial implementation of Typed Arrays.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 273 ++++++++++++++++++++++++++++-- dlls/jscript/error.c | 3 + dlls/jscript/jscript.h | 4 + dlls/jscript/jscript.rc | 3 + dlls/jscript/jsutils.c | 2 +- dlls/jscript/resource.h | 3 + dlls/mshtml/tests/documentmode.js | 2 +- dlls/mshtml/tests/es5.js | 172 ++++++++++++++++++- 8 files changed, 445 insertions(+), 17 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 82df57243eb..847cabe92b6 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -39,6 +39,14 @@ typedef struct { DWORD size; } DataViewInstance;
+typedef struct { + jsdisp_t dispex; + + ArrayBufferInstance *buffer; + DWORD offset; + DWORD length; +} TypedArrayInstance; + static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex); @@ -49,6 +57,11 @@ static inline DataViewInstance *dataview_from_jsdisp(jsdisp_t *jsdisp) return CONTAINING_RECORD(jsdisp, DataViewInstance, dispex); }
+static inline TypedArrayInstance *typedarr_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, TypedArrayInstance, dispex); +} + static inline ArrayBufferInstance *arraybuf_this(jsval_t vthis) { jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; @@ -701,28 +714,213 @@ ALL_TYPED_ARRAYS #undef X };
+struct typed_array_desc { + unsigned size; + double (*get)(const void*); + void (*set)(void*,double); +}; + +static double get_s8(const void *p) { return *(const INT8 *)p; } +static double get_u8(const void *p) { return *(const UINT8 *)p; } +static void set_u8(void *p, double v) { *(UINT8 *)p = double_to_int32(v); } +static double get_s16(const void *p) { return *(const INT16 *)p; } +static double get_u16(const void *p) { return *(const UINT16 *)p; } +static void set_u16(void *p, double v) { *(UINT16 *)p = double_to_int32(v); } +static double get_s32(const void *p) { return *(const INT32 *)p; } +static double get_u32(const void *p) { return *(const UINT32 *)p; } +static void set_u32(void *p, double v) { *(UINT32 *)p = double_to_int32(v); } +static double get_f32(const void *p) { return *(const float *)p; } +static void set_f32(void *p, double v) { *(float *)p = v; } +static double get_f64(const void *p) { return *(const double *)p; } +static void set_f64(void *p, double v) { *(double *)p = v; } + +static const struct typed_array_desc typed_array_descs[NUM_TYPEDARRAY_TYPES] = { + [Int8Array_desc_idx] = { 1, get_s8, set_u8 }, + [Int16Array_desc_idx] = { 2, get_s16, set_u16 }, + [Int32Array_desc_idx] = { 4, get_s32, set_u32 }, + [Uint8Array_desc_idx] = { 1, get_u8, set_u8 }, + [Uint16Array_desc_idx] = { 2, get_u16, set_u16 }, + [Uint32Array_desc_idx] = { 4, get_u32, set_u32 }, + [Float32Array_desc_idx] = { 4, get_f32, set_f32 }, + [Float64Array_desc_idx] = { 8, get_f64, set_f64 } +}; + static HRESULT TypedArray_get_buffer(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { - FIXME("%p\n", jsthis); - return E_NOTIMPL; + TRACE("%p\n", jsthis); + + *r = jsval_obj(jsdisp_addref(&typedarr_from_jsdisp(jsthis)->buffer->dispex)); + return S_OK; }
static HRESULT TypedArray_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { - FIXME("%p\n", jsthis); - return E_NOTIMPL; + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length * typed_array_descs[jsthis->builtin_info->class - FIRST_TYPEDARRAY_JSCLASS].size); + return S_OK; }
static HRESULT TypedArray_get_byteOffset(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { - FIXME("%p\n", jsthis); - return E_NOTIMPL; + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->offset); + return S_OK; }
static HRESULT TypedArray_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { - FIXME("%p\n", jsthis); - return E_NOTIMPL; + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length); + return S_OK; +} + +static void TypedArray_destructor(jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + if(typedarr->buffer) + jsdisp_release(&typedarr->buffer->dispex); +} + +static HRESULT TypedArray_lookup_prop(jsdisp_t *dispex, const WCHAR *name, unsigned flags, struct property_info *desc) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + + /* Typed Arrays override every positive index */ + return jsdisp_index_lookup(&typedarr->dispex, name, INT_MAX, desc); +} + +static inline HRESULT TypedArray_prop_get(unsigned desc_idx, jsdisp_t *dispex, unsigned idx, jsval_t *r) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + + if(idx >= typedarr->length) + *r = jsval_undefined(); + else + *r = jsval_number(typed_array_descs[desc_idx].get(&typedarr->buffer->buf[typedarr->offset + idx * typed_array_descs[desc_idx].size])); + return S_OK; +} + +static inline HRESULT TypedArray_prop_put(unsigned desc_idx, jsdisp_t *dispex, unsigned idx, jsval_t val) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + HRESULT hres; + double n; + + if(idx >= typedarr->length) + return S_OK; + + hres = to_number(typedarr->dispex.ctx, val, &n); + if(SUCCEEDED(hres)) + typed_array_descs[desc_idx].set(&typedarr->buffer->buf[typedarr->offset + idx * typed_array_descs[desc_idx].size], n); + return hres; +} + +static HRESULT TypedArray_fill_props(jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + + return jsdisp_fill_indices(&typedarr->dispex, typedarr->length); +} + +static HRESULT TypedArray_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + return typedarr->buffer ? gc_process_linked_obj(gc_ctx, op, dispex, &typedarr->buffer->dispex, (void**)&typedarr->buffer) : S_OK; +} + +static const builtin_prop_t TypedArrayInst_props[] = { + {L"buffer", NULL, 0, TypedArray_get_buffer}, + {L"byteLength", NULL, 0, TypedArray_get_byteLength}, + {L"byteOffset", NULL, 0, TypedArray_get_byteOffset}, + {L"length", NULL, 0, TypedArray_get_length}, +}; + +static HRESULT create_typedarr(const builtin_info_t *info, script_ctx_t *ctx, ArrayBufferInstance *buffer, + DWORD offset, DWORD length, jsdisp_t **ret) +{ + TypedArrayInstance *typedarr; + HRESULT hres; + + if(!(typedarr = calloc(1, sizeof(TypedArrayInstance)))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&typedarr->dispex, ctx, info, ctx->typedarr_constr[info->class - FIRST_TYPEDARRAY_JSCLASS]); + if(FAILED(hres)) { + free(typedarr); + return hres; + } + + jsdisp_addref(&buffer->dispex); + typedarr->buffer = buffer; + typedarr->offset = offset; + typedarr->length = length; + + *ret = &typedarr->dispex; + return S_OK; +} + +static HRESULT TypedArrayConstr_value(const builtin_info_t *info, script_ctx_t *ctx, jsval_t vthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + const unsigned desc_idx = info->class - FIRST_TYPEDARRAY_JSCLASS; + const unsigned elem_size = typed_array_descs[desc_idx].size; + ArrayBufferInstance *buffer = NULL; + DWORD offset = 0, length = 0; + jsdisp_t *typedarr; + HRESULT hres; + double n; + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(argc) { + if(is_object_instance(argv[0])) { + jsdisp_t *obj = to_jsdisp(get_object(argv[0])); + + if(!obj) + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + + FIXME("Construction from object not implemented\n"); + return E_NOTIMPL; + }else if(is_number(argv[0])) { + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + if(n * elem_size > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + length = n; + }else + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + } + + if(!r) + return S_OK; + + if(!buffer) { + hres = create_arraybuf(ctx, length * elem_size, &buffer); + if(FAILED(hres)) + return hres; + } + + hres = create_typedarr(info, ctx, buffer, offset, length, &typedarr); + jsdisp_release(&buffer->dispex); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(typedarr); + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; }
#define X(name) \ @@ -738,6 +936,18 @@ static HRESULT name##_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns return E_NOTIMPL; \ } \ \ +static HRESULT name##_prop_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) \ +{ \ + TRACE("%p[%u]\n", dispex, idx); \ + return TypedArray_prop_get(name##_desc_idx, dispex, idx, r); \ +} \ + \ +static HRESULT name##_prop_put(jsdisp_t *dispex, unsigned idx, jsval_t val) \ +{ \ + TRACE("%p[%u] = %s\n", dispex, idx, debugstr_jsval(val)); \ + return TypedArray_prop_put(name##_desc_idx, dispex, idx, val); \ +} \ + \ static const builtin_prop_t name##_props[] = { \ {L"buffer", NULL, 0, TypedArray_get_buffer}, \ {L"byteLength", NULL, 0, TypedArray_get_byteLength}, \ @@ -752,12 +962,30 @@ static const builtin_info_t name##_info = .class = FIRST_TYPEDARRAY_JSCLASS + name ##_desc_idx, \ .props_cnt = ARRAY_SIZE(name##_props), \ .props = name##_props, \ + .destructor = TypedArray_destructor, \ + .lookup_prop = TypedArray_lookup_prop, \ + .prop_get = name##_prop_get, \ + .prop_put = name##_prop_put, \ + .fill_props = TypedArray_fill_props, \ + .gc_traverse = TypedArray_gc_traverse, \ }; \ \ +static const builtin_info_t name##Inst_info = \ +{ \ + .class = FIRST_TYPEDARRAY_JSCLASS + name##_desc_idx, \ + .props_cnt = ARRAY_SIZE(TypedArrayInst_props), \ + .props = TypedArrayInst_props, \ + .destructor = TypedArray_destructor, \ + .lookup_prop = TypedArray_lookup_prop, \ + .prop_get = name##_prop_get, \ + .prop_put = name##_prop_put, \ + .fill_props = TypedArray_fill_props, \ + .gc_traverse = TypedArray_gc_traverse, \ +}; \ static HRESULT name ## Constr_value(script_ctx_t *ctx, jsval_t jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ { \ - FIXME("\n"); \ - return E_NOTIMPL; \ + TRACE("\n"); \ + return TypedArrayConstr_value(&name##Inst_info, ctx, jsthis, flags, argc, argv, r); \ } ALL_TYPED_ARRAYS #undef X @@ -770,15 +998,32 @@ static const builtin_info_t TypedArrayConstr_info = { static HRESULT init_typed_array_constructor(script_ctx_t *ctx, builtin_invoke_t func, const WCHAR *name, const builtin_info_t *info, unsigned int type_idx) { - jsdisp_t *prototype; + TypedArrayInstance *prototype; HRESULT hres;
- hres = create_dispex(ctx, info, ctx->object_prototype, &prototype); + if(!(prototype = calloc(1, sizeof(*prototype)))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, 0, &prototype->buffer); + if(FAILED(hres)) { + free(prototype); + return hres; + } + + hres = init_dispex(&prototype->dispex, ctx, info, ctx->object_prototype); + if(FAILED(hres)) { + jsdisp_release(&prototype->buffer->dispex); + free(prototype); + return hres; + } + + hres = create_builtin_constructor(ctx, func, name, &TypedArrayConstr_info, PROPF_CONSTR|1, &prototype->dispex, &ctx->typedarr_constr[type_idx]); + jsdisp_release(&prototype->dispex); if(FAILED(hres)) return hres;
- hres = create_builtin_constructor(ctx, func, name, &TypedArrayConstr_info, PROPF_CONSTR|1, prototype, &ctx->typedarr_constr[type_idx]); - jsdisp_release(prototype); + hres = jsdisp_define_data_property(ctx->typedarr_constr[type_idx], L"BYTES_PER_ELEMENT", 0, + jsval_number(typed_array_descs[type_idx].size)); if(FAILED(hres)) return hres;
diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 9f22b7feefa..48e9826040c 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -497,6 +497,8 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_OBJECT_NONEXTENSIBLE: case JS_E_NONCONFIGURABLE_REDEFINED: case JS_E_NONWRITABLE_MODIFIED: + case JS_E_TYPEDARRAY_BAD_CTOR_ARG: + case JS_E_NOT_TYPEDARRAY: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_WRONG_THIS: @@ -511,6 +513,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_FRACTION_DIGITS_OUT_OF_RANGE: case JS_E_PRECISION_OUT_OF_RANGE: case JS_E_INVALID_LENGTH: + case JS_E_TYPEDARRAY_INVALID_OFFSLEN: case JS_E_DATAVIEW_INVALID_ACCESS: case JS_E_DATAVIEW_INVALID_OFFSET: constr = ctx->range_error_constr; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 5a8910565b3..db0f2e3d6a7 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -320,6 +320,7 @@ HRESULT to_uint32(script_ctx_t*,jsval_t,UINT32*); HRESULT to_string(script_ctx_t*,jsval_t,jsstr_t**); HRESULT to_flat_string(script_ctx_t*,jsval_t,jsstr_t**,const WCHAR**); HRESULT to_object(script_ctx_t*,jsval_t,IDispatch**); +INT32 double_to_int32(double);
HRESULT jsval_strict_equal(jsval_t,jsval_t,BOOL*);
@@ -578,6 +579,9 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_OBJECT_NONEXTENSIBLE MAKE_JSERROR(IDS_OBJECT_NONEXTENSIBLE) #define JS_E_NONCONFIGURABLE_REDEFINED MAKE_JSERROR(IDS_NONCONFIGURABLE_REDEFINED) #define JS_E_NONWRITABLE_MODIFIED MAKE_JSERROR(IDS_NONWRITABLE_MODIFIED) +#define JS_E_TYPEDARRAY_BAD_CTOR_ARG MAKE_JSERROR(IDS_TYPEDARRAY_BAD_CTOR_ARG) +#define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) +#define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 189f6fe19a3..91bbf09d034 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -79,6 +79,9 @@ STRINGTABLE IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Cannot redefine non-configurable property '|'" IDS_NONWRITABLE_MODIFIED "Cannot modify non-writable property '|'" + IDS_NOT_TYPEDARRAY "'this' is not a typed array object" + IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" + IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index 1d6fa06a993..190c97d08ec 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -676,7 +676,7 @@ HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret) return S_OK; }
-static INT32 double_to_int32(double number) +INT32 double_to_int32(double number) { INT32 exp, result; union { diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 7b37a7ae8ea..0f8e6f2dc7f 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -77,6 +77,9 @@ #define IDS_OBJECT_NONEXTENSIBLE 0x13D5 #define IDS_NONCONFIGURABLE_REDEFINED 0x13D6 #define IDS_NONWRITABLE_MODIFIED 0x13D7 +#define IDS_TYPEDARRAY_BAD_CTOR_ARG 0x13DA +#define IDS_NOT_TYPEDARRAY 0x13DB +#define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index be141928453..dcd8fa77663 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -4566,7 +4566,7 @@ sync_test("typed arrays", function() { "unexpected " + constr + " porototype's prototype " + Object.getPrototypeOf(constr.prototype)); test_own_props(constr, constr, ["BYTES_PER_ELEMENT", "arguments", "caller", "length", "prototype"], - ["BYTES_PER_ELEMENT", "arguments", "caller"]); + ["arguments", "caller"]); test_own_props(constr.prototype, constr + ".prototype", ["BYTES_PER_ELEMENT", "buffer", "byteLength", "byteOffset", "constructor", "length", "set", "subarray"], ["BYTES_PER_ELEMENT"]); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index ef2c80a2c07..c929eaae0fa 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -33,6 +33,9 @@ var JS_E_INVALID_LENGTH = 0x800a13a5; var JS_E_INVALID_WRITABLE_PROP_DESC = 0x800a13ac; var JS_E_NONCONFIGURABLE_REDEFINED = 0x800a13d6; var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7; +var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; +var JS_E_NOT_TYPEDARRAY = 0x800a13db; +var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -1747,7 +1750,7 @@ sync_test("RegExp", function() { });
sync_test("ArrayBuffers & Views", function() { - var i, r, buf, buf2, view, view2, arr; + var i, r, buf, buf2, view, view2, arr, arr2;
var types = [ [ "Int8", 1 ], @@ -2090,6 +2093,173 @@ sync_test("ArrayBuffers & Views", function() { ok(r === undefined, "buf.slice(-9) view(1).setFloat64(0, 11.875) returned " + r); r = view2.getFloat64(0); ok(r === 11.875, "buf.slice(-9) view(1).getFloat64(0) returned " + r); + + for(i = 0; i < types.length; i++) { + var name = types[i][0] + "Array", arrType = window[name], typeSz = types[i][1]; + + arr = arrType; + test_own_data_prop_desc(arr, "BYTES_PER_ELEMENT", false, false, false); + ok(arr.BYTES_PER_ELEMENT === typeSz, name + ".BYTES_PER_ELEMENT = " + arr.BYTES_PER_ELEMENT); + r = arr.length; + ok(r === 1, name + ".length = " + r); + r = arr.prototype.set.length; + ok(r === 2, name + ".prototype.set.length = " + r); + r = arr.prototype.subarray.length; + ok(r === 2, name + ".prototype.subarray.length = " + r); + + r = Object.getPrototypeOf(arrType); + ok(r === Function.prototype, name + "'s prototype is not Function.prototype: " + r); + r = Object.getPrototypeOf(arrType.prototype); + ok(r === Object.prototype, name + ".prototype's prototype is not Object.prototype: " + r); + r = Object.prototype.toString.call(new arrType(3)); + ok(r === "[object " + name + "]", "Object toString(new " + name + "(3)) = " + r); + r = arrType.prototype; + test_own_data_prop_desc(r, "byteLength", false, false, false); + test_own_data_prop_desc(r, "byteOffset", false, false, false); + test_own_data_prop_desc(r, "length", false, false, false); + test_own_data_prop_desc(r, "buffer", false, false, false); + + try { + new arrType(-1); + ok(false, "new " + name + "(-1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(-1) threw " + n); + } + try { + new arrType('9'); + ok(false, "new " + name + "('9') did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + name + "('9') threw " + n); + } + try { + new arrType(null); + ok(false, "new " + name + "(null) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + name + "(null) threw " + n); + } + + arr = new arrType(); + ok(arr.byteLength === 0, name + "().byteLength = " + arr.byteLength); + ok(arr.byteOffset === 0, name + "().byteOffset = " + arr.byteOffset); + ok(arr.length === 0, name + "().length = " + arr.length); + ok(arr.buffer.byteLength === 0, name + "().buffer.byteLength = " + arr.buffer.byteLength); + test_readonly(arr, "byteLength", 0); + test_readonly(arr, "byteOffset", 0); + test_readonly(arr, "length", 0); + test_own_data_prop_desc(arr, "byteLength", false, false, false); + test_own_data_prop_desc(arr, "byteOffset", false, false, false); + test_own_data_prop_desc(arr, "length", false, false, false); + test_own_data_prop_desc(arr, "buffer", false, false, false); + + Object.freeze(arr); + ok(Object.isFrozen(arr) === true, name + "() not frozen"); + + arr = arrType(9.1); + ok(arr.byteLength === 9 * typeSz, name + "(9.1).byteLength = " + arr.byteLength); + ok(arr.byteOffset === 0, name + "(9.1).byteOffset = " + arr.byteOffset); + ok(arr.length === 9, name + "(9.1).length = " + arr.length); + ok(arr.buffer.byteLength === arr.byteLength, name + "(9.1).buffer.byteLength = " + arr.buffer.byteLength); + for(var j = 0; j < 9; j++) + ok(arr[j] === 0, "arr[" + j + "] = " + arr[j]); + arr[5] = 42; + ok(arr[5] === 42, name + "(9.1)[5] = " + arr[5]); + arr[9] = 50; + ok(arr[9] === undefined, name + "(9.1)[9] = " + arr[9]); + + arrType.prototype[6] = "foo"; + r = arrType.prototype[6]; + ok(r === undefined, name + ".prototype[6] = " + r); + ok(arr[6] === 0, name + "(9.1)[6] after set in prototype = " + arr[6]); + arr[6] = 0; + ok(arr.hasOwnProperty("6"), "'6' not a property of " + name + "(9.1)[6]"); + test_own_data_prop_desc(arr, "6", true, true, false); + r = (delete arr[6]); + ok(r === false, "delete " + name + "(9.1)[6] returned " + r); + try { + Object.defineProperty(arr, "6", {writable: false, enumerable: false, configurable: true, value: 10}); + ok(false, "redefining " + name + "(9.1)[6] with different flags did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NONCONFIGURABLE_REDEFINED, "redefining " + name + "(9.1)[6] with different flags threw " + n); + } + Object.defineProperty(arr, "6", {writable: true, enumerable: true, configurable: false, value: 10}); + ok(arr[6] === 10, name + "(9.1)[6] after definition = " + arr[6]); + Object.defineProperty(arr, "6", {writable: true, enumerable: true, configurable: false, value: "foo"}); + if(name.substr(0, 5) === "Float") + todo_wine. + ok(arr[6] !== arr[6] /* NaN */, name + "(9.1)[6] after definition to string = " + arr[6]); + else + todo_wine. + ok(arr[6] === 0, name + "(9.1)[6] after definition to string = " + arr[6]); + + arrType.prototype[100] = "foobar"; + r = arrType.prototype[100]; + ok(r === undefined, name + ".prototype[100] = " + r); + ok(arr[100] === undefined, name + "(9.1)[100] after set in prototype = " + arr[100]); + arr[100] = 0; + ok(arr[100] === undefined, name + "(9.1)[100] after set to zero = " + arr[100]); + todo_wine. + ok(!arr.hasOwnProperty("100"), "'100' is a property of " + name + "(9.1)[100]"); + r = (delete arr[100]); + ok(r === false, "delete " + name + "(9.1)[100] returned " + r); + try { + Object.defineProperty(arr, "100", {writable: false, enumerable: false, configurable: true, value: 10}); + ok(false, "redefining " + name + "(9.1)[100] with different flags did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NONCONFIGURABLE_REDEFINED, "redefining " + name + "(9.1)[100] with different flags threw " + n); + } + Object.defineProperty(arr, "100", {writable: true, enumerable: true, configurable: false, value: 10}); + todo_wine. + ok(arr[100] === undefined, name + "(9.1)[100] after defined to 10 = " + arr[100]); + todo_wine. + ok(!arr.hasOwnProperty("100"), "'100' is a property of " + name + "(9.1)[100] after definition"); + todo_wine. + ok(arr[100] === undefined, name + "(9.1)[100] after definition = " + arr[100]); + + r = 0; + for(var idx in arr) { + todo_wine_if(r == 10). + ok(idx === ""+r, name + "(9.1) enum idx " + r + " = " + idx); + r++; + } + todo_wine. + ok(r === 9, name + "(9.1) enum did " + r + " iterations"); + + arrType.prototype[-1] = "barfoo"; + r = arrType.prototype[-1]; + ok(r === "barfoo", name + ".prototype[-1] = " + r); + ok(arr[-1] === "barfoo", name + "(9.1)[-1] after set in prototype = " + arr[-1]); + + arrType.prototype.foo = "bar"; + r = arrType.prototype.foo; + ok(r === "bar", name + ".prototype.foo = " + r); + ok(arr.foo === "bar", name + "(9.1).foo after set in prototype = " + arr.foo); + Object.freeze(arr); + todo_wine. + ok(Object.isFrozen(arr) === true, name + "(9.1) not frozen"); + arr = arrType.prototype; + delete arr[-1]; + delete arr.foo; + } + + arr = new Int16Array(2); + arr[0] = 65535; + arr[1] = -65535; + ok(arr[0] == -1, "16-bit arr[0] after overflow = " + arr[0]); + ok(arr[1] == 1, "16-bit arr[1] after overflow = " + arr[1]); + + arr = new Uint8Array(2); + arr[0] = -2; + arr[1] = 258; + ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]); + ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]); + + arr = new Int8Array(); + arr2 = new Int32Array(); });
sync_test("builtin_context", function() {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 34 +++++++++++++++++++++-- dlls/mshtml/tests/es5.js | 58 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 847cabe92b6..2832d5fdad3 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -883,8 +883,38 @@ static HRESULT TypedArrayConstr_value(const builtin_info_t *info, script_ctx_t * if(!obj) return JS_E_TYPEDARRAY_BAD_CTOR_ARG;
- FIXME("Construction from object not implemented\n"); - return E_NOTIMPL; + if(obj->builtin_info->class == JSCLASS_ARRAYBUFFER) { + buffer = arraybuf_from_jsdisp(obj); + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0 || n > buffer->size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + offset = n; + if(offset % elem_size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + } + if(argc > 2 && !is_undefined(argv[2])) { + hres = to_integer(ctx, argv[2], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0 || n > UINT_MAX) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + length = n; + if(offset + length * elem_size > buffer->size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + }else { + length = buffer->size - offset; + if(length % elem_size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + length /= elem_size; + } + jsdisp_addref(&buffer->dispex); + }else { + FIXME("Construction from object not implemented\n"); + return E_NOTIMPL; + } }else if(is_number(argv[0])) { hres = to_integer(ctx, argv[0], &n); if(FAILED(hres)) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index c929eaae0fa..ebbec939cf8 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2119,6 +2119,7 @@ sync_test("ArrayBuffers & Views", function() { test_own_data_prop_desc(r, "length", false, false, false); test_own_data_prop_desc(r, "buffer", false, false, false);
+ buf = ArrayBuffer(34); try { new arrType(-1); ok(false, "new " + name + "(-1) did not throw exception"); @@ -2126,6 +2127,27 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(-1) threw " + n); } + try { + new arrType(buf, -1); + ok(false, "new " + name + "(buf, -1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(buf, -1) threw " + n); + } + try { + new arrType(buf, 36); + ok(false, "new " + name + "(buf, 36) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(buf, 36) threw " + n); + } + try { + new arrType(buf, 32, 4); + ok(false, "new " + name + "(buf, 32, 4) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(buf, 32, 4) threw " + n); + } try { new arrType('9'); ok(false, "new " + name + "('9') did not throw exception"); @@ -2140,6 +2162,26 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + name + "(null) threw " + n); } + if(typeSz > 1) { + /* test misalignment */ + var a = typeSz >>> 1; + try { + new arrType(buf, a, 1); + ok(false, "new " + name + "(buf, " + a + ", 1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(buf, " + a + ", 1) threw " + n); + } + a += typeSz; + var b = new ArrayBuffer(a); + try { + new arrType(b); + ok(false, "new " + name + "(new ArrayBuffer(" + a + ")) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + name + "(new ArrayBuffer(" + a + ")) threw " + n); + } + }
arr = new arrType(); ok(arr.byteLength === 0, name + "().byteLength = " + arr.byteLength); @@ -2244,6 +2286,22 @@ sync_test("ArrayBuffers & Views", function() { arr = arrType.prototype; delete arr[-1]; delete arr.foo; + + arr = arrType(buf, typeSz, 2); + name = name + "(buf, " + typeSz + ", 2)"; + ok(arr.byteLength === 2 * typeSz, name + ".byteLength = " + arr.byteLength); + ok(arr.byteOffset === typeSz, name + ".byteOffset = " + arr.byteOffset); + ok(arr.length === 2, name + ".length = " + arr.length); + ok(arr.buffer === buf, name + ".buffer = " + arr.buffer); + view = DataView(buf); + view["set" + types[i][0]](typeSz, 10, true); + ok(arr[0] === 10, "arr[0] after DataView(buf).set" + types[i][0] + " = " + arr[0]); + arr[0] = 12; + r = view["get" + types[i][0]](typeSz, true); + ok(r === 12, "DataView(buf).get" + types[i][0] + " after arr[0] set = " + r); + Object.freeze(arr); + todo_wine. + ok(Object.isFrozen(arr) === true, name + " not frozen"); }
arr = new Int16Array(2);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 15 +++++++++++++-- dlls/jscript/jscript.h | 2 ++ dlls/mshtml/tests/es5.js | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 2832d5fdad3..716aa3cf93d 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -171,9 +171,20 @@ static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, ArrayBufferInstanc static HRESULT ArrayBufferConstr_isView(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("not implemented\n"); + BOOL ret = FALSE; + jsdisp_t *obj;
- return E_NOTIMPL; + TRACE("\n"); + + if(!r) + return S_OK; + + if(argc && is_object_instance(argv[0]) && (obj = to_jsdisp(get_object(argv[0]))) && + obj->builtin_info->class >= FIRST_VIEW_JSCLASS && obj->builtin_info->class <= LAST_VIEW_JSCLASS) + ret = TRUE; + + *r = jsval_bool(ret); + return S_OK; }
static HRESULT ArrayBufferConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index db0f2e3d6a7..8597a039e57 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -115,6 +115,8 @@ typedef enum {
FIRST_TYPEDARRAY_JSCLASS = JSCLASS_INT8ARRAY, LAST_TYPEDARRAY_JSCLASS = JSCLASS_FLOAT64ARRAY, + FIRST_VIEW_JSCLASS = JSCLASS_DATAVIEW, + LAST_VIEW_JSCLASS = JSCLASS_FLOAT64ARRAY, } jsclass_t;
enum { NUM_TYPEDARRAY_TYPES = LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1 }; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index ebbec939cf8..a70c49e8a33 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1826,6 +1826,13 @@ sync_test("ArrayBuffers & Views", function() { test_readonly(buf, "byteLength", 10); test_own_data_prop_desc(buf, "byteLength", false, false, false);
+ ok(ArrayBuffer.isView() === false, "ArrayBuffer.isView() returned true"); + ok(ArrayBuffer.isView([]) === false, "ArrayBuffer.isView([]) returned true"); + ok(ArrayBuffer.isView({}) === false, "ArrayBuffer.isView({}) returned true"); + ok(ArrayBuffer.isView(undefined) === false, "ArrayBuffer.isView(undefined) returned true"); + ok(ArrayBuffer.isView(null) === false, "ArrayBuffer.isView(null) returned true"); + ok(ArrayBuffer.isView(buf) === false, "ArrayBuffer.isView(ArrayBuffer) returned true"); + test_own_props("DataView.prototype", [ "buffer", "byteLength", "byteOffset", "getInt8", "setInt8", "getUint8", "setUint8", @@ -1946,6 +1953,9 @@ sync_test("ArrayBuffers & Views", function() { ok(view.byteLength === 10, "DataView(buf).byteLength = " + view.byteLength); ok(view.byteOffset === 0, "DataView(buf).byteOffset = " + view.byteOffset);
+ ok(ArrayBuffer.isView(DataView) === false, "ArrayBuffer.isView(DataView) returned true"); + ok(ArrayBuffer.isView(view) === true, "ArrayBuffer.isView(DataView(buf)) returned false"); + for(i = 0; i < 10; i++) { r = view.getInt8(i); ok(r === 0, "view byte " + i + " = " + r); @@ -2080,6 +2090,8 @@ sync_test("ArrayBuffers & Views", function() { ok(buf2.byteLength === 9, "buf.slice(-9).byteLength = " + buf2.byteLength); view2 = DataView(buf2, 1); ok(view2.byteLength === 8, "buf.slice(-9) view(1).byteLength = " + view2.byteLength); + ok(ArrayBuffer.isView(buf2) === false, "ArrayBuffer.isView(buf.slice(-9)) returned true"); + ok(ArrayBuffer.isView(view2) === true, "ArrayBuffer.isView(DataView(buf.slice(-9))) returned false");
r = view2.getUint32(0); ok(r === 4294967040, "buf.slice(-9) view(1).getUint32(0) returned " + r); @@ -2196,6 +2208,7 @@ sync_test("ArrayBuffers & Views", function() { test_own_data_prop_desc(arr, "length", false, false, false); test_own_data_prop_desc(arr, "buffer", false, false, false);
+ ok(ArrayBuffer.isView(arr) === true, "ArrayBuffer.isView(" + name + "()) returned false"); Object.freeze(arr); ok(Object.isFrozen(arr) === true, name + "() not frozen");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
fill_typedarr_data_from_object will also be used for 'set'. --- dlls/jscript/arraybuf.c | 58 ++++++++++++++++++++++++++++++++++++++-- dlls/mshtml/tests/es5.js | 47 +++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 716aa3cf93d..369988996af 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -18,6 +18,7 @@
#include <limits.h> +#include <assert.h>
#include "jscript.h"
@@ -788,6 +789,32 @@ static HRESULT TypedArray_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_ return S_OK; }
+static HRESULT fill_typedarr_data_from_object(unsigned desc_idx, script_ctx_t *ctx, BYTE *data, jsdisp_t *obj, DWORD length) +{ + HRESULT hres; + jsval_t val; + UINT32 i; + + for(i = 0; i < length; i++) { + double n; + + hres = jsdisp_get_idx(obj, i, &val); + if(FAILED(hres)) { + if(hres != DISP_E_UNKNOWNNAME) + return hres; + val = jsval_undefined(); + } + + hres = to_number(ctx, val, &n); + jsval_release(val); + if(FAILED(hres)) + return hres; + typed_array_descs[desc_idx].set(&data[i * typed_array_descs[desc_idx].size], n); + } + + return S_OK; +} + static void TypedArray_destructor(jsdisp_t *dispex) { TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); @@ -923,8 +950,35 @@ static HRESULT TypedArrayConstr_value(const builtin_info_t *info, script_ctx_t * } jsdisp_addref(&buffer->dispex); }else { - FIXME("Construction from object not implemented\n"); - return E_NOTIMPL; + jsval_t val; + UINT32 len; + DWORD size; + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + return hres; + if(is_undefined(val)) + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + return hres; + + length = len; + size = length * elem_size; + if(size < length || size > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, size, &buffer); + if(FAILED(hres)) + return hres; + + hres = fill_typedarr_data_from_object(desc_idx, ctx, buffer->buf, obj, length); + if(FAILED(hres)) { + jsdisp_release(&buffer->dispex); + return hres; + } } }else if(is_number(argv[0])) { hres = to_integer(ctx, argv[0], &n); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index a70c49e8a33..eca06223a9e 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2174,6 +2174,13 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + name + "(null) threw " + n); } + try { + new arrType({}); + ok(false, "new " + name + "({}) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + name + "({}) threw " + n); + } if(typeSz > 1) { /* test misalignment */ var a = typeSz >>> 1; @@ -2300,6 +2307,23 @@ sync_test("ArrayBuffers & Views", function() { delete arr[-1]; delete arr.foo;
+ arr2 = { length: 4 }; + arr2[0] = 1.5; + arr2[1] = '3'; + arr2[3] = 12; + arr = arrType(arr2); + r = name + "(array-like object)"; + ok(arr.byteLength === 4 * typeSz, r + ".byteLength = " + arr.byteLength); + ok(arr.byteOffset === 0, r + ".byteOffset = " + arr.byteOffset); + ok(arr.length === 4, r + ".length = " + arr.length); + if(isNaN(arr[2])) { + ok(arr[0] === 1.5, r + "[0] = " + arr[0]); + ok(arr[1] === 3, r + "[1] = " + arr[1]); + ok(arr[3] === 12, r + "[3] = " + arr[3]); + }else + for(var j = 0; j < 4; j++) + ok(arr[j] === [1, 3, 0, 12][j], r + "[" + j + "] = " + arr[j]); + arr = arrType(buf, typeSz, 2); name = name + "(buf, " + typeSz + ", 2)"; ok(arr.byteLength === 2 * typeSz, name + ".byteLength = " + arr.byteLength); @@ -2315,7 +2339,28 @@ sync_test("ArrayBuffers & Views", function() { Object.freeze(arr); todo_wine. ok(Object.isFrozen(arr) === true, name + " not frozen"); - } + + arr2 = arrType(arr); + ok(arr2.byteLength === arr.byteLength, name + " copy.byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 0, name + " copy.byteOffset = " + arr2.byteOffset); + ok(arr2.length === arr.length, name + " copy.length = " + arr2.length); + ok(arr2.buffer !== arr.buffer, name + " copy.buffer = " + arr2.buffer); + } + + arr = new Float32Array(3); + arr[0] = 1.125; + arr[1] = 2.25; + arr[2] = 3.375; + arr2 = new Uint16Array(arr); + ok(arr[0] === 1.125, "arr[0] = " + arr[0]); + ok(arr[1] === 2.25, "arr[1] = " + arr[1]); + ok(arr[2] === 3.375, "arr[2] = " + arr[2]); + ok(arr2[0] === 1, "arr2[0] = " + arr2[0]); + ok(arr2[1] === 2, "arr2[1] = " + arr2[1]); + ok(arr2[2] === 3, "arr2[2] = " + arr2[2]); + arr2[0] = 100; + ok(arr[0] === 1.125, "arr[0] after arr2[0] changed = " + arr[0]); + ok(arr2[0] === 100, "arr2[0] after change = " + arr2[0]);
arr = new Int16Array(2); arr[0] = 65535;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 62 ++++++++++++++++++++++++++++++++++++-- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/es5.js | 65 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 369988996af..d1132b6b762 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -757,6 +757,14 @@ static const struct typed_array_desc typed_array_descs[NUM_TYPEDARRAY_TYPES] = { [Float64Array_desc_idx] = { 8, get_f64, set_f64 } };
+static inline TypedArrayInstance *typedarr_this(jsval_t vthis, jsclass_t class) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, class)) ? typedarr_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT create_typedarr(const builtin_info_t*,script_ctx_t*,ArrayBufferInstance*,DWORD,DWORD,jsdisp_t**); + static HRESULT TypedArray_get_buffer(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { TRACE("%p\n", jsthis); @@ -815,6 +823,54 @@ static HRESULT fill_typedarr_data_from_object(unsigned desc_idx, script_ctx_t *c return S_OK; }
+static HRESULT TypedArray_subarray(const builtin_info_t *info, script_ctx_t *ctx, jsval_t vthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + TypedArrayInstance *typedarr; + DWORD begin = 0, end; + jsdisp_t *obj; + HRESULT hres; + double n; + + if(!(typedarr = typedarr_this(vthis, info->class))) + return JS_E_NOT_TYPEDARRAY; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SUBARRAY; + if(!r) + return S_OK; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + end = typedarr->length; + if(n < 0.0) + n += typedarr->length; + if(n >= 0.0) + begin = n < typedarr->length ? n : typedarr->length; + + if(argc > 1 && !is_undefined(argv[1])) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += typedarr->length; + if(n >= 0.0) { + end = n < typedarr->length ? n : typedarr->length; + end = end < begin ? begin : end; + }else + end = begin; + } + + hres = create_typedarr(info, ctx, typedarr->buffer, + typedarr->offset + begin * typed_array_descs[info->class - FIRST_TYPEDARRAY_JSCLASS].size, + end - begin, &obj); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(obj); + return S_OK; +} + static void TypedArray_destructor(jsdisp_t *dispex) { TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); @@ -1019,6 +1075,8 @@ static HRESULT TypedArrayConstr_value(const builtin_info_t *info, script_ctx_t * }
#define X(name) \ +static const builtin_info_t name##_info; \ + \ static HRESULT name##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ { \ FIXME("\n"); \ @@ -1027,8 +1085,8 @@ static HRESULT name##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned \ static HRESULT name##_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ { \ - FIXME("\n"); \ - return E_NOTIMPL; \ + TRACE("\n"); \ + return TypedArray_subarray(&name##_info, ctx, vthis, flags, argc, argv, r); \ } \ \ static HRESULT name##_prop_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) \ diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 48e9826040c..d85cb811214 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -514,6 +514,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_PRECISION_OUT_OF_RANGE: case JS_E_INVALID_LENGTH: case JS_E_TYPEDARRAY_INVALID_OFFSLEN: + case JS_E_TYPEDARRAY_INVALID_SUBARRAY: case JS_E_DATAVIEW_INVALID_ACCESS: case JS_E_DATAVIEW_INVALID_OFFSET: constr = ctx->range_error_constr; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 8597a039e57..057a6ee9432 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -584,6 +584,7 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_TYPEDARRAY_BAD_CTOR_ARG MAKE_JSERROR(IDS_TYPEDARRAY_BAD_CTOR_ARG) #define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) #define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) +#define JS_E_TYPEDARRAY_INVALID_SUBARRAY MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SUBARRAY) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 91bbf09d034..6c73f045b5d 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -82,6 +82,7 @@ STRINGTABLE IDS_NOT_TYPEDARRAY "'this' is not a typed array object" IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" + IDS_TYPEDARRAY_INVALID_SUBARRAY "Invalid begin/end value in typed array subarray method" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 0f8e6f2dc7f..416c608eb0b 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -80,6 +80,7 @@ #define IDS_TYPEDARRAY_BAD_CTOR_ARG 0x13DA #define IDS_NOT_TYPEDARRAY 0x13DB #define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC +#define IDS_TYPEDARRAY_INVALID_SUBARRAY 0x13DD #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index eca06223a9e..781abca04c4 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -36,6 +36,7 @@ var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7; var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; var JS_E_NOT_TYPEDARRAY = 0x800a13db; var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; +var JS_E_TYPEDARRAY_INVALID_SUBARRAY = 0x800a13dd; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -2324,6 +2325,55 @@ sync_test("ArrayBuffers & Views", function() { for(var j = 0; j < 4; j++) ok(arr[j] === [1, 3, 0, 12][j], r + "[" + j + "] = " + arr[j]);
+ arr = arrType(10); + r = name + "(10)"; + try { + arr.subarray.call(null, 0); + ok(false, r + ": calling subarray with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, r + ": calling subarray with null context threw " + n); + } + try { + arr.subarray.call({}, 0); + ok(false, r + ": calling subarray with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, r + ": calling subarray with an object context threw " + n); + } + try { + arr.subarray(); + ok(false, r + " subarray() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SUBARRAY, r + " subarray() threw " + n); + } + arr2 = arr.subarray(4); + ok(arr2.byteLength === 6 * typeSz, r + ".subarray(4).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 4 * typeSz, r + ".subarray(4).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 6, r + ".subarray(4).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, r + ".subarray(4).buffer = " + arr2.buffer); + arr2 = arr.subarray(4, 2); + ok(arr2.byteLength === 0, r + ".subarray(4, 2).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 4 * typeSz, r + ".subarray(4, 2).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 0, r + ".subarray(4, 2).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, r + ".subarray(4, 2).buffer = " + arr2.buffer); + arr2 = arr.subarray(-3, 100); + ok(arr2.byteLength === 3 * typeSz, r + ".subarray(-3, 100).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 7 * typeSz, r + ".subarray(-3, 100).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 3, r + ".subarray(-3, 100).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, r + ".subarray(-3, 100).buffer = " + arr2.buffer); + arr2 = arr.subarray(42, -1); + ok(arr2.byteLength === 0, r + ".subarray(42, -1).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 10 * typeSz, r + ".subarray(42, -1).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 0, r + ".subarray(42, -1).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, r + ".subarray(42, -1).buffer = " + arr2.buffer); + arr2 = arr.subarray(2, -3); + ok(arr2.byteLength === 5 * typeSz, r + ".subarray(2, -3).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 2 * typeSz, r + ".subarray(2, -3).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 5, r + ".subarray(2, -3).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, r + ".subarray(2, -3).buffer = " + arr2.buffer); + arr = arrType(buf, typeSz, 2); name = name + "(buf, " + typeSz + ", 2)"; ok(arr.byteLength === 2 * typeSz, name + ".byteLength = " + arr.byteLength); @@ -2345,6 +2395,11 @@ sync_test("ArrayBuffers & Views", function() { ok(arr2.byteOffset === 0, name + " copy.byteOffset = " + arr2.byteOffset); ok(arr2.length === arr.length, name + " copy.length = " + arr2.length); ok(arr2.buffer !== arr.buffer, name + " copy.buffer = " + arr2.buffer); + arr2 = arr.subarray(undefined, "1"); + ok(arr2.byteLength === typeSz, name + " subarray(undefined, '1').byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === arr.byteOffset, name + " subarray(undefined, '1').byteOffset = " + arr2.byteOffset); + ok(arr2.length === 1, name + " subarray(undefined, '1').length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + " subarray(undefined, '1').buffer = " + arr2.buffer); }
arr = new Float32Array(3); @@ -2376,6 +2431,16 @@ sync_test("ArrayBuffers & Views", function() {
arr = new Int8Array(); arr2 = new Int32Array(); + + /* methods are incompatible, even though thrown error is not explicit */ + ok(Uint16Array.prototype.subarray !== Int32Array.prototype.subarray, "Uint16Array and Int32Array have same subarray methods"); + try { + Uint32Array.prototype.subarray.call(arr2, 0); + ok(false, "calling Uint32Array's subarray with Int32Array context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, "calling Uint32Array's subarray with Int32Array context threw " + n); + } });
sync_test("builtin_context", function() {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 84 ++++++++++++++++++++++++++++++- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/es5.js | 105 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 189 insertions(+), 4 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index d1132b6b762..bf166bf6eb4 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -823,6 +823,86 @@ static HRESULT fill_typedarr_data_from_object(unsigned desc_idx, script_ctx_t *c return S_OK; }
+static HRESULT TypedArray_set(unsigned desc_idx, script_ctx_t *ctx, jsval_t vthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + TypedArrayInstance *typedarr; + DWORD begin = 0, size; + BYTE *dest, *data; + IDispatch *disp; + jsdisp_t *obj; + HRESULT hres; + jsval_t val; + UINT32 len; + double n; + + if(!(typedarr = typedarr_this(vthis, FIRST_TYPEDARRAY_JSCLASS + desc_idx))) + return JS_E_NOT_TYPEDARRAY; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + hres = to_object(ctx, argv[0], &disp); + if(FAILED(hres)) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + if(!(obj = to_jsdisp(disp))) { + FIXME("Non-JS array object\n"); + hres = JS_E_TYPEDARRAY_INVALID_SOURCE; + goto done; + } + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + goto done; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + goto done; + + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + goto done; + if(n < 0.0 || n > typedarr->length) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + begin = n; + } + + if(len > typedarr->length - begin) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + size = len * typed_array_descs[desc_idx].size; + dest = data = &typedarr->buffer->buf[typedarr->offset + begin * typed_array_descs[desc_idx].size]; + + /* If they overlap, make a temporary copy */ + if(obj->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && obj->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) { + TypedArrayInstance *src_arr = typedarr_from_jsdisp(obj); + const BYTE *src = src_arr->buffer->buf + src_arr->offset; + + if(dest < src + len * typed_array_descs[obj->builtin_info->class - FIRST_TYPEDARRAY_JSCLASS].size && + dest + size > src) { + if(!(data = malloc(size))) { + hres = E_OUTOFMEMORY; + goto done; + } + } + } + + hres = fill_typedarr_data_from_object(desc_idx, ctx, data, obj, len); + if(SUCCEEDED(hres) && dest != data) { + memcpy(dest, data, size); + free(data); + } + +done: + IDispatch_Release(disp); + return hres; +} + static HRESULT TypedArray_subarray(const builtin_info_t *info, script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -1079,8 +1159,8 @@ static const builtin_info_t name##_info; \ static HRESULT name##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ { \ - FIXME("\n"); \ - return E_NOTIMPL; \ + TRACE("\n"); \ + return TypedArray_set(name##_desc_idx, ctx, vthis, flags, argc, argv, r); \ } \ \ static HRESULT name##_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index d85cb811214..b387972a5f4 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -499,6 +499,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_NONWRITABLE_MODIFIED: case JS_E_TYPEDARRAY_BAD_CTOR_ARG: case JS_E_NOT_TYPEDARRAY: + case JS_E_TYPEDARRAY_INVALID_SOURCE: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_WRONG_THIS: diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 057a6ee9432..66dd2e227db 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -585,6 +585,7 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) #define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) #define JS_E_TYPEDARRAY_INVALID_SUBARRAY MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SUBARRAY) +#define JS_E_TYPEDARRAY_INVALID_SOURCE MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SOURCE) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 6c73f045b5d..cbddcb90058 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -83,6 +83,7 @@ STRINGTABLE IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" IDS_TYPEDARRAY_INVALID_SUBARRAY "Invalid begin/end value in typed array subarray method" + IDS_TYPEDARRAY_INVALID_SOURCE "Invalid source in typed array set" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 416c608eb0b..22bc3a551e3 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -81,6 +81,7 @@ #define IDS_NOT_TYPEDARRAY 0x13DB #define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC #define IDS_TYPEDARRAY_INVALID_SUBARRAY 0x13DD +#define IDS_TYPEDARRAY_INVALID_SOURCE 0x13DE #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 781abca04c4..5d0f7ac6cd0 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -37,6 +37,7 @@ var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; var JS_E_NOT_TYPEDARRAY = 0x800a13db; var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; var JS_E_TYPEDARRAY_INVALID_SUBARRAY = 0x800a13dd; +var JS_E_TYPEDARRAY_INVALID_SOURCE = 0x800a13de; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -2374,6 +2375,87 @@ sync_test("ArrayBuffers & Views", function() { ok(arr2.length === 5, r + ".subarray(2, -3).length = " + arr2.length); ok(arr2.buffer === arr.buffer, r + ".subarray(2, -3).buffer = " + arr2.buffer);
+ try { + arr.set.call(null, [1]); + ok(false, name + ": calling set with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, name + ": calling set with null context threw " + n); + } + try { + arr.set.call({}, [1]); + ok(false, name + ": calling set with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, name + ": calling set with an object context threw " + n); + } + try { + arr.set(); + ok(false, name + ".set() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SOURCE, name + ".set() threw " + n); + } + try { + arr.set(null); + ok(false, name + ".set(null) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SOURCE, name + ".set(null) threw " + n); + } + try { + arr.set([1,2,3], 8); + ok(false, name + ".set([1,2,3], 8) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, name + ".set([1,2,3], 8) threw " + n); + } + try { + arr.set([99], -3); + ok(false, name + ".set([99], -3) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, name + ".set([99], -3) threw " + n); + } + + r = arr.set(5); + ok(r === undefined, name + ".set(5) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === 0, name + ".set(5): arr[" + j + "] = " + arr[j]); + + r = arr.set({}); + ok(r === undefined, name + ".set({}) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === 0, name + ".set({}): arr[" + j + "] = " + arr[j]); + + r = arr.set("12"); + ok(r === undefined, name + ".set('12') returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 1, 2, 0, 0, 0, 0, 0, 0, 0, 0 ][j], name + ".set('12'): arr[" + j + "] = " + arr[j]); + + arr2 = { length: 2 }; + arr2[0] = 9; + arr2[1] = 7; + r = arr.set(arr2); + ok(r === undefined, name + ".set(array-like obj) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 0, 0, 0, 0, 0, 0, 0 ][j], name + ".set(array-like obj): arr[" + j + "] = " + arr[j]); + + r = arr.set([12, 10, 11], 3); + ok(r === undefined, name + ".set([12, 10, 11], 3) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 12, 10, 11, 0, 0, 0, 0 ][j], name + ".set([12, 10, 11], 3): arr[" + j + "] = " + arr[j]); + + r = arr.set(arr.subarray(4, 6), 5); + ok(r === undefined, name + ".set(arr.subarray(4, 2), 5) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 12, 10, 10, 11, 0, 0, 0 ][j], name + ".set(arr.subarray(4, 2), 5): arr[" + j + "] = " + arr[j]); + + r = arr.set(arr.subarray(3, 7), 2); + ok(r === undefined, name + ".set(arr.subarray(3, 7), 2) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 12, 10, 10, 11, 11, 0, 0, 0 ][j], name + ".set(arr.subarray(3, 7), 2): arr[" + j + "] = " + arr[j]); + arr = arrType(buf, typeSz, 2); name = name + "(buf, " + typeSz + ", 2)"; ok(arr.byteLength === 2 * typeSz, name + ".byteLength = " + arr.byteLength); @@ -2429,11 +2511,30 @@ sync_test("ArrayBuffers & Views", function() { ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]); ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]);
- arr = new Int8Array(); - arr2 = new Int32Array(); + arr = new Int8Array(12); + arr.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + for(var j = 0; j < 12; j++) + ok(arr[j] === j + 1, "sequential arr[" + j + "] = " + arr[j]); + arr2 = new Int32Array(arr.buffer); + ok(arr2.buffer === arr.buffer, "arr2.buffer = " + arr2.buffer); + for(var j = 0; j < 3; j++) + ok(arr2[j] === [ 0x04030201, 0x08070605, 0x0c0b0a09 ][j], "sequential 32-bit arr[" + j + "] = " + arr2[j]); + + /* test overlap */ + arr2.set(arr.subarray(1, 4)); + for(var j = 0; j < 3; j++) + ok(arr2[j] === j + 2, "arr with overlap[" + j + "] = " + arr[j]);
/* methods are incompatible, even though thrown error is not explicit */ ok(Uint16Array.prototype.subarray !== Int32Array.prototype.subarray, "Uint16Array and Int32Array have same subarray methods"); + ok(Int8Array.prototype.set !== Float32Array.prototype.set, "Int8Array and Float32Array have same set methods"); + try { + Uint8Array.prototype.set.call(arr, [12, 50]); + ok(false, "calling Uint8Array's set with Int8Array context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, "calling Uint8Array's set with Int8Array context threw " + n); + } try { Uint32Array.prototype.subarray.call(arr2, 0); ok(false, "calling Uint32Array's subarray with Int32Array context did not throw exception");
Rebased and removed the `Uint8ClampedArray` from this MR, I will send that on next MR with a couple more fixes now.
Jacek Caban (@jacek) commented about dlls/jscript/arraybuf.c:
+static void TypedArray_destructor(jsdisp_t *dispex) +{
- TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex);
- if(typedarr->buffer)
jsdisp_release(&typedarr->buffer->dispex);+}
+static HRESULT TypedArray_lookup_prop(jsdisp_t *dispex, const WCHAR *name, unsigned flags, struct property_info *desc) +{
- TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex);
- /* Typed Arrays override every positive index */
- return jsdisp_index_lookup(&typedarr->dispex, name, INT_MAX, desc);
+}
+static inline HRESULT TypedArray_prop_get(unsigned desc_idx, jsdisp_t *dispex, unsigned idx, jsval_t *r)
I'd suggest passing the descriptor as a struct pointer (moving resolving `typed_array_descs` to the caller) where possible.
Jacek Caban (@jacek) commented about dlls/jscript/arraybuf.c:
- hres = init_dispex(&prototype->dispex, ctx, info, ctx->object_prototype);
- if(FAILED(hres)) {
jsdisp_release(&prototype->buffer->dispex);free(prototype);return hres;- }
- hres = create_builtin_constructor(ctx, func, name, &TypedArrayConstr_info, PROPF_CONSTR|1, &prototype->dispex, &ctx->typedarr_constr[type_idx]);
- jsdisp_release(&prototype->dispex); if(FAILED(hres)) return hres;
- hres = create_builtin_constructor(ctx, func, name, &TypedArrayConstr_info, PROPF_CONSTR|1, prototype, &ctx->typedarr_constr[type_idx]);
- jsdisp_release(prototype);
- hres = jsdisp_define_data_property(ctx->typedarr_constr[type_idx], L"BYTES_PER_ELEMENT", 0,
jsval_number(typed_array_descs[type_idx].size));
Please move "BYTES_PER_ELEMENT" to a separate commit.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
ok(r === undefined, "buf.slice(-9) view(1).setFloat64(0, 11.875) returned " + r); r = view2.getFloat64(0); ok(r === 11.875, "buf.slice(-9) view(1).getFloat64(0) returned " + r);
- for(i = 0; i < types.length; i++) {
var name = types[i][0] + "Array", arrType = window[name], typeSz = types[i][1];
`arrType` is a constructor not an array type, please name it like that.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
ok(r === undefined, "buf.slice(-9) view(1).setFloat64(0, 11.875) returned " + r); r = view2.getFloat64(0); ok(r === 11.875, "buf.slice(-9) view(1).getFloat64(0) returned " + r);
- for(i = 0; i < types.length; i++) {
var name = types[i][0] + "Array", arrType = window[name], typeSz = types[i][1];arr = arrType;
`arr` is used for array instances in the same function, which makes things confusing.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
arr = arrType;test_own_data_prop_desc(arr, "BYTES_PER_ELEMENT", false, false, false);ok(arr.BYTES_PER_ELEMENT === typeSz, name + ".BYTES_PER_ELEMENT = " + arr.BYTES_PER_ELEMENT);r = arr.length;ok(r === 1, name + ".length = " + r);r = arr.prototype.set.length;ok(r === 2, name + ".prototype.set.length = " + r);r = arr.prototype.subarray.length;ok(r === 2, name + ".prototype.subarray.length = " + r);r = Object.getPrototypeOf(arrType);ok(r === Function.prototype, name + "'s prototype is not Function.prototype: " + r);r = Object.getPrototypeOf(arrType.prototype);ok(r === Object.prototype, name + ".prototype's prototype is not Object.prototype: " + r);r = Object.prototype.toString.call(new arrType(3));ok(r === "[object " + name + "]", "Object toString(new " + name + "(3)) = " + r);
This is already tested in documentmode.js.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
ok(arr.BYTES_PER_ELEMENT === typeSz, name + ".BYTES_PER_ELEMENT = " + arr.BYTES_PER_ELEMENT);r = arr.length;ok(r === 1, name + ".length = " + r);r = arr.prototype.set.length;ok(r === 2, name + ".prototype.set.length = " + r);r = arr.prototype.subarray.length;ok(r === 2, name + ".prototype.subarray.length = " + r);r = Object.getPrototypeOf(arrType);ok(r === Function.prototype, name + "'s prototype is not Function.prototype: " + r);r = Object.getPrototypeOf(arrType.prototype);ok(r === Object.prototype, name + ".prototype's prototype is not Object.prototype: " + r);r = Object.prototype.toString.call(new arrType(3));ok(r === "[object " + name + "]", "Object toString(new " + name + "(3)) = " + r);r = arrType.prototype;test_own_data_prop_desc(r, "byteLength", false, false, false);
Something like `test_own_data_prop_desc(constr.prototype, ....);` would make it easier to see what you're testing.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
arr = arrType.prototype;delete arr[-1];delete arr.foo;- }
- arr = new Int16Array(2);
- arr[0] = 65535;
- arr[1] = -65535;
- ok(arr[0] == -1, "16-bit arr[0] after overflow = " + arr[0]);
- ok(arr[1] == 1, "16-bit arr[1] after overflow = " + arr[1]);
- arr = new Uint8Array(2);
- arr[0] = -2;
- arr[1] = 258;
- ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]);
- ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]);
Testing other types like that would be nice.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
- }
- arr = new Int16Array(2);
- arr[0] = 65535;
- arr[1] = -65535;
- ok(arr[0] == -1, "16-bit arr[0] after overflow = " + arr[0]);
- ok(arr[1] == 1, "16-bit arr[1] after overflow = " + arr[1]);
- arr = new Uint8Array(2);
- arr[0] = -2;
- arr[1] = 258;
- ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]);
- ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]);
- arr = new Int8Array();
- arr2 = new Int32Array();
Is it a leftover?
Jacek Caban (@jacek) commented about dlls/jscript/jscript.h:
FIRST_TYPEDARRAY_JSCLASS = JSCLASS_INT8ARRAY, LAST_TYPEDARRAY_JSCLASS = JSCLASS_FLOAT64ARRAY,
- FIRST_VIEW_JSCLASS = JSCLASS_DATAVIEW,
- LAST_VIEW_JSCLASS = JSCLASS_FLOAT64ARRAY,
It doesn't seem all that useful, you could just check for `class == JSCLASS_DATAVIEW || (check *_TYPEDARRAY_JSCLASS)`.