From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
It's the only thing it was used for anyway. --- dlls/jscript/dispex.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index c5e1fb7e8a9..897df1a0773 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -108,7 +108,7 @@ static inline BOOL is_function_prop(dispex_prop_t *prop) return ret; }
-static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) +static BOOL is_enumerable(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { dispex_prop_t *parent = NULL; @@ -118,13 +118,13 @@ static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; - return 0; + return FALSE; }
- return get_flags(This->prototype, parent); + return is_enumerable(This->prototype, parent); }
- return prop->flags; + return !!(prop->flags & PROPF_ENUMERABLE); }
static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens) @@ -3170,7 +3170,7 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty continue; if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF) continue; - if(enum_type != JSDISP_ENUM_OWN && !(get_flags(obj, iter) & PROPF_ENUMERABLE)) + if(enum_type != JSDISP_ENUM_OWN && !is_enumerable(obj, iter)) continue; *ret = prop_to_id(obj, iter); return S_OK;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 897df1a0773..77029e059bb 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -758,9 +758,29 @@ static HRESULT fill_props(jsdisp_t *obj) return S_OK; }
+static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref) +{ + dispex_prop_t *prop; + HRESULT hres; + + hres = find_prop_name(This, hash, name, FALSE, NULL, &prop); + if(FAILED(hres)) + return hres; + if(prop) { + if(prop->type != PROP_DELETED) + return S_OK; + prop->type = PROP_PROTREF; + prop->flags = 0; + prop->u.ref = ref; + }else if(!alloc_protref(This, name, ref)) { + return E_OUTOFMEMORY; + } + return S_OK; +} + static HRESULT fill_protrefs(jsdisp_t *This) { - dispex_prop_t *iter, *prop; + dispex_prop_t *iter; HRESULT hres;
hres = fill_props(This); @@ -775,20 +795,9 @@ static HRESULT fill_protrefs(jsdisp_t *This) return hres;
for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - hres = find_prop_name(This, iter->hash, iter->name, FALSE, NULL, &prop); - if(FAILED(hres)) + hres = fill_protref(This, iter->hash, iter->name, iter - This->prototype->props); + if(hres != S_OK) return hres; - if(!prop || prop->type==PROP_DELETED) { - if(prop) { - prop->type = PROP_PROTREF; - prop->flags = 0; - prop->u.ref = iter - This->prototype->props; - }else { - prop = alloc_protref(This, iter->name, iter - This->prototype->props); - if(!prop) - return E_OUTOFMEMORY; - } - } }
return S_OK;
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 355 ++++++++++++++++++++++++++++++ dlls/jscript/error.c | 3 + dlls/jscript/jscript.h | 19 +- dlls/jscript/jscript.rc | 3 + dlls/jscript/object.c | 8 + dlls/jscript/resource.h | 3 + dlls/mshtml/tests/documentmode.js | 8 +- dlls/mshtml/tests/es5.js | 206 ++++++++++++++++- 8 files changed, 599 insertions(+), 6 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index fc01773338f..d989cb20a66 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; @@ -684,6 +697,311 @@ static const builtin_info_t DataViewConstr_info = { .call = Function_value, };
+#define TYPEDARRAY_LIST \ +X(Int8Array, JSCLASS_INT8ARRAY, INT8, to_int32, INT) \ +X(Int16Array, JSCLASS_INT16ARRAY, INT16, to_int32, INT) \ +X(Int32Array, JSCLASS_INT32ARRAY, INT32, to_int32, INT) \ +X(Uint8Array, JSCLASS_UINT8ARRAY, UINT8, to_int32, INT) \ +X(Uint16Array, JSCLASS_UINT16ARRAY, UINT16, to_int32, INT) \ +X(Uint32Array, JSCLASS_UINT32ARRAY, UINT32, to_int32, INT) \ +X(Float32Array, JSCLASS_FLOAT32ARRAY, float, to_number, double) \ +X(Float64Array, JSCLASS_FLOAT64ARRAY, double, to_number, double) + +#define TYPEDARRAY_INDEX(JSCLASS) ((JSCLASS) - FIRST_TYPEDARRAY_JSCLASS) + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = L"" #NAME, +static const WCHAR *const TypedArray_name[] = { TYPEDARRAY_LIST }; +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = sizeof(TYPE), +static const unsigned TypedArray_elem_size[] = { TYPEDARRAY_LIST }; +#undef X + +static inline TypedArrayInstance *typedarr_this(jsval_t vthis, jsclass_t jsclass) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, jsclass)) ? typedarr_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT TypedArray_get_buffer(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + 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) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length * TypedArray_elem_size[TYPEDARRAY_INDEX(jsthis->builtin_info->class)]); + return S_OK; +} + +static HRESULT TypedArray_get_byteOffset(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + 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) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length); + return S_OK; +} + +static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + TypedArrayInstance *typedarr; + + FIXME("not implemented\n"); + + if(!(typedarr = typedarr_this(vthis, jsclass))) + return JS_E_NOT_TYPEDARRAY; + return E_NOTIMPL; +} + +static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + TypedArrayInstance *typedarr; + + FIXME("not implemented\n"); + + if(!(typedarr = typedarr_this(vthis, jsclass))) + return JS_E_NOT_TYPEDARRAY; + return E_NOTIMPL; +} + +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 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 gc_process_linked_obj(gc_ctx, op, dispex, &typedarr->buffer->dispex, (void**)&typedarr->buffer); +} + +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}, +}; + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +static HRESULT NAME ##_prop_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) \ +{ \ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); \ + \ + TRACE("%p[%u]\n", typedarr, idx); \ + \ + if(idx >= typedarr->length) \ + *r = jsval_undefined(); \ + else \ + *r = jsval_number(*(TYPE*)&typedarr->buffer->buf[typedarr->offset + idx * sizeof(TYPE)]); \ + return S_OK; \ +} \ + \ +static HRESULT NAME ##_prop_put(jsdisp_t *dispex, unsigned idx, jsval_t val) \ +{ \ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); \ + HRESULT hres; \ + NUM_TYPE n; \ + \ + TRACE("%p[%u] = %s\n", typedarr, idx, debugstr_jsval(val)); \ + \ + if(idx >= typedarr->length) \ + return S_OK; \ + \ + hres = CONVERT(typedarr->dispex.ctx, val, &n); \ + if(SUCCEEDED(hres)) \ + *(TYPE*)&typedarr->buffer->buf[typedarr->offset + idx * sizeof(TYPE)] = n; \ + return hres; \ +} \ + \ +static HRESULT NAME ##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArray_set(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} \ + \ +static HRESULT NAME ##_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArray_subarray(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} \ + \ +static const builtin_prop_t NAME ##_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}, \ + {L"set", NAME ##_set, PROPF_METHOD|2}, \ + {L"subarray", NAME ##_subarray, PROPF_METHOD|2}, \ +}; +TYPEDARRAY_LIST +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +[TYPEDARRAY_INDEX(JSCLASS)] = \ +{ \ + .class = JSCLASS, \ + .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 TypedArray_info[] = { TYPEDARRAY_LIST }; +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +[TYPEDARRAY_INDEX(JSCLASS)] = \ +{ \ + .class = JSCLASS, \ + .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 const builtin_info_t TypedArrayInst_info[] = { TYPEDARRAY_LIST }; +#undef X + +static HRESULT create_typedarr(script_ctx_t *ctx, jsclass_t jsclass, 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, &TypedArrayInst_info[TYPEDARRAY_INDEX(jsclass)], + ctx->typedarr_constr[TYPEDARRAY_INDEX(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(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + const unsigned typedarr_idx = TYPEDARRAY_INDEX(jsclass); + unsigned elem_size = TypedArray_elem_size[typedarr_idx]; + ArrayBufferInstance *buffer = NULL; + DWORD offset = 0, length = 0; + jsdisp_t *typedarr; + HRESULT hres; + double n; + + TRACE("\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(ctx, jsclass, 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, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +static HRESULT NAME ## Constr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArrayConstr_value(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} +TYPEDARRAY_LIST +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = NAME ## Constr_value, +static const builtin_invoke_t TypedArray_constr[] = { TYPEDARRAY_LIST }; +#undef X + +static const builtin_info_t TypedArrayConstr_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, +}; + HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { static const struct { @@ -695,6 +1013,7 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { L"byteOffset", DataView_get_byteOffset }, }; ArrayBufferInstance *arraybuf; + TypedArrayInstance *typedarr; DataViewInstance *view; property_desc_t desc; HRESULT hres; @@ -766,6 +1085,42 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx)
hres = jsdisp_define_data_property(ctx->global, L"DataView", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->dataview_constr)); + if(FAILED(hres)) + return hres; + + for(i = 0; i < ARRAY_SIZE(TypedArray_info); i++) { + if(!(typedarr = calloc(1, sizeof(TypedArrayInstance)))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, 0, &typedarr->buffer); + if(FAILED(hres)) { + free(typedarr); + return hres; + } + + hres = init_dispex(&typedarr->dispex, ctx, &TypedArray_info[i], ctx->object_prototype); + if(FAILED(hres)) { + jsdisp_release(&typedarr->buffer->dispex); + free(typedarr); + return hres; + } + + hres = create_builtin_constructor(ctx, TypedArray_constr[i], TypedArray_name[i], &TypedArrayConstr_info, + PROPF_CONSTR|1, &typedarr->dispex, &ctx->typedarr_constr[i]); + jsdisp_release(&typedarr->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->typedarr_constr[i], L"BYTES_PER_ELEMENT", 0, + jsval_number(TypedArray_elem_size[i])); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, TypedArray_name[i], PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->typedarr_constr[i])); + if(FAILED(hres)) + return 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 0540bce380d..65e8d33908e 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -113,12 +113,25 @@ typedef enum { JSCLASS_JSON, JSCLASS_ARRAYBUFFER, JSCLASS_DATAVIEW, + JSCLASS_INT8ARRAY, + JSCLASS_INT16ARRAY, + JSCLASS_INT32ARRAY, + JSCLASS_UINT8ARRAY, + JSCLASS_UINT16ARRAY, + JSCLASS_UINT32ARRAY, + JSCLASS_FLOAT32ARRAY, + JSCLASS_FLOAT64ARRAY, JSCLASS_MAP, JSCLASS_SET, JSCLASS_WEAKMAP, JSCLASS_HOST, + + FIRST_TYPEDARRAY_JSCLASS = JSCLASS_INT8ARRAY, + LAST_TYPEDARRAY_JSCLASS = JSCLASS_FLOAT64ARRAY, } jsclass_t;
+enum { NUM_TYPEDARRAY_TYPES = LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1 }; + jsdisp_t *iface_to_jsdisp(IDispatch*);
typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); @@ -433,11 +446,12 @@ struct _script_ctx_t { jsdisp_t *vbarray_constr; jsdisp_t *arraybuf_constr; jsdisp_t *dataview_constr; + jsdisp_t *typedarr_constr[LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1]; jsdisp_t *map_prototype; jsdisp_t *set_prototype; jsdisp_t *weakmap_prototype; }; - jsdisp_t *global_objects[25]; + jsdisp_t *global_objects[25 + LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1]; }; }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); @@ -577,6 +591,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/object.c b/dlls/jscript/object.c index a1ba990695b..bda4d28ecef 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -53,6 +53,14 @@ HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned a L"[object Object]", L"[object ArrayBuffer]", L"[object Object]", + L"[object Int8Array]", + L"[object Int16Array]", + L"[object Int32Array]", + L"[object Uint8Array]", + L"[object Uint16Array]", + L"[object Uint32Array]", + L"[object Float32Array]", + L"[object Float64Array]", L"[object Object]", L"[object Object]", L"[object Object]", 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 6cacb0f2303..d8dc6763167 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -4631,7 +4631,7 @@ async_test("window own props", function() { "CompositionEvent", "ControlRangeCollection", "Coordinates", ["Crypto",11], ["CryptoOperation",11], "CSSFontFaceRule", "CSSImportRule", ["CSSKeyframeRule",10], ["CSSKeyframesRule",10], "CSSMediaRule", "CSSNamespaceRule", "CSSPageRule", "CSSRuleList", "DataTransfer", ["DataView",9,9], "Debug", ["DeviceAcceleration",11], ["DeviceMotionEvent",11], ["DeviceOrientationEvent",11], ["DeviceRotationRate",11], ["DOMError",10], "DOMException", ["DOMSettableTokenList",10], ["DOMStringList",10], ["DOMStringMap",11], - "DragEvent", ["ErrorEvent",10], "EventException", ["EXT_texture_filter_anisotropic",11], ["File",10], ["FileList",10], ["FileReader",10], ["Float32Array",10], ["Float64Array",10], + "DragEvent", ["ErrorEvent",10], "EventException", ["EXT_texture_filter_anisotropic",11], ["File",10], ["FileList",10], ["FileReader",10], ["Float32Array",9,9], ["Float64Array",9,9], "FocusEvent", ["FormData",10], "Geolocation", "GetObject", ["HTMLAllCollection",11], "HTMLAppletElement", "HTMLAreasCollection", "HTMLAudioElement", "HTMLBaseElement", "HTMLBaseFontElement", "HTMLBGSoundElement", "HTMLBlockElement", "HTMLBRElement", "HTMLCanvasElement", ["HTMLDataListElement",10], "HTMLDDElement", "HTMLDirectoryElement", "HTMLDivElement", "HTMLDListElement", "HTMLDTElement", "HTMLFieldSetElement", "HTMLFontElement", "HTMLFrameSetElement", "HTMLHeadingElement", "HTMLHRElement", "HTMLIsIndexElement", @@ -4639,7 +4639,7 @@ async_test("window own props", function() { "HTMLOptGroupElement", "HTMLParagraphElement", "HTMLParamElement", "HTMLPhraseElement", "HTMLPreElement", ["HTMLProgressElement",10], "HTMLQuoteElement", "HTMLSourceElement", "HTMLSpanElement", "HTMLTableCaptionElement", "HTMLTableColElement", "HTMLTableHeaderCellElement", "HTMLTableSectionElement", ["HTMLTrackElement",10], "HTMLUListElement", "HTMLVideoElement", ["IDBCursor",10], ["IDBCursorWithValue",10], ["IDBDatabase",10], ["IDBFactory",10], ["IDBIndex",10], ["IDBKeyRange",10], ["IDBObjectStore",10], ["IDBOpenDBRequest",10], - ["IDBRequest",10], ["IDBTransaction",10], ["IDBVersionChangeEvent",10], "ImageData", ["Int16Array",10], ["Int32Array",10], ["Int8Array",10], ["Intl",11], ["Key",11], ["KeyOperation",11], + ["IDBRequest",10], ["IDBTransaction",10], ["IDBVersionChangeEvent",10], "ImageData", ["Int16Array",9,9], ["Int32Array",9,9], ["Int8Array",9,9], ["Intl",11], ["Key",11], ["KeyOperation",11], ["KeyPair",11], "Location", "MediaError", "MediaList", ["MediaSource",11], ["MessageChannel",10], ["MessagePort",10], ["MimeType",11], ["MimeTypeArray",9,10], "MouseWheelEvent", "MSBehaviorUrnsCollection", ["MSBlobBuilder",10], "MSCompatibleInfo", "MSCompatibleInfoCollection", ["MSCSSMatrix",10], ["MSGesture",10], ["MSGestureEvent",10], ["MSGraphicsTrust",11], ["MSInputMethodContext",11], ["MSManipulationEvent",10], ["MSMediaKeyError",11], ["MSMediaKeyMessageEvent",11], ["MSMediaKeyNeededEvent",11], ["MSMediaKeys",11], ["MSMediaKeySession",11], @@ -4662,8 +4662,8 @@ async_test("window own props", function() { "SVGPatternElement", "SVGPoint", "SVGPointList", "SVGPolygonElement", "SVGPolylineElement", "SVGPreserveAspectRatio", "SVGRadialGradientElement", "SVGRect", "SVGRectElement", "SVGScriptElement", "SVGStopElement", "SVGStringList", "SVGStyleElement", "SVGSwitchElement", "SVGSymbolElement", "SVGTextElement", "SVGTextPathElement", "SVGTitleElement", "SVGTransform", "SVGTransformList", "SVGUnitTypes", "SVGUseElement", "SVGViewElement", "SVGZoomAndPan", "SVGZoomEvent", "TextEvent", "TextMetrics", "TextRangeCollection", ["TextTrack",10], - ["TextTrackCue",10], ["TextTrackCueList",10], ["TextTrackList",10], "TimeRanges", ["TrackEvent",10], ["TransitionEvent",10], "TreeWalker", ["Uint16Array",10], ["Uint32Array",10], - ["Uint8Array",10], ["Uint8ClampedArray",11], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], + ["TextTrackCue",10], ["TextTrackCueList",10], ["TextTrackList",10], "TimeRanges", ["TrackEvent",10], ["TransitionEvent",10], "TreeWalker", ["Uint16Array",9,9], ["Uint32Array",9,9], + ["Uint8Array",9,9], ["Uint8ClampedArray",11], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], ["WebGLFramebuffer",11], ["WebGLObject",11], ["WebGLProgram",11], ["WebGLRenderbuffer",11], ["WebGLRenderingContext",11], ["WebGLShader",11], ["WebGLShaderPrecisionFormat",11], ["WebGLTexture",11], ["WebGLUniformLocation",11], ["WEBGL_compressed_texture_s3tc",11], ["WEBGL_debug_renderer_info",11], ["WebSocket",10], "WheelEvent", ["Worker",10], ["XMLHttpRequestEventTarget",10], "XMLSerializer" diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 402be2f9d9a..71ea4c9bb1a 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,199 @@ 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]; + test_own_props(name, [ "BYTES_PER_ELEMENT" ]); + test_not_own_props(name, [ "from", "of" ]); + test_own_props(name + ".prototype", [ "buffer", "byteLength", "byteOffset", "length", "set", "subarray" ]); + test_not_own_props(name + ".prototype", [ + "at", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "forEach", + "includes", "indexOf", "join", "keys", "lastIndexOf", "map", "reduce", "reduceRight", + "reverse", "slice", "some", "sort", "toLocaleString", "toString", "values" + ]); + + 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(Object.prototype.hasOwnProperty.call(arr, "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(!Object.prototype.hasOwnProperty.call(arr, "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(!Object.prototype.hasOwnProperty.call(arr, "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(); + + /* 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"); + }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() { @@ -2186,7 +2382,12 @@ sync_test("globals override", function() { "Error", "escape", "EvalError", + "Float32Array", + "Float64Array", "Function", + "Int8Array", + "Int16Array", + "Int32Array", "isFinite", "isNaN", "JSON", @@ -2206,6 +2407,9 @@ sync_test("globals override", function() { "String", "SyntaxError", "TypeError", + "Uint8Array", + "Uint16Array", + "Uint32Array", "unescape", "URIError", "VBArray",
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 d989cb20a66..a69e4c44f57 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -945,8 +945,38 @@ static HRESULT TypedArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD fla 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 71ea4c9bb1a..6aeab3c4098 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2127,6 +2127,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"); @@ -2134,6 +2135,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"); @@ -2148,6 +2170,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); @@ -2252,6 +2294,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 a69e4c44f57..6fbe54f4333 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 65e8d33908e..7c0d7bb58fa 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -128,6 +128,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 6aeab3c4098..8be0d7e1d47 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); @@ -2204,6 +2216,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 | 66 ++++++++++++++++++++++++++++++++++++++-- dlls/mshtml/tests/es5.js | 47 +++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 6fbe54f4333..79b4784c5a9 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -18,6 +18,7 @@
#include <limits.h> +#include <assert.h>
#include "jscript.h"
@@ -766,6 +767,40 @@ static HRESULT TypedArray_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_ return S_OK; }
+static HRESULT fill_typedarr_data_from_object(script_ctx_t *ctx, BYTE *data, jsdisp_t *obj, DWORD length, jsclass_t jsclass) +{ + HRESULT hres = S_OK; + jsval_t val; + UINT32 i; + + switch(jsclass) { +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ + case JSCLASS: \ + for(i = 0; i < length; i++) { \ + NUM_TYPE n; \ + \ + hres = jsdisp_get_idx(obj, i, &val); \ + if(FAILED(hres)) { \ + if(hres != DISP_E_UNKNOWNNAME) \ + break; \ + val = jsval_undefined(); \ + } \ + \ + hres = CONVERT(ctx, val, &n); \ + jsval_release(val); \ + if(FAILED(hres)) \ + break; \ + *(TYPE*)&data[i * sizeof(TYPE)] = n; \ + } \ + break; + TYPEDARRAY_LIST + DEFAULT_UNREACHABLE; +#undef X + } + + return hres; +} + static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, jsclass_t jsclass) { @@ -985,8 +1020,35 @@ static HRESULT TypedArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD fla } 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(ctx, buffer->buf, obj, length, jsclass); + 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 8be0d7e1d47..3a5ab5a1b7f 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2182,6 +2182,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; @@ -2308,6 +2315,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); @@ -2323,7 +2347,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 | 44 ++++++++++++++++++++++++++++++-- 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 | 55 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 79b4784c5a9..32014ad0f3c 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -735,6 +735,8 @@ static inline TypedArrayInstance *typedarr_this(jsval_t vthis, jsclass_t jsclass return (jsdisp && is_class(jsdisp, jsclass)) ? typedarr_from_jsdisp(jsdisp) : NULL; }
+static HRESULT create_typedarr(script_ctx_t*,jsclass_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); @@ -817,12 +819,50 @@ static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, jsval_t *r, jsclass_t jsclass) { TypedArrayInstance *typedarr; + DWORD begin = 0, end; + jsdisp_t *obj; + HRESULT hres; + double n;
- FIXME("not implemented\n"); + TRACE("\n");
if(!(typedarr = typedarr_this(vthis, jsclass))) return JS_E_NOT_TYPEDARRAY; - return E_NOTIMPL; + 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(ctx, jsclass, typedarr->buffer, + typedarr->offset + begin * TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)], + end - begin, &obj); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(obj); + return S_OK; }
static void TypedArray_destructor(jsdisp_t *dispex) 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 7c0d7bb58fa..e9ec5baaf0f 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -596,6 +596,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 3a5ab5a1b7f..32a6277e33c 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; @@ -2332,6 +2333,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); @@ -2353,6 +2403,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);
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 75 ++++++++++++++++++++++++++++++- 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 | 97 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 172 insertions(+), 4 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 32014ad0f3c..85681e2180e 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -806,13 +806,84 @@ static HRESULT fill_typedarr_data_from_object(script_ctx_t *ctx, BYTE *data, jsd static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, jsclass_t jsclass) { + const unsigned elem_size = TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)]; TypedArrayInstance *typedarr; + DWORD begin = 0, size; + BYTE *dest, *data; + IDispatch *disp; + jsdisp_t *obj; + HRESULT hres; + jsval_t val; + UINT32 len; + double n;
- FIXME("not implemented\n"); + TRACE("\n");
if(!(typedarr = typedarr_this(vthis, jsclass))) return JS_E_NOT_TYPEDARRAY; - return E_NOTIMPL; + 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 * elem_size; + dest = data = &typedarr->buffer->buf[typedarr->offset + begin * elem_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 * TypedArray_elem_size[TYPEDARRAY_INDEX(obj->builtin_info->class)] && + dest + size > src) { + if(!(data = malloc(size))) { + hres = E_OUTOFMEMORY; + goto done; + } + } + } + + hres = fill_typedarr_data_from_object(ctx, data, obj, len, jsclass); + if(SUCCEEDED(hres) && dest != data) { + memcpy(dest, data, size); + free(data); + } + +done: + IDispatch_Release(disp); + return hres; }
static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, 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 e9ec5baaf0f..662560d3394 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -597,6 +597,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 32a6277e33c..b9f5bebcded 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; @@ -2382,6 +2383,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); @@ -2437,8 +2519,19 @@ 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");
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 18 ++++++++++++++++++ dlls/jscript/jscript.h | 1 + dlls/jscript/object.c | 1 + dlls/mshtml/tests/documentmode.js | 2 +- dlls/mshtml/tests/es5.js | 13 +++++++++++++ 5 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 85681e2180e..7440d24dc99 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -17,6 +17,7 @@ */
+#include <math.h> #include <limits.h> #include <assert.h>
@@ -709,11 +710,28 @@ static const builtin_info_t DataViewConstr_info = { .call = Function_value, };
+static HRESULT clamped_u8(script_ctx_t *ctx, jsval_t v, UINT8 *ret) +{ + HRESULT hres; + double n; + + hres = to_number(ctx, v, &n); + if(FAILED(hres)) + return hres; + + if(!isfinite(n)) + *ret = (n == INFINITY ? 255 : 0); + else + *ret = (n >= 255.0 ? 255 : n <= 0 ? 0 : lround(n)); + return S_OK; +} + #define TYPEDARRAY_LIST \ X(Int8Array, JSCLASS_INT8ARRAY, INT8, to_int32, INT) \ X(Int16Array, JSCLASS_INT16ARRAY, INT16, to_int32, INT) \ X(Int32Array, JSCLASS_INT32ARRAY, INT32, to_int32, INT) \ X(Uint8Array, JSCLASS_UINT8ARRAY, UINT8, to_int32, INT) \ +X(Uint8ClampedArray, JSCLASS_UINT8CLAMPEDARRAY, UINT8, clamped_u8, UINT8) \ X(Uint16Array, JSCLASS_UINT16ARRAY, UINT16, to_int32, INT) \ X(Uint32Array, JSCLASS_UINT32ARRAY, UINT32, to_int32, INT) \ X(Float32Array, JSCLASS_FLOAT32ARRAY, float, to_number, double) \ diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 662560d3394..52cddbf117f 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -117,6 +117,7 @@ typedef enum { JSCLASS_INT16ARRAY, JSCLASS_INT32ARRAY, JSCLASS_UINT8ARRAY, + JSCLASS_UINT8CLAMPEDARRAY, JSCLASS_UINT16ARRAY, JSCLASS_UINT32ARRAY, JSCLASS_FLOAT32ARRAY, diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index bda4d28ecef..836b49e684c 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -57,6 +57,7 @@ HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned a L"[object Int16Array]", L"[object Int32Array]", L"[object Uint8Array]", + L"[object Uint8ClampedArray]", L"[object Uint16Array]", L"[object Uint32Array]", L"[object Float32Array]", diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index d8dc6763167..19baab64076 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -4663,7 +4663,7 @@ async_test("window own props", function() { "SVGScriptElement", "SVGStopElement", "SVGStringList", "SVGStyleElement", "SVGSwitchElement", "SVGSymbolElement", "SVGTextElement", "SVGTextPathElement", "SVGTitleElement", "SVGTransform", "SVGTransformList", "SVGUnitTypes", "SVGUseElement", "SVGViewElement", "SVGZoomAndPan", "SVGZoomEvent", "TextEvent", "TextMetrics", "TextRangeCollection", ["TextTrack",10], ["TextTrackCue",10], ["TextTrackCueList",10], ["TextTrackList",10], "TimeRanges", ["TrackEvent",10], ["TransitionEvent",10], "TreeWalker", ["Uint16Array",9,9], ["Uint32Array",9,9], - ["Uint8Array",9,9], ["Uint8ClampedArray",11], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], + ["Uint8Array",9,9], ["Uint8ClampedArray",9,10], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], ["WebGLFramebuffer",11], ["WebGLObject",11], ["WebGLProgram",11], ["WebGLRenderbuffer",11], ["WebGLRenderingContext",11], ["WebGLShader",11], ["WebGLShaderPrecisionFormat",11], ["WebGLTexture",11], ["WebGLUniformLocation",11], ["WEBGL_compressed_texture_s3tc",11], ["WEBGL_debug_renderer_info",11], ["WebSocket",10], "WheelEvent", ["Worker",10], ["XMLHttpRequestEventTarget",10], "XMLSerializer" diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index b9f5bebcded..1d370b88e05 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2550,6 +2550,18 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_NOT_TYPEDARRAY, "calling Uint32Array's subarray with Int32Array context threw " + n); } + + /* clamped array */ + arr = new Uint8ClampedArray(7); + arr2 = new Uint8Array(7); + arr.set ([42, -1, 999, 0.9, NaN, Infinity, -Infinity]); + arr2.set([42, -1, 999, 0.9, NaN, Infinity, -Infinity]); + for(var j = 0; j < 7; j++) { + ok(arr[j] === [42, 0, 255, 1, 0, 255, 0][j], "clamped arr[" + j + "] = " + arr[j]); + ok(arr2[j] === [42, 255, 231, 0, 0, 0, 0][j], "non-clamped arr[" + j + "] = " + arr2[j]); + } + r = Object.prototype.toString.call(arr); + ok(r === "[object Uint8ClampedArray]", "Object toString for Uint8ClampedArray = " + r); });
sync_test("builtin_context", function() { @@ -2672,6 +2684,7 @@ sync_test("globals override", function() { "SyntaxError", "TypeError", "Uint8Array", + "Uint8ClampedArray", "Uint16Array", "Uint32Array", "unescape",
Jacek Caban (@jacek) commented about dlls/jscript/dispex.c:
return S_OK;}
+static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref)
There is only a single caller, so it makes little sense on its own. I guess it's a part of some another change, so let's skip it for now.
Jacek Caban (@jacek) commented about dlls/jscript/arraybuf.c:
.call = Function_value,};
+#define TYPEDARRAY_LIST \ +X(Int8Array, JSCLASS_INT8ARRAY, INT8, to_int32, INT) \
I think it would be good to avoid using macros where possible, especially for generating entire functions. Instead, you could introduce typed array descriptors that hold the class, element size, and element getters/setters, e.g. `jsval_t get(const void*)` and `void set(void*, jsval_t)`. The constructor would take the descriptor, and the implementation could retrieve it from the "this" object when needed.
Some sort of macro may still be useful, but something like: ``` #define ALL_TYPED_ARRAYS \ X(Int16Array) \ ... ``` should be enough.
Jacek Caban (@jacek) commented about dlls/mshtml/tests/es5.js:
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(Object.prototype.hasOwnProperty.call(arr, "6"), "'6' not a property of " + name + "(9.1)[6]");
That's `arr.hasOwnProperty(...)`, there is more of those.
On Mon Oct 27 22:27:54 2025 +0000, Jacek Caban wrote:
I think it would be good to avoid using macros where possible, especially for generating entire functions. Instead, you could introduce typed array descriptors that hold the class, element size, and element getters/setters, e.g. `jsval_t get(const void*)` and `void set(void*, jsval_t)`. The constructor would take the descriptor, and the implementation could retrieve it from the "this" object when needed. Some sort of macro may still be useful, but something like:
#define ALL_TYPED_ARRAYS \ X(Int16Array) \ ...should be enough.
Sorry I don't understand, how will that help? The purpose of the macros generating the functions/`builtin_info_t` is to avoid boilerplate and copy-pasting (basically, almost-identical functions) for each Typed Array of a different type. The only things that change are e.g. variable types, the convert function, and so on. I can't use a function pointer since those functions take different types (and obviously compile to different code at machine level, like float vs int).
There's not much point to make indirection via getters/setters, since I'll have to write those methods for each Typed Array due to different types, and this was exactly what I wanted to avoid. Otherwise, without macros, I can simply just copy-paste the functions that are different (like the get/set) and change the type, what the macro is actually doing. Sort of how we have it for DataView. I mean, it will still be duplication, but at least no indirection.
I just don't see the point of having another getter/setter indirection? Even if we go without macros.
Also, do you mean we generate the `builtin_info_t` on the fly as well? Since that will also have to be duplicated (at the very least for the class!). Or can I use macro there at least?
On Tue Oct 28 17:36:49 2025 +0000, Gabriel Ivăncescu wrote:
Sorry I don't understand, how will that help? The purpose of the macros generating the functions/`builtin_info_t` is to avoid boilerplate and copy-pasting (basically, almost-identical functions) for each Typed Array of a different type. The only things that change are e.g. variable types, the convert function, and so on. I can't use a function pointer since those functions take different types (and obviously compile to different code at machine level, like float vs int). There's not much point to make indirection via getters/setters, since I'll have to write those methods for each Typed Array due to different types, and this was exactly what I wanted to avoid. Otherwise, without macros, I can simply just copy-paste the functions that are different (like the get/set) and change the type, what the macro is actually doing. Sort of how we have it for DataView. I mean, it will still be duplication, but at least no indirection. I just don't see the point of having another getter/setter indirection? Even if we go without macros. Also, do you mean we generate the `builtin_info_t` on the fly as well? Since that will also have to be duplicated (at the very least for the class!). Or can I use macro there at least?
As I said, some use of macros is fine, but I think some of the code that uses them doesn’t really need to. I’d need to try it myself to be sure, but I imagine we could have something like:
``` 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 const ... Uint8Array_type = { .size = sizeof(UINT8), .get = get_u8, .set = set_u8 }; ``` Then, instead of passing the class id around, you could pass the type descriptor with `&name##_type`. We could do something similar for the remaining ones, like `prop_put` and `prop_get`. All conversions go through `to_number`, and that’s the annoying part since it may fail. We could just call it in the common code and let the per-type functions handle conversion to and from double.
If you passed such a descriptor to `fill_typedarr_data_from_object` instead of the class id, you wouldn’t need the macro or the switch at all.
While using the class id is possible, it seems inconvenient, so I’d be tempted to bend the abstraction slightly and store the array type descriptor pointer in `builtin_info_t` itself. `isView` could simply check whether it’s non-null, and “this” validation could use that instead of the id. I’m not entirely sure though, maybe that part (or more of above) is not worth it.
On Wed Oct 29 00:52:56 2025 +0000, Jacek Caban wrote:
As I said, some use of macros is fine, but I think some of the code that uses them doesn’t really need to. I’d need to try it myself to be sure, but I imagine we could have something like:
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 const ... Uint8Array_type = { .size = sizeof(UINT8), .get = get_u8, .set = set_u8 };Then, instead of passing the class id around, you could pass the type descriptor with `&name##_type`. We could do something similar for the remaining ones, like `prop_put` and `prop_get`. All conversions go through `to_number`, and that’s the annoying part since it may fail. We could just call it in the common code and let the per-type functions handle conversion to and from double. If you passed such a descriptor to `fill_typedarr_data_from_object` instead of the class id, you wouldn’t need the macro or the switch at all. While using the class id is possible, it seems inconvenient, so I’d be tempted to bend the abstraction slightly and store the array type descriptor pointer in `builtin_info_t` itself. `isView` could simply check whether it’s non-null, and “this” validation could use that instead of the id. I’m not entirely sure though, maybe that part (or more of above) is not worth it.
So I tried a bunch of things and went with a compromise of sorts, still using only an `ALL_TYPED_ARRAYS` macro as suggested though. But now I'm passing "desc indices" around since I'm keeping the typed array descs into an array, which enables both looking it up and creating them by looping, and can also compute the class from them (needed in e.g. `TypedArray_get_byteLength`).
I didn't like the idea of extending `builtin_info_t` just for typed arrays, I think bleeding such object-specific entries outside arraybuf.c is not worth the complication. Also, isView should also work for DataView and those wouldn't have a desc in there.
Note that I still generate some functions via the macros, but those functions are just forwards to the underlying implementations, we just need to pass the desc idx so they know which type of array it is supposed to be.