From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 397 ++++++++++++++++++++++++++++++ dlls/jscript/error.c | 3 + dlls/jscript/jscript.h | 20 +- dlls/jscript/jscript.rc | 3 + dlls/jscript/jsutils.c | 2 +- dlls/jscript/object.c | 8 + dlls/jscript/resource.h | 3 + dlls/mshtml/tests/documentmode.js | 8 +- dlls/mshtml/tests/es5.js | 206 +++++++++++++++- 9 files changed, 643 insertions(+), 7 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index fc01773338f..bd530ec9cfd 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,353 @@ static const builtin_info_t DataViewConstr_info = { .call = Function_value, };
+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 void set_s8(void *p, double v) { *(INT8 *)p = double_to_int32(v); } +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 void set_s16(void *p, double v) { *(INT16 *)p = double_to_int32(v); } +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 void set_s32(void *p, double v) { *(INT32 *)p = double_to_int32(v); } +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; } + +/* NOTE: Keep in sync with the JSCLASS ordering of typed arrays */ +#define ALL_TYPED_ARRAYS \ +X(Int8Array) \ +X(Int16Array) \ +X(Int32Array) \ +X(Uint8Array) \ +X(Uint16Array) \ +X(Uint32Array) \ +X(Float32Array) \ +X(Float64Array) + +enum { +#define X(NAME) NAME ##_desc_idx, +ALL_TYPED_ARRAYS +#undef X +}; + +static const struct typed_array_desc typed_array_descs[NUM_TYPEDARRAY_TYPES] = { + [Int8Array_desc_idx] = { 1, get_s8, set_s8 }, + [Int16Array_desc_idx] = { 2, get_s16, set_s16 }, + [Int32Array_desc_idx] = { 4, get_s32, set_s32 }, + [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 inline TypedArrayInstance *typedarr_this(jsval_t vthis, unsigned desc_idx) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, FIRST_TYPEDARRAY_JSCLASS + desc_idx)) ? 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 * 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) +{ + 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(unsigned desc_idx, script_ctx_t *ctx, jsval_t vthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + TypedArrayInstance *typedarr; + + FIXME("not implemented\n"); + + if(!(typedarr = typedarr_this(vthis, desc_idx))) + return JS_E_NOT_TYPEDARRAY; + return E_NOTIMPL; +} + +static HRESULT TypedArray_subarray(unsigned desc_idx, script_ctx_t *ctx, jsval_t vthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + TypedArrayInstance *typedarr; + + FIXME("not implemented\n"); + + if(!(typedarr = typedarr_this(vthis, desc_idx))) + 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 inline HRESULT TypedArray_prop_get(unsigned desc_idx, 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(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; + + TRACE("%p[%u] = %s\n", typedarr, idx, debugstr_jsval(val)); + + 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 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) \ +static HRESULT NAME ##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + 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) \ +{ \ + return TypedArray_subarray(NAME ##_desc_idx, ctx, vthis, flags, argc, argv, r); \ +} \ + \ +static HRESULT NAME ##_prop_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) \ +{ \ + return TypedArray_prop_get(NAME ##_desc_idx, dispex, idx, r); \ +} \ + \ +static HRESULT NAME ##_prop_put(jsdisp_t *dispex, unsigned idx, jsval_t 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}, \ + {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}, \ +}; +ALL_TYPED_ARRAYS +#undef X + +#define X(NAME) \ +{ \ + .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 TypedArray_info[] = { ALL_TYPED_ARRAYS }; +#undef X + +#define X(NAME) \ +{ \ + .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 const builtin_info_t TypedArrayInst_info[] = { ALL_TYPED_ARRAYS }; +#undef X + +static HRESULT create_typedarr(unsigned desc_idx, 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, &TypedArrayInst_info[desc_idx], ctx->typedarr_constr[desc_idx]); + 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(unsigned desc_idx, script_ctx_t *ctx, jsval_t vthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + 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; + + 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(desc_idx, 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) \ +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(NAME ##_desc_idx, ctx, vthis, flags, argc, argv, r); \ +} +ALL_TYPED_ARRAYS +#undef X + +#define X(NAME) NAME ## Constr_value, +static const builtin_invoke_t TypedArray_constr[] = { ALL_TYPED_ARRAYS }; +#undef X + +#define X(NAME) L"" #NAME, +static const WCHAR *const TypedArray_name[] = { ALL_TYPED_ARRAYS }; +#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 +1055,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 +1127,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(typed_array_descs); 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(typed_array_descs[i].size)); + 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..99271e74b83 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*); @@ -320,6 +333,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*);
@@ -433,11 +447,12 @@ struct _script_ctx_t { jsdisp_t *vbarray_constr; jsdisp_t *arraybuf_constr; jsdisp_t *dataview_constr; + jsdisp_t *typedarr_constr[NUM_TYPEDARRAY_TYPES]; jsdisp_t *map_prototype; jsdisp_t *set_prototype; jsdisp_t *weakmap_prototype; }; - jsdisp_t *global_objects[25]; + jsdisp_t *global_objects[25 + NUM_TYPEDARRAY_TYPES]; }; }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); @@ -577,6 +592,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/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..87df5f86cbd 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(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(); + + /* 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",