diff --git a/dll/win32/jscript/CMakeLists.txt b/dll/win32/jscript/CMakeLists.txt index d201c6b67fe..43fa3f49e49 100644 --- a/dll/win32/jscript/CMakeLists.txt +++ b/dll/win32/jscript/CMakeLists.txt @@ -1,14 +1,10 @@ -add_definitions( - -D__WINESRC__ - -D__ROS_LONG64__ - -D_USE_MATH_DEFINES) - spec2def(jscript.dll jscript.spec) list(APPEND SOURCE activex.c array.c + arraybuf.c bool.c compile.c date.c @@ -30,21 +26,20 @@ list(APPEND SOURCE number.c object.c regexp.c + set.c string.c vbarray.c) -BISON_TARGET(cc_parser cc_parser.y ${CMAKE_CURRENT_BINARY_DIR}/cc_parser.tab.c COMPILE_FLAGS "-p cc_parser_") -BISON_TARGET(parser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.c COMPILE_FLAGS "-p parser_") +BISON_TARGET(cc_parser cc_parser.y ${CMAKE_CURRENT_BINARY_DIR}/cc_parser.tab.c) +BISON_TARGET(parser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.c) list(APPEND PCH_SKIP_SOURCE + guid.c ${BISON_cc_parser_OUTPUTS} ${BISON_parser_OUTPUTS}) list(APPEND jscript_rc_deps - ${CMAKE_CURRENT_SOURCE_DIR}/jscript.rgs - ${CMAKE_CURRENT_SOURCE_DIR}/jscript_classes.rgs - ${CMAKE_CURRENT_SOURCE_DIR}/jsglobal.rgs - ${CMAKE_CURRENT_BINARY_DIR}/jsglobal.tlb) + ${CMAKE_CURRENT_SOURCE_DIR}/jscript.rgs) set_source_files_properties(rsrc.rc PROPERTIES OBJECT_DEPENDS "${jscript_rc_deps}") @@ -54,8 +49,6 @@ add_library(jscript MODULE rsrc.rc ${CMAKE_CURRENT_BINARY_DIR}/jscript.def) -target_compile_definitions(jscript PRIVATE _CRT_NON_CONFORMING_SWPRINTFS) - if(MSVC) # Disable warning C4146: unary minus operator applied to unsigned type, result still unsigned # Disable warning C4267: '=': conversion from 'size_t' to 'WCHAR', possible loss of data @@ -63,10 +56,13 @@ if(MSVC) endif() add_idl_headers(jscript_idlheader jscript_classes.idl) -add_typelib(jsglobal.idl) -add_dependencies(jscript jscript_idlheader stdole2) +add_idl_headers(jscript_jsdisp_header jsdisp.idl) +add_idl_reg_scripts(jscript registry jscript_classes.idl) +add_idl_reg_scripts(jscript regtypelib jsglobal.idl) +add_dependencies(jscript jscript_idlheader jscript_jsdisp_header stdole2) set_module_type(jscript win32dll) -target_link_libraries(jscript uuid wine oldnames) +target_link_libraries(jscript uuid wine oldnames wine_dll_register) add_importlibs(jscript user32 ole32 oleaut32 advapi32 msvcrt kernel32 ntdll) add_pch(jscript precomp.h "${PCH_SKIP_SOURCE}") add_cd_file(TARGET jscript DESTINATION reactos/system32 FOR all) +set_wine_module_FIXME(jscript) # CORE-5743: No ARRAY_SIZE nor CONST_VTABLE diff --git a/dll/win32/jscript/activex.c b/dll/win32/jscript/activex.c index 1c2631cc774..a74f6acb529 100644 --- a/dll/win32/jscript/activex.c +++ b/dll/win32/jscript/activex.c @@ -138,7 +138,7 @@ static IUnknown *create_activex_object(script_ctx_t *ctx, const WCHAR *progid) return obj; } -static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT ActiveXObject_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t * progid_str; @@ -156,7 +156,7 @@ static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag if(ctx->safeopt != (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER) && ctx->safeopt != INTERFACE_USES_DISPEX) { - FIXME("Unsupported safeopt %x\n", ctx->safeopt); + FIXME("Unsupported safeopt %lx\n", ctx->safeopt); return E_NOTIMPL; } @@ -172,7 +172,7 @@ static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag obj = create_activex_object(ctx, progid); jsstr_release(progid_str); if(!obj) - return throw_generic_error(ctx, JS_E_CANNOT_CREATE_OBJ, NULL); + return JS_E_CANNOT_CREATE_OBJ; hres = IUnknown_QueryInterface(obj, &IID_IDispatch, (void**)&disp); IUnknown_Release(obj); @@ -181,7 +181,8 @@ static HRESULT ActiveXObject_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag return E_NOTIMPL; } - *r = jsval_disp(disp); + if(r) *r = jsval_disp(disp); + else IDispatch_Release(disp); return S_OK; } @@ -190,13 +191,11 @@ HRESULT create_activex_constr(script_ctx_t *ctx, jsdisp_t **ret) jsdisp_t *prototype; HRESULT hres; - static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0}; - hres = create_object(ctx, NULL, &prototype); if(FAILED(hres)) return hres; - hres = create_builtin_function(ctx, ActiveXObject_value, ActiveXObjectW, NULL, + hres = create_builtin_function(ctx, ActiveXObject_value, L"ActiveXObject", NULL, PROPF_CONSTR|1, prototype, ret); jsdisp_release(prototype); diff --git a/dll/win32/jscript/array.c b/dll/win32/jscript/array.c index fbd72e84be5..bf1785698a0 100644 --- a/dll/win32/jscript/array.c +++ b/dll/win32/jscript/array.c @@ -36,38 +36,15 @@ typedef struct { DWORD length; } ArrayInstance; -static const WCHAR lengthW[] = {'l','e','n','g','t','h',0}; -static const WCHAR concatW[] = {'c','o','n','c','a','t',0}; -static const WCHAR forEachW[] = {'f','o','r','E','a','c','h',0}; -static const WCHAR joinW[] = {'j','o','i','n',0}; -static const WCHAR popW[] = {'p','o','p',0}; -static const WCHAR pushW[] = {'p','u','s','h',0}; -static const WCHAR reverseW[] = {'r','e','v','e','r','s','e',0}; -static const WCHAR shiftW[] = {'s','h','i','f','t',0}; -static const WCHAR sliceW[] = {'s','l','i','c','e',0}; -static const WCHAR sortW[] = {'s','o','r','t',0}; -static const WCHAR spliceW[] = {'s','p','l','i','c','e',0}; -static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; -static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0}; -static const WCHAR unshiftW[] = {'u','n','s','h','i','f','t',0}; -static const WCHAR indexOfW[] = {'i','n','d','e','x','O','f',0}; -static const WCHAR mapW[] = {'m','a','p',0}; - -static const WCHAR default_separatorW[] = {',',0}; - static inline ArrayInstance *array_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, ArrayInstance, dispex); } -static inline ArrayInstance *array_from_vdisp(vdisp_t *vdisp) +static inline ArrayInstance *array_this(jsval_t vthis) { - return array_from_jsdisp(vdisp->u.jsdisp); -} - -static inline ArrayInstance *array_this(vdisp_t *jsthis) -{ - return is_vclass(jsthis, JSCLASS_ARRAY) ? array_from_vdisp(jsthis) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_ARRAY)) ? array_from_jsdisp(jsdisp) : NULL; } unsigned array_get_length(jsdisp_t *array) @@ -76,33 +53,38 @@ unsigned array_get_length(jsdisp_t *array) return array_from_jsdisp(array)->length; } -static HRESULT get_length(script_ctx_t *ctx, vdisp_t *vdisp, jsdisp_t **jsthis, DWORD *ret) +static HRESULT get_length(script_ctx_t *ctx, jsval_t vthis, jsdisp_t **jsthis, UINT32 *ret) { - ArrayInstance *array; + jsdisp_t *jsdisp; + IDispatch *disp; jsval_t val; HRESULT hres; - array = array_this(vdisp); - if(array) { - *jsthis = &array->dispex; - *ret = array->length; + hres = to_object(ctx, vthis, &disp); + if(FAILED(hres)) + return hres; + + jsdisp = iface_to_jsdisp(disp); + IDispatch_Release(disp); + if(!jsdisp) + return JS_E_JSCRIPT_EXPECTED; + *jsthis = jsdisp; + + if(is_class(jsdisp, JSCLASS_ARRAY)) { + *ret = array_from_jsdisp(jsdisp)->length; return S_OK; } - if(!is_jsdisp(vdisp)) - return throw_type_error(ctx, JS_E_JSCRIPT_EXPECTED, NULL); + hres = jsdisp_propget_name(jsdisp, L"length", &val); + if(SUCCEEDED(hres)) { + hres = to_uint32(ctx, val, ret); + jsval_release(val); + if(SUCCEEDED(hres)) + return hres; + } - hres = jsdisp_propget_name(vdisp->u.jsdisp, lengthW, &val); - if(FAILED(hres)) - return hres; - - hres = to_uint32(ctx, val, ret); - jsval_release(val); - if(FAILED(hres)) - return hres; - - *jsthis = vdisp->u.jsdisp; - return S_OK; + jsdisp_release(jsdisp); + return hres; } static HRESULT set_length(jsdisp_t *obj, DWORD length) @@ -112,10 +94,10 @@ static HRESULT set_length(jsdisp_t *obj, DWORD length) return S_OK; } - return jsdisp_propput_name(obj, lengthW, jsval_number(length)); + return jsdisp_propput_name(obj, L"length", jsval_number(length)); } -static WCHAR *idx_to_str(DWORD idx, WCHAR *ptr) +WCHAR *idx_to_str(DWORD idx, WCHAR *ptr) { if(!idx) { *ptr = '0'; @@ -145,7 +127,7 @@ static HRESULT Array_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t val DWORD i; HRESULT hres; - TRACE("%p %d\n", This, This->length); + TRACE("%p %ld\n", This, This->length); hres = to_number(ctx, value, &len); if(FAILED(hres)) @@ -153,7 +135,7 @@ static HRESULT Array_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t val len = floor(len); if(len!=(DWORD)len) - return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL); + return JS_E_INVALID_LENGTH; for(i=len; i < This->length; i++) { hres = jsdisp_delete_idx(&This->dispex, i); @@ -206,20 +188,25 @@ static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len) return jsdisp_propput_idx(array, (*len)++, jsval_disp(obj)); } -static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_concat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + IDispatch *jsthis; jsdisp_t *ret; DWORD len = 0; HRESULT hres; TRACE("\n"); - hres = create_array(ctx, 0, &ret); + hres = to_object(ctx, vthis, &jsthis); if(FAILED(hres)) return hres; - hres = concat_obj(ret, jsthis->u.disp, &len); + hres = create_array(ctx, 0, &ret); + if(FAILED(hres)) + goto done; + + hres = concat_obj(ret, jsthis, &len); if(SUCCEEDED(hres)) { DWORD i; @@ -234,17 +221,19 @@ static HRESULT Array_concat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi } if(FAILED(hres)) - return hres; + goto done; if(r) *r = jsval_obj(ret); else jsdisp_release(ret); +done: + IDispatch_Release(jsthis); return S_OK; } static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep, - unsigned seplen, jsval_t *r) + unsigned seplen, HRESULT (*to_string)(script_ctx_t*,jsval_t,jsstr_t**), jsval_t *r) { jsstr_t **str_tab, *ret = NULL; jsval_t val; @@ -257,7 +246,7 @@ static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, cons return S_OK; } - str_tab = heap_alloc_zero(length * sizeof(*str_tab)); + str_tab = calloc(length, sizeof(*str_tab)); if(!str_tab) return E_OUTOFMEMORY; @@ -319,7 +308,7 @@ static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, cons if(str_tab[i]) jsstr_release(str_tab[i]); } - heap_free(str_tab); + free(str_tab); if(FAILED(hres)) return hres; @@ -333,11 +322,11 @@ static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, cons } /* ECMA-262 3rd Edition 15.4.4.5 */ -static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_join(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; - DWORD length; + UINT32 length; HRESULT hres; TRACE("\n"); @@ -352,24 +341,26 @@ static HRESULT Array_join(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigne hres = to_flat_string(ctx, argv[0], &sep_str, &sep); if(FAILED(hres)) - return hres; + goto done; - hres = array_join(ctx, jsthis, length, sep, jsstr_length(sep_str), r); + hres = array_join(ctx, jsthis, length, sep, jsstr_length(sep_str), to_string, r); jsstr_release(sep_str); }else { - hres = array_join(ctx, jsthis, length, default_separatorW, lstrlenW(default_separatorW), r); + hres = array_join(ctx, jsthis, length, L",", 1, to_string, r); } +done: + jsdisp_release(jsthis); return hres; } -static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_pop(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; jsval_t val; - DWORD length; + UINT32 length; HRESULT hres; TRACE("\n"); @@ -381,11 +372,11 @@ static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned if(!length) { hres = set_length(jsthis, 0); if(FAILED(hres)) - return hres; + goto done; if(r) *r = jsval_undefined(); - return S_OK; + goto done; } length--; @@ -396,29 +387,31 @@ static HRESULT Array_pop(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned val = jsval_undefined(); hres = S_OK; }else - return hres; + goto done; if(SUCCEEDED(hres)) hres = set_length(jsthis, length); if(FAILED(hres)) { jsval_release(val); - return hres; + goto done; } if(r) *r = val; else jsval_release(val); +done: + jsdisp_release(jsthis); return hres; } /* ECMA-262 3rd Edition 15.4.4.7 */ -static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_push(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; - DWORD length = 0; + UINT32 length = 0; unsigned i; HRESULT hres; @@ -431,23 +424,25 @@ static HRESULT Array_push(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigne for(i=0; i < argc; i++) { hres = jsdisp_propput_idx(jsthis, length+i, argv[i]); if(FAILED(hres)) - return hres; + goto done; } hres = set_length(jsthis, length+argc); if(FAILED(hres)) - return hres; + goto done; if(r) *r = jsval_number(length+argc); - return S_OK; +done: + jsdisp_release(jsthis); + return hres; } -static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_reverse(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; - DWORD length, k, l; + UINT32 length, k, l; jsval_t v1, v2; HRESULT hres1, hres2; @@ -462,12 +457,13 @@ static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi hres1 = jsdisp_get_idx(jsthis, k, &v1); if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME) - return hres1; + goto done; hres2 = jsdisp_get_idx(jsthis, l, &v2); if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) { jsval_release(v1); - return hres2; + hres1 = hres2; + goto done; } if(hres1 == DISP_E_UNKNOWNNAME) @@ -478,7 +474,7 @@ static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi if(FAILED(hres1)) { jsval_release(v1); jsval_release(v2); - return hres1; + goto done; } if(hres2 == DISP_E_UNKNOWNNAME) @@ -488,21 +484,24 @@ static HRESULT Array_reverse(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi if(FAILED(hres2)) { jsval_release(v2); - return hres2; + hres1 = hres2; + goto done; } } if(r) *r = jsval_obj(jsdisp_addref(jsthis)); - return S_OK; +done: + jsdisp_release(jsthis); + return hres1; } /* ECMA-262 3rd Edition 15.4.4.9 */ -static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_shift(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; - DWORD length = 0, i; + UINT32 length = 0, i; jsval_t v, ret; HRESULT hres; @@ -515,11 +514,11 @@ static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsign if(!length) { hres = set_length(jsthis, 0); if(FAILED(hres)) - return hres; + goto done; if(r) *r = jsval_undefined(); - return S_OK; + goto done; } hres = jsdisp_get_idx(jsthis, 0, &ret); @@ -532,8 +531,10 @@ static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsign hres = jsdisp_get_idx(jsthis, i, &v); if(hres == DISP_E_UNKNOWNNAME) hres = jsdisp_delete_idx(jsthis, i-1); - else if(SUCCEEDED(hres)) + else if(SUCCEEDED(hres)) { hres = jsdisp_propput_idx(jsthis, i-1, v); + jsval_release(v); + } } if(SUCCEEDED(hres)) { @@ -543,21 +544,23 @@ static HRESULT Array_shift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsign } if(FAILED(hres)) - return hres; + goto done; if(r) *r = ret; else jsval_release(ret); +done: + jsdisp_release(jsthis); return hres; } /* ECMA-262 3rd Edition 15.4.4.10 */ -static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Array_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *arr, *jsthis; DOUBLE range; - DWORD length, start, end, idx; + UINT32 length, start, end, idx; HRESULT hres; TRACE("\n"); @@ -569,7 +572,7 @@ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsign if(argc) { hres = to_number(ctx, argv[0], &range); if(FAILED(hres)) - return hres; + goto done; range = floor(range); if(-range>length || isnan(range)) start = 0; @@ -582,7 +585,7 @@ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsign if(argc > 1) { hres = to_number(ctx, argv[1], &range); if(FAILED(hres)) - return hres; + goto done; range = floor(range); if(-range>length) end = 0; @@ -594,7 +597,7 @@ static HRESULT Array_slice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsign hres = create_array(ctx, (end>start)?end-start:0, &arr); if(FAILED(hres)) - return hres; + goto done; for(idx=start; idx 1) { - WARN("invalid arg_cnt %d\n", argc); - return E_FAIL; - } - - if(argc == 1) { - if(!is_object_instance(argv[0])) { - WARN("arg is not dispatch\n"); - return E_FAIL; - } - - cmp_func = iface_to_jsdisp(get_object(argv[0])); - if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) { - WARN("cmp_func is not a function\n"); - if(cmp_func) - jsdisp_release(cmp_func); - return E_FAIL; + if(argc >= 1) { + if(is_object_instance(argv[0])) { + if(argc > 1 && ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + WARN("invalid arg_cnt %d\n", argc); + hres = JS_E_JSCRIPT_EXPECTED; + goto done; + } + cmp_func = iface_to_jsdisp(get_object(argv[0])); + if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) { + WARN("cmp_func is not a function\n"); + if(cmp_func) + jsdisp_release(cmp_func); + hres = JS_E_JSCRIPT_EXPECTED; + goto done; + } + }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? !is_undefined(argv[0]) : + (!is_null(argv[0]) || is_null_disp(argv[0]))) { + WARN("invalid arg %s\n", debugstr_jsval(argv[0])); + hres = JS_E_JSCRIPT_EXPECTED; + goto done; } } @@ -717,10 +723,10 @@ static HRESULT Array_sort(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigne jsdisp_release(cmp_func); if(r) *r = jsval_obj(jsdisp_addref(jsthis)); - return S_OK; + goto done; } - vtab = heap_alloc_zero(length * sizeof(*vtab)); + vtab = calloc(length, sizeof(*vtab)); if(vtab) { for(i=0; i= 0) @@ -858,7 +866,7 @@ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsig if(argc >= 2) { hres = to_integer(ctx, argv[1], &d); if(FAILED(hres)) - return hres; + goto done; if(is_int32(d)) { if((n = d) > 0) @@ -868,12 +876,14 @@ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsig } add_args = argc-2; + } else if (argc && ctx->version >= SCRIPTLANGUAGEVERSION_ES5) { + delete_cnt = length-start; } if(r) { hres = create_array(ctx, 0, &ret_array); if(FAILED(hres)) - return hres; + goto done; for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) { hres = jsdisp_get_idx(jsthis, start+i, &val); @@ -886,7 +896,7 @@ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsig } if(SUCCEEDED(hres)) - hres = jsdisp_propput_name(ret_array, lengthW, jsval_number(delete_cnt)); + hres = jsdisp_propput_name(ret_array, L"length", jsval_number(delete_cnt)); } if(add_args < delete_cnt) { @@ -918,46 +928,247 @@ static HRESULT Array_splice(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsig hres = jsdisp_propput_idx(jsthis, start+i, argv[i+2]); if(SUCCEEDED(hres)) - hres = jsdisp_propput_name(jsthis, lengthW, jsval_number(length-delete_cnt+add_args)); + hres = jsdisp_propput_name(jsthis, L"length", jsval_number(length-delete_cnt+add_args)); if(FAILED(hres)) { if(ret_array) jsdisp_release(ret_array); - return hres; + goto done; } if(r) *r = jsval_obj(ret_array); - return S_OK; +done: + jsdisp_release(jsthis); + return hres; } /* ECMA-262 3rd Edition 15.4.4.2 */ -static HRESULT Array_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { ArrayInstance *array; TRACE("\n"); - array = array_this(jsthis); + array = array_this(vthis); if(!array) - return throw_type_error(ctx, JS_E_ARRAY_EXPECTED, NULL); + return JS_E_ARRAY_EXPECTED; - return array_join(ctx, &array->dispex, array->length, default_separatorW, - lstrlenW(default_separatorW), r); + return array_join(ctx, &array->dispex, array->length, L",", 1, to_string, r); } -static HRESULT Array_toLocaleString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, - jsval_t *r) +static HRESULT to_locale_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str) { - FIXME("\n"); - return E_NOTIMPL; + jsdisp_t *jsdisp; + IDispatch *obj; + HRESULT hres; + + switch(jsval_type(val)) { + case JSV_OBJECT: + hres = disp_call_name(ctx, get_object(val), L"toLocaleString", DISPATCH_METHOD, 0, NULL, &val); + if(FAILED(hres)) { + if(hres == JS_E_INVALID_PROPERTY && ctx->version >= SCRIPTLANGUAGEVERSION_ES5) + hres = JS_E_FUNCTION_EXPECTED; + return hres; + } + break; + case JSV_NUMBER: + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) + return localize_number(ctx, get_number(val), FALSE, str); + /* fall through */ + default: + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) + break; + + hres = to_object(ctx, val, &obj); + if(FAILED(hres)) + return hres; + + jsdisp = as_jsdisp(obj); + hres = jsdisp_call_name(jsdisp, L"toLocaleString", DISPATCH_METHOD, 0, NULL, &val); + jsdisp_release(jsdisp); + if(FAILED(hres)) + return hres; + break; + } + + return to_string(ctx, val, str); } -static HRESULT Array_forEach(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + jsdisp_t *jsthis; + UINT32 length; + HRESULT hres; + WCHAR buf[5]; + int len; + + TRACE("\n"); + + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + ArrayInstance *array = array_this(vthis); + if(!array) + return JS_E_ARRAY_EXPECTED; + jsthis = jsdisp_addref(&array->dispex); + length = array->length; + }else { + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) + return hres; + } + + if(!(len = GetLocaleInfoW(ctx->lcid, LOCALE_SLIST, buf, ARRAY_SIZE(buf) - 1))) { + buf[len++] = ','; + len++; + } + buf[len - 1] = ' '; + buf[len] = '\0'; + + hres = array_join(ctx, jsthis, length, buf, len, to_locale_string, r); + jsdisp_release(jsthis); + return hres; +} + +static HRESULT Array_every(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + jsval_t context_this = jsval_undefined(); jsval_t value, args[3], res; + BOOL boolval, ret = TRUE; + IDispatch *callback; + unsigned length, i; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) + return hres; + + /* FIXME: check IsCallable */ + if(!argc || !is_object_instance(argv[0])) { + FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); + hres = E_INVALIDARG; + goto done; + } + callback = get_object(argv[0]); + + if(argc > 1) + context_this = argv[1]; + + for(i = 0; i < length; i++) { + hres = jsdisp_get_idx(jsthis, i, &value); + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) + continue; + goto done; + } + args[0] = value; + args[1] = jsval_number(i); + args[2] = jsval_obj(jsthis); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + jsval_release(value); + if(FAILED(hres)) + goto done; + + hres = to_boolean(res, &boolval); + jsval_release(res); + if(FAILED(hres)) + goto done; + if(!boolval) { + ret = FALSE; + break; + } + } + + if(r) + *r = jsval_bool(ret); + hres = S_OK; +done: + jsdisp_release(jsthis); + return hres; +} + +static HRESULT Array_filter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + jsval_t context_this = jsval_undefined(); + jsval_t value, args[3], res; + unsigned length, i, j = 0; + jsdisp_t *jsthis, *arr; + IDispatch *callback; + HRESULT hres; + BOOL boolval; + + TRACE("\n"); + + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) + return hres; + + /* FIXME: check IsCallable */ + if(!argc || !is_object_instance(argv[0])) { + FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); + hres = E_INVALIDARG; + goto done; + } + callback = get_object(argv[0]); + + if(argc > 1) + context_this = argv[1]; + + hres = create_array(ctx, 0, &arr); + if(FAILED(hres)) + goto done; + + for(i = 0; i < length; i++) { + hres = jsdisp_get_idx(jsthis, i, &value); + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) { + hres = S_OK; + continue; + } + break; + } + args[0] = value; + args[1] = jsval_number(i); + args[2] = jsval_obj(jsthis); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + if(SUCCEEDED(hres)) { + hres = to_boolean(res, &boolval); + jsval_release(res); + if(SUCCEEDED(hres) && boolval) + hres = jsdisp_propput_idx(arr, j++, value); + } + jsval_release(value); + if(FAILED(hres)) + break; + } + + if(FAILED(hres)) { + jsdisp_release(arr); + goto done; + } + set_length(arr, j); + + if(r) + *r = jsval_obj(arr); + else + jsdisp_release(arr); +done: + jsdisp_release(jsthis); + return hres; +} + +static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + jsval_t context_this = jsval_undefined(); + jsval_t value, args[3], res; + IDispatch *callback; jsdisp_t *jsthis; unsigned length, i; HRESULT hres; @@ -969,38 +1180,41 @@ static HRESULT Array_forEach(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi return hres; /* Fixme check IsCallable */ - if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { + if(!argc || !is_object_instance(argv[0])) { FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); - return E_INVALIDARG; + hres = E_INVALIDARG; + goto done; } + callback = get_object(argv[0]); - if(argc > 1 && !is_undefined(argv[1])) { - FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1])); - return E_NOTIMPL; - } + if(argc > 1) + context_this = argv[1]; for(i = 0; i < length; i++) { hres = jsdisp_get_idx(jsthis, i, &value); if(hres == DISP_E_UNKNOWNNAME) continue; if(FAILED(hres)) - return hres; + goto done; args[0] = value; args[1] = jsval_number(i); args[2] = jsval_obj(jsthis); - hres = disp_call_value(ctx, get_object(argv[0]), NULL, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); jsval_release(value); if(FAILED(hres)) - return hres; + goto done; jsval_release(res); } if(r) *r = jsval_undefined(); - return S_OK; + hres = S_OK; +done: + jsdisp_release(jsthis); + return hres; } -static HRESULT Array_indexOf(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_indexOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; @@ -1016,7 +1230,7 @@ static HRESULT Array_indexOf(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi return hres; if(!length) { if(r) *r = jsval_number(-1); - return S_OK; + goto done; } search = argc ? argv[0] : jsval_undefined(); @@ -1026,7 +1240,7 @@ static HRESULT Array_indexOf(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi hres = to_integer(ctx, argv[1], &from_arg); if(FAILED(hres)) - return hres; + goto done; if(from_arg >= 0) from = min(from_arg, length); @@ -1039,28 +1253,94 @@ static HRESULT Array_indexOf(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi if(hres == DISP_E_UNKNOWNNAME) continue; if(FAILED(hres)) - return hres; + goto done; hres = jsval_strict_equal(value, search, &eq); jsval_release(value); if(FAILED(hres)) - return hres; + goto done; if(eq) { if(r) *r = jsval_number(i); - return S_OK; + goto done; } } if(r) *r = jsval_number(-1); - return S_OK; + hres = S_OK; +done: + jsdisp_release(jsthis); + return hres; } -static HRESULT Array_map(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Array_lastIndexOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) { - IDispatch *context_this = NULL, *callback; + jsval_t search, value; + unsigned i, length; + jsdisp_t *jsthis; + HRESULT hres; + BOOL eq; + + TRACE("\n"); + + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) + return hres; + if(!length) + goto notfound; + + search = argc ? argv[0] : jsval_undefined(); + + i = length - 1; + if(argc > 1) { + double from_arg; + + hres = to_integer(ctx, argv[1], &from_arg); + if(FAILED(hres)) + goto done; + + if(from_arg >= 0.0) + i = min(from_arg, i); + else { + from_arg += length; + if(from_arg < 0.0) + goto notfound; + i = from_arg; + } + } + + do { + hres = jsdisp_get_idx(jsthis, i, &value); + if(hres == DISP_E_UNKNOWNNAME) + continue; + if(FAILED(hres)) + goto done; + + hres = jsval_strict_equal(value, search, &eq); + jsval_release(value); + if(FAILED(hres)) + goto done; + if(eq) { + if(r) *r = jsval_number(i); + goto done; + } + } while(i--); + +notfound: + if(r) *r = jsval_number(-1); + hres = S_OK; +done: + jsdisp_release(jsthis); + return hres; +} + +static HRESULT Array_map(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + jsval_t context_this = jsval_undefined(); jsval_t callback_args[3], mapped_value; jsdisp_t *jsthis, *array; - DWORD length, k; + IDispatch *callback; + UINT32 length, k; HRESULT hres; TRACE("\n"); @@ -1071,30 +1351,27 @@ static HRESULT Array_map(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned return hres; } - /* Fixme check IsCallable */ - if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { + /* FIXME: check IsCallable */ + if(!argc || !is_object_instance(argv[0])) { FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); - return E_INVALIDARG; + hres = E_INVALIDARG; + goto done; } callback = get_object(argv[0]); - if(argc > 1) { - if(is_object_instance(argv[1]) && get_object(argv[1])) { - context_this = get_object(argv[1]); - }else if(!is_undefined(argv[1])) { - FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1])); - return E_NOTIMPL; - } - } + if(argc > 1) + context_this = argv[1]; - hres = create_array(ctx, length, &array); + hres = create_array(ctx, 0, &array); if(FAILED(hres)) - return hres; + goto done; for(k = 0; k < length; k++) { hres = jsdisp_get_idx(jsthis, k, &callback_args[0]); - if(hres == DISP_E_UNKNOWNNAME) + if(hres == DISP_E_UNKNOWNNAME) { + hres = S_OK; continue; + } if(FAILED(hres)) break; @@ -1114,16 +1391,152 @@ static HRESULT Array_map(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned *r = jsval_obj(array); else jsdisp_release(array); +done: + jsdisp_release(jsthis); + return hres; +} + +static HRESULT Array_reduce(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + jsval_t callback_args[4], acc, new_acc; + BOOL have_value = FALSE; + IDispatch *callback; + jsdisp_t *jsthis; + UINT32 length, k; + HRESULT hres; + + TRACE("\n"); + + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) { + FIXME("Could not get length\n"); + return hres; + } + + /* Fixme check IsCallable */ + if(!argc || !is_object_instance(argv[0])) { + FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); + hres = E_INVALIDARG; + goto done; + } + callback = get_object(argv[0]); + + if(argc > 1) { + have_value = TRUE; + hres = jsval_copy(argv[1], &acc); + if(FAILED(hres)) + goto done; + } + + for(k = 0; k < length; k++) { + hres = jsdisp_get_idx(jsthis, k, &callback_args[1]); + if(hres == DISP_E_UNKNOWNNAME) { + hres = S_OK; + continue; + } + if(FAILED(hres)) + break; + + if(!have_value) { + have_value = TRUE; + acc = callback_args[1]; + continue; + } + + callback_args[0] = acc; + callback_args[2] = jsval_number(k); + callback_args[3] = jsval_obj(jsthis); + hres = disp_call_value(ctx, callback, jsval_undefined(), DISPATCH_METHOD, ARRAY_SIZE(callback_args), callback_args, &new_acc); + jsval_release(callback_args[1]); + if(FAILED(hres)) + break; + + jsval_release(acc); + acc = new_acc; + } + + if(SUCCEEDED(hres) && !have_value) { + WARN("No array element\n"); + hres = JS_E_INVALID_ACTION; + } + + if(SUCCEEDED(hres) && r) + *r = acc; + else if(have_value) + jsval_release(acc); +done: + jsdisp_release(jsthis); + return hres; +} + +static HRESULT Array_some(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + jsval_t context_this = jsval_undefined(); + jsval_t value, args[3], res; + BOOL boolval, ret = FALSE; + IDispatch *callback; + unsigned length, i; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) + return hres; + + /* FIXME: check IsCallable */ + if(!argc || !is_object_instance(argv[0])) { + FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); + hres = E_INVALIDARG; + goto done; + } + callback = get_object(argv[0]); + + if(argc > 1) + context_this = argv[1]; + + for(i = 0; i < length; i++) { + hres = jsdisp_get_idx(jsthis, i, &value); + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) + continue; + goto done; + } + args[0] = value; + args[1] = jsval_number(i); + args[2] = jsval_obj(jsthis); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + jsval_release(value); + if(FAILED(hres)) + goto done; + + hres = to_boolean(res, &boolval); + jsval_release(res); + if(FAILED(hres)) + goto done; + if(boolval) { + ret = TRUE; + break; + } + } + + if(r) + *r = jsval_bool(ret); + hres = S_OK; +done: + jsdisp_release(jsthis); return hres; } /* ECMA-262 3rd Edition 15.4.4.13 */ -static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Array_unshift(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; WCHAR buf[14], *buf_end, *str; - DWORD i, length; + UINT32 i, length; jsval_t val; DISPID id; HRESULT hres; @@ -1146,50 +1559,38 @@ static HRESULT Array_unshift(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsi if(SUCCEEDED(hres)) { hres = jsdisp_propget(jsthis, id, &val); if(FAILED(hres)) - return hres; + goto done; hres = jsdisp_propput_idx(jsthis, i+argc, val); jsval_release(val); }else if(hres == DISP_E_UNKNOWNNAME) { - hres = IDispatchEx_DeleteMemberByDispID(vthis->u.dispex, id); + hres = IDispatchEx_DeleteMemberByDispID(to_dispex(jsthis), id); } } if(FAILED(hres)) - return hres; + goto done; } for(i=0; iversion < 2 ? jsval_undefined() : jsval_number(length); - return S_OK; -} - -static HRESULT Array_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - ArrayInstance *array = array_from_jsdisp(jsthis); - - TRACE("\n"); - - return array_join(ctx, &array->dispex, array->length, default_separatorW, - lstrlenW(default_separatorW), r); -} - -static void Array_destructor(jsdisp_t *dispex) -{ - heap_free(dispex); + hres = S_OK; +done: + jsdisp_release(jsthis); + return hres; } static void Array_on_put(jsdisp_t *dispex, const WCHAR *name) @@ -1198,10 +1599,10 @@ static void Array_on_put(jsdisp_t *dispex, const WCHAR *name) const WCHAR *ptr = name; DWORD id = 0; - if(!iswdigit(*ptr)) + if(!is_digit(*ptr)) return; - while(*ptr && iswdigit(*ptr)) { + while(*ptr && is_digit(*ptr)) { id = id*10 + (*ptr-'0'); ptr++; } @@ -1214,48 +1615,49 @@ static void Array_on_put(jsdisp_t *dispex, const WCHAR *name) } static const builtin_prop_t Array_props[] = { - {concatW, Array_concat, PROPF_METHOD|1}, - {forEachW, Array_forEach, PROPF_METHOD|PROPF_ES5|1}, - {indexOfW, Array_indexOf, PROPF_METHOD|PROPF_ES5|1}, - {joinW, Array_join, PROPF_METHOD|1}, - {lengthW, NULL,0, Array_get_length, Array_set_length}, - {mapW, Array_map, PROPF_METHOD|PROPF_ES5|1}, - {popW, Array_pop, PROPF_METHOD}, - {pushW, Array_push, PROPF_METHOD|1}, - {reverseW, Array_reverse, PROPF_METHOD}, - {shiftW, Array_shift, PROPF_METHOD}, - {sliceW, Array_slice, PROPF_METHOD|2}, - {sortW, Array_sort, PROPF_METHOD|1}, - {spliceW, Array_splice, PROPF_METHOD|2}, - {toLocaleStringW, Array_toLocaleString, PROPF_METHOD}, - {toStringW, Array_toString, PROPF_METHOD}, - {unshiftW, Array_unshift, PROPF_METHOD|1}, + {L"concat", Array_concat, PROPF_METHOD|1}, + {L"every", Array_every, PROPF_METHOD|PROPF_ES5|1}, + {L"filter", Array_filter, PROPF_METHOD|PROPF_ES5|1}, + {L"forEach", Array_forEach, PROPF_METHOD|PROPF_ES5|1}, + {L"indexOf", Array_indexOf, PROPF_METHOD|PROPF_ES5|1}, + {L"join", Array_join, PROPF_METHOD|1}, + {L"lastIndexOf", Array_lastIndexOf, PROPF_METHOD|PROPF_ES5|1}, + {L"length", NULL,0, Array_get_length, Array_set_length}, + {L"map", Array_map, PROPF_METHOD|PROPF_ES5|1}, + {L"pop", Array_pop, PROPF_METHOD}, + {L"push", Array_push, PROPF_METHOD|1}, + {L"reduce", Array_reduce, PROPF_METHOD|PROPF_ES5|1}, + {L"reverse", Array_reverse, PROPF_METHOD}, + {L"shift", Array_shift, PROPF_METHOD}, + {L"slice", Array_slice, PROPF_METHOD|2}, + {L"some", Array_some, PROPF_METHOD|PROPF_ES5|1}, + {L"sort", Array_sort, PROPF_METHOD|1}, + {L"splice", Array_splice, PROPF_METHOD|2}, + {L"toLocaleString", Array_toLocaleString, PROPF_METHOD}, + {L"toString", Array_toString, PROPF_METHOD}, + {L"unshift", Array_unshift, PROPF_METHOD|1}, }; static const builtin_info_t Array_info = { - JSCLASS_ARRAY, - {NULL, NULL,0, Array_get_value}, - ARRAY_SIZE(Array_props), - Array_props, - Array_destructor, - Array_on_put + .class = JSCLASS_ARRAY, + .props_cnt = ARRAY_SIZE(Array_props), + .props = Array_props, + .on_put = Array_on_put, }; static const builtin_prop_t ArrayInst_props[] = { - {lengthW, NULL,0, Array_get_length, Array_set_length} + {L"length", NULL,0, Array_get_length, Array_set_length} }; static const builtin_info_t ArrayInst_info = { - JSCLASS_ARRAY, - {NULL, NULL,0, Array_get_value}, - ARRAY_SIZE(ArrayInst_props), - ArrayInst_props, - Array_destructor, - Array_on_put + .class = JSCLASS_ARRAY, + .props_cnt = ARRAY_SIZE(ArrayInst_props), + .props = ArrayInst_props, + .on_put = Array_on_put, }; /* ECMA-262 5.1 Edition 15.4.3.2 */ -static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *obj; @@ -1266,13 +1668,12 @@ static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, vdisp_t *vthis, WORD flags return S_OK; } - obj = iface_to_jsdisp(get_object(argv[0])); + obj = to_jsdisp(get_object(argv[0])); if(r) *r = jsval_bool(obj && is_class(obj, JSCLASS_ARRAY)); - if(obj) jsdisp_release(obj); return S_OK; } -static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT ArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *obj; @@ -1288,7 +1689,9 @@ static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, double n = get_number(argv[0]); if(n < 0 || !is_int32(n)) - return throw_range_error(ctx, JS_E_INVALID_LENGTH, NULL); + return JS_E_INVALID_LENGTH; + if(!r) + return S_OK; hres = create_array(ctx, n, &obj); if(FAILED(hres)) @@ -1298,6 +1701,8 @@ static HRESULT ArrayConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, return S_OK; } + if(!r) + return S_OK; hres = create_array(ctx, argc, &obj); if(FAILED(hres)) return hres; @@ -1328,7 +1733,7 @@ static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayI ArrayInstance *array; HRESULT hres; - array = heap_alloc_zero(sizeof(ArrayInstance)); + array = calloc(1, sizeof(ArrayInstance)); if(!array) return E_OUTOFMEMORY; @@ -1338,7 +1743,7 @@ static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayI hres = init_dispex_from_constr(&array->dispex, ctx, &ArrayInst_info, ctx->array_constr); if(FAILED(hres)) { - heap_free(array); + free(array); return hres; } @@ -1346,19 +1751,15 @@ static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayI return S_OK; } -static const WCHAR isArrayW[] = {'i','s','A','r','r','a','y',0}; - static const builtin_prop_t ArrayConstr_props[] = { - {isArrayW, ArrayConstr_isArray, PROPF_ES5|PROPF_METHOD|1} + {L"isArray", ArrayConstr_isArray, PROPF_ES5|PROPF_METHOD|1} }; static const builtin_info_t ArrayConstr_info = { - JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, - ARRAY_SIZE(ArrayConstr_props), - ArrayConstr_props, - NULL, - NULL + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(ArrayConstr_props), + .props = ArrayConstr_props, }; HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) @@ -1366,13 +1767,11 @@ HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdis ArrayInstance *array; HRESULT hres; - static const WCHAR ArrayW[] = {'A','r','r','a','y',0}; - hres = alloc_array(ctx, object_prototype, &array); if(FAILED(hres)) return hres; - hres = create_builtin_constructor(ctx, ArrayConstr_value, ArrayW, &ArrayConstr_info, PROPF_CONSTR|1, &array->dispex, ret); + hres = create_builtin_constructor(ctx, ArrayConstr_value, L"Array", &ArrayConstr_info, PROPF_CONSTR|1, &array->dispex, ret); jsdisp_release(&array->dispex); return hres; diff --git a/dll/win32/jscript/arraybuf.c b/dll/win32/jscript/arraybuf.c new file mode 100644 index 00000000000..81a151e006a --- /dev/null +++ b/dll/win32/jscript/arraybuf.c @@ -0,0 +1,776 @@ +/* + * Copyright 2024 Gabriel Ivăncescu for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include + +#include "jscript.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(jscript); + +typedef struct { + jsdisp_t dispex; + DWORD size; +/* FIXME: Inspect */ +#if defined(__REACTOS__) && defined(_MSC_VER) + DECLSPEC_ALIGN(8) BYTE buf[]; +#else + DECLSPEC_ALIGN(sizeof(double)) BYTE buf[]; +#endif +} ArrayBufferInstance; + +typedef struct { + jsdisp_t dispex; + + ArrayBufferInstance *buffer; + DWORD offset; + DWORD size; +} DataViewInstance; + +static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex); +} + +static inline DataViewInstance *dataview_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, DataViewInstance, dispex); +} + +static inline ArrayBufferInstance *arraybuf_this(jsval_t vthis) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_ARRAYBUFFER)) ? arraybuf_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT create_arraybuf(script_ctx_t*,DWORD,ArrayBufferInstance**); + +static HRESULT ArrayBuffer_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(arraybuf_from_jsdisp(jsthis)->size); + return S_OK; +} + +static HRESULT ArrayBuffer_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + ArrayBufferInstance *arraybuf, *ret; + DWORD begin = 0, end, size; + HRESULT hres; + double n; + + TRACE("\n"); + + if(!(arraybuf = arraybuf_this(vthis))) + return JS_E_ARRAYBUFFER_EXPECTED; + end = arraybuf->size; + if(!r) + return S_OK; + + if(argc) { + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += arraybuf->size; + if(n >= 0.0 && n < arraybuf->size) { + begin = n; + if(argc > 1 && !is_undefined(argv[1])) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += arraybuf->size; + if(n >= 0.0) { + end = n < arraybuf->size ? n : arraybuf->size; + end = end < begin ? begin : end; + }else + end = begin; + } + }else + end = 0; + } + + size = end - begin; + hres = create_arraybuf(ctx, size, &ret); + if(FAILED(hres)) + return hres; + memcpy(ret->buf, arraybuf->buf + begin, size); + + *r = jsval_obj(&ret->dispex); + return S_OK; +} + +static const builtin_prop_t ArrayBuffer_props[] = { + {L"byteLength", NULL, 0, ArrayBuffer_get_byteLength}, + {L"slice", ArrayBuffer_slice, PROPF_METHOD|2}, +}; + +static const builtin_info_t ArrayBuffer_info = { + .class = JSCLASS_ARRAYBUFFER, + .props_cnt = ARRAY_SIZE(ArrayBuffer_props), + .props = ArrayBuffer_props, +}; + +static const builtin_prop_t ArrayBufferInst_props[] = { + {L"byteLength", NULL, 0, ArrayBuffer_get_byteLength}, +}; + +static const builtin_info_t ArrayBufferInst_info = { + .class = JSCLASS_ARRAYBUFFER, + .props_cnt = ARRAY_SIZE(ArrayBufferInst_props), + .props = ArrayBufferInst_props, +}; + +static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, ArrayBufferInstance **ret) +{ + ArrayBufferInstance *arraybuf; + HRESULT hres; + + if(!(arraybuf = calloc(1, FIELD_OFFSET(ArrayBufferInstance, buf[size])))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&arraybuf->dispex, ctx, &ArrayBufferInst_info, ctx->arraybuf_constr); + if(FAILED(hres)) { + free(arraybuf); + return hres; + } + arraybuf->size = size; + + *ret = arraybuf; + return S_OK; +} + +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"); + + return E_NOTIMPL; +} + +static HRESULT ArrayBufferConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + ArrayBufferInstance *arraybuf; + DWORD size = 0; + HRESULT hres; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(argc) { + double n; + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + return JS_E_INVALID_LENGTH; + if(n > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + size = n; + } + + if(r) { + hres = create_arraybuf(ctx, size, &arraybuf); + if(FAILED(hres)) + return hres; + *r = jsval_obj(&arraybuf->dispex); + } + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +static const builtin_prop_t ArrayBufferConstr_props[] = { + {L"isView", ArrayBufferConstr_isView, PROPF_METHOD|1}, +}; + +static const builtin_info_t ArrayBufferConstr_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(ArrayBufferConstr_props), + .props = ArrayBufferConstr_props, +}; + +static inline DataViewInstance *dataview_this(jsval_t vthis) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_DATAVIEW)) ? dataview_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT DataView_get_buffer(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DataViewInstance *view; + + TRACE("\n"); + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(r) *r = jsval_obj(jsdisp_addref(&view->buffer->dispex)); + return S_OK; +} + +static HRESULT DataView_get_byteLength(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DataViewInstance *view; + + TRACE("\n"); + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(r) *r = jsval_number(view->size); + return S_OK; +} + +static HRESULT DataView_get_byteOffset(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DataViewInstance *view; + + TRACE("\n"); + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(r) *r = jsval_number(view->offset); + return S_OK; +} + +static inline void copy_type_data(void *dst, const void *src, unsigned type_size, BOOL little_endian) +{ + const BYTE *in = src; + BYTE *out = dst; + unsigned i; + + if(little_endian) + memcpy(out, in, type_size); + else + for(i = 0; i < type_size; i++) + out[i] = in[type_size - i - 1]; +} + +static HRESULT get_data(script_ctx_t *ctx, jsval_t vthis, unsigned argc, jsval_t *argv, unsigned type_size, void *ret) +{ + BOOL little_endian = FALSE; + DataViewInstance *view; + HRESULT hres; + DWORD offset; + BYTE *data; + double n; + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(!argc || is_undefined(argv[0])) + return JS_E_DATAVIEW_NO_ARGUMENT; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + + if(n < 0.0 || n + type_size > view->size) + return JS_E_DATAVIEW_INVALID_ACCESS; + + offset = n; + data = &view->buffer->buf[view->offset + offset]; + + if(type_size == 1) { + *(BYTE*)ret = data[0]; + return S_OK; + } + + if(argc > 1) { + hres = to_boolean(argv[1], &little_endian); + if(FAILED(hres)) + return hres; + } + + copy_type_data(ret, data, type_size, little_endian); + return S_OK; +} + +static HRESULT set_data(script_ctx_t *ctx, jsval_t vthis, unsigned argc, jsval_t *argv, unsigned type_size, const void *val) +{ + BOOL little_endian = FALSE; + DataViewInstance *view; + HRESULT hres; + DWORD offset; + BYTE *data; + double n; + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(is_undefined(argv[0]) || is_undefined(argv[1])) + return JS_E_DATAVIEW_NO_ARGUMENT; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + + if(n < 0.0 || n + type_size > view->size) + return JS_E_DATAVIEW_INVALID_ACCESS; + + offset = n; + data = &view->buffer->buf[view->offset + offset]; + + if(type_size == 1) { + data[0] = *(const BYTE*)val; + return S_OK; + } + + if(argc > 2) { + hres = to_boolean(argv[2], &little_endian); + if(FAILED(hres)) + return hres; + } + + copy_type_data(data, val, type_size, little_endian); + return S_OK; +} + +static HRESULT DataView_getFloat32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + float v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getFloat64(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + double v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getInt8(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT8 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getInt16(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT16 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getInt32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getUint8(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + UINT8 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getUint16(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + UINT16 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getUint32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + UINT32 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_setFloat32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + double n; + float v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_number(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + v = n; /* FIXME: don't assume rounding mode is round-to-nearest ties-to-even */ + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setFloat64(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + double v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_number(ctx, argv[1], &v); + if(FAILED(hres)) + return hres; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setInt8(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 n; + INT8 v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_int32(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + v = n; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setInt16(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 n; + INT16 v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_int32(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + v = n; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setInt32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_int32(ctx, argv[1], &v); + if(FAILED(hres)) + return hres; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static const builtin_prop_t DataView_props[] = { + {L"getFloat32", DataView_getFloat32, PROPF_METHOD|1}, + {L"getFloat64", DataView_getFloat64, PROPF_METHOD|1}, + {L"getInt16", DataView_getInt16, PROPF_METHOD|1}, + {L"getInt32", DataView_getInt32, PROPF_METHOD|1}, + {L"getInt8", DataView_getInt8, PROPF_METHOD|1}, + {L"getUint16", DataView_getUint16, PROPF_METHOD|1}, + {L"getUint32", DataView_getUint32, PROPF_METHOD|1}, + {L"getUint8", DataView_getUint8, PROPF_METHOD|1}, + {L"setFloat32", DataView_setFloat32, PROPF_METHOD|1}, + {L"setFloat64", DataView_setFloat64, PROPF_METHOD|1}, + {L"setInt16", DataView_setInt16, PROPF_METHOD|1}, + {L"setInt32", DataView_setInt32, PROPF_METHOD|1}, + {L"setInt8", DataView_setInt8, PROPF_METHOD|1}, + {L"setUint16", DataView_setInt16, PROPF_METHOD|1}, + {L"setUint32", DataView_setInt32, PROPF_METHOD|1}, + {L"setUint8", DataView_setInt8, PROPF_METHOD|1}, +}; + +static void DataView_destructor(jsdisp_t *dispex) +{ + DataViewInstance *view = dataview_from_jsdisp(dispex); + if(view->buffer) + jsdisp_release(&view->buffer->dispex); +} + +static HRESULT DataView_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + DataViewInstance *view = dataview_from_jsdisp(dispex); + return gc_process_linked_obj(gc_ctx, op, dispex, &view->buffer->dispex, (void**)&view->buffer); +} + +static const builtin_info_t DataView_info = { + .class = JSCLASS_DATAVIEW, + .props_cnt = ARRAY_SIZE(DataView_props), + .props = DataView_props, + .destructor = DataView_destructor, + .gc_traverse = DataView_gc_traverse +}; + +static const builtin_info_t DataViewInst_info = { + .class = JSCLASS_DATAVIEW, + .destructor = DataView_destructor, + .gc_traverse = DataView_gc_traverse +}; + +static HRESULT DataViewConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + ArrayBufferInstance *arraybuf; + DataViewInstance *view; + DWORD offset = 0, size; + HRESULT hres; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(!argc || !(arraybuf = arraybuf_this(argv[0]))) + return JS_E_DATAVIEW_NO_ARGUMENT; + size = arraybuf->size; + + if(argc > 1) { + double offs, len, maxsize = size; + hres = to_integer(ctx, argv[1], &offs); + if(FAILED(hres)) + return hres; + if(offs < 0.0 || offs > maxsize) + return JS_E_DATAVIEW_INVALID_OFFSET; + offset = offs; + + if(argc > 2 && !is_undefined(argv[2])) { + hres = to_integer(ctx, argv[2], &len); + if(FAILED(hres)) + return hres; + if(len < 0.0 || offs+len > maxsize) + return JS_E_DATAVIEW_INVALID_OFFSET; + size = len; + }else + size -= offset; + } + + if(!r) + return S_OK; + + if(!(view = calloc(1, sizeof(DataViewInstance)))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&view->dispex, ctx, &DataViewInst_info, ctx->dataview_constr); + if(FAILED(hres)) { + free(view); + return hres; + } + + jsdisp_addref(&arraybuf->dispex); + view->buffer = arraybuf; + view->offset = offset; + view->size = size; + + *r = jsval_obj(&view->dispex); + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +static const builtin_info_t DataViewConstr_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, +}; + +HRESULT init_arraybuf_constructors(script_ctx_t *ctx) +{ + static const struct { + const WCHAR *name; + builtin_invoke_t get; + } DataView_getters[] = { + { L"buffer", DataView_get_buffer }, + { L"byteLength", DataView_get_byteLength }, + { L"byteOffset", DataView_get_byteOffset }, + }; + ArrayBufferInstance *arraybuf; + DataViewInstance *view; + property_desc_t desc; + HRESULT hres; + unsigned i; + + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) + return S_OK; + + if(!(arraybuf = calloc(1, FIELD_OFFSET(ArrayBufferInstance, buf[0])))) + return E_OUTOFMEMORY; + + hres = init_dispex(&arraybuf->dispex, ctx, &ArrayBuffer_info, ctx->object_prototype); + if(FAILED(hres)) { + free(arraybuf); + return hres; + } + + hres = create_builtin_constructor(ctx, ArrayBufferConstr_value, L"ArrayBuffer", &ArrayBufferConstr_info, + PROPF_CONSTR|1, &arraybuf->dispex, &ctx->arraybuf_constr); + jsdisp_release(&arraybuf->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, L"ArrayBuffer", PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->arraybuf_constr)); + if(FAILED(hres)) + return hres; + + if(!(view = calloc(1, sizeof(DataViewInstance)))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, 0, &view->buffer); + if(FAILED(hres)) { + free(view); + return hres; + } + + hres = init_dispex(&view->dispex, ctx, &DataView_info, ctx->object_prototype); + if(FAILED(hres)) { + jsdisp_release(&view->buffer->dispex); + free(view); + return hres; + } + + desc.flags = PROPF_CONFIGURABLE; + desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = desc.explicit_setter = TRUE; + desc.explicit_value = FALSE; + desc.setter = NULL; + + /* FIXME: If we find we need builtin accessors in other places, we should consider a more generic solution */ + for(i = 0; i < ARRAY_SIZE(DataView_getters); i++) { + hres = create_builtin_function(ctx, DataView_getters[i].get, NULL, NULL, PROPF_METHOD, NULL, &desc.getter); + if(SUCCEEDED(hres)) { + hres = jsdisp_define_property(&view->dispex, DataView_getters[i].name, &desc); + jsdisp_release(desc.getter); + } + if(FAILED(hres)) { + jsdisp_release(&view->dispex); + return hres; + } + } + + hres = create_builtin_constructor(ctx, DataViewConstr_value, L"DataView", &DataViewConstr_info, + PROPF_CONSTR|1, &view->dispex, &ctx->dataview_constr); + jsdisp_release(&view->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, L"DataView", PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->dataview_constr)); + + return hres; +} diff --git a/dll/win32/jscript/bool.c b/dll/win32/jscript/bool.c index 2d0b9d0c1b4..709a0579c58 100644 --- a/dll/win32/jscript/bool.c +++ b/dll/win32/jscript/bool.c @@ -31,22 +31,21 @@ typedef struct { BOOL val; } BoolInstance; -static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; -static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; - static inline BoolInstance *bool_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, BoolInstance, dispex); } -static inline BoolInstance *bool_from_vdisp(vdisp_t *vdisp) +static inline HRESULT boolval_this(jsval_t vthis, BOOL *ret) { - return bool_from_jsdisp(vdisp->u.jsdisp); -} - -static inline BoolInstance *bool_this(vdisp_t *jsthis) -{ - return is_vclass(jsthis, JSCLASS_BOOLEAN) ? bool_from_vdisp(jsthis) : NULL; + jsdisp_t *jsdisp; + if(is_bool(vthis)) + *ret = get_bool(vthis); + else if(is_object_instance(vthis) && (jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_BOOLEAN)) + *ret = bool_from_jsdisp(jsdisp)->val; + else + return JS_E_BOOLEAN_EXPECTED; + return S_OK; } BOOL bool_obj_value(jsdisp_t *obj) @@ -56,22 +55,21 @@ BOOL bool_obj_value(jsdisp_t *obj) } /* ECMA-262 3rd Edition 15.6.4.2 */ -static HRESULT Bool_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Bool_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - BoolInstance *bool; - - static const WCHAR trueW[] = {'t','r','u','e',0}; - static const WCHAR falseW[] = {'f','a','l','s','e',0}; + BOOL boolval; + HRESULT hres; TRACE("\n"); - if(!(bool = bool_this(jsthis))) - return throw_type_error(ctx, JS_E_BOOLEAN_EXPECTED, NULL); + hres = boolval_this(vthis, &boolval); + if(FAILED(hres)) + return hres; if(r) { jsstr_t *val; - val = jsstr_alloc(bool->val ? trueW : falseW); + val = jsstr_alloc(boolval ? L"true" : L"false"); if(!val) return E_OUTOFMEMORY; @@ -82,28 +80,30 @@ static HRESULT Bool_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns } /* ECMA-262 3rd Edition 15.6.4.3 */ -static HRESULT Bool_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Bool_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - BoolInstance *bool; + BOOL boolval; + HRESULT hres; TRACE("\n"); - if(!(bool = bool_this(jsthis))) - return throw_type_error(ctx, JS_E_BOOLEAN_EXPECTED, NULL); + hres = boolval_this(vthis, &boolval); + if(FAILED(hres)) + return hres; if(r) - *r = jsval_bool(bool->val); + *r = jsval_bool(boolval); return S_OK; } -static HRESULT Bool_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Bool_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); switch(flags) { case INVOKE_FUNC: - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + return JS_E_FUNCTION_EXPECTED; default: FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; @@ -114,28 +114,23 @@ static HRESULT Bool_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsign } static const builtin_prop_t Bool_props[] = { - {toStringW, Bool_toString, PROPF_METHOD}, - {valueOfW, Bool_valueOf, PROPF_METHOD} + {L"toString", Bool_toString, PROPF_METHOD}, + {L"valueOf", Bool_valueOf, PROPF_METHOD} }; static const builtin_info_t Bool_info = { - JSCLASS_BOOLEAN, - {NULL, Bool_value, 0}, - ARRAY_SIZE(Bool_props), - Bool_props, - NULL, - NULL + .class = JSCLASS_BOOLEAN, + .call = Bool_value, + .props_cnt = ARRAY_SIZE(Bool_props), + .props = Bool_props, }; static const builtin_info_t BoolInst_info = { - JSCLASS_BOOLEAN, - {NULL, Bool_value, 0}, - 0, NULL, - NULL, - NULL + .class = JSCLASS_BOOLEAN, + .call = Bool_value, }; -static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT BoolConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { BOOL value = FALSE; @@ -149,13 +144,16 @@ static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, switch(flags) { case DISPATCH_CONSTRUCT: { - jsdisp_t *bool; + jsdisp_t *b; - hres = create_bool(ctx, value, &bool); + if(!r) + return S_OK; + + hres = create_bool(ctx, value, &b); if(FAILED(hres)) return hres; - *r = jsval_obj(bool); + *r = jsval_obj(b); return S_OK; } @@ -174,56 +172,54 @@ static HRESULT BoolConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, static HRESULT alloc_bool(script_ctx_t *ctx, jsdisp_t *object_prototype, BoolInstance **ret) { - BoolInstance *bool; + BoolInstance *b; HRESULT hres; - bool = heap_alloc_zero(sizeof(BoolInstance)); - if(!bool) + b = calloc(1, sizeof(BoolInstance)); + if(!b) return E_OUTOFMEMORY; if(object_prototype) - hres = init_dispex(&bool->dispex, ctx, &Bool_info, object_prototype); + hres = init_dispex(&b->dispex, ctx, &Bool_info, object_prototype); else - hres = init_dispex_from_constr(&bool->dispex, ctx, &BoolInst_info, ctx->bool_constr); + hres = init_dispex_from_constr(&b->dispex, ctx, &BoolInst_info, ctx->bool_constr); if(FAILED(hres)) { - heap_free(bool); + free(b); return hres; } - *ret = bool; + *ret = b; return S_OK; } HRESULT create_bool_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) { - BoolInstance *bool; + BoolInstance *b; HRESULT hres; - static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0}; - - hres = alloc_bool(ctx, object_prototype, &bool); + hres = alloc_bool(ctx, object_prototype, &b); if(FAILED(hres)) return hres; - hres = create_builtin_constructor(ctx, BoolConstr_value, BooleanW, NULL, - PROPF_CONSTR|1, &bool->dispex, ret); + hres = create_builtin_constructor(ctx, BoolConstr_value, L"Boolean", NULL, + PROPF_CONSTR|1, &b->dispex, ret); - jsdisp_release(&bool->dispex); + jsdisp_release(&b->dispex); return hres; } -HRESULT create_bool(script_ctx_t *ctx, BOOL b, jsdisp_t **ret) +HRESULT create_bool(script_ctx_t *ctx, BOOL bval, jsdisp_t **ret) { - BoolInstance *bool; + BoolInstance *b; HRESULT hres; - hres = alloc_bool(ctx, NULL, &bool); + hres = alloc_bool(ctx, NULL, &b); if(FAILED(hres)) return hres; - bool->val = b; + b->val = bval; - *ret = &bool->dispex; + *ret = &b->dispex; return S_OK; } diff --git a/dll/win32/jscript/cc_parser.y b/dll/win32/jscript/cc_parser.y index 4bc6260f194..0f6d4316c28 100644 --- a/dll/win32/jscript/cc_parser.y +++ b/dll/win32/jscript/cc_parser.y @@ -30,6 +30,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); %lex-param { parser_ctx_t *ctx } %parse-param { parser_ctx_t *ctx } +%define api.prefix {cc_parser_} %define api.pure %start CCExpr @@ -143,7 +144,9 @@ static int cc_parser_lex(void *lval, parser_ctx_t *ctx) /* FIXME: Implement missing expressions. */ CCExpr - : CCUnaryExpression { ctx->ccval = $1; YYACCEPT; } + : CCUnaryExpression { ctx->ccval = $1; + (void)cc_parser_nerrs; /* avoid unused variable warning */ + YYACCEPT; } CCUnaryExpression : tCCValue { $$ = $1; } @@ -161,7 +164,7 @@ CCLogicalORExpression CCLogicalANDExpression : CCBitwiseORExpression { $$ = $1; } | CCBitwiseANDExpression tAND CCBitwiseORExpression - { FIXME("'&&' expression not implemented\n"); ctx->hres = E_NOTIMPL; YYABORT; } + { $$ = ccval_bool(get_ccbool($1) && get_ccbool($3)); } CCBitwiseORExpression : CCBitwiseXORExpression { $$ = $1; } diff --git a/dll/win32/jscript/compile.c b/dll/win32/jscript/compile.c index db05d3c3600..2d2c2c9f40a 100644 --- a/dll/win32/jscript/compile.c +++ b/dll/win32/jscript/compile.c @@ -39,6 +39,9 @@ typedef struct _statement_ctx_t { const labelled_statement_t *labelled_stat; + unsigned int scope_index; + BOOL block_scope; + BOOL scope_has_functions; struct _statement_ctx_t *next; } statement_ctx_t; @@ -61,14 +64,24 @@ typedef struct _compiler_ctx_t { unsigned labels_size; unsigned labels_cnt; - struct wine_rb_tree locals; - unsigned locals_cnt; + struct + { + struct wine_rb_tree locals; + unsigned int locals_cnt; + unsigned int *ref_index; + } + *local_scopes; + unsigned local_scope_count; + unsigned local_scope_size; statement_ctx_t *stat_ctx; function_code_t *func; + unsigned loc; + function_expression_t *func_head; function_expression_t *func_tail; + function_expression_t *current_function_expr; heap_pool_t heap; } compiler_ctx_t; @@ -125,6 +138,49 @@ static void dump_code(compiler_ctx_t *ctx, unsigned off) static HRESULT compile_expression(compiler_ctx_t*,expression_t*,BOOL); static HRESULT compile_statement(compiler_ctx_t*,statement_ctx_t*,statement_t*); +static int function_local_cmp(const void *key, const struct wine_rb_entry *entry) +{ + function_local_t *local = WINE_RB_ENTRY_VALUE(entry, function_local_t, entry); + return wcscmp(key, local->name); +} + +static BOOL alloc_local_scope(compiler_ctx_t *ctx, unsigned int *scope_index) +{ + unsigned int scope, new_size; + void *new_alloc; + + scope = ctx->local_scope_count++; + if (scope == ctx->local_scope_size) + { + new_size = max(1, ctx->local_scope_size * 2); + if (!(new_alloc = realloc(ctx->local_scopes, new_size * sizeof(*ctx->local_scopes)))) + return FALSE; + ctx->local_scopes = new_alloc; + ctx->local_scope_size = new_size; + } + + ctx->local_scopes[scope].locals_cnt = 0; + ctx->local_scopes[scope].ref_index = scope_index; + wine_rb_init(&ctx->local_scopes[scope].locals, function_local_cmp); + *scope_index = scope; + + return TRUE; +} + +static void remove_local_scope(compiler_ctx_t *ctx, unsigned int scope_index) +{ + unsigned int i; + + assert(scope_index < ctx->local_scope_count); + --ctx->local_scope_count; + assert(scope_index == *ctx->local_scopes[scope_index].ref_index); + *ctx->local_scopes[scope_index].ref_index = 0; + memmove(&ctx->local_scopes[scope_index], &ctx->local_scopes[scope_index + 1], + sizeof(*ctx->local_scopes) * (ctx->local_scope_count - scope_index)); + for (i = scope_index; i < ctx->local_scope_count; ++i) + --*ctx->local_scopes[i].ref_index; +} + static inline void *compiler_alloc(bytecode_t *code, size_t size) { return heap_pool_alloc(&code->heap, size); @@ -135,14 +191,14 @@ jsstr_t *compiler_alloc_string_len(compiler_ctx_t *ctx, const WCHAR *str, unsign jsstr_t *new_str; if(!ctx->code->str_pool_size) { - ctx->code->str_pool = heap_alloc(8 * sizeof(jsstr_t*)); + ctx->code->str_pool = malloc(8 * sizeof(jsstr_t*)); if(!ctx->code->str_pool) return NULL; ctx->code->str_pool_size = 8; }else if(ctx->code->str_pool_size == ctx->code->str_cnt) { jsstr_t **new_pool; - new_pool = heap_realloc(ctx->code->str_pool, ctx->code->str_pool_size*2*sizeof(jsstr_t*)); + new_pool = realloc(ctx->code->str_pool, ctx->code->str_pool_size*2*sizeof(jsstr_t*)); if(!new_pool) return NULL; @@ -166,14 +222,14 @@ static jsstr_t *compiler_alloc_string(compiler_ctx_t *ctx, const WCHAR *str) static BOOL ensure_bstr_slot(compiler_ctx_t *ctx) { if(!ctx->code->bstr_pool_size) { - ctx->code->bstr_pool = heap_alloc(8 * sizeof(BSTR)); + ctx->code->bstr_pool = malloc(8 * sizeof(BSTR)); if(!ctx->code->bstr_pool) return FALSE; ctx->code->bstr_pool_size = 8; }else if(ctx->code->bstr_pool_size == ctx->code->bstr_cnt) { BSTR *new_pool; - new_pool = heap_realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR)); + new_pool = realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR)); if(!new_pool) return FALSE; @@ -208,6 +264,11 @@ static BSTR compiler_alloc_bstr_len(compiler_ctx_t *ctx, const WCHAR *str, size_ return ctx->code->bstr_pool[ctx->code->bstr_cnt++]; } +void set_compiler_loc(compiler_ctx_t *ctx, unsigned loc) +{ + ctx->loc = loc; +} + static unsigned push_instr(compiler_ctx_t *ctx, jsop_t op) { assert(ctx->code_size >= ctx->code_off); @@ -215,7 +276,7 @@ static unsigned push_instr(compiler_ctx_t *ctx, jsop_t op) if(ctx->code_size == ctx->code_off) { instr_t *new_instrs; - new_instrs = heap_realloc(ctx->code->instrs, ctx->code_size*2*sizeof(instr_t)); + new_instrs = realloc(ctx->code->instrs, ctx->code_size*2*sizeof(instr_t)); if(!new_instrs) return 0; @@ -224,6 +285,7 @@ static unsigned push_instr(compiler_ctx_t *ctx, jsop_t op) } ctx->code->instrs[ctx->code_off].op = op; + ctx->code->instrs[ctx->code_off].loc = ctx->loc; return ctx->code_off++; } @@ -395,14 +457,14 @@ static HRESULT compile_member_expression(compiler_ctx_t *ctx, member_expression_ static unsigned alloc_label(compiler_ctx_t *ctx) { if(!ctx->labels_size) { - ctx->labels = heap_alloc(8 * sizeof(*ctx->labels)); + ctx->labels = malloc(8 * sizeof(*ctx->labels)); if(!ctx->labels) return 0; ctx->labels_size = 8; }else if(ctx->labels_size == ctx->labels_cnt) { unsigned *new_labels; - new_labels = heap_realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels)); + new_labels = realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels)); if(!new_labels) return 0; @@ -431,10 +493,19 @@ static BOOL bind_local(compiler_ctx_t *ctx, const WCHAR *identifier, int *ret_re for(iter = ctx->stat_ctx; iter; iter = iter->next) { if(iter->using_scope) - return FALSE; + { + if (!iter->block_scope) + return FALSE; + + if ((ref = lookup_local(ctx->func, identifier, iter->scope_index))) + { + *ret_ref = ref->ref; + return TRUE; + } + } } - ref = lookup_local(ctx->func, identifier); + ref = lookup_local(ctx->func, identifier, 0); if(!ref) return FALSE; @@ -458,18 +529,11 @@ static HRESULT emit_identifier(compiler_ctx_t *ctx, const WCHAR *identifier) return push_instr_bstr(ctx, OP_ident, identifier); } -static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags) +static HRESULT emit_member_expression(compiler_ctx_t *ctx, expression_t *expr) { - HRESULT hres = S_OK; + HRESULT hres; - switch(expr->type) { - case EXPR_IDENT: { - identifier_expression_t *ident_expr = (identifier_expression_t*)expr; - - hres = emit_identifier_ref(ctx, ident_expr->identifier, flags); - break; - } - case EXPR_ARRAY: { + if(expr->type == EXPR_ARRAY) { binary_expression_t *array_expr = (binary_expression_t*)expr; hres = compile_expression(ctx, array_expr->expression1, TRUE); @@ -480,18 +544,18 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex if(FAILED(hres)) return hres; - hres = push_instr_uint(ctx, OP_memberid, flags); - break; - } - case EXPR_MEMBER: { + if(!push_instr(ctx, OP_to_string)) + return E_OUTOFMEMORY; + }else { member_expression_t *member_expr = (member_expression_t*)expr; jsstr_t *jsstr; + assert(expr->type == EXPR_MEMBER); + hres = compile_expression(ctx, member_expr->expression, TRUE); if(FAILED(hres)) return hres; - /* FIXME: Potential optimization */ jsstr = compiler_alloc_string(ctx, member_expr->identifier); if(!jsstr) return E_OUTOFMEMORY; @@ -499,14 +563,43 @@ static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *ex hres = push_instr_str(ctx, OP_str, jsstr); if(FAILED(hres)) return hres; - - hres = push_instr_uint(ctx, OP_memberid, flags); - break; - } - DEFAULT_UNREACHABLE; } - return hres; + return S_OK; +} + +static void push_compiler_statement_ctx(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx) +{ + if (stat_ctx) + { + stat_ctx->next = ctx->stat_ctx; + ctx->stat_ctx = stat_ctx; + } +} + +static void pop_compiler_statement_ctx(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx) +{ + if (stat_ctx) + { + assert(ctx->stat_ctx == stat_ctx); + ctx->stat_ctx = stat_ctx->next; + } +} + +static HRESULT compile_memberid_expression(compiler_ctx_t *ctx, expression_t *expr, unsigned flags) +{ + HRESULT hres; + + if(expr->type == EXPR_IDENT) { + identifier_expression_t *ident_expr = (identifier_expression_t*)expr; + return emit_identifier_ref(ctx, ident_expr->identifier, flags); + } + + hres = emit_member_expression(ctx, expr); + if(FAILED(hres)) + return hres; + + return push_instr_uint(ctx, OP_memberid, flags); } static HRESULT compile_increment_expression(compiler_ctx_t *ctx, unary_expression_t *expr, jsop_t op, int n) @@ -627,16 +720,20 @@ static HRESULT compile_new_expression(compiler_ctx_t *ctx, call_expression_t *ex static HRESULT compile_call_expression(compiler_ctx_t *ctx, call_expression_t *expr, BOOL emit_ret) { - unsigned arg_cnt = 0, extra_args; + unsigned arg_cnt = 0, extra_args = 0; + HRESULT hres = S_OK; argument_t *arg; unsigned instr; jsop_t op; - HRESULT hres; if(is_memberid_expr(expr->expression->type)) { - op = OP_call_member; - extra_args = 2; - hres = compile_memberid_expression(ctx, expr->expression, 0); + if(expr->expression->type == EXPR_IDENT && !wcscmp(((identifier_expression_t*)expr->expression)->identifier, L"eval")) + op = OP_call_eval; + else { + op = OP_call_member; + extra_args = 2; + hres = compile_memberid_expression(ctx, expr->expression, 0); + } }else { op = OP_call; extra_args = 1; @@ -711,15 +808,13 @@ static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t case EXPR_IDENT: return push_instr_bstr(ctx, OP_delete_ident, ((identifier_expression_t*)expr->expression)->identifier); default: { - static const WCHAR fixmeW[] = {'F','I','X','M','E',0}; - WARN("invalid delete, unimplemented exception message\n"); hres = compile_expression(ctx, expr->expression, TRUE); if(FAILED(hres)) return hres; - return push_instr_uint_str(ctx, OP_throw_type, JS_E_INVALID_DELETE, fixmeW); + return push_instr_uint_str(ctx, OP_throw_type, JS_E_INVALID_DELETE, L"FIXME"); } } @@ -728,7 +823,7 @@ static HRESULT compile_delete_expression(compiler_ctx_t *ctx, unary_expression_t static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_t *expr, jsop_t op) { - BOOL use_throw_path = FALSE; + jsop_t assign_op = OP_throw_ref; unsigned arg_cnt = 0; HRESULT hres; @@ -764,33 +859,30 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_ if(!push_instr(ctx, OP_push_acc)) return E_OUTOFMEMORY; } - }else { - use_throw_path = TRUE; + assign_op = OP_assign_call; } }else if(is_memberid_expr(expr->expression1->type)) { - hres = compile_memberid_expression(ctx, expr->expression1, fdexNameEnsure); - if(FAILED(hres)) - return hres; - if(op != OP_LAST && !push_instr(ctx, OP_refval)) - return E_OUTOFMEMORY; - }else { - use_throw_path = TRUE; + if(op != OP_LAST || expr->expression1->type == EXPR_IDENT) { + hres = compile_memberid_expression(ctx, expr->expression1, fdexNameEnsure); + if(FAILED(hres)) + return hres; + if(op != OP_LAST && !push_instr(ctx, OP_refval)) + return E_OUTOFMEMORY; + assign_op = OP_assign; + }else { + hres = emit_member_expression(ctx, expr->expression1); + if(FAILED(hres)) + return hres; + assign_op = OP_set_member; + } } - if(use_throw_path) { + if(assign_op == OP_throw_ref) { /* Illegal assignment: evaluate and throw */ hres = compile_expression(ctx, expr->expression1, TRUE); if(FAILED(hres)) return hres; - - hres = compile_expression(ctx, expr->expression2, TRUE); - if(FAILED(hres)) - return hres; - - if(op != OP_LAST && !push_instr(ctx, op)) - return E_OUTOFMEMORY; - - return push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN); + arg_cnt = JS_E_ILLEGAL_ASSIGN; } hres = compile_expression(ctx, expr->expression2, TRUE); @@ -800,13 +892,7 @@ static HRESULT compile_assign_expression(compiler_ctx_t *ctx, binary_expression_ if(op != OP_LAST && !push_instr(ctx, op)) return E_OUTOFMEMORY; - if(arg_cnt) - return push_instr_uint(ctx, OP_assign_call, arg_cnt); - - if(!push_instr(ctx, OP_assign)) - return E_OUTOFMEMORY; - - return S_OK; + return push_instr_uint(ctx, assign_op, arg_cnt); } static HRESULT compile_typeof_expression(compiler_ctx_t *ctx, unary_expression_t *expr) @@ -917,6 +1003,18 @@ static HRESULT compile_object_literal(compiler_ctx_t *ctx, property_value_expres static HRESULT compile_function_expression(compiler_ctx_t *ctx, function_expression_t *expr, BOOL emit_ret) { + statement_ctx_t *stat_ctx; + + assert(ctx->current_function_expr); + + for(stat_ctx = ctx->stat_ctx; stat_ctx; stat_ctx = stat_ctx->next) + { + if(stat_ctx->block_scope) + break; + } + ctx->current_function_expr->scope_index = stat_ctx ? stat_ctx->scope_index : 0; + ctx->current_function_expr = ctx->current_function_expr->next; + return emit_ret ? push_instr_uint(ctx, OP_func, expr->func_id) : S_OK; } @@ -1110,18 +1208,33 @@ static inline BOOL is_loop_statement(statement_type_t type) } /* ECMA-262 3rd Edition 12.1 */ -static HRESULT compile_block_statement(compiler_ctx_t *ctx, statement_t *iter) +static HRESULT compile_block_statement(compiler_ctx_t *ctx, block_statement_t *block, statement_t *iter) { + statement_ctx_t stat_ctx = {0, TRUE}; + BOOL needs_scope; HRESULT hres; + needs_scope = block && block->scope_index; + if (needs_scope) + { + if(FAILED(hres = push_instr_uint(ctx, OP_push_block_scope, block->scope_index))) + return hres; + + stat_ctx.scope_index = block->scope_index; + stat_ctx.block_scope = TRUE; + } + while(iter) { - hres = compile_statement(ctx, NULL, iter); + hres = compile_statement(ctx, needs_scope ? &stat_ctx : NULL, iter); if(FAILED(hres)) return hres; iter = iter->next; } + if(needs_scope && !push_instr(ctx, OP_pop_scope)) + return E_OUTOFMEMORY; + return S_OK; } @@ -1137,6 +1250,9 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t if(!iter->expr) continue; + if (iter->constant) + FIXME("Constant variables are not supported.\n"); + hres = emit_identifier_ref(ctx, iter->identifier, 0); if(FAILED(hres)) return hres; @@ -1245,6 +1361,7 @@ static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *s if(FAILED(hres)) return hres; + set_compiler_loc(ctx, stat->stat.loc); if(stat->do_while) { label_set_addr(ctx, stat_ctx.continue_label); hres = compile_expression(ctx, stat->expr, TRUE); @@ -1264,61 +1381,87 @@ static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *s return S_OK; } -/* ECMA-262 3rd Edition 12.6.3 */ +/* ECMA-262 10th Edition 13.7.4 */ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat) { statement_ctx_t stat_ctx = {0, FALSE, FALSE}; + statement_ctx_t scope_stat_ctx = {0, TRUE}; unsigned expr_off; HRESULT hres; + if (stat->scope_index) + { + if(FAILED(hres = push_instr_uint(ctx, OP_push_block_scope, stat->scope_index))) + return hres; + + scope_stat_ctx.scope_index = stat->scope_index; + scope_stat_ctx.block_scope = TRUE; + push_compiler_statement_ctx(ctx, &scope_stat_ctx); + } + if(stat->variable_list) { hres = compile_variable_list(ctx, stat->variable_list); if(FAILED(hres)) - return hres; + goto done; }else if(stat->begin_expr) { hres = compile_expression(ctx, stat->begin_expr, FALSE); if(FAILED(hres)) - return hres; + goto done; } stat_ctx.break_label = alloc_label(ctx); if(!stat_ctx.break_label) - return E_OUTOFMEMORY; + { + hres = E_OUTOFMEMORY; + goto done; + } stat_ctx.continue_label = alloc_label(ctx); if(!stat_ctx.continue_label) - return E_OUTOFMEMORY; - + { + hres = E_OUTOFMEMORY; + goto done; + } expr_off = ctx->code_off; if(stat->expr) { + set_compiler_loc(ctx, stat->expr_loc); hres = compile_expression(ctx, stat->expr, TRUE); if(FAILED(hres)) - return hres; + goto done; hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label); if(FAILED(hres)) - return hres; + goto done; } hres = compile_statement(ctx, &stat_ctx, stat->statement); if(FAILED(hres)) - return hres; + goto done; label_set_addr(ctx, stat_ctx.continue_label); if(stat->end_expr) { + set_compiler_loc(ctx, stat->end_loc); hres = compile_expression(ctx, stat->end_expr, FALSE); if(FAILED(hres)) - return hres; + goto done; } hres = push_instr_uint(ctx, OP_jmp, expr_off); if(FAILED(hres)) - return hres; + goto done; label_set_addr(ctx, stat_ctx.break_label); - return S_OK; + hres = S_OK; +done: + if (stat->scope_index) + { + pop_compiler_statement_ctx(ctx, &scope_stat_ctx); + if(SUCCEEDED(hres) && !push_instr(ctx, OP_pop_scope)) + return E_OUTOFMEMORY; + } + return hres; } /* ECMA-262 3rd Edition 12.6.4 */ @@ -1540,7 +1683,7 @@ static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *sta if(FAILED(hres)) return hres; - if(!push_instr(ctx, OP_push_scope)) + if(!push_instr(ctx, OP_push_with_scope)) return E_OUTOFMEMORY; hres = compile_statement(ctx, &stat_ctx, stat->statement); @@ -1602,7 +1745,7 @@ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t case_cnt++; } - case_jmps = heap_alloc(case_cnt * sizeof(*case_jmps)); + case_jmps = malloc(case_cnt * sizeof(*case_jmps)); if(!case_jmps) return E_OUTOFMEMORY; @@ -1613,6 +1756,7 @@ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t continue; } + set_compiler_loc(ctx, iter->loc); hres = compile_expression(ctx, iter->expr, TRUE); if(FAILED(hres)) break; @@ -1635,7 +1779,7 @@ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t } if(FAILED(hres)) { - heap_free(case_jmps); + free(case_jmps); return hres; } @@ -1658,7 +1802,7 @@ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t break; } - heap_free(case_jmps); + free(case_jmps); if(FAILED(hres)) return hres; assert(i == case_cnt); @@ -1751,6 +1895,7 @@ static HRESULT compile_try_statement(compiler_ctx_t *ctx, try_statement_t *stat) if(FAILED(hres)) return hres; + set_compiler_loc(ctx, stat->finally_loc); if(!push_instr(ctx, OP_end_finally)) return E_OUTOFMEMORY; } @@ -1767,14 +1912,13 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx, { HRESULT hres; - if(stat_ctx) { - stat_ctx->next = ctx->stat_ctx; - ctx->stat_ctx = stat_ctx; - } + push_compiler_statement_ctx(ctx, stat_ctx); + + set_compiler_loc(ctx, stat->loc); switch(stat->type) { case STAT_BLOCK: - hres = compile_block_statement(ctx, ((block_statement_t*)stat)->stat_list); + hres = compile_block_statement(ctx, (block_statement_t*)stat, ((block_statement_t*)stat)->stat_list); break; case STAT_BREAK: hres = compile_break_statement(ctx, (branch_statement_t*)stat); @@ -1825,27 +1969,18 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx, DEFAULT_UNREACHABLE; } - if(stat_ctx) { - assert(ctx->stat_ctx == stat_ctx); - ctx->stat_ctx = stat_ctx->next; - } + pop_compiler_statement_ctx(ctx, stat_ctx); return hres; } -static int function_local_cmp(const void *key, const struct wine_rb_entry *entry) +static inline function_local_t *find_local(compiler_ctx_t *ctx, const WCHAR *name, unsigned int scope) { - function_local_t *local = WINE_RB_ENTRY_VALUE(entry, function_local_t, entry); - return wcscmp(key, local->name); -} - -static inline function_local_t *find_local(compiler_ctx_t *ctx, const WCHAR *name) -{ - struct wine_rb_entry *entry = wine_rb_get(&ctx->locals, name); + struct wine_rb_entry *entry = wine_rb_get(&ctx->local_scopes[scope].locals, name); return entry ? WINE_RB_ENTRY_VALUE(entry, function_local_t, entry) : NULL; } -static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref) +static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref, unsigned int scope) { function_local_t *local; @@ -1855,32 +1990,48 @@ static BOOL alloc_local(compiler_ctx_t *ctx, BSTR name, int ref) local->name = name; local->ref = ref; - wine_rb_put(&ctx->locals, name, &local->entry); - ctx->locals_cnt++; + wine_rb_put(&ctx->local_scopes[scope].locals, name, &local->entry); + ctx->local_scopes[scope].locals_cnt++; return TRUE; } -static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name) +static BOOL alloc_variable(compiler_ctx_t *ctx, const WCHAR *name, unsigned int scope) { BSTR ident; - if(find_local(ctx, name)) + if(find_local(ctx, name, scope)) return TRUE; ident = compiler_alloc_bstr(ctx, name); if(!ident) return FALSE; - return alloc_local(ctx, ident, ctx->func->var_cnt++); + return alloc_local(ctx, ident, ctx->func->var_cnt++, scope); } static HRESULT visit_function_expression(compiler_ctx_t *ctx, function_expression_t *expr) { + statement_ctx_t *stat_ctx; + expr->func_id = ctx->func->func_cnt++; ctx->func_tail = ctx->func_tail ? (ctx->func_tail->next = expr) : (ctx->func_head = expr); - return !expr->identifier || expr->event_target || alloc_variable(ctx, expr->identifier) - ? S_OK : E_OUTOFMEMORY; + if(!expr->identifier || expr->event_target) + return S_OK; + + for (stat_ctx = ctx->stat_ctx; stat_ctx; stat_ctx = stat_ctx->next) + { + if (stat_ctx->block_scope) + { + stat_ctx->scope_has_functions = TRUE; + break; + } + } + + if(!expr->is_statement && ctx->parser->script->version >= SCRIPTLANGUAGEVERSION_ES5) + return S_OK; + + return alloc_variable(ctx, expr->identifier, stat_ctx ? stat_ctx->scope_index : 0) ? S_OK : E_OUTOFMEMORY; } static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr) @@ -2016,11 +2167,18 @@ static HRESULT visit_expression(compiler_ctx_t *ctx, expression_t *expr) static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t *list) { variable_declaration_t *iter; + statement_ctx_t *stat_ctx; HRESULT hres; for(iter = list; iter; iter = iter->next) { - if(!alloc_variable(ctx, iter->identifier)) - return E_OUTOFMEMORY; + for (stat_ctx = ctx->stat_ctx; stat_ctx; stat_ctx = stat_ctx->next) + { + if (stat_ctx->block_scope) + break; + } + + if(!alloc_variable(ctx, iter->identifier, iter->block_scope && stat_ctx ? stat_ctx->scope_index : 0)) + return E_OUTOFMEMORY; if(iter->expr) { hres = visit_expression(ctx, iter->expr); @@ -2032,36 +2190,61 @@ static HRESULT visit_variable_list(compiler_ctx_t *ctx, variable_declaration_t * return S_OK; } -static HRESULT visit_statement(compiler_ctx_t*,statement_t*); +static HRESULT visit_statement(compiler_ctx_t*,statement_ctx_t *,statement_t*); -static HRESULT visit_block_statement(compiler_ctx_t *ctx, statement_t *iter) +static HRESULT visit_block_statement(compiler_ctx_t *ctx, block_statement_t *block, statement_t *iter) { + statement_ctx_t stat_ctx = {0, TRUE}; + BOOL needs_scope; HRESULT hres; + needs_scope = block && ctx->parser->script->version >= SCRIPTLANGUAGEVERSION_ES5; + if (needs_scope) + { + if (!alloc_local_scope(ctx, &block->scope_index)) + return E_OUTOFMEMORY; + + stat_ctx.scope_index = block->scope_index; + stat_ctx.block_scope = TRUE; + } + while(iter) { - hres = visit_statement(ctx, iter); + hres = visit_statement(ctx, needs_scope ? &stat_ctx : NULL, iter); if(FAILED(hres)) return hres; iter = iter->next; } + if (needs_scope && !(ctx->local_scopes[stat_ctx.scope_index].locals_cnt || stat_ctx.scope_has_functions)) + remove_local_scope(ctx, block->scope_index); + return S_OK; } -static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) +static HRESULT visit_statement(compiler_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat) { HRESULT hres = S_OK; + push_compiler_statement_ctx(ctx, stat_ctx); + switch(stat->type) { case STAT_BLOCK: - hres = visit_block_statement(ctx, ((block_statement_t*)stat)->stat_list); + hres = visit_block_statement(ctx, (block_statement_t*)stat, ((block_statement_t*)stat)->stat_list); break; case STAT_BREAK: case STAT_CONTINUE: case STAT_EMPTY: break; - case STAT_EXPR: + case STAT_EXPR: { + expression_statement_t *expr_stat = (expression_statement_t*)stat; + if(expr_stat->expr) { + if(expr_stat->expr->type == EXPR_FUNC) + ((function_expression_t*)expr_stat->expr)->is_statement = TRUE; + hres = visit_expression(ctx, expr_stat->expr); + } + break; + } case STAT_RETURN: case STAT_THROW: { expression_statement_t *expr_stat = (expression_statement_t*)stat; @@ -2070,27 +2253,61 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) break; } case STAT_FOR: { + statement_ctx_t stat_ctx_data = {0, TRUE}, *stat_ctx = NULL; for_statement_t *for_stat = (for_statement_t*)stat; if(for_stat->variable_list) + { + variable_declaration_t *var; + + for(var = for_stat->variable_list; var; var = var->next) + { + if (var->block_scope) + { + stat_ctx = &stat_ctx_data; + break; + } + } + + if (stat_ctx) + { + if (!alloc_local_scope(ctx, &for_stat->scope_index)) + { + hres = E_OUTOFMEMORY; + break; + } + stat_ctx->scope_index = for_stat->scope_index; + stat_ctx->block_scope = TRUE; + push_compiler_statement_ctx(ctx, stat_ctx); + } hres = visit_variable_list(ctx, for_stat->variable_list); + } else if(for_stat->begin_expr) hres = visit_expression(ctx, for_stat->begin_expr); if(FAILED(hres)) + { + pop_compiler_statement_ctx(ctx, stat_ctx); break; + } if(for_stat->expr) { hres = visit_expression(ctx, for_stat->expr); if(FAILED(hres)) + { + pop_compiler_statement_ctx(ctx, stat_ctx); break; + } } - hres = visit_statement(ctx, for_stat->statement); + hres = visit_statement(ctx, NULL, for_stat->statement); if(FAILED(hres)) + { + pop_compiler_statement_ctx(ctx, stat_ctx); break; - + } if(for_stat->end_expr) hres = visit_expression(ctx, for_stat->end_expr); + pop_compiler_statement_ctx(ctx, stat_ctx); break; } case STAT_FORIN: { @@ -2112,7 +2329,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) return hres; } - hres = visit_statement(ctx, forin_stat->statement); + hres = visit_statement(ctx, NULL, forin_stat->statement); break; } case STAT_IF: { @@ -2122,16 +2339,16 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) if(FAILED(hres)) return hres; - hres = visit_statement(ctx, if_stat->if_stat); + hres = visit_statement(ctx, NULL, if_stat->if_stat); if(FAILED(hres)) return hres; if(if_stat->else_stat) - hres = visit_statement(ctx, if_stat->else_stat); + hres = visit_statement(ctx, NULL, if_stat->else_stat); break; } case STAT_LABEL: - hres = visit_statement(ctx, ((labelled_statement_t*)stat)->statement); + hres = visit_statement(ctx, NULL, ((labelled_statement_t*)stat)->statement); break; case STAT_SWITCH: { switch_statement_t *switch_stat = (switch_statement_t*)stat; @@ -2155,7 +2372,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) iter = iter->next; for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter); stat_iter = stat_iter->next) { - hres = visit_statement(ctx, stat_iter); + hres = visit_statement(ctx, NULL, stat_iter); if(FAILED(hres)) return hres; } @@ -2165,18 +2382,18 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) case STAT_TRY: { try_statement_t *try_stat = (try_statement_t*)stat; - hres = visit_statement(ctx, try_stat->try_statement); + hres = visit_statement(ctx, NULL, try_stat->try_statement); if(FAILED(hres)) return hres; if(try_stat->catch_block) { - hres = visit_statement(ctx, try_stat->catch_block->statement); + hres = visit_statement(ctx, NULL, try_stat->catch_block->statement); if(FAILED(hres)) return hres; } if(try_stat->finally_statement) - hres = visit_statement(ctx, try_stat->finally_statement); + hres = visit_statement(ctx, NULL, try_stat->finally_statement); break; } case STAT_VAR: @@ -2189,7 +2406,7 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) if(FAILED(hres)) return hres; - hres = visit_statement(ctx, while_stat->statement); + hres = visit_statement(ctx, NULL, while_stat->statement); break; } case STAT_WITH: { @@ -2199,12 +2416,14 @@ static HRESULT visit_statement(compiler_ctx_t *ctx, statement_t *stat) if(FAILED(hres)) return hres; - hres = visit_statement(ctx, with_stat->statement); + hres = visit_statement(ctx, NULL, with_stat->statement); break; } DEFAULT_UNREACHABLE; } + pop_compiler_statement_ctx(ctx, stat_ctx); + return hres; } @@ -2223,6 +2442,20 @@ static void resolve_labels(compiler_ctx_t *ctx, unsigned off) ctx->labels_cnt = 0; } +unsigned get_location_line(bytecode_t *code, unsigned loc, unsigned *char_pos) +{ + unsigned line = code->start_line; + const WCHAR *nl, *p; + + for(nl = p = code->source; p < code->source + loc; p++) { + if(*p != '\n') continue; + line++; + nl = p + 1; + } + *char_pos = loc - (nl - code->source); + return line; +} + void release_bytecode(bytecode_t *code) { unsigned i; @@ -2235,30 +2468,42 @@ void release_bytecode(bytecode_t *code) for(i=0; i < code->str_cnt; i++) jsstr_release(code->str_pool[i]); - heap_free(code->source); + if(code->named_item) + release_named_item(code->named_item); + free(code->source); heap_pool_free(&code->heap); - heap_free(code->bstr_pool); - heap_free(code->str_pool); - heap_free(code->instrs); - heap_free(code); + free(code->bstr_pool); + free(code->str_pool); + free(code->instrs); + free(code); } -static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source) +static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source, UINT64 source_context, unsigned start_line) { - compiler->code = heap_alloc_zero(sizeof(bytecode_t)); + size_t len = source ? lstrlenW(source) : 0; + + if(len > INT32_MAX) + return E_OUTOFMEMORY; + + compiler->code = calloc(1, sizeof(bytecode_t)); if(!compiler->code) return E_OUTOFMEMORY; compiler->code->ref = 1; + compiler->code->source_context = source_context; + compiler->code->start_line = start_line; heap_pool_init(&compiler->code->heap); - compiler->code->source = heap_strdupW(source); + compiler->code->source = malloc((len + 1) * sizeof(WCHAR)); if(!compiler->code->source) { release_bytecode(compiler->code); return E_OUTOFMEMORY; } + if(len) + memcpy(compiler->code->source, source, len * sizeof(WCHAR)); + compiler->code->source[len] = 0; - compiler->code->instrs = heap_alloc(64 * sizeof(instr_t)); + compiler->code->instrs = malloc(64 * sizeof(instr_t)); if(!compiler->code->instrs) { release_bytecode(compiler->code); return E_OUTOFMEMORY; @@ -2269,21 +2514,26 @@ static HRESULT init_code(compiler_ctx_t *compiler, const WCHAR *source) return S_OK; } -static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, function_expression_t *func_expr, +static HRESULT compile_function(compiler_ctx_t *ctx, statement_t *source, function_expression_t *func_expr, BOOL from_eval, function_code_t *func) { function_expression_t *iter; function_local_t *local; - unsigned off, i; + unsigned off, i, scope; HRESULT hres; TRACE("\n"); + func->bytecode = ctx->code; + func->local_ref = INVALID_LOCAL_REF; + func->scope_index = 0; ctx->func_head = ctx->func_tail = NULL; ctx->from_eval = from_eval; ctx->func = func; - ctx->locals_cnt = 0; - wine_rb_init(&ctx->locals, function_local_cmp); + ctx->local_scope_count = 0; + if (!alloc_local_scope(ctx, &scope)) + return E_OUTOFMEMORY; + assert(!scope); if(func_expr) { parameter_t *param_iter; @@ -2317,43 +2567,53 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, } } - for(i = 0; i < func->param_cnt; i++) { - if(!find_local(ctx, func->params[i]) && !alloc_local(ctx, func->params[i], -i-1)) + for(i = func->param_cnt; i--;) { + if(!find_local(ctx, func->params[i], 0) && !alloc_local(ctx, func->params[i], -i-1, 0)) return E_OUTOFMEMORY; } - hres = visit_block_statement(ctx, source->statement); + hres = visit_block_statement(ctx, NULL, source); if(FAILED(hres)) return hres; - func->locals = compiler_alloc(ctx->code, ctx->locals_cnt * sizeof(*func->locals)); - if(!func->locals) + func->local_scope_count = ctx->local_scope_count; + func->local_scopes = compiler_alloc(ctx->code, func->local_scope_count * sizeof(*func->local_scopes)); + if(!func->local_scopes) return E_OUTOFMEMORY; - func->locals_cnt = ctx->locals_cnt; func->variables = compiler_alloc(ctx->code, func->var_cnt * sizeof(*func->variables)); if(!func->variables) return E_OUTOFMEMORY; - i = 0; - WINE_RB_FOR_EACH_ENTRY(local, &ctx->locals, function_local_t, entry) { - func->locals[i].name = local->name; - func->locals[i].ref = local->ref; - if(local->ref >= 0) { - func->variables[local->ref].name = local->name; - func->variables[local->ref].func_id = -1; + for (scope = 0; scope < func->local_scope_count; ++scope) + { + func->local_scopes[scope].locals = compiler_alloc(ctx->code, + ctx->local_scopes[scope].locals_cnt * sizeof(*func->local_scopes[scope].locals)); + if(!func->local_scopes[scope].locals) + return E_OUTOFMEMORY; + func->local_scopes[scope].locals_cnt = ctx->local_scopes[scope].locals_cnt; + + i = 0; + WINE_RB_FOR_EACH_ENTRY(local, &ctx->local_scopes[scope].locals, function_local_t, entry) { + func->local_scopes[scope].locals[i].name = local->name; + func->local_scopes[scope].locals[i].ref = local->ref; + if(local->ref >= 0) { + func->variables[local->ref].name = local->name; + func->variables[local->ref].func_id = -1; + } + i++; } - i++; + assert(i == ctx->local_scopes[scope].locals_cnt); } - assert(i == ctx->locals_cnt); func->funcs = compiler_alloc(ctx->code, func->func_cnt * sizeof(*func->funcs)); if(!func->funcs) return E_OUTOFMEMORY; memset(func->funcs, 0, func->func_cnt * sizeof(*func->funcs)); + ctx->current_function_expr = ctx->func_head; off = ctx->code_off; - hres = compile_block_statement(ctx, source->statement); + hres = compile_block_statement(ctx, NULL, source); if(FAILED(hres)) return hres; @@ -2369,13 +2629,17 @@ static HRESULT compile_function(compiler_ctx_t *ctx, source_elements_t *source, func->instr_off = off; for(iter = ctx->func_head, i=0; iter; iter = iter->next, i++) { - hres = compile_function(ctx, iter->source_elements, iter, FALSE, func->funcs+i); + hres = compile_function(ctx, iter->statement_list, iter, FALSE, func->funcs+i); if(FAILED(hres)) return hres; - TRACE("[%d] func %s\n", i, debugstr_w(func->funcs[i].name)); - if(func->funcs[i].name && !func->funcs[i].event_target) { - local_ref_t *local_ref = lookup_local(func, func->funcs[i].name); + func->funcs[i].scope_index = iter->scope_index; + + TRACE("[%d] func %s, scope_index %u\n", i, debugstr_w(func->funcs[i].name), iter->scope_index); + if((ctx->parser->script->version < SCRIPTLANGUAGEVERSION_ES5 || iter->is_statement) && + func->funcs[i].name && !func->funcs[i].event_target) { + local_ref_t *local_ref = lookup_local(func, func->funcs[i].name, func->funcs[i].scope_index); + func->funcs[i].local_ref = local_ref->ref; TRACE("found ref %s %d for %s\n", debugstr_w(local_ref->name), local_ref->ref, debugstr_w(func->funcs[i].name)); if(local_ref->ref >= 0) @@ -2458,13 +2722,14 @@ static HRESULT compile_arguments(compiler_ctx_t *ctx, const WCHAR *args) return parse_arguments(ctx, args, ctx->code->global_code.params, NULL); } -HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args, const WCHAR *delimiter, - BOOL from_eval, BOOL use_decode, bytecode_t **ret) +HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, UINT64 source_context, unsigned start_line, + const WCHAR *args, const WCHAR *delimiter, BOOL from_eval, BOOL use_decode, + named_item_t *named_item, bytecode_t **ret) { compiler_ctx_t compiler = {0}; HRESULT hres; - hres = init_code(&compiler, code); + hres = init_code(&compiler, code, source_context, start_line); if(FAILED(hres)) return hres; @@ -2482,7 +2747,7 @@ HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args, } } - hres = script_parse(ctx, &compiler, compiler.code->source, delimiter, from_eval, &compiler.parser); + hres = script_parse(ctx, &compiler, compiler.code, delimiter, from_eval, &compiler.parser); if(FAILED(hres)) { release_bytecode(compiler.code); return hres; @@ -2490,11 +2755,20 @@ HRESULT compile_script(script_ctx_t *ctx, const WCHAR *code, const WCHAR *args, heap_pool_init(&compiler.heap); hres = compile_function(&compiler, compiler.parser->source, NULL, from_eval, &compiler.code->global_code); + free(compiler.local_scopes); heap_pool_free(&compiler.heap); parser_release(compiler.parser); if(FAILED(hres)) { + if(hres != DISP_E_EXCEPTION) + throw_error(ctx, hres, NULL); + set_error_location(ctx->ei, compiler.code, compiler.loc, IDS_COMPILATION_ERROR, NULL); release_bytecode(compiler.code); - return hres; + return DISP_E_EXCEPTION; + } + + if(named_item) { + compiler.code->named_item = named_item; + named_item->ref++; } *ret = compiler.code; diff --git a/dll/win32/jscript/date.c b/dll/win32/jscript/date.c index 74d436f447d..9ed976c155a 100644 --- a/dll/win32/jscript/date.c +++ b/dll/win32/jscript/date.c @@ -32,9 +32,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); -/* 1601 to 1970 is 369 years plus 89 leap days */ -#define TIME_EPOCH ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000) - typedef struct { jsdisp_t dispex; @@ -48,64 +45,25 @@ typedef struct { LONG daylightBias; } DateInstance; -static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; -static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0}; -static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; -static const WCHAR toISOStringW[] = {'t','o','I','S','O','S','t','r','i','n','g',0}; -static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0}; -static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0}; -static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0}; -static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0}; -static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0}; -static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0}; -static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0}; -static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0}; -static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0}; -static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0}; -static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0}; -static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0}; -static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0}; -static const WCHAR getDayW[] = {'g','e','t','D','a','y',0}; -static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0}; -static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0}; -static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0}; -static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0}; -static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0}; -static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0}; -static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0}; -static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0}; -static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0}; -static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0}; -static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0}; -static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0}; -static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0}; -static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0}; -static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0}; -static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0}; -static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0}; -static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0}; -static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0}; -static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0}; -static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0}; -static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0}; -static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0}; -static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0}; -static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0}; -static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0}; -static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0}; - -static const WCHAR UTCW[] = {'U','T','C',0}; -static const WCHAR nowW[] = {'n','o','w',0}; -static const WCHAR parseW[] = {'p','a','r','s','e',0}; - static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, DateInstance, dispex); } -static inline DateInstance *date_this(vdisp_t *jsthis) +static inline DateInstance *date_this(jsval_t vthis) { - return is_vclass(jsthis, JSCLASS_DATE) ? date_from_jsdisp(jsthis->u.jsdisp) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_DATE)) ? date_from_jsdisp(jsdisp) : NULL; +} + +static inline double file_time_to_date_time(const FILETIME *ftime) +{ + /* 1601 to 1970 is 369 years plus 89 leap days */ + const LONGLONG time_epoch = (LONGLONG)(369 * 365 + 89) * 86400 * 1000; + + LONGLONG time = (((ULONGLONG)ftime->dwHighDateTime << 32) | ftime->dwLowDateTime) / 10000; + + return time - time_epoch; } /*ECMA-262 3rd Edition 15.9.1.2 */ @@ -459,12 +417,9 @@ static inline DOUBLE time_clip(DOUBLE time) static double date_now(void) { FILETIME ftime; - LONGLONG time; GetSystemTimeAsFileTime(&ftime); - time = ((LONGLONG)ftime.dwHighDateTime << 32) + ftime.dwLowDateTime; - - return time/10000 - TIME_EPOCH; + return file_time_to_date_time(&ftime); } static SYSTEMTIME create_systemtime(DOUBLE time) @@ -485,18 +440,6 @@ static SYSTEMTIME create_systemtime(DOUBLE time) static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r) { - static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ', - '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ', - 'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 }; - static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ', - '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ', - 'U','T','C',' ','%','d','%','s',0 }; - static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ', - '%','d',' ','%','0','2','d',':','%','0','2','d',':', - '%','0','2','d',' ','%','d','%','s',0 }; - static const WCHAR ADW[] = { 0 }; - static const WCHAR BCW[] = { ' ','B','.','C','.',0 }; - static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 }; @@ -507,7 +450,7 @@ static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 }; - BOOL formatAD = TRUE; + const WCHAR *formatEra = L""; WCHAR week[64], month[64]; WCHAR buf[192]; jsstr_t *date_jsstr; @@ -532,7 +475,7 @@ static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, year = year_from_time(time); if(year<0) { - formatAD = FALSE; + formatEra = L" B.C."; year = -year+1; } @@ -544,18 +487,18 @@ static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, } if(!show_offset) - swprintf(buf, formatNoOffsetW, week, month, day, + swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %02d:%02d:%02d %d%s", week, month, day, (int)hour_from_time(time), (int)min_from_time(time), - (int)sec_from_time(time), year, formatAD?ADW:BCW); + (int)sec_from_time(time), year, formatEra); else if(offset) - swprintf(buf, formatW, week, month, day, + swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %02d:%02d:%02d UTC%c%02d%02d %d%s", week, month, day, (int)hour_from_time(time), (int)min_from_time(time), (int)sec_from_time(time), sign, offset/60, offset%60, - year, formatAD?ADW:BCW); + year, formatEra); else - swprintf(buf, formatUTCW, week, month, day, + swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %02d:%02d:%02d UTC %d%s", week, month, day, (int)hour_from_time(time), (int)min_from_time(time), - (int)sec_from_time(time), year, formatAD?ADW:BCW); + (int)sec_from_time(time), year, formatEra); date_jsstr = jsstr_alloc(buf); if(!date_jsstr) @@ -579,20 +522,20 @@ static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r) return date_to_string(time, TRUE, offset, r); } -static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Date_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; return dateobj_to_string(date, r); } /* ECMA-262 3rd Edition 15.9.1.5 */ -static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { SYSTEMTIME st; @@ -602,8 +545,8 @@ static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(isnan(date->time)) { if(r) @@ -635,22 +578,17 @@ static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag return S_OK; } -static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toISOString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; WCHAR buf[64], *p = buf; double year; - static const WCHAR short_year_formatW[] = {'%','0','4','d',0}; - static const WCHAR long_year_formatW[] = {'%','0','6','d',0}; - static const WCHAR formatW[] = {'-','%','0','2','d','-','%','0','2','d', - 'T','%','0','2','d',':','%','0','2','d',':','%','0','2','d','.','%','0','3','d','Z',0}; - TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; year = year_from_time(date->time); if(isnan(year) || year > 999999 || year < -999999) { @@ -660,15 +598,15 @@ static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, if(year < 0) { *p++ = '-'; - p += swprintf(p, long_year_formatW, -(int)year); + p += swprintf(p, ARRAY_SIZE(buf) - 1, L"%06d", -(int)year); }else if(year > 9999) { *p++ = '+'; - p += swprintf(p, long_year_formatW, (int)year); + p += swprintf(p, ARRAY_SIZE(buf) - 1, L"%06d", (int)year); }else { - p += swprintf(p, short_year_formatW, (int)year); + p += swprintf(p, ARRAY_SIZE(buf), L"%04d", (int)year); } - swprintf(p, formatW, + swprintf(p, ARRAY_SIZE(buf) - (p - buf), L"-%02d-%02dT%02d:%02d:%02d.%03dZ", (int)month_from_time(date->time) + 1, (int)date_from_time(date->time), (int)hour_from_time(date->time), (int)min_from_time(date->time), (int)sec_from_time(date->time), (int)ms_from_time(date->time)); @@ -682,28 +620,23 @@ static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, return S_OK; } -static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(date->time); return S_OK; } -static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r) +static inline HRESULT create_utc_string(script_ctx_t *ctx, jsval_t vthis, jsval_t *r) { - static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ', - '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 }; - static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ', - '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 }; - static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 }; @@ -714,7 +647,7 @@ static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsva LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 }; - BOOL formatAD = TRUE; + const WCHAR *formatEra = L""; WCHAR week[64], month[64]; WCHAR buf[192]; DateInstance *date; @@ -722,8 +655,8 @@ static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsva int year, day; DWORD lcid_en; - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(isnan(date->time)) { if(r) @@ -742,13 +675,14 @@ static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsva year = year_from_time(date->time); if(year<0) { - formatAD = FALSE; + formatEra = L" B.C."; year = -year+1; } day = date_from_time(date->time); - swprintf(buf, formatAD ? formatADW : formatBCW, week, day, month, year, + swprintf(buf, ARRAY_SIZE(buf), + L"%s, %d %s %d%s %02d:%02d:%02d UTC", week, day, month, year, formatEra, (int)hour_from_time(date->time), (int)min_from_time(date->time), (int)sec_from_time(date->time)); @@ -762,26 +696,23 @@ static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsva } /* ECMA-262 3rd Edition 15.9.5.42 */ -static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toUTCString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); - return create_utc_string(ctx, jsthis, r); + return create_utc_string(ctx, vthis, r); } -static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toGMTString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); - return create_utc_string(ctx, jsthis, r); + return create_utc_string(ctx, vthis, r); } /* ECMA-262 3rd Edition 15.9.5.3 */ static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r) { - static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 }; - static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 }; - static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 }; @@ -792,7 +723,7 @@ static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r) LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 }; - BOOL formatAD = TRUE; + const WCHAR *formatEra = L""; WCHAR week[64], month[64]; WCHAR buf[192]; jsstr_t *date_str; @@ -819,13 +750,13 @@ static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r) year = year_from_time(time); if(year<0) { - formatAD = FALSE; + formatEra = L" B.C."; year = -year+1; } day = date_from_time(time); - swprintf(buf, formatAD ? formatADW : formatBCW, week, month, day, year); + swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %d%s", week, month, day, year, formatEra); date_str = jsstr_alloc(buf); if(!date_str) @@ -836,25 +767,21 @@ static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r) return S_OK; } -static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toDateString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; return dateobj_to_date_string(date, r); } /* ECMA-262 3rd Edition 15.9.5.4 */ -static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toTimeString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d', - ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 }; - static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d', - ':','%','0','2','d',' ','U','T','C',0 }; DateInstance *date; jsstr_t *date_str; WCHAR buf[32]; @@ -864,8 +791,8 @@ static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(isnan(date->time)) { if(r) @@ -886,11 +813,11 @@ static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, else sign = '-'; if(offset) - swprintf(buf, formatW, (int)hour_from_time(time), + swprintf(buf, ARRAY_SIZE(buf), L"%02d:%02d:%02d UTC%c%02d%02d", (int)hour_from_time(time), (int)min_from_time(time), (int)sec_from_time(time), sign, offset/60, offset%60); else - swprintf(buf, formatUTCW, (int)hour_from_time(time), + swprintf(buf, ARRAY_SIZE(buf), L"%02d:%02d:%02d UTC", (int)hour_from_time(time), (int)min_from_time(time), (int)sec_from_time(time)); date_str = jsstr_alloc(buf); @@ -903,7 +830,7 @@ static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.6 */ -static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { SYSTEMTIME st; @@ -913,8 +840,8 @@ static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(isnan(date->time)) { if(r) @@ -942,7 +869,7 @@ static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD } /* ECMA-262 3rd Edition 15.9.5.7 */ -static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { SYSTEMTIME st; @@ -952,8 +879,8 @@ static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(isnan(date->time)) { if(r) @@ -964,7 +891,7 @@ static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD st = create_systemtime(local_time(date->time, date)); if(st.wYear<1601 || st.wYear>9999) - return Date_toTimeString(ctx, jsthis, flags, argc, argv, r); + return Date_toTimeString(ctx, vthis, flags, argc, argv, r); if(r) { WCHAR *ptr; @@ -981,15 +908,15 @@ static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD } /* ECMA-262 3rd Edition 15.9.5.9 */ -static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getTime(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(date->time); @@ -997,15 +924,15 @@ static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi } /* ECMA-262 3rd Edition 15.9.5.10 */ -static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) { DOUBLE time = local_time(date->time, date); @@ -1016,15 +943,15 @@ static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.11 */ -static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(year_from_time(date->time)); @@ -1032,14 +959,14 @@ static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag } /* ECMA-262 3rd Edition 15.9.5.12 */ -static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Date_getMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(month_from_time(local_time(date->time, date))); @@ -1047,15 +974,15 @@ static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns } /* ECMA-262 3rd Edition 15.9.5.13 */ -static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(month_from_time(date->time)); @@ -1063,14 +990,14 @@ static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.14 */ -static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Date_getDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(date_from_time(local_time(date->time, date))); @@ -1078,15 +1005,15 @@ static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi } /* ECMA-262 3rd Edition 15.9.5.15 */ -static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(date_from_time(date->time)); @@ -1094,15 +1021,15 @@ static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.9.5.16 */ -static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getDay(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(week_day(local_time(date->time, date))); @@ -1110,15 +1037,15 @@ static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsig } /* ECMA-262 3rd Edition 15.9.5.17 */ -static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCDay(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(week_day(date->time)); @@ -1126,15 +1053,15 @@ static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un } /* ECMA-262 3rd Edition 15.9.5.18 */ -static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(hour_from_time(local_time(date->time, date))); @@ -1142,15 +1069,15 @@ static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns } /* ECMA-262 3rd Edition 15.9.5.19 */ -static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(hour_from_time(date->time)); @@ -1158,15 +1085,15 @@ static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.20 */ -static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(min_from_time(local_time(date->time, date))); @@ -1174,15 +1101,15 @@ static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.9.5.21 */ -static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(min_from_time(date->time)); @@ -1190,14 +1117,14 @@ static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags } /* ECMA-262 3rd Edition 15.9.5.22 */ -static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Date_getSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(sec_from_time(local_time(date->time, date))); @@ -1205,15 +1132,15 @@ static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.9.5.23 */ -static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(sec_from_time(date->time)); @@ -1221,15 +1148,15 @@ static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags } /* ECMA-262 3rd Edition 15.9.5.24 */ -static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(ms_from_time(local_time(date->time, date))); @@ -1237,15 +1164,15 @@ static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla } /* ECMA-262 3rd Edition 15.9.5.25 */ -static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(ms_from_time(date->time)); @@ -1253,15 +1180,15 @@ static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD } /* ECMA-262 3rd Edition 15.9.5.26 */ -static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(r) *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE)); @@ -1269,7 +1196,7 @@ static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD f } /* ECMA-262 3rd Edition 15.9.5.27 */ -static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setTime(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { double n; @@ -1278,11 +1205,11 @@ static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) @@ -1296,7 +1223,7 @@ static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi } /* ECMA-262 3rd Edition 15.9.5.28 */ -static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1305,11 +1232,11 @@ static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) @@ -1326,7 +1253,7 @@ static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla } /* ECMA-262 3rd Edition 15.9.5.29 */ -static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1335,11 +1262,11 @@ static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) @@ -1356,7 +1283,7 @@ static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD } /* ECMA-262 3rd Edition 15.9.5.30 */ -static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1365,11 +1292,11 @@ static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = local_time(date->time, date); @@ -1395,7 +1322,7 @@ static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.9.5.31 */ -static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1404,11 +1331,11 @@ static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = date->time; @@ -1434,7 +1361,7 @@ static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags } /* ECMA-262 3rd Edition 15.9.5.33 */ -static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1443,11 +1370,11 @@ static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = local_time(date->time, date); @@ -1481,7 +1408,7 @@ static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.9.5.34 */ -static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1490,11 +1417,11 @@ static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = date->time; @@ -1528,7 +1455,7 @@ static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags } /* ECMA-262 3rd Edition 15.9.5.35 */ -static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1537,11 +1464,11 @@ static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = local_time(date->time, date); @@ -1582,7 +1509,7 @@ static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns } /* ECMA-262 3rd Edition 15.9.5.36 */ -static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1591,11 +1518,11 @@ static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = date->time; @@ -1636,7 +1563,7 @@ static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.36 */ -static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1645,11 +1572,11 @@ static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) @@ -1665,7 +1592,7 @@ static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi } /* ECMA-262 3rd Edition 15.9.5.37 */ -static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1674,11 +1601,11 @@ static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; hres = to_number(ctx, argv[0], &n); if(FAILED(hres)) @@ -1694,7 +1621,7 @@ static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.9.5.38 */ -static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1703,11 +1630,11 @@ static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = local_time(date->time, date); @@ -1733,7 +1660,7 @@ static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns } /* ECMA-262 3rd Edition 15.9.5.39 */ -static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1742,11 +1669,11 @@ static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = date->time; @@ -1772,7 +1699,7 @@ static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.40 */ -static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1781,11 +1708,11 @@ static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = local_time(date->time, date); @@ -1818,7 +1745,7 @@ static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } /* ECMA-262 3rd Edition 15.9.5.41 */ -static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1827,11 +1754,11 @@ static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = date->time; @@ -1864,7 +1791,7 @@ static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag } /* ECMA-262 3rd Edition B2.4 */ -static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_getYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1872,8 +1799,8 @@ static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; t = local_time(date->time, date); if(isnan(t)) { @@ -1889,7 +1816,7 @@ static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi } /* ECMA-262 3rd Edition B2.5 */ -static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Date_setYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { DateInstance *date; @@ -1898,11 +1825,11 @@ static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi TRACE("\n"); - if(!(date = date_this(jsthis))) - return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL); + if(!(date = date_this(vthis))) + return JS_E_DATE_EXPECTED; if(!argc) - return throw_type_error(ctx, JS_E_MISSING_ARG, NULL); + return JS_E_MISSING_ARG; t = local_time(date->time, date); @@ -1928,79 +1855,65 @@ static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsi return S_OK; } -static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) -{ - TRACE("\n"); - - return dateobj_to_string(date_from_jsdisp(jsthis), r); -} - static const builtin_prop_t Date_props[] = { - {getDateW, Date_getDate, PROPF_METHOD}, - {getDayW, Date_getDay, PROPF_METHOD}, - {getFullYearW, Date_getFullYear, PROPF_METHOD}, - {getHoursW, Date_getHours, PROPF_METHOD}, - {getMillisecondsW, Date_getMilliseconds, PROPF_METHOD}, - {getMinutesW, Date_getMinutes, PROPF_METHOD}, - {getMonthW, Date_getMonth, PROPF_METHOD}, - {getSecondsW, Date_getSeconds, PROPF_METHOD}, - {getTimeW, Date_getTime, PROPF_METHOD}, - {getTimezoneOffsetW, Date_getTimezoneOffset, PROPF_METHOD}, - {getUTCDateW, Date_getUTCDate, PROPF_METHOD}, - {getUTCDayW, Date_getUTCDay, PROPF_METHOD}, - {getUTCFullYearW, Date_getUTCFullYear, PROPF_METHOD}, - {getUTCHoursW, Date_getUTCHours, PROPF_METHOD}, - {getUTCMillisecondsW, Date_getUTCMilliseconds, PROPF_METHOD}, - {getUTCMinutesW, Date_getUTCMinutes, PROPF_METHOD}, - {getUTCMonthW, Date_getUTCMonth, PROPF_METHOD}, - {getUTCSecondsW, Date_getUTCSeconds, PROPF_METHOD}, - {getYearW, Date_getYear, PROPF_METHOD}, - {setDateW, Date_setDate, PROPF_METHOD|1}, - {setFullYearW, Date_setFullYear, PROPF_METHOD|3}, - {setHoursW, Date_setHours, PROPF_METHOD|4}, - {setMillisecondsW, Date_setMilliseconds, PROPF_METHOD|1}, - {setMinutesW, Date_setMinutes, PROPF_METHOD|3}, - {setMonthW, Date_setMonth, PROPF_METHOD|2}, - {setSecondsW, Date_setSeconds, PROPF_METHOD|2}, - {setTimeW, Date_setTime, PROPF_METHOD|1}, - {setUTCDateW, Date_setUTCDate, PROPF_METHOD|1}, - {setUTCFullYearW, Date_setUTCFullYear, PROPF_METHOD|3}, - {setUTCHoursW, Date_setUTCHours, PROPF_METHOD|4}, - {setUTCMillisecondsW, Date_setUTCMilliseconds, PROPF_METHOD|1}, - {setUTCMinutesW, Date_setUTCMinutes, PROPF_METHOD|3}, - {setUTCMonthW, Date_setUTCMonth, PROPF_METHOD|2}, - {setUTCSecondsW, Date_setUTCSeconds, PROPF_METHOD|2}, - {setYearW, Date_setYear, PROPF_METHOD|1}, - {toDateStringW, Date_toDateString, PROPF_METHOD}, - {toGMTStringW, Date_toGMTString, PROPF_METHOD}, - {toISOStringW, Date_toISOString, PROPF_METHOD|PROPF_ES5}, - {toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD}, - {toLocaleStringW, Date_toLocaleString, PROPF_METHOD}, - {toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD}, - {toStringW, Date_toString, PROPF_METHOD}, - {toTimeStringW, Date_toTimeString, PROPF_METHOD}, - {toUTCStringW, Date_toUTCString, PROPF_METHOD}, - {valueOfW, Date_valueOf, PROPF_METHOD}, + {L"getDate", Date_getDate, PROPF_METHOD}, + {L"getDay", Date_getDay, PROPF_METHOD}, + {L"getFullYear", Date_getFullYear, PROPF_METHOD}, + {L"getHours", Date_getHours, PROPF_METHOD}, + {L"getMilliseconds", Date_getMilliseconds, PROPF_METHOD}, + {L"getMinutes", Date_getMinutes, PROPF_METHOD}, + {L"getMonth", Date_getMonth, PROPF_METHOD}, + {L"getSeconds", Date_getSeconds, PROPF_METHOD}, + {L"getTime", Date_getTime, PROPF_METHOD}, + {L"getTimezoneOffset", Date_getTimezoneOffset, PROPF_METHOD}, + {L"getUTCDate", Date_getUTCDate, PROPF_METHOD}, + {L"getUTCDay", Date_getUTCDay, PROPF_METHOD}, + {L"getUTCFullYear", Date_getUTCFullYear, PROPF_METHOD}, + {L"getUTCHours", Date_getUTCHours, PROPF_METHOD}, + {L"getUTCMilliseconds", Date_getUTCMilliseconds, PROPF_METHOD}, + {L"getUTCMinutes", Date_getUTCMinutes, PROPF_METHOD}, + {L"getUTCMonth", Date_getUTCMonth, PROPF_METHOD}, + {L"getUTCSeconds", Date_getUTCSeconds, PROPF_METHOD}, + {L"getYear", Date_getYear, PROPF_METHOD}, + {L"setDate", Date_setDate, PROPF_METHOD|1}, + {L"setFullYear", Date_setFullYear, PROPF_METHOD|3}, + {L"setHours", Date_setHours, PROPF_METHOD|4}, + {L"setMilliseconds", Date_setMilliseconds, PROPF_METHOD|1}, + {L"setMinutes", Date_setMinutes, PROPF_METHOD|3}, + {L"setMonth", Date_setMonth, PROPF_METHOD|2}, + {L"setSeconds", Date_setSeconds, PROPF_METHOD|2}, + {L"setTime", Date_setTime, PROPF_METHOD|1}, + {L"setUTCDate", Date_setUTCDate, PROPF_METHOD|1}, + {L"setUTCFullYear", Date_setUTCFullYear, PROPF_METHOD|3}, + {L"setUTCHours", Date_setUTCHours, PROPF_METHOD|4}, + {L"setUTCMilliseconds", Date_setUTCMilliseconds, PROPF_METHOD|1}, + {L"setUTCMinutes", Date_setUTCMinutes, PROPF_METHOD|3}, + {L"setUTCMonth", Date_setUTCMonth, PROPF_METHOD|2}, + {L"setUTCSeconds", Date_setUTCSeconds, PROPF_METHOD|2}, + {L"setYear", Date_setYear, PROPF_METHOD|1}, + {L"toDateString", Date_toDateString, PROPF_METHOD}, + {L"toGMTString", Date_toGMTString, PROPF_METHOD}, + {L"toISOString", Date_toISOString, PROPF_METHOD|PROPF_ES5}, + {L"toLocaleDateString", Date_toLocaleDateString, PROPF_METHOD}, + {L"toLocaleString", Date_toLocaleString, PROPF_METHOD}, + {L"toLocaleTimeString", Date_toLocaleTimeString, PROPF_METHOD}, + {L"toString", Date_toString, PROPF_METHOD}, + {L"toTimeString", Date_toTimeString, PROPF_METHOD}, + {L"toUTCString", Date_toUTCString, PROPF_METHOD}, + {L"valueOf", Date_valueOf, PROPF_METHOD}, }; static const builtin_info_t Date_info = { - JSCLASS_DATE, - {NULL, NULL,0, Date_get_value}, - ARRAY_SIZE(Date_props), - Date_props, - NULL, - NULL + .class = JSCLASS_DATE, + .props_cnt = ARRAY_SIZE(Date_props), + .props = Date_props, }; static const builtin_info_t DateInst_info = { - JSCLASS_DATE, - {NULL, NULL,0, Date_get_value}, - 0, NULL, - NULL, - NULL + .class = JSCLASS_DATE, }; -static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret) +static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, DateInstance **ret) { DateInstance *date; HRESULT hres; @@ -2008,7 +1921,7 @@ static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE GetTimeZoneInformation(&tzi); - date = heap_alloc_zero(sizeof(DateInstance)); + date = calloc(1, sizeof(DateInstance)); if(!date) return E_OUTOFMEMORY; @@ -2017,7 +1930,7 @@ static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE else hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr); if(FAILED(hres)) { - heap_free(date); + free(date); return hres; } @@ -2028,7 +1941,7 @@ static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE date->daylightDate = tzi.DaylightDate; date->daylightBias = tzi.DaylightBias; - *ret = &date->dispex; + *ret = date; return S_OK; } @@ -2070,7 +1983,7 @@ static inline HRESULT date_parse(jsstr_t *input_str, double *ret) { else if(!nest_level) parse_len++; } - parse = heap_alloc((parse_len+1)*sizeof(WCHAR)); + parse = malloc((parse_len+1)*sizeof(WCHAR)); if(!parse) return E_OUTOFMEMORY; nest_level = 0; @@ -2093,12 +2006,12 @@ static inline HRESULT date_parse(jsstr_t *input_str, double *ret) { lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT); for(i=0; i= 0) - heap_free(strings[i]); - heap_free(parse); + free(strings[i]); + free(parse); return E_OUTOFMEMORY; } GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size); @@ -2273,7 +2186,7 @@ static inline HRESULT date_parse(jsstr_t *input_str, double *ret) { size -= i; for(j=0; jtime = utc(di->time, di); + date->time = utc(date->time, date); } } - *r = jsval_obj(date); + if(r) *r = jsval_obj(&date->dispex); + else jsdisp_release(&date->dispex); return S_OK; case INVOKE_FUNC: { FILETIME system_time, local_time; - LONGLONG lltime; GetSystemTimeAsFileTime(&system_time); FileTimeToLocalFileTime(&system_time, &local_time); - lltime = ((LONGLONG)local_time.dwHighDateTime<<32) - + local_time.dwLowDateTime; - return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r); + return date_to_string(file_time_to_date_time(&local_time), FALSE, 0, r); } default: @@ -2517,34 +2427,76 @@ static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } static const builtin_prop_t DateConstr_props[] = { - {UTCW, DateConstr_UTC, PROPF_METHOD}, - {nowW, DateConstr_now, PROPF_HTML|PROPF_METHOD}, - {parseW, DateConstr_parse, PROPF_METHOD} + {L"UTC", DateConstr_UTC, PROPF_METHOD}, + {L"now", DateConstr_now, PROPF_HTML|PROPF_METHOD}, + {L"parse", DateConstr_parse, PROPF_METHOD} }; static const builtin_info_t DateConstr_info = { - JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, - ARRAY_SIZE(DateConstr_props), - DateConstr_props, - NULL, - NULL + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(DateConstr_props), + .props = DateConstr_props, }; HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) { - jsdisp_t *date; + DateInstance *date; HRESULT hres; - static const WCHAR DateW[] = {'D','a','t','e',0}; - hres = create_date(ctx, object_prototype, 0.0, &date); if(FAILED(hres)) return hres; - hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info, - PROPF_CONSTR|7, date, ret); + hres = create_builtin_constructor(ctx, DateConstr_value, L"Date", &DateConstr_info, + PROPF_CONSTR|7, &date->dispex, ret); - jsdisp_release(date); + jsdisp_release(&date->dispex); + return hres; +} + +HRESULT variant_date_to_number(double date, double *ret) +{ + SYSTEMTIME st; + UDATE udate; + HRESULT hres; + + hres = VarUdateFromDate(date, 0, &udate); + if(FAILED(hres)) + return hres; + + if(!TzSpecificLocalTimeToSystemTime(NULL, &udate.st, &st)) + return E_FAIL; + + TRACE("%uy %um %u %ud %uh %um %u.%us\n", st.wYear, st.wMonth, st.wDayOfWeek, st.wDay, st.wHour, st.wMinute, + st.wSecond, st.wMilliseconds); + + *ret = make_date(make_day(st.wYear, st.wMonth - 1, st.wDay), + make_time(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds)); + return S_OK; +} + +HRESULT variant_date_to_string(script_ctx_t *ctx, double date, jsstr_t **r) +{ + DateInstance *date_obj; + jsval_t val; + double time; + HRESULT hres; + + hres = variant_date_to_number(date, &time); + if(FAILED(hres)) + return hres; + + hres = create_date(ctx, NULL, time, &date_obj); + if(FAILED(hres)) + return hres; + + hres = dateobj_to_string(date_obj, &val); + jsdisp_release(&date_obj->dispex); + if(FAILED(hres)) + return hres; + + assert(is_string(val)); + *r = get_string(val); return hres; } diff --git a/dll/win32/jscript/decode.c b/dll/win32/jscript/decode.c index 283aa2ed947..6a87d55e0e0 100644 --- a/dll/win32/jscript/decode.c +++ b/dll/win32/jscript/decode.c @@ -113,14 +113,14 @@ HRESULT decode_source(WCHAR *code) const WCHAR *src = code; WCHAR *dst = code; - static const WCHAR decode_beginW[] = {'#','@','~','^'}; - static const WCHAR decode_endW[] = {'^','#','~','@'}; + static const WCHAR decode_beginW[] = L"#@~^"; + static const WCHAR decode_endW[] = L"^#~@"; while(*src) { - if(!wcsncmp(src, decode_beginW, ARRAY_SIZE(decode_beginW))) { + if(!wcsncmp(src, decode_beginW, ARRAY_SIZE(decode_beginW)-1)) { DWORD len, i, j=0, csum, s=0; - src += ARRAY_SIZE(decode_beginW); + src += ARRAY_SIZE(decode_beginW) - 1; if(!decode_dword(src, &len)) return JS_E_INVALID_CHAR; @@ -165,9 +165,9 @@ HRESULT decode_source(WCHAR *code) return JS_E_INVALID_CHAR; src += 8; - if(wcsncmp(src, decode_endW, ARRAY_SIZE(decode_endW))) + if(wcsncmp(src, decode_endW, ARRAY_SIZE(decode_endW)-1)) return JS_E_INVALID_CHAR; - src += ARRAY_SIZE(decode_endW); + src += ARRAY_SIZE(decode_endW) - 1; }else { *dst++ = *src++; } diff --git a/dll/win32/jscript/dispex.c b/dll/win32/jscript/dispex.c index 8b45bebb082..d5ed3adf4fb 100644 --- a/dll/win32/jscript/dispex.c +++ b/dll/win32/jscript/dispex.c @@ -19,11 +19,14 @@ #include #include "jscript.h" +#include "engine.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(jscript); +static const GUID GUID_JScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}}; + #define FDEX_VERSION_MASK 0xf0000000 #define GOLDEN_RATIO 0x9E3779B9U @@ -33,7 +36,7 @@ typedef enum { PROP_PROTREF, PROP_ACCESSOR, PROP_DELETED, - PROP_IDX + PROP_EXTERN } prop_type_t; struct _dispex_prop_t { @@ -46,7 +49,7 @@ struct _dispex_prop_t { jsval_t val; const builtin_prop_t *p; DWORD ref; - unsigned idx; + unsigned id; struct { jsdisp_t *getter; jsdisp_t *setter; @@ -57,24 +60,63 @@ struct _dispex_prop_t { int bucket_next; }; +static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) +{ + DWORD ref; + + if(prop->type != PROP_PROTREF) + return; + ref = prop->u.ref; + + while((jsdisp = jsdisp->prototype)) { + if(ref >= jsdisp->prop_cnt || jsdisp->props[ref].type == PROP_DELETED) + break; + if(jsdisp->props[ref].type != PROP_PROTREF) + return; + ref = jsdisp->props[ref].u.ref; + } + prop->type = PROP_DELETED; +} + static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop) { - return prop - This->props; + /* don't overlap with DISPID_VALUE */ + return prop - This->props + 1; } static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) { - if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED) - return NULL; + DWORD idx = id - 1; - return This->props+id; + if(idx >= This->prop_cnt) + return NULL; + fix_protref_prop(This, &This->props[idx]); + + return This->props[idx].type == PROP_DELETED ? NULL : &This->props[idx]; +} + +static inline BOOL is_function_prop(dispex_prop_t *prop) +{ + BOOL ret = FALSE; + + if (is_object_instance(prop->u.val)) + { + jsdisp_t *jsdisp = to_jsdisp(get_object(prop->u.val)); + + if (jsdisp) ret = is_class(jsdisp, JSCLASS_FUNCTION); + } + return ret; } static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { - dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref); - if(!parent) { + dispex_prop_t *parent = NULL; + + if(prop->u.ref < This->prototype->prop_cnt) + parent = &This->prototype->props[prop->u.ref]; + + if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; return 0; } @@ -85,28 +127,24 @@ static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) return prop->flags; } -static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name) +static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens) { - int min = 0, max, i, r; + int min = 0, max = This->builtin_info->props_cnt-1, i, r; + unsigned version; + + if(case_insens) { + for(i = min; i <= max; i++) + if(!wcsicmp(name, This->builtin_info->props[i].name)) + goto found; + return NULL; + } - max = This->builtin_info->props_cnt-1; while(min <= max) { i = (min+max)/2; r = wcscmp(name, This->builtin_info->props[i].name); - if(!r) { - /* Skip prop if it's available only in higher compatibility mode. */ - unsigned version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK) - >> PROPF_VERSION_SHIFT; - if(version && version > This->ctx->version) - return NULL; - - /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */ - if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode) - return NULL; - - return This->builtin_info->props + i; - } + if(!r) + goto found; if(r < 0) max = i-1; @@ -115,6 +153,18 @@ static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name } return NULL; + +found: + /* Skip prop if it's available only in higher compatibility mode. */ + version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK) >> PROPF_VERSION_SHIFT; + if(version && version > This->ctx->version) + return NULL; + + /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */ + if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode) + return NULL; + + return This->builtin_info->props + i; } static inline unsigned string_hash(const WCHAR *name) @@ -138,18 +188,18 @@ static inline HRESULT resize_props(jsdisp_t *This) if(This->buf_size != This->prop_cnt) return S_FALSE; - props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2); + props = realloc(This->props, sizeof(dispex_prop_t) * This->buf_size * 2); if(!props) return E_OUTOFMEMORY; This->buf_size *= 2; This->props = props; for(i=0; ibuf_size; i++) { - This->props[i].bucket_head = 0; - This->props[i].bucket_next = 0; + This->props[i].bucket_head = ~0; + This->props[i].bucket_next = ~0; } - for(i=1; iprop_cnt; i++) { + for(i=0; iprop_cnt; i++) { props = This->props+i; bucket = get_props_idx(This, props->hash); @@ -169,7 +219,7 @@ static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_ return NULL; prop = &This->props[This->prop_cnt]; - prop->name = heap_strdupW(name); + prop->name = wcsdup(name); if(!prop->name) return NULL; prop->type = type; @@ -194,39 +244,148 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref return ret; } -static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret) +static dispex_prop_t *lookup_dispex_prop(jsdisp_t *obj, unsigned hash, const WCHAR *name, BOOL case_insens) { - const builtin_prop_t *builtin; - unsigned bucket, pos, prev = 0; - dispex_prop_t *prop; + unsigned bucket, pos, prev = ~0; - bucket = get_props_idx(This, hash); - pos = This->props[bucket].bucket_head; - while(pos != 0) { - if(!wcscmp(name, This->props[pos].name)) { - if(prev != 0) { - This->props[prev].bucket_next = This->props[pos].bucket_next; - This->props[pos].bucket_next = This->props[bucket].bucket_head; - This->props[bucket].bucket_head = pos; + bucket = get_props_idx(obj, hash); + pos = obj->props[bucket].bucket_head; + while(pos != ~0) { + if(case_insens ? !wcsicmp(name, obj->props[pos].name) : !wcscmp(name, obj->props[pos].name)) { + if(prev != ~0) { + obj->props[prev].bucket_next = obj->props[pos].bucket_next; + obj->props[pos].bucket_next = obj->props[bucket].bucket_head; + obj->props[bucket].bucket_head = pos; } - *ret = &This->props[pos]; - return S_OK; + return &obj->props[pos]; } prev = pos; - pos = This->props[pos].bucket_next; + pos = obj->props[pos].bucket_next; } - builtin = find_builtin_prop(This, name); - if(builtin) { + return NULL; +} + +static HRESULT update_external_prop(jsdisp_t *obj, const WCHAR *name, dispex_prop_t *prop, const struct property_info *desc, dispex_prop_t **ret) +{ + HRESULT hres; + + if(desc->name) + name = desc->name; + + if(!desc->iid) { + if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0))) + return E_OUTOFMEMORY; + prop->type = PROP_EXTERN; + prop->u.id = desc->id; + }else if(prop) { + /* If a property for a host non-volatile already exists, it must have been deleted. */ + *ret = prop; + return S_OK; + }else if(desc->flags & PROPF_METHOD) { + jsdisp_t *func; + + hres = create_host_function(obj->ctx, desc, DISPATCH_METHOD, &func); + if(FAILED(hres)) + return hres; + + if(!(prop = alloc_prop(obj, name, PROP_JSVAL, 0))) + return E_OUTOFMEMORY; + prop->u.val = jsval_obj(func); + }else { + jsdisp_t *getter, *setter = NULL; + + hres = create_host_function(obj->ctx, desc, DISPATCH_PROPERTYGET, &getter); + if(FAILED(hres)) + return hres; + + if(desc->flags & PROPF_WRITABLE) { + hres = create_host_function(obj->ctx, desc, DISPATCH_PROPERTYPUT, &setter); + if(FAILED(hres)) { + jsdisp_release(getter); + return hres; + } + } + + if(!(prop = alloc_prop(obj, name, PROP_ACCESSOR, 0))) + return E_OUTOFMEMORY; + prop->u.accessor.getter = getter; + prop->u.accessor.setter = setter; + } + + prop->flags = desc->flags & PROPF_ALL; + *ret = prop; + return S_OK; +} + +static HRESULT find_external_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens, dispex_prop_t *prop, dispex_prop_t **ret) +{ + if(This->builtin_info->lookup_prop) { + struct property_info desc; + HRESULT hres; + + hres = This->builtin_info->lookup_prop(This, name, + case_insens ? fdexNameCaseInsensitive : fdexNameCaseSensitive, &desc); + if(hres != DISP_E_UNKNOWNNAME) { + if(FAILED(hres)) + return hres; + + if(prop && desc.name && wcscmp(prop->name, desc.name)) { + prop = lookup_dispex_prop(This, string_hash(desc.name), desc.name, case_insens); + if(prop && prop->type != PROP_EXTERN && prop->type != PROP_DELETED && prop->type != PROP_PROTREF) { + *ret = prop; + return S_OK; + } + } + + return update_external_prop(This, name, prop, &desc, ret); + }else if(prop && prop->type == PROP_EXTERN) { + prop->type = PROP_DELETED; + } + } + + *ret = prop; + return S_OK; +} + +static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, + dispex_prop_t *prop, dispex_prop_t **ret) +{ + const builtin_prop_t *builtin; + HRESULT hres; + + if(!prop) + prop = lookup_dispex_prop(This, hash, name, case_insens); + if(prop && prop->type != PROP_DELETED && prop->type != PROP_EXTERN) { + *ret = prop; + return S_OK; + } + + if(!prop && (builtin = find_builtin_prop(This, name, case_insens))) { unsigned flags = builtin->flags; - if(flags & PROPF_METHOD) - flags |= PROPF_WRITABLE | PROPF_CONFIGURABLE; - else if(builtin->setter) + if(flags & PROPF_METHOD) { + jsdisp_t *obj; + + hres = create_builtin_function(This->ctx, builtin->invoke, builtin->name, NULL, flags, NULL, &obj); + if(FAILED(hres)) + return hres; + + prop = alloc_prop(This, builtin->name, PROP_JSVAL, (flags & PROPF_ALL) | PROPF_WRITABLE | PROPF_CONFIGURABLE); + if(!prop) { + jsdisp_release(obj); + return E_OUTOFMEMORY; + } + + prop->type = PROP_JSVAL; + prop->u.val = jsval_obj(obj); + *ret = prop; + return S_OK; + }else if(builtin->setter) flags |= PROPF_WRITABLE; flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; - prop = alloc_prop(This, name, PROP_BUILTIN, flags); + prop = alloc_prop(This, builtin->name, PROP_BUILTIN, flags); if(!prop) return E_OUTOFMEMORY; @@ -235,85 +394,83 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return S_OK; } - if(This->builtin_info->idx_length) { - const WCHAR *ptr; - unsigned idx = 0; - - for(ptr = name; iswdigit(*ptr) && idx < 0x10000; ptr++) - idx = idx*10 + (*ptr-'0'); - if(!*ptr && idx < This->builtin_info->idx_length(This)) { - prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? PROPF_WRITABLE : 0); - if(!prop) - return E_OUTOFMEMORY; - - prop->u.idx = idx; - *ret = prop; - return S_OK; - } - } - - *ret = NULL; - return S_OK; + return find_external_prop(This, name, case_insens, prop, ret); } -static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret) +static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, + dispex_prop_t *own_prop, dispex_prop_t **ret) { - dispex_prop_t *prop, *del=NULL; + dispex_prop_t *prot_prop = NULL; HRESULT hres; - hres = find_prop_name(This, hash, name, &prop); + hres = find_prop_name(This, hash, name, case_insens, own_prop, &own_prop); if(FAILED(hres)) return hres; - if(prop && prop->type==PROP_DELETED) { - del = prop; - } else if(prop) { - *ret = prop; - return S_OK; + if(own_prop) { + if(own_prop->type == PROP_PROTREF) { + prot_prop = &This->prototype->props[own_prop->u.ref]; + }else if(own_prop->type != PROP_DELETED) { + *ret = own_prop; + return S_OK; + } } if(This->prototype) { - hres = find_prop_name_prot(This->prototype, hash, name, &prop); + hres = find_prop_name_prot(This->prototype, hash, name, case_insens, prot_prop, &prot_prop); if(FAILED(hres)) return hres; - if(prop) { - if(del) { - del->type = PROP_PROTREF; - del->u.ref = prop - This->prototype->props; - prop = del; + if(prot_prop && prot_prop->type != PROP_DELETED) { + if(own_prop && case_insens && wcscmp(prot_prop->name, own_prop->name)) { + hres = find_prop_name(This, prot_prop->hash, prot_prop->name, FALSE, NULL, &own_prop); + if(FAILED(hres)) + return hres; + if(own_prop && own_prop->type != PROP_DELETED) { + *ret = own_prop; + return S_OK; + } + } + if(own_prop) { + own_prop->type = PROP_PROTREF; + own_prop->u.ref = prot_prop - This->prototype->props; }else { - prop = alloc_protref(This, prop->name, prop - This->prototype->props); - if(!prop) + own_prop = alloc_protref(This, prot_prop->name, prot_prop - This->prototype->props); + if(!own_prop) return E_OUTOFMEMORY; } - - *ret = prop; - return S_OK; + }else if(own_prop) { + own_prop->type = PROP_DELETED; } } - *ret = del; + *ret = own_prop; return S_OK; } -static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, dispex_prop_t **ret) +static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, dispex_prop_t **ret) { dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(This, string_hash(name), name, &prop); + hres = find_prop_name_prot(This, string_hash(name), name, case_insens, NULL, &prop); if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) { - TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags); + TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); - if(prop) { - prop->type = PROP_JSVAL; - prop->flags = create_flags; - prop->u.val = jsval_undefined(); - }else { - prop = alloc_prop(This, name, PROP_JSVAL, create_flags); + if(!prop) { + prop = alloc_prop(This, name, PROP_DELETED, 0); if(!prop) return E_OUTOFMEMORY; } + if(This->builtin_info->lookup_prop) { + struct property_info desc; + hres = This->builtin_info->lookup_prop(This, name, fdexNameEnsure, &desc); + if(hres == S_OK) + return update_external_prop(This, name, prop, &desc, ret); + } + + hres = S_OK; + prop->type = PROP_JSVAL; + prop->flags = create_flags; prop->u.val = jsval_undefined(); } @@ -321,6 +478,44 @@ static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_ return hres; } +HRESULT jsdisp_index_lookup(jsdisp_t *obj, const WCHAR *name, unsigned length, struct property_info *desc) +{ + const WCHAR *ptr; + unsigned idx = 0; + + for(ptr = name; is_digit(*ptr); ptr++) { + idx = idx * 10 + (*ptr - '0'); + if (idx >= length) + return DISP_E_UNKNOWNNAME; + } + if(*ptr) + return DISP_E_UNKNOWNNAME; + + desc->id = idx; + desc->flags = PROPF_ENUMERABLE; + if(obj->builtin_info->prop_put) + desc->flags |= PROPF_WRITABLE; + desc->name = NULL; + desc->index = idx; + desc->iid = 0; + return S_OK; +} + +HRESULT jsdisp_next_index(jsdisp_t *obj, unsigned length, unsigned id, struct property_info *desc) +{ + if(id + 1 == length) + return S_FALSE; + + desc->id = id + 1; + desc->flags = PROPF_ENUMERABLE; + if(obj->builtin_info->prop_put) + desc->flags |= PROPF_WRITABLE; + desc->name = NULL; + desc->index = desc->id; + desc->iid = 0; + return S_OK; +} + static IDispatch *get_this(DISPPARAMS *dp) { DWORD i; @@ -339,7 +534,7 @@ static IDispatch *get_this(DISPPARAMS *dp) return NULL; } -static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret) +static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret) { jsval_t *argv; unsigned cnt; @@ -349,7 +544,7 @@ static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc cnt = dp->cArgs - dp->cNamedArgs; if(cnt > 6) { - argv = heap_alloc(cnt * sizeof(*argv)); + argv = malloc(cnt * sizeof(*argv)); if(!argv) return E_OUTOFMEMORY; }else { @@ -357,12 +552,12 @@ static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc } for(i = 0; i < cnt; i++) { - hres = variant_to_jsval(dp->rgvarg+dp->cArgs-i-1, argv+i); + hres = variant_to_jsval(ctx, dp->rgvarg+dp->cArgs-i-1, argv+i); if(FAILED(hres)) { while(i--) jsval_release(argv[i]); if(argv != buf) - heap_free(argv); + free(argv); return hres; } } @@ -372,63 +567,7 @@ static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc return S_OK; } -static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags, - unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) -{ - HRESULT hres; - - switch(prop->type) { - case PROP_BUILTIN: { - if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) { - WARN("%s is not a constructor\n", debugstr_w(prop->name)); - return E_INVALIDARG; - } - - if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) { - vdisp_t vthis; - - if(This->builtin_info->class != JSCLASS_FUNCTION && prop->u.p->invoke != JSGlobal_eval) - flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - if(jsthis) - set_disp(&vthis, jsthis); - else - set_jsdisp(&vthis, This); - hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r); - vdisp_release(&vthis); - }else { - /* Function object calls are special case */ - hres = Function_invoke(This, jsthis, flags, argc, argv, r); - } - return hres; - } - case PROP_PROTREF: - return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref, - flags, argc, argv, r, caller); - case PROP_JSVAL: { - if(!is_object_instance(prop->u.val)) { - FIXME("invoke %s\n", debugstr_jsval(prop->u.val)); - return E_FAIL; - } - - TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val)); - - return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r); - } - case PROP_ACCESSOR: - FIXME("accessor\n"); - return E_NOTIMPL; - case PROP_IDX: - FIXME("Invoking PROP_IDX not yet supported\n"); - return E_NOTIMPL; - case PROP_DELETED: - assert(0); - } - - assert(0); - return E_FAIL; -} - -static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r) +static HRESULT prop_get(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, jsval_t *r) { jsdisp_t *prop_obj = This; HRESULT hres; @@ -440,38 +579,22 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r) switch(prop->type) { case PROP_BUILTIN: - if(prop->u.p->getter) { - hres = prop->u.p->getter(This->ctx, This, r); - }else { - jsdisp_t *obj; - - assert(prop->u.p->invoke != NULL); - hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL, - prop->u.p->flags, NULL, &obj); - if(FAILED(hres)) - break; - - prop->type = PROP_JSVAL; - prop->u.val = jsval_obj(obj); - - jsdisp_addref(obj); - *r = jsval_obj(obj); - } + hres = prop->u.p->getter(This->ctx, prop_obj, r); break; case PROP_JSVAL: hres = jsval_copy(prop->u.val, r); break; case PROP_ACCESSOR: if(prop->u.accessor.getter) { - hres = jsdisp_call_value(prop->u.accessor.getter, to_disp(This), + hres = jsdisp_call_value(prop->u.accessor.getter, jsval_disp(jsthis), DISPATCH_METHOD, 0, NULL, r); }else { *r = jsval_undefined(); hres = S_OK; } break; - case PROP_IDX: - hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); + case PROP_EXTERN: + hres = prop_obj->builtin_info->prop_get(prop_obj, prop->u.id, r); break; default: ERR("type %d\n", prop->type); @@ -479,11 +602,11 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r) } if(FAILED(hres)) { - TRACE("fail %08x\n", hres); + TRACE("fail %08lx\n", hres); return hres; } - TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_jsval(*r)); + TRACE("%p.%s ret %s\n", This, debugstr_w(prop->name), debugstr_jsval(*r)); return hres; } @@ -513,6 +636,8 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) return prop->u.p->setter(This->ctx, This, val); case PROP_PROTREF: case PROP_DELETED: + if(!This->extensible) + return S_OK; prop->type = PROP_JSVAL; prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE; prop->u.val = jsval_undefined(); @@ -528,19 +653,25 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) TRACE("no setter\n"); return S_OK; } - return jsdisp_call_value(prop->u.accessor.setter, to_disp(This), DISPATCH_METHOD, 1, &val, NULL); - case PROP_IDX: - if(!This->builtin_info->idx_put) { - TRACE("no put_idx\n"); + return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(This), DISPATCH_METHOD, 1, &val, NULL); + case PROP_EXTERN: + if(!This->builtin_info->prop_put) { + TRACE("no prop_put\n"); return S_OK; } - return This->builtin_info->idx_put(This, prop->u.idx, val); + hres = This->builtin_info->prop_put(This, prop->u.id, val); + if(hres != S_FALSE) + return hres; + prop->type = PROP_JSVAL; + prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE; + prop->u.val = jsval_undefined(); + break; default: ERR("type %d\n", prop->type); return E_FAIL; } - TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val)); + TRACE("%p.%s = %s\n", This, debugstr_w(prop->name), debugstr_jsval(val)); hres = jsval_copy(val, &prop->u.val); if(FAILED(hres)) @@ -552,26 +683,120 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) return S_OK; } +static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) +{ + HRESULT hres; + + switch(prop->type) { + case PROP_BUILTIN: + return JS_E_FUNCTION_EXPECTED; + case PROP_PROTREF: + return invoke_prop_func(This->prototype, jsthis ? jsthis : to_disp(This), + This->prototype->props+prop->u.ref, flags, argc, argv, r, caller); + case PROP_JSVAL: { + if(!is_object_instance(prop->u.val)) { + FIXME("value %s is not a function\n", debugstr_jsval(prop->u.val)); + return JS_E_FUNCTION_EXPECTED; + } + + TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val)); + + return disp_call_value_with_caller(This->ctx, get_object(prop->u.val), + jsval_disp(jsthis ? jsthis : to_disp(This)), + flags, argc, argv, r, caller); + } + case PROP_ACCESSOR: + case PROP_EXTERN: { + jsval_t val; + + hres = prop_get(This, jsthis ? jsthis : to_disp(This), prop, &val); + if(FAILED(hres)) + return hres; + + if(is_object_instance(val)) { + jsdisp_t *jsfunc = to_jsdisp(get_object(val)); + if(!jsfunc || is_class(jsfunc, JSCLASS_FUNCTION)) + hres = disp_call_value_with_caller(This->ctx, get_object(val), + jsval_disp(jsthis ? jsthis : to_disp(This)), + flags, argc, argv, r, caller); + else + hres = JS_E_INVALID_PROPERTY; + }else { + WARN("value %s is not a function\n", debugstr_jsval(val)); + hres = JS_E_FUNCTION_EXPECTED; + } + + jsval_release(val); + return hres; + } + case PROP_DELETED: + assert(0); + break; + } + + return E_FAIL; +} + HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) { TRACE("%p %s\n", jsthis, debugstr_jsval(value)); return S_OK; } +static HRESULT fill_props(jsdisp_t *obj) +{ + dispex_prop_t *prop; + HRESULT hres; + + if(obj->builtin_info->next_prop) { + struct property_info desc; + unsigned id = ~0; + WCHAR buf[12]; + + for(;;) { + hres = obj->builtin_info->next_prop(obj, id, &desc); + if(FAILED(hres)) + return hres; + if(hres == S_FALSE) + break; + + if(!desc.name) { + swprintf(buf, ARRAYSIZE(buf), L"%u", desc.index); + desc.name = buf; + } + + prop = lookup_dispex_prop(obj, string_hash(desc.name), desc.name, FALSE); + if(!prop) { + hres = update_external_prop(obj, desc.name, NULL, &desc, &prop); + if(FAILED(hres)) + return hres; + } + id = desc.id; + } + } + + return S_OK; +} + static HRESULT fill_protrefs(jsdisp_t *This) { dispex_prop_t *iter, *prop; HRESULT hres; + hres = fill_props(This); + if(FAILED(hres)) + return hres; + if(!This->prototype) return S_OK; - fill_protrefs(This->prototype); + hres = fill_protrefs(This->prototype); + if(FAILED(hres)) + return hres; for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - if(!iter->name) - continue; - hres = find_prop_name(This, iter->hash, iter->name, &prop); + hres = find_prop_name(This, iter->hash, iter->name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; if(!prop || prop->type==PROP_DELETED) { @@ -590,395 +815,1064 @@ static HRESULT fill_protrefs(jsdisp_t *This) return S_OK; } -static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface) +static void unlink_jsdisp(jsdisp_t *jsdisp) { - return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface); + dispex_prop_t *prop = jsdisp->props, *end; + + for(end = prop + jsdisp->prop_cnt; prop < end; prop++) { + switch(prop->type) { + case PROP_DELETED: + continue; + case PROP_JSVAL: + jsval_release(prop->u.val); + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) + jsdisp_release(prop->u.accessor.getter); + if(prop->u.accessor.setter) + jsdisp_release(prop->u.accessor.setter); + break; + default: + break; + } + prop->type = PROP_DELETED; + } + + if(jsdisp->prototype) { + jsdisp_release(jsdisp->prototype); + jsdisp->prototype = NULL; + } + + if(jsdisp->builtin_info->gc_traverse) + jsdisp->builtin_info->gc_traverse(NULL, GC_TRAVERSE_UNLINK, jsdisp); } -static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - if(IsEqualGUID(&IID_IUnknown, riid)) { - TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); - *ppv = &This->IDispatchEx_iface; - }else if(IsEqualGUID(&IID_IDispatch, riid)) { - TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv); - *ppv = &This->IDispatchEx_iface; - }else if(IsEqualGUID(&IID_IDispatchEx, riid)) { - TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv); - *ppv = &This->IDispatchEx_iface; - }else { + +/* + * To deal with circular refcounts, a basic Garbage Collector is used with a variant of the + * mark-and-sweep algorithm that doesn't require knowing or traversing any specific "roots". + * This works based on the assumption that circular references can only happen when objects + * end up pointing to each other, and each other alone, without any external refs. + * + * An "external ref" is a ref to the object that's not from any other object. Example of such + * refs can be local variables, the script ctx (which keeps a ref to the global object), etc. + * + * At a high level, there are 3 logical passes done on the entire list of objects: + * + * 1. Speculatively decrease refcounts of each linked-to-object from each object. This ensures + * that the only remaining refcount on each object is the number of "external refs" to it. + * At the same time, mark all of the objects so that they can be potentially collected. + * + * 2. For each object with a non-zero "external refcount", clear the mark from step 1, and + * recursively traverse all linked objects from it, clearing their marks as well (regardless + * of their refcount), stopping a given path when the object is unmarked (and then going back + * up the GC stack). This basically unmarks all of the objects with "external refcounts" + * and those accessible from them, and only the leaked dangling objects will still be marked. + * + * 3. For each object that is marked, unlink all of the objects linked from it, because they + * are dangling in a circular refcount and not accessible. This should release them. + * + * During unlinking (GC_TRAVERSE_UNLINK), it is important that we unlink *all* linked objects + * from the object, to be certain that releasing the object later will not delete any other + * objects. Otherwise calculating the "next" object in the list becomes impossible. + * + * This collection process has to be done periodically, but can be pretty expensive so there + * has to be a balance between reclaiming dangling objects and performance. + * + */ +struct gc_stack_chunk { + jsdisp_t *objects[1020]; + struct gc_stack_chunk *prev; +}; + +struct gc_ctx { + struct gc_stack_chunk *chunk; + struct gc_stack_chunk *next; + unsigned idx; +}; + +static HRESULT gc_stack_push(struct gc_ctx *gc_ctx, jsdisp_t *obj) +{ + if(!gc_ctx->idx) { + if(gc_ctx->next) + gc_ctx->chunk = gc_ctx->next; + else { + struct gc_stack_chunk *prev, *tmp = malloc(sizeof(*tmp)); + if(!tmp) + return E_OUTOFMEMORY; + prev = gc_ctx->chunk; + gc_ctx->chunk = tmp; + gc_ctx->chunk->prev = prev; + } + gc_ctx->idx = ARRAY_SIZE(gc_ctx->chunk->objects); + gc_ctx->next = NULL; + } + gc_ctx->chunk->objects[--gc_ctx->idx] = obj; + return S_OK; +} + +static jsdisp_t *gc_stack_pop(struct gc_ctx *gc_ctx) +{ + jsdisp_t *obj = gc_ctx->chunk->objects[gc_ctx->idx]; + + if(++gc_ctx->idx == ARRAY_SIZE(gc_ctx->chunk->objects)) { + free(gc_ctx->next); + gc_ctx->next = gc_ctx->chunk; + gc_ctx->chunk = gc_ctx->chunk->prev; + gc_ctx->idx = 0; + } + return obj; +} + +HRESULT gc_run(script_ctx_t *ctx) +{ + /* Save original refcounts in a linked list of chunks */ + struct chunk + { + struct chunk *next; + LONG ref[1020]; + } *head, *chunk; + struct thread_data *thread_data = ctx->thread_data; + jsdisp_t *obj, *obj2, *link, *link2; + dispex_prop_t *prop, *props_end; + struct gc_ctx gc_ctx = { 0 }; + unsigned chunk_idx = 0; + HRESULT hres = S_OK; + struct list *iter; + + /* Prevent recursive calls from side-effects during unlinking (e.g. CollectGarbage from host object's Release) */ + if(thread_data->gc_is_unlinking) + return S_OK; + + if(!(head = malloc(sizeof(*head)))) + return E_OUTOFMEMORY; + head->next = NULL; + chunk = head; + + /* 1. Save actual refcounts and decrease them speculatively as-if we unlinked the objects */ + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { + if(chunk_idx == ARRAY_SIZE(chunk->ref)) { + if(!(chunk->next = malloc(sizeof(*chunk)))) { + do { + chunk = head->next; + free(head); + head = chunk; + } while(head); + return E_OUTOFMEMORY; + } + chunk = chunk->next; chunk_idx = 0; + chunk->next = NULL; + } + chunk->ref[chunk_idx++] = obj->ref; + } + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { + /* Skip objects with external reference counter */ + if(obj->builtin_info->addref) { + obj->gc_marked = FALSE; + continue; + } + for(prop = obj->props, props_end = prop + obj->prop_cnt; prop < props_end; prop++) { + switch(prop->type) { + case PROP_JSVAL: + if(is_object_instance(prop->u.val) && (link = to_jsdisp(get_object(prop->u.val)))) + link->ref--; + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) + prop->u.accessor.getter->ref--; + if(prop->u.accessor.setter) + prop->u.accessor.setter->ref--; + break; + default: + break; + } + } + + if(obj->prototype) + obj->prototype->ref--; + if(obj->builtin_info->gc_traverse) + obj->builtin_info->gc_traverse(&gc_ctx, GC_TRAVERSE_SPECULATIVELY, obj); + obj->gc_marked = TRUE; + } + + /* 2. Clear mark on objects with non-zero "external refcount" and all objects accessible from them */ + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { + if(!obj->ref || !obj->gc_marked) + continue; + + hres = gc_stack_push(&gc_ctx, NULL); + if(FAILED(hres)) + break; + + obj2 = obj; + do + { + obj2->gc_marked = FALSE; + + for(prop = obj2->props, props_end = prop + obj2->prop_cnt; prop < props_end; prop++) { + switch(prop->type) { + case PROP_JSVAL: + if(!is_object_instance(prop->u.val)) + continue; + link = to_jsdisp(get_object(prop->u.val)); + link2 = NULL; + break; + case PROP_ACCESSOR: + link = prop->u.accessor.getter; + link2 = prop->u.accessor.setter; + break; + default: + continue; + } + if(link && link->gc_marked) { + hres = gc_stack_push(&gc_ctx, link); + if(FAILED(hres)) + break; + } + if(link2 && link2->gc_marked) { + hres = gc_stack_push(&gc_ctx, link2); + if(FAILED(hres)) + break; + } + } + + if(FAILED(hres)) + break; + + if(obj2->prototype && obj2->prototype->gc_marked) { + hres = gc_stack_push(&gc_ctx, obj2->prototype); + if(FAILED(hres)) + break; + } + + if(obj2->builtin_info->gc_traverse) { + hres = obj2->builtin_info->gc_traverse(&gc_ctx, GC_TRAVERSE, obj2); + if(FAILED(hres)) + break; + } + + /* For weak refs, traverse paths accessible from it via the WeakMaps, if the WeakMaps are alive at this point. + We need both the key and the WeakMap for the entry to actually be accessible (and thus traversed). */ + if(obj2->has_weak_refs) { + struct list *list = &RB_ENTRY_VALUE(rb_get(&thread_data->weak_refs, obj2), struct weak_refs_entry, entry)->list; + struct weakmap_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, list, struct weakmap_entry, weak_refs_entry) { + if(!entry->weakmap->gc_marked && is_object_instance(entry->value) && (link = to_jsdisp(get_object(entry->value)))) { + hres = gc_stack_push(&gc_ctx, link); + if(FAILED(hres)) + break; + } + } + + if(FAILED(hres)) + break; + } + + do obj2 = gc_stack_pop(&gc_ctx); while(obj2 && !obj2->gc_marked); + } while(obj2); + + if(FAILED(hres)) { + do obj2 = gc_stack_pop(&gc_ctx); while(obj2); + break; + } + } + free(gc_ctx.next); + + /* Restore */ + chunk = head; chunk_idx = 0; + LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { + obj->ref = chunk->ref[chunk_idx++]; + if(chunk_idx == ARRAY_SIZE(chunk->ref)) { + struct chunk *next = chunk->next; + free(chunk); + chunk = next; chunk_idx = 0; + } + } + free(chunk); + + if(FAILED(hres)) + return hres; + + /* 3. Remove all the links from the marked objects, since they are dangling */ + thread_data->gc_is_unlinking = TRUE; + + iter = list_head(&thread_data->objects); + while(iter) { + obj = LIST_ENTRY(iter, jsdisp_t, entry); + if(!obj->gc_marked) { + iter = list_next(&thread_data->objects, iter); + continue; + } + + /* Grab it since it gets removed when unlinked */ + jsdisp_addref(obj); + unlink_jsdisp(obj); + + /* Releasing unlinked object should not delete any other object, + so we can safely obtain the next pointer now */ + iter = list_next(&thread_data->objects, iter); + jsdisp_release(obj); + } + + thread_data->gc_is_unlinking = FALSE; + thread_data->gc_last_tick = GetTickCount(); + return S_OK; +} + +HRESULT gc_process_linked_obj(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *obj, jsdisp_t *link, void **unlink_ref) +{ + if(op == GC_TRAVERSE_UNLINK) { + *unlink_ref = NULL; + jsdisp_release(link); + return S_OK; + } + + if(op == GC_TRAVERSE_SPECULATIVELY) + link->ref--; + else if(link->gc_marked) + return gc_stack_push(gc_ctx, link); + return S_OK; +} + +HRESULT gc_process_linked_val(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *obj, jsval_t *link) +{ + jsdisp_t *jsdisp; + + if(op == GC_TRAVERSE_UNLINK) { + jsval_t val = *link; + *link = jsval_undefined(); + jsval_release(val); + return S_OK; + } + + if(!is_object_instance(*link) || !(jsdisp = to_jsdisp(get_object(*link)))) + return S_OK; + if(op == GC_TRAVERSE_SPECULATIVELY) + jsdisp->ref--; + else if(jsdisp->gc_marked) + return gc_stack_push(gc_ctx, jsdisp); + return S_OK; +} + + + +struct typeinfo_func { + dispex_prop_t *prop; + function_code_t *code; +}; + +typedef struct { + ITypeInfo ITypeInfo_iface; + ITypeComp ITypeComp_iface; + LONG ref; + + UINT num_funcs; + UINT num_vars; + struct typeinfo_func *funcs; + dispex_prop_t **vars; + + jsdisp_t *jsdisp; +} ScriptTypeInfo; + +static struct typeinfo_func *get_func_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid) +{ + UINT a = 0, b = typeinfo->num_funcs; + + while (a < b) + { + UINT i = (a + b - 1) / 2; + MEMBERID func_memid = prop_to_id(typeinfo->jsdisp, typeinfo->funcs[i].prop); + + if (memid == func_memid) + return &typeinfo->funcs[i]; + else if (memid < func_memid) + b = i; + else + a = i + 1; + } + return NULL; +} + +static dispex_prop_t *get_var_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid) +{ + UINT a = 0, b = typeinfo->num_vars; + + while (a < b) + { + UINT i = (a + b - 1) / 2; + MEMBERID var_memid = prop_to_id(typeinfo->jsdisp, typeinfo->vars[i]); + + if (memid == var_memid) + return typeinfo->vars[i]; + else if (memid < var_memid) + b = i; + else + a = i + 1; + } + return NULL; +} + +static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) +{ + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface); +} + +static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface) +{ + return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface); +} + +static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid)) + *ppv = &This->ITypeInfo_iface; + else if (IsEqualGUID(&IID_ITypeComp, riid)) + *ppv = &This->ITypeComp_iface; + else + { WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); *ppv = NULL; return E_NOINTERFACE; } - jsdisp_addref(This); + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } -static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface) { - jsdisp_t *This = impl_from_IDispatchEx(iface); - jsdisp_addref(This); - return This->ref; -} + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); -static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - ULONG ref = --This->ref; - TRACE("(%p) ref=%d\n", This, ref); - if(!ref) - jsdisp_free(This); return ref; } -static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) { - jsdisp_t *This = impl_from_IDispatchEx(iface); - - TRACE("(%p)->(%p)\n", This, pctinfo); - - *pctinfo = 1; - return S_OK; -} - -static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, - ITypeInfo **ppTInfo) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); - return E_NOTIMPL; -} - -static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, - LPOLESTR *rgszNames, UINT cNames, LCID lcid, - DISPID *rgDispId) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + LONG ref = InterlockedDecrement(&This->ref); UINT i; - HRESULT hres; - TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, - lcid, rgDispId); + TRACE("(%p) ref=%ld\n", This, ref); - for(i=0; i < cNames; i++) { - hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i); - if(FAILED(hres)) - return hres; + if (!ref) + { + for (i = This->num_funcs; i--;) + release_bytecode(This->funcs[i].code->bytecode); + jsdisp_release(This->jsdisp); + free(This->funcs); + free(This->vars); + free(This); } + return ref; +} +static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + TYPEATTR *attr; + + TRACE("(%p)->(%p)\n", This, ppTypeAttr); + + if (!ppTypeAttr) return E_INVALIDARG; + + attr = calloc(1, sizeof(*attr)); + if (!attr) return E_OUTOFMEMORY; + + attr->guid = GUID_JScriptTypeInfo; + attr->lcid = LOCALE_USER_DEFAULT; + attr->memidConstructor = MEMBERID_NIL; + attr->memidDestructor = MEMBERID_NIL; + attr->cbSizeInstance = 4; + attr->typekind = TKIND_DISPATCH; + attr->cFuncs = This->num_funcs; + attr->cVars = This->num_vars; + attr->cImplTypes = 1; + attr->cbSizeVft = sizeof(IDispatchVtbl); + attr->cbAlignment = 4; + attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE; + attr->wMajorVerNum = JSCRIPT_MAJOR_VERSION; + attr->wMinorVerNum = JSCRIPT_MINOR_VERSION; + + *ppTypeAttr = attr; return S_OK; } -static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, - REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, - VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp) { - jsdisp_t *This = impl_from_IDispatchEx(iface); + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); - TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), - lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + TRACE("(%p)->(%p)\n", This, ppTComp); - return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, - pDispParams, pVarResult, pExcepInfo, NULL); + if (!ppTComp) return E_INVALIDARG; + + *ppTComp = &This->ITypeComp_iface; + ITypeInfo_AddRef(iface); + return S_OK; } -static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc) { - jsdisp_t *This = impl_from_IDispatchEx(iface); + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + struct typeinfo_func *func; + FUNCDESC *desc; + unsigned i; - TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); + TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc); - if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) { - FIXME("Unsupported grfdex %x\n", grfdex); - return E_NOTIMPL; - } + if (!ppFuncDesc) return E_INVALIDARG; + if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND; + func = &This->funcs[index]; - return jsdisp_get_id(This, bstrName, grfdex, pid); + /* Store the parameter array after the FUNCDESC structure */ + desc = calloc(1, sizeof(*desc) + sizeof(ELEMDESC) * func->code->param_cnt); + if (!desc) return E_OUTOFMEMORY; + + desc->memid = prop_to_id(This->jsdisp, func->prop); + desc->funckind = FUNC_DISPATCH; + desc->invkind = INVOKE_FUNC; + desc->callconv = CC_STDCALL; + desc->cParams = func->code->param_cnt; + desc->elemdescFunc.tdesc.vt = VT_VARIANT; + + if (func->code->param_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1); + for (i = 0; i < func->code->param_cnt; i++) + desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT; + + *ppFuncDesc = desc; + return S_OK; } -static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, - VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc) { - jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; - HRESULT hres; + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + VARDESC *desc; - TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc); - if(pvarRes) - V_VT(pvarRes) = VT_EMPTY; + if (!ppVarDesc) return E_INVALIDARG; + if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND; - prop = get_prop(This, id); - if(!prop || prop->type == PROP_DELETED) { - TRACE("invalid id\n"); - return DISP_E_MEMBERNOTFOUND; + desc = calloc(1, sizeof(*desc)); + if (!desc) return E_OUTOFMEMORY; + + desc->memid = prop_to_id(This->jsdisp, This->vars[index]); + desc->varkind = VAR_DISPATCH; + desc->elemdescVar.tdesc.vt = VT_VARIANT; + + *ppVarDesc = desc; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames, + UINT cMaxNames, UINT *pcNames) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + struct typeinfo_func *func; + ITypeInfo *disp_typeinfo; + dispex_prop_t *var; + HRESULT hr; + UINT i = 0; + + TRACE("(%p)->(%ld %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); + + if (!rgBstrNames || !pcNames) return E_INVALIDARG; + if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND; + + func = get_func_from_memid(This, memid); + if (!func) + { + var = get_var_from_memid(This, memid); + if (!var) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetNames(disp_typeinfo, memid, rgBstrNames, cMaxNames, pcNames); + } } - clear_ei(This->ctx); + *pcNames = 0; + if (!cMaxNames) return S_OK; - switch(wFlags) { - case DISPATCH_METHOD|DISPATCH_PROPERTYGET: - wFlags = DISPATCH_METHOD; - /* fall through */ - case DISPATCH_METHOD: - case DISPATCH_CONSTRUCT: { - jsval_t *argv, buf[6], r; - unsigned argc; + rgBstrNames[0] = SysAllocString(func ? func->prop->name : var->name); + if (!rgBstrNames[0]) return E_OUTOFMEMORY; + i++; - hres = convert_params(pdp, buf, &argc, &argv); - if(FAILED(hres)) - return hres; + if (func) + { + unsigned num = min(cMaxNames, func->code->param_cnt + 1); - hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); - if(argv != buf) - heap_free(argv); - if(SUCCEEDED(hres) && pvarRes) { - hres = jsval_to_variant(r, pvarRes); - jsval_release(r); + for (; i < num; i++) + { + if (!(rgBstrNames[i] = SysAllocString(func->code->params[i - 1]))) + { + do SysFreeString(rgBstrNames[--i]); while (i); + return E_OUTOFMEMORY; + } } - break; } - case DISPATCH_PROPERTYGET: { - jsval_t r; - hres = prop_get(This, prop, &r); - if(SUCCEEDED(hres)) { - hres = jsval_to_variant(r, pvarRes); - jsval_release(r); + *pcNames = i; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%u %p)\n", This, index, pRefType); + + /* We only inherit from IDispatch */ + if (!pRefType) return E_INVALIDARG; + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + *pRefType = 1; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags); + + if (!pImplTypeFlags) return E_INVALIDARG; + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + *pImplTypeFlags = 0; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames, + MEMBERID *pMemId) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + const WCHAR *name; + HRESULT hr = S_OK; + int i, j, arg; + + TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId); + + if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG; + + for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL; + name = rgszNames[0]; + + for (i = 0; i < This->num_funcs; i++) + { + struct typeinfo_func *func = &This->funcs[i]; + + if (wcsicmp(name, func->prop->name)) continue; + pMemId[0] = prop_to_id(This->jsdisp, func->prop); + + for (j = 1; j < cNames; j++) + { + name = rgszNames[j]; + for (arg = func->code->param_cnt; --arg >= 0;) + if (!wcsicmp(name, func->code->params[arg])) + break; + if (arg >= 0) + pMemId[j] = arg; + else + hr = DISP_E_UNKNOWNNAME; } - break; + return hr; } - case DISPATCH_PROPERTYPUT: { - jsval_t val; - DWORD i; - for(i=0; i < pdp->cNamedArgs; i++) { - if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT) - break; - } + for (i = 0; i < This->num_vars; i++) + { + dispex_prop_t *var = This->vars[i]; - if(i == pdp->cNamedArgs) { - TRACE("no value to set\n"); - return DISP_E_PARAMNOTOPTIONAL; - } - - hres = variant_to_jsval(pdp->rgvarg+i, &val); - if(FAILED(hres)) - return hres; - - hres = prop_put(This, prop, val); - jsval_release(val); - break; + if (wcsicmp(name, var->name)) continue; + pMemId[0] = prop_to_id(This->jsdisp, var); + return S_OK; } - default: - FIXME("Unimplemented flags %x\n", wFlags); + + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId); +} + +static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags, + DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + IDispatch *disp; + HRESULT hr; + + TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This, pvInstance, memid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + + if (!pvInstance) return E_INVALIDARG; + if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND; + + if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid)) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_Invoke(disp_typeinfo, pvInstance, memid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); + } + + hr = IUnknown_QueryInterface((IUnknown*)pvInstance, &IID_IDispatch, (void**)&disp); + if (FAILED(hr)) return hr; + + hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + IDispatch_Release(disp); + + return hr; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName, + BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + struct typeinfo_func *func; + ITypeInfo *disp_typeinfo; + dispex_prop_t *var; + HRESULT hr; + + TRACE("(%p)->(%ld %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + + if (pBstrDocString) *pBstrDocString = NULL; + if (pdwHelpContext) *pdwHelpContext = 0; + if (pBstrHelpFile) *pBstrHelpFile = NULL; + + if (memid == MEMBERID_NIL) + { + if (pBstrName && !(*pBstrName = SysAllocString(L"JScriptTypeInfo"))) + return E_OUTOFMEMORY; + if (pBstrDocString && + !(*pBstrDocString = SysAllocString(L"JScript Type Info"))) + { + if (pBstrName) SysFreeString(*pBstrName); + return E_OUTOFMEMORY; + } + return S_OK; + } + if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND; + + func = get_func_from_memid(This, memid); + if (!func) + { + var = get_var_from_memid(This, memid); + if (!var) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetDocumentation(disp_typeinfo, memid, pBstrName, pBstrDocString, + pdwHelpContext, pBstrHelpFile); + } + } + + if (pBstrName) + { + *pBstrName = SysAllocString(func ? func->prop->name : var->name); + + if (!*pBstrName) + return E_OUTOFMEMORY; + } + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, + BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + HRESULT hr; + + TRACE("(%p)->(%ld %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + + if (pBstrDllName) *pBstrDllName = NULL; + if (pBstrName) *pBstrName = NULL; + if (pwOrdinal) *pwOrdinal = 0; + + if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid)) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetDllEntry(disp_typeinfo, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + } + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + HRESULT hr; + + TRACE("(%p)->(%lx %p)\n", This, hRefType, ppTInfo); + + if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG; + + if (hRefType & ~3) return E_FAIL; + if (hRefType & 1) + { + hr = get_dispatch_typeinfo(ppTInfo); + if (FAILED(hr)) return hr; + } + else + *ppTInfo = iface; + + ITypeInfo_AddRef(*ppTInfo); + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + HRESULT hr; + + TRACE("(%p)->(%ld %d %p)\n", This, memid, invKind, ppv); + + if (!ppv) return E_INVALIDARG; + *ppv = NULL; + + if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid)) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_AddressOfMember(disp_typeinfo, memid, invKind, ppv); + } + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj); + + if (!ppvObj) return E_INVALIDARG; + + *ppvObj = NULL; + return TYPE_E_BADMODULEKIND; +} + +static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + ITypeInfo *disp_typeinfo; + HRESULT hr; + + TRACE("(%p)->(%ld %p)\n", This, memid, pBstrMops); + + if (!pBstrMops) return E_INVALIDARG; + + if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid)) + { + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + return ITypeInfo_GetMops(disp_typeinfo, memid, pBstrMops); + } + + *pBstrMops = NULL; + return S_OK; +} + +static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex); + + return E_NOTIMPL; +} + +static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, pTypeAttr); + + free(pTypeAttr); +} + +static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, pFuncDesc); + + free(pFuncDesc); +} + +static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); + + TRACE("(%p)->(%p)\n", This, pVarDesc); + + free(pVarDesc); +} + +static const ITypeInfoVtbl ScriptTypeInfoVtbl = { + ScriptTypeInfo_QueryInterface, + ScriptTypeInfo_AddRef, + ScriptTypeInfo_Release, + ScriptTypeInfo_GetTypeAttr, + ScriptTypeInfo_GetTypeComp, + ScriptTypeInfo_GetFuncDesc, + ScriptTypeInfo_GetVarDesc, + ScriptTypeInfo_GetNames, + ScriptTypeInfo_GetRefTypeOfImplType, + ScriptTypeInfo_GetImplTypeFlags, + ScriptTypeInfo_GetIDsOfNames, + ScriptTypeInfo_Invoke, + ScriptTypeInfo_GetDocumentation, + ScriptTypeInfo_GetDllEntry, + ScriptTypeInfo_GetRefTypeInfo, + ScriptTypeInfo_AddressOfMember, + ScriptTypeInfo_CreateInstance, + ScriptTypeInfo_GetMops, + ScriptTypeInfo_GetContainingTypeLib, + ScriptTypeInfo_ReleaseTypeAttr, + ScriptTypeInfo_ReleaseFuncDesc, + ScriptTypeInfo_ReleaseVarDesc +}; + +static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv); +} + +static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_AddRef(&This->ITypeInfo_iface); +} + +static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + return ITypeInfo_Release(&This->ITypeInfo_iface); +} + +static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags, + ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr) +{ + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + UINT flags = wFlags ? wFlags : ~0; + ITypeInfo *disp_typeinfo; + ITypeComp *disp_typecomp; + HRESULT hr; + UINT i; + + TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This, debugstr_w(szName), lHashVal, + wFlags, ppTInfo, pDescKind, pBindPtr); + + if (!szName || !ppTInfo || !pDescKind || !pBindPtr) return E_INVALIDARG; - } - if(pei) - *pei = This->ctx->ei.ei; - return hres; -} + for (i = 0; i < This->num_funcs; i++) + { + if (wcsicmp(szName, This->funcs[i].prop->name)) continue; + if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH; -static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret) -{ - if(!(prop->flags & PROPF_CONFIGURABLE)) { - *ret = FALSE; + hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc); + if (FAILED(hr)) return hr; + + *pDescKind = DESCKIND_FUNCDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); return S_OK; } - *ret = TRUE; /* FIXME: not exactly right */ + for (i = 0; i < This->num_vars; i++) + { + if (wcsicmp(szName, This->vars[i]->name)) continue; + if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH; - if(prop->type == PROP_JSVAL) { - jsval_release(prop->u.val); - prop->type = PROP_DELETED; - } - if(prop->type == PROP_ACCESSOR) - FIXME("not supported on accessor property\n"); - return S_OK; -} + hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc); + if (FAILED(hr)) return hr; -static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; - BOOL b; - HRESULT hres; - - TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex); - - if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) - FIXME("Unsupported grfdex %x\n", grfdex); - - hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop); - if(FAILED(hres)) - return hres; - if(!prop) { - TRACE("not found\n"); + *pDescKind = DESCKIND_VARDESC; + *ppTInfo = &This->ITypeInfo_iface; + ITypeInfo_AddRef(*ppTInfo); return S_OK; } - return delete_prop(prop, &b); + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr); + ITypeComp_Release(disp_typecomp); + return hr; } -static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, + ITypeInfo **ppTInfo, ITypeComp **ppTComp) { - jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; - BOOL b; + ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface); + ITypeInfo *disp_typeinfo; + ITypeComp *disp_typecomp; + HRESULT hr; - TRACE("(%p)->(%x)\n", This, id); + TRACE("(%p)->(%s %08lx %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp); - prop = get_prop(This, id); - if(!prop) { - WARN("invalid id\n"); - return DISP_E_MEMBERNOTFOUND; - } + if (!szName || !ppTInfo || !ppTComp) + return E_INVALIDARG; - return delete_prop(prop, &b); + /* Look into the inherited IDispatch */ + hr = get_dispatch_typeinfo(&disp_typeinfo); + if (FAILED(hr)) return hr; + + hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp); + if (FAILED(hr)) return hr; + + hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp); + ITypeComp_Release(disp_typecomp); + return hr; } -static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex); - return E_NOTIMPL; -} - -static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - dispex_prop_t *prop; - - TRACE("(%p)->(%x %p)\n", This, id, pbstrName); - - prop = get_prop(This, id); - if(!prop || !prop->name || prop->type == PROP_DELETED) - return DISP_E_MEMBERNOTFOUND; - - *pbstrName = SysAllocString(prop->name); - if(!*pbstrName) - return E_OUTOFMEMORY; - - return S_OK; -} - -static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - HRESULT hres; - - TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid); - - hres = jsdisp_next_prop(This, id, FALSE, pid); - if(hres == S_FALSE) - *pid = DISPID_STARTENUM; - return hres; -} - -static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) -{ - jsdisp_t *This = impl_from_IDispatchEx(iface); - FIXME("(%p)->(%p)\n", This, ppunk); - return E_NOTIMPL; -} - -static IDispatchExVtbl DispatchExVtbl = { - DispatchEx_QueryInterface, - DispatchEx_AddRef, - DispatchEx_Release, - DispatchEx_GetTypeInfoCount, - DispatchEx_GetTypeInfo, - DispatchEx_GetIDsOfNames, - DispatchEx_Invoke, - DispatchEx_GetDispID, - DispatchEx_InvokeEx, - DispatchEx_DeleteMemberByName, - DispatchEx_DeleteMemberByDispID, - DispatchEx_GetMemberProperties, - DispatchEx_GetMemberName, - DispatchEx_GetNextDispID, - DispatchEx_GetNameSpaceParent +static const ITypeCompVtbl ScriptTypeCompVtbl = { + ScriptTypeComp_QueryInterface, + ScriptTypeComp_AddRef, + ScriptTypeComp_Release, + ScriptTypeComp_Bind, + ScriptTypeComp_BindType }; -jsdisp_t *as_jsdisp(IDispatch *disp) -{ - assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl); - return impl_from_IDispatchEx((IDispatchEx*)disp); -} - -jsdisp_t *to_jsdisp(IDispatch *disp) -{ - return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL; -} - -HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype) -{ - TRACE("%p (%p)\n", dispex, prototype); - - dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl; - dispex->ref = 1; - dispex->builtin_info = builtin_info; - - dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4)); - if(!dispex->props) - return E_OUTOFMEMORY; - - dispex->prototype = prototype; - if(prototype) - jsdisp_addref(prototype); - - dispex->prop_cnt = 1; - if(builtin_info->value_prop.invoke || builtin_info->value_prop.getter) { - dispex->props[0].type = PROP_BUILTIN; - dispex->props[0].u.p = &builtin_info->value_prop; - }else { - dispex->props[0].type = PROP_DELETED; - } - - script_addref(ctx); - dispex->ctx = ctx; - - return S_OK; -} - -static const builtin_info_t dispex_info = { - JSCLASS_NONE, - {NULL, NULL, 0}, - 0, NULL, - NULL, - NULL -}; - -HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex) -{ - jsdisp_t *ret; - HRESULT hres; - - ret = heap_alloc_zero(sizeof(jsdisp_t)); - if(!ret) - return E_OUTOFMEMORY; - - hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype); - if(FAILED(hres)) { - heap_free(ret); - return hres; - } - - *dispex = ret; - return S_OK; -} - -void jsdisp_free(jsdisp_t *obj) +static void jsdisp_free(jsdisp_t *obj) { dispex_prop_t *prop; + list_remove(&obj->entry); + TRACE("(%p)\n", obj); + if(obj->has_weak_refs) { + struct list *list = &RB_ENTRY_VALUE(rb_get(&obj->ctx->thread_data->weak_refs, obj), struct weak_refs_entry, entry)->list; + do { + remove_weakmap_entry(LIST_ENTRY(list->next, struct weakmap_entry, weak_refs_entry)); + } while(obj->has_weak_refs); + } + for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) { switch(prop->type) { case PROP_JSVAL: @@ -993,39 +1887,627 @@ void jsdisp_free(jsdisp_t *obj) default: break; }; - heap_free(prop->name); + free(prop->name); } - heap_free(obj->props); + free(obj->props); script_release(obj->ctx); if(obj->prototype) jsdisp_release(obj->prototype); if(obj->builtin_info->destructor) obj->builtin_info->destructor(obj); + free(obj); +} + +jsdisp_t *jsdisp_addref(jsdisp_t *obj) +{ + if(obj->builtin_info->addref) + obj->builtin_info->addref(obj); else - heap_free(obj); + ++obj->ref; + return obj; } -#ifdef TRACE_REFCNT - -jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp) +ULONG jsdisp_release(jsdisp_t *obj) { - ULONG ref = ++jsdisp->ref; - TRACE("(%p) ref=%d\n", jsdisp, ref); - return jsdisp; -} + ULONG ref; -void jsdisp_release(jsdisp_t *jsdisp) -{ - ULONG ref = --jsdisp->ref; - - TRACE("(%p) ref=%d\n", jsdisp, ref); + if(obj->builtin_info->release) + return obj->builtin_info->release(obj); + ref = --obj->ref; if(!ref) - jsdisp_free(jsdisp); + jsdisp_free(obj); + return ref; } -#endif +static inline jsdisp_t *impl_from_IWineJSDispatch(IWineJSDispatch *iface) +{ + return CONTAINING_RECORD(iface, jsdisp_t, IWineJSDispatch_iface); +} + +static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatch *iface, REFIID riid, void **ppv) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IWineJSDispatch_iface; + }else if(IsEqualGUID(&IID_IDispatch, riid)) { + TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv); + *ppv = &This->IWineJSDispatch_iface; + }else if(IsEqualGUID(&IID_IDispatchEx, riid)) { + TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv); + *ppv = &This->IWineJSDispatch_iface; + }else if(IsEqualGUID(&IID_IWineJSDispatch, riid)) { + TRACE("(%p)->(IID_IWineJSDispatch %p)\n", This, ppv); + *ppv = &This->IWineJSDispatch_iface; + }else { + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + jsdisp_addref(This); + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IWineJSDispatch *iface) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + if(This->builtin_info->addref) + return This->builtin_info->addref(This); + jsdisp_addref(This); + return This->ref; +} + +static ULONG WINAPI DispatchEx_Release(IWineJSDispatch *iface) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + return jsdisp_release(This); +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IWineJSDispatch *iface, UINT *pctinfo) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + + TRACE("(%p)->(%p)\n", This, pctinfo); + + *pctinfo = 1; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IWineJSDispatch *iface, UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + dispex_prop_t *prop, *cur, *end, **typevar; + UINT num_funcs = 0, num_vars = 0; + struct typeinfo_func *typefunc; + function_code_t *func_code; + ScriptTypeInfo *typeinfo; + unsigned pos; + + TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo); + + if (iTInfo != 0) return DISP_E_BADINDEX; + + for (prop = This->props, end = prop + This->prop_cnt; prop != end; prop++) + { + if (prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + /* If two identifiers differ only by case, the TypeInfo fails */ + pos = This->props[get_props_idx(This, prop->hash)].bucket_head; + while (pos != ~0) + { + cur = This->props + pos; + + if (prop->hash == cur->hash && prop != cur && + cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) && + !wcsicmp(prop->name, cur->name)) + { + return TYPE_E_AMBIGUOUSNAME; + } + pos = cur->bucket_next; + } + + if (is_function_prop(prop)) + { + if (Function_get_code(as_jsdisp(get_object(prop->u.val)))) + num_funcs++; + } + else num_vars++; + } + + if (!(typeinfo = malloc(sizeof(*typeinfo)))) + return E_OUTOFMEMORY; + + typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; + typeinfo->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl; + typeinfo->ref = 1; + typeinfo->num_vars = num_vars; + typeinfo->num_funcs = num_funcs; + typeinfo->jsdisp = This; + + typeinfo->funcs = malloc(sizeof(*typeinfo->funcs) * num_funcs); + if (!typeinfo->funcs) + { + free(typeinfo); + return E_OUTOFMEMORY; + } + + typeinfo->vars = malloc(sizeof(*typeinfo->vars) * num_vars); + if (!typeinfo->vars) + { + free(typeinfo->funcs); + free(typeinfo); + return E_OUTOFMEMORY; + } + + typefunc = typeinfo->funcs; + typevar = typeinfo->vars; + for (prop = This->props; prop != end; prop++) + { + if (prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + if (is_function_prop(prop)) + { + func_code = Function_get_code(as_jsdisp(get_object(prop->u.val))); + if (!func_code) continue; + + typefunc->prop = prop; + typefunc->code = func_code; + typefunc++; + + /* The function may be deleted, so keep a ref */ + bytecode_addref(func_code->bytecode); + } + else + *typevar++ = prop; + } + + /* Keep a ref to the props and their names */ + jsdisp_addref(This); + + *ppTInfo = &typeinfo->ITypeInfo_iface; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IWineJSDispatch *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, + DISPID *rgDispId) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + UINT i; + HRESULT hres; + + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, + lcid, rgDispId); + + if(cNames == 0) + return S_OK; + + hres = jsdisp_get_id(This, rgszNames[0], 0, rgDispId); + if(FAILED(hres)) + return hres; + + /* DISPIDs for parameters don't seem to be supported */ + if(cNames > 1) { + for(i = 1; i < cNames; i++) + rgDispId[i] = DISPID_UNKNOWN; + hres = DISP_E_UNKNOWNNAME; + } + + return hres; +} + +static HRESULT WINAPI DispatchEx_Invoke(IWineJSDispatch *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + return IDispatchEx_InvokeEx(to_dispex(This), dispIdMember, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, NULL); +} + +static HRESULT WINAPI DispatchEx_GetDispID(IWineJSDispatch *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + + TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); + + if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) { + FIXME("Unsupported grfdex %lx\n", grfdex); + return E_NOTIMPL; + } + + return jsdisp_get_id(This, bstrName, grfdex, pid); +} + +static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + IServiceProvider *prev_caller; + dispex_prop_t *prop; + jsexcept_t ei; + HRESULT hres; + + TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + + if(pvarRes) + V_VT(pvarRes) = VT_EMPTY; + + prop = get_prop(This, id); + if(!prop && id != DISPID_VALUE) { + TRACE("invalid id\n"); + return DISP_E_MEMBERNOTFOUND; + } + + enter_script(This->ctx, &ei); + + prev_caller = This->ctx->jscaller->caller; + This->ctx->jscaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + + switch(wFlags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + wFlags = DISPATCH_METHOD; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + jsval_t *argv, buf[6], r; + IDispatch *passed_this; + unsigned argc; + + hres = convert_params(This->ctx, pdp, buf, &argc, &argv); + if(FAILED(hres)) + break; + + passed_this = get_this(pdp); + if(prop) + hres = invoke_prop_func(This, passed_this, prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); + else + hres = jsdisp_call_value(This, passed_this ? jsval_disp(passed_this) : jsval_undefined(), wFlags, argc, argv, pvarRes ? &r : NULL); + + while(argc--) + jsval_release(argv[argc]); + if(argv != buf) + free(argv); + if(SUCCEEDED(hres) && pvarRes) { + hres = jsval_to_variant(r, pvarRes); + jsval_release(r); + } + break; + } + case DISPATCH_PROPERTYGET: { + jsval_t r; + + if(prop) + hres = prop_get(This, to_disp(This), prop, &r); + else { + hres = to_primitive(This->ctx, jsval_obj(This), &r, NO_HINT); + if(hres == JS_E_TO_PRIMITIVE) + hres = DISP_E_MEMBERNOTFOUND; + } + + if(SUCCEEDED(hres)) { + hres = jsval_to_variant(r, pvarRes); + jsval_release(r); + } + break; + } + case DISPATCH_PROPERTYPUTREF | DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUTREF: + case DISPATCH_PROPERTYPUT: { + jsval_t val; + DWORD i; + + if(!prop) { + hres = DISP_E_MEMBERNOTFOUND; + break; + } + + for(i=0; i < pdp->cNamedArgs; i++) { + if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT) + break; + } + + if(i == pdp->cNamedArgs) { + TRACE("no value to set\n"); + hres = DISP_E_PARAMNOTOPTIONAL; + break; + } + + hres = variant_to_jsval(This->ctx, pdp->rgvarg+i, &val); + if(FAILED(hres)) + break; + + hres = prop_put(This, prop, val); + jsval_release(val); + break; + } + default: + FIXME("Unimplemented flags %x\n", wFlags); + hres = E_INVALIDARG; + break; + } + + This->ctx->jscaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); + return leave_script(This->ctx, hres); +} + +static HRESULT delete_prop(jsdisp_t *obj, dispex_prop_t *prop, BOOL *ret) +{ + if(prop->type == PROP_PROTREF || prop->type == PROP_DELETED) { + *ret = TRUE; + return S_OK; + } + + if(!(prop->flags & PROPF_CONFIGURABLE)) { + *ret = FALSE; + return S_OK; + } + + *ret = TRUE; + + switch(prop->type) { + case PROP_JSVAL: + jsval_release(prop->u.val); + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) + jsdisp_release(prop->u.accessor.getter); + if(prop->u.accessor.setter) + jsdisp_release(prop->u.accessor.setter); + break; + case PROP_EXTERN: + if(obj->builtin_info->prop_delete) { + HRESULT hres; + hres = obj->builtin_info->prop_delete(obj, prop->u.id); + if(FAILED(hres)) + return hres; + } + break; + default: + break; + } + prop->type = PROP_DELETED; + return S_OK; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IWineJSDispatch *iface, BSTR bstrName, DWORD grfdex) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + dispex_prop_t *prop; + BOOL b; + HRESULT hres; + + TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex); + + if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) + FIXME("Unsupported grfdex %lx\n", grfdex); + + hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, NULL, &prop); + if(FAILED(hres)) + return hres; + if(!prop) { + TRACE("not found\n"); + return S_OK; + } + + return delete_prop(This, prop, &b); +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IWineJSDispatch *iface, DISPID id) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + dispex_prop_t *prop; + BOOL b; + + TRACE("(%p)->(%lx)\n", This, id); + + prop = get_prop(This, id); + if(!prop) { + WARN("invalid id\n"); + return DISP_E_MEMBERNOTFOUND; + } + + return delete_prop(This, prop, &b); +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IWineJSDispatch *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + dispex_prop_t *prop; + + TRACE("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); + + prop = get_prop(This, id); + if(!prop) + return DISP_E_MEMBERNOTFOUND; + *pgrfdex = 0; + + if(grfdexFetch) { + FIXME("unimplemented flags %08lx\n", grfdexFetch); + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IWineJSDispatch *iface, DISPID id, BSTR *pbstrName) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + dispex_prop_t *prop; + + TRACE("(%p)->(%lx %p)\n", This, id, pbstrName); + + prop = get_prop(This, id); + if(!prop) + return DISP_E_MEMBERNOTFOUND; + + *pbstrName = SysAllocString(prop->name); + if(!*pbstrName) + return E_OUTOFMEMORY; + + return S_OK; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IWineJSDispatch *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + HRESULT hres = S_FALSE; + + TRACE("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid); + + if(id != DISPID_VALUE) + hres = jsdisp_next_prop(This, id, JSDISP_ENUM_ALL, pid); + if(hres == S_FALSE) + *pid = DISPID_STARTENUM; + return hres; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IWineJSDispatch *iface, IUnknown **ppunk) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + FIXME("(%p)->(%p)\n", This, ppunk); + return E_NOTIMPL; +} + +static void WINAPI WineJSDispatch_Free(IWineJSDispatch *iface) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + jsdisp_free(This); +} + +static HRESULT WINAPI WineJSDispatch_GetPropertyFlags(IWineJSDispatch *iface, DISPID id, UINT32 *ret) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + dispex_prop_t *prop = get_prop(This, id); + + if(!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) + return DISP_E_MEMBERNOTFOUND; + + *ret = prop->flags & PROPF_PUBLIC_MASK; + return S_OK; +} + +static HRESULT WINAPI WineJSDispatch_GetScriptGlobal(IWineJSDispatch *iface, IWineJSDispatchHost **ret) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + IDispatch *disp; + + if(!This->ctx->site) + return E_UNEXPECTED; + + if(!(disp = lookup_global_host(This->ctx))) + return E_NOINTERFACE; + + *ret = get_host_dispatch(disp); + return S_OK; +} + +static IWineJSDispatchVtbl DispatchExVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + DispatchEx_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent, + WineJSDispatch_Free, + WineJSDispatch_GetPropertyFlags, + WineJSDispatch_GetScriptGlobal, +}; + +jsdisp_t *as_jsdisp(IDispatch *disp) +{ + assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl); + return impl_from_IWineJSDispatch((IWineJSDispatch*)disp); +} + +jsdisp_t *to_jsdisp(IDispatch *disp) +{ + if(disp->lpVtbl != (IDispatchVtbl*)&DispatchExVtbl) + return NULL; + return impl_from_IWineJSDispatch((IWineJSDispatch*)disp); +} + +HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype) +{ + unsigned i; + + /* FIXME: Use better heuristics to decide when to run the GC */ + if(GetTickCount() - ctx->thread_data->gc_last_tick > 30000) + gc_run(ctx); + + TRACE("%p (%p)\n", dispex, prototype); + + dispex->IWineJSDispatch_iface.lpVtbl = &DispatchExVtbl; + dispex->ref = 1; + dispex->builtin_info = builtin_info; + dispex->extensible = TRUE; + dispex->is_constructor = builtin_info->class == JSCLASS_FUNCTION; + dispex->prop_cnt = 0; + + dispex->props = calloc(1, sizeof(dispex_prop_t)*(dispex->buf_size=4)); + if(!dispex->props) + return E_OUTOFMEMORY; + + for(i = 0; i < dispex->buf_size; i++) { + dispex->props[i].bucket_head = ~0; + dispex->props[i].bucket_next = ~0; + } + + dispex->prototype = prototype; + if(prototype) + jsdisp_addref(prototype); + + script_addref(ctx); + dispex->ctx = ctx; + + list_add_tail(&ctx->thread_data->objects, &dispex->entry); + return S_OK; +} + +static const builtin_info_t dispex_info = { .class = JSCLASS_NONE }; + +HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex) +{ + jsdisp_t *ret; + HRESULT hres; + + ret = calloc(1, sizeof(jsdisp_t)); + if(!ret) + return E_OUTOFMEMORY; + + hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype); + if(FAILED(hres)) { + free(ret); + return hres; + } + + *dispex = ret; + return S_OK; +} HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr) { @@ -1033,13 +2515,11 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built dispex_prop_t *prop; HRESULT hres; - static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0}; - - hres = find_prop_name_prot(constr, string_hash(prototypeW), prototypeW, &prop); + hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, NULL, &prop); if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { jsval_t val; - hres = prop_get(constr, prop, &val); + hres = prop_get(constr, to_disp(constr), prop, &val); if(FAILED(hres)) { ERR("Could not get prototype\n"); return hres; @@ -1047,6 +2527,9 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built if(is_object_instance(val)) prot = iface_to_jsdisp(get_object(val)); + else + prot = jsdisp_addref(ctx->object_prototype); + jsval_release(val); } @@ -1060,7 +2543,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built jsdisp_t *iface_to_jsdisp(IDispatch *iface) { return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl - ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface)) + ? jsdisp_addref( impl_from_IWineJSDispatch((IWineJSDispatch*)iface)) : NULL; } @@ -1069,11 +2552,11 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * dispex_prop_t *prop; HRESULT hres; - if(flags & fdexNameEnsure) + if(jsdisp->extensible && (flags & fdexNameEnsure)) hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, - &prop); + flags & fdexNameCaseInsensitive, &prop); else - hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop); + hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, NULL, &prop); if(FAILED(hres)) return hres; @@ -1083,29 +2566,37 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * } TRACE("not found %s\n", debugstr_w(name)); + *id = DISPID_UNKNOWN; return DISP_E_UNKNOWNNAME; } -HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +HRESULT jsdisp_get_idx_id(jsdisp_t *jsdisp, DWORD idx, DISPID *id) +{ + WCHAR name[11]; + + swprintf(name, ARRAY_SIZE(name), L"%u", idx); + return jsdisp_get_id(jsdisp, name, 0, id); +} + +HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { HRESULT hres; assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK))); if(is_class(jsfunc, JSCLASS_FUNCTION)) { - hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r); + hres = Function_invoke(jsfunc, vthis, flags, argc, argv, r); }else { - vdisp_t vdisp; - - if(!jsfunc->builtin_info->value_prop.invoke) { + if(!jsfunc->builtin_info->call) { WARN("Not a function\n"); - return throw_type_error(jsfunc->ctx, JS_E_FUNCTION_EXPECTED, NULL); + return JS_E_FUNCTION_EXPECTED; } - set_disp(&vdisp, jsthis); + if(jsfunc->ctx->state == SCRIPTSTATE_UNINITIALIZED || jsfunc->ctx->state == SCRIPTSTATE_CLOSED) + return E_UNEXPECTED; + flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r); - vdisp_release(&vdisp); + hres = jsfunc->builtin_info->call(jsfunc->ctx, vthis, flags, argc, argv, r); } return hres; } @@ -1118,7 +2609,7 @@ HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_ if(!prop) return DISP_E_MEMBERNOTFOUND; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL); + return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); } HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) @@ -1126,26 +2617,65 @@ HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(disp, string_hash(name), name, &prop); + hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL); + if(!prop || prop->type == PROP_DELETED) + return JS_E_INVALID_PROPERTY; + + return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); +} + +static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r, + IServiceProvider *caller) +{ + IDispatchEx *dispex; + EXCEPINFO ei; + HRESULT hres; + + memset(&ei, 0, sizeof(ei)); + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres)) { + hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, params, r, &ei, caller); + IDispatchEx_Release(dispex); + }else { + UINT err = 0; + + if(flags == DISPATCH_CONSTRUCT) { + WARN("IDispatch cannot be constructor\n"); + return DISP_E_MEMBERNOTFOUND; + } + + if(params->cNamedArgs == 1 && params->rgdispidNamedArgs[0] == DISPID_THIS) { + params->cNamedArgs = 0; + params->rgdispidNamedArgs = NULL; + params->cArgs--; + params->rgvarg++; + } + + TRACE("using IDispatch\n"); + hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, params, r, &ei, &err); + } + + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(ctx, &ei); + return hres; } HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret) { - IDispatchEx *dispex; - jsdisp_t *jsdisp; VARIANT buf[6], retv; + jsdisp_t *jsdisp; DISPPARAMS dp; unsigned i; HRESULT hres; jsdisp = iface_to_jsdisp(disp); - if(jsdisp) { + if(jsdisp && jsdisp->ctx == ctx) { if(flags & DISPATCH_PROPERTYPUT) { FIXME("disp_call(propput) on builtin object\n"); + jsdisp_release(jsdisp); return E_FAIL; } @@ -1155,6 +2685,8 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns jsdisp_release(jsdisp); return hres; } + if(jsdisp) + jsdisp_release(jsdisp); flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; if(ret && argc) @@ -1172,8 +2704,8 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns dp.rgdispidNamedArgs = NULL; } - if(argc > 6) { - dp.rgvarg = heap_alloc(argc*sizeof(VARIANT)); + if(dp.cArgs > ARRAY_SIZE(buf)) { + dp.rgvarg = malloc(argc * sizeof(VARIANT)); if(!dp.rgvarg) return E_OUTOFMEMORY; }else { @@ -1186,81 +2718,87 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns while(i--) VariantClear(dp.rgvarg+argc-i-1); if(dp.rgvarg != buf) - heap_free(dp.rgvarg); + free(dp.rgvarg); return hres; } } V_VT(&retv) = VT_EMPTY; - clear_ei(ctx); - hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei, - &ctx->jscaller->IServiceProvider_iface); - IDispatchEx_Release(dispex); - }else { - UINT err = 0; - - if(flags == DISPATCH_CONSTRUCT) { - WARN("IDispatch cannot be constructor\n"); - return DISP_E_MEMBERNOTFOUND; - } - - TRACE("using IDispatch\n"); - hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei, &err); - } + hres = disp_invoke(ctx, disp, id, flags, &dp, ret ? &retv : NULL, &ctx->jscaller->IServiceProvider_iface); for(i=0; ictx == ctx) + return jsdisp_call_name(jsdisp, name, flags, argc, argv, ret); + + if(!(bstr = SysAllocString(name))) + return E_OUTOFMEMORY; + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres) && dispex) { + hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id); + IDispatchEx_Release(dispex); + }else { + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id); + } + SysFreeString(bstr); + if(FAILED(hres)) + return hres; + + return disp_call(ctx, disp, id, flags, argc, argv, ret); +} + +HRESULT disp_call_value_with_caller(script_ctx_t *ctx, IDispatch *disp, jsval_t vthis, WORD flags, unsigned argc, + jsval_t *argv, jsval_t *r, IServiceProvider *caller) +{ + VARIANT buf[6], retv, *args = buf; + IDispatch *jsthis; + jsdisp_t *jsdisp; DISPPARAMS dp; unsigned i; - HRESULT hres; + HRESULT hres = S_OK; + + static DISPID this_id = DISPID_THIS; assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK))); jsdisp = iface_to_jsdisp(disp); - if(jsdisp) { - if(ctx != jsdisp->ctx) - flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; - hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r); + if(jsdisp && jsdisp->ctx == ctx) { + hres = jsdisp_call_value(jsdisp, vthis, flags, argc, argv, r); jsdisp_release(jsdisp); return hres; } + if(jsdisp) + jsdisp_release(jsdisp); + + if(is_object_instance(vthis) && (ctx->version < SCRIPTLANGUAGEVERSION_ES5 || + ((jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_OBJECT)))) + jsthis = get_object(vthis); + else + jsthis = NULL; flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; if(r && argc && flags == DISPATCH_METHOD) flags |= DISPATCH_PROPERTYGET; - hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if(FAILED(hres)) { - TRACE("using IDispatch\n"); - dispex = NULL; - jsthis = NULL; - } - if(jsthis) { - static DISPID this_id = DISPID_THIS; - - dp.cArgs = argc+1; + dp.cArgs = argc + 1; dp.cNamedArgs = 1; dp.rgdispidNamedArgs = &this_id; }else { @@ -1269,91 +2807,66 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, W dp.rgdispidNamedArgs = NULL; } - if(dp.cArgs > ARRAY_SIZE(buf)) { - dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT)); - if(!dp.rgvarg) { - if(dispex) - IDispatchEx_Release(dispex); - return E_OUTOFMEMORY; - } - }else { - dp.rgvarg = buf; - } + if(dp.cArgs > ARRAY_SIZE(buf) && !(args = malloc(dp.cArgs * sizeof(VARIANT)))) + return E_OUTOFMEMORY; + dp.rgvarg = args; - for(i=0; ilcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, - &ctx->jscaller->IServiceProvider_iface); - IDispatchEx_Release(dispex); - }else { - UINT err = 0; + for(i=0; SUCCEEDED(hres) && i < argc; i++) + hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1); - if(flags == DISPATCH_CONSTRUCT) { - WARN("IDispatch cannot be constructor\n"); - return DISP_E_MEMBERNOTFOUND; - } - - hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &err); + if(SUCCEEDED(hres)) { + V_VT(&retv) = VT_EMPTY; + hres = disp_invoke(ctx, disp, DISPID_VALUE, flags, &dp, r ? &retv : NULL, caller); } - for(i=0; iextensible) + hres = ensure_prop_name(obj, name, flags, FALSE, &prop); + else + hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; + if(!prop || (prop->type == PROP_DELETED && !obj->extensible)) + return throw ? JS_E_INVALID_ACTION : S_OK; return prop_put(obj, prop, val); } HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val) { - return jsdisp_propput(obj, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, val); + return jsdisp_propput(obj, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, FALSE, val); } HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val) { WCHAR buf[12]; - static const WCHAR formatW[] = {'%','d',0}; - - swprintf(buf, formatW, idx); - return jsdisp_propput_name(obj, buf, val); + swprintf(buf, ARRAY_SIZE(buf), L"%d", idx); + return jsdisp_propput(obj, buf, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, TRUE, val); } HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) @@ -1362,7 +2875,7 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) HRESULT hres; jsdisp = iface_to_jsdisp(disp); - if(jsdisp) { + if(jsdisp && jsdisp->ctx == ctx) { dispex_prop_t *prop; prop = get_prop(jsdisp, id); @@ -1377,8 +2890,9 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) DWORD flags = DISPATCH_PROPERTYPUT; VARIANT var; DISPPARAMS dp = {&var, &dispid, 1, 1}; - IDispatchEx *dispex; + if(jsdisp) + jsdisp_release(jsdisp); hres = jsval_to_variant(val, &var); if(FAILED(hres)) return hres; @@ -1386,31 +2900,55 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) if(V_VT(&var) == VT_DISPATCH) flags |= DISPATCH_PROPERTYPUTREF; - clear_ei(ctx); - hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, NULL, &ctx->ei.ei, - &ctx->jscaller->IServiceProvider_iface); - IDispatchEx_Release(dispex); - }else { - ULONG err = 0; - - TRACE("using IDispatch\n"); - hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, NULL, &ctx->ei.ei, &err); - } - + hres = disp_invoke(ctx, disp, id, flags, &dp, NULL, &ctx->jscaller->IServiceProvider_iface); VariantClear(&var); } return hres; } +HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, jsval_t val) +{ + jsdisp_t *jsdisp; + HRESULT hres; + + jsdisp = iface_to_jsdisp(disp); + if(!jsdisp || jsdisp->ctx != ctx) { + IDispatchEx *dispex; + BSTR str; + DISPID id; + + if(jsdisp) + jsdisp_release(jsdisp); + if(!(str = SysAllocString(name))) + return E_OUTOFMEMORY; + + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres)) { + hres = IDispatchEx_GetDispID(dispex, str, make_grfdex(ctx, fdexNameEnsure|fdexNameCaseSensitive), &id); + IDispatchEx_Release(dispex); + }else { + TRACE("using IDispatch\n"); + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &str, 1, 0, &id); + } + SysFreeString(str); + if(FAILED(hres)) + return hres; + + return disp_propput(ctx, disp, id, val); + } + + hres = jsdisp_propput_name(jsdisp, name, val); + jsdisp_release(jsdisp); + return hres; +} + HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) { dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(obj, string_hash(name), name, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; @@ -1419,7 +2957,7 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) return S_OK; } - return prop_get(obj, prop, val); + return prop_get(obj, to_disp(obj), prop, val); } HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) @@ -1428,11 +2966,9 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) dispex_prop_t *prop; HRESULT hres; - static const WCHAR formatW[] = {'%','d',0}; + swprintf(name, ARRAY_SIZE(name), L"%d", idx); - swprintf(name, formatW, idx); - - hres = find_prop_name_prot(obj, string_hash(name), name, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; @@ -1441,7 +2977,7 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) return DISP_E_UNKNOWNNAME; } - return prop_get(obj, prop, r); + return prop_get(obj, to_disp(obj), prop, r); } HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) @@ -1452,60 +2988,51 @@ HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) if(!prop) return DISP_E_MEMBERNOTFOUND; - return prop_get(jsdisp, prop, val); + return prop_get(jsdisp, to_disp(jsdisp), prop, val); } HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val) { DISPPARAMS dp = {NULL,NULL,0,0}; - IDispatchEx *dispex; jsdisp_t *jsdisp; VARIANT var; HRESULT hres; jsdisp = iface_to_jsdisp(disp); - if(jsdisp) { + if(jsdisp && jsdisp->ctx == ctx) { hres = jsdisp_propget(jsdisp, id, val); jsdisp_release(jsdisp); return hres; } + if(jsdisp) + jsdisp_release(jsdisp); V_VT(&var) = VT_EMPTY; - clear_ei(ctx); - hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + hres = disp_invoke(ctx, disp, id, INVOKE_PROPERTYGET, &dp, &var, &ctx->jscaller->IServiceProvider_iface); if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei, - &ctx->jscaller->IServiceProvider_iface); - IDispatchEx_Release(dispex); - }else { - ULONG err = 0; - - TRACE("using IDispatch\n"); - hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei, &err); + hres = variant_to_jsval(ctx, &var, val); + VariantClear(&var); } - if(FAILED(hres)) - return hres; - - hres = variant_to_jsval(&var, val); - VariantClear(&var); return hres; } HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) { - static const WCHAR formatW[] = {'%','d',0}; WCHAR buf[12]; dispex_prop_t *prop; BOOL b; HRESULT hres; - swprintf(buf, formatW, idx); + swprintf(buf, ARRAY_SIZE(buf), L"%d", idx); - hres = find_prop_name(obj, string_hash(buf), buf, &prop); + hres = find_prop_name(obj, string_hash(buf), buf, FALSE, NULL, &prop); if(FAILED(hres) || !prop) return hres; - return delete_prop(prop, &b); + hres = delete_prop(obj, prop, &b); + if(FAILED(hres)) + return hres; + return b ? S_OK : JS_E_INVALID_ACTION; } HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) @@ -1520,7 +3047,7 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) prop = get_prop(jsdisp, id); if(prop) - hres = delete_prop(prop, ret); + hres = delete_prop(jsdisp, prop, ret); else hres = DISP_E_MEMBERNOTFOUND; @@ -1543,31 +3070,42 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) return S_OK; } -HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, BOOL own_only, DISPID *ret) +HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_type, DISPID *ret) { dispex_prop_t *iter; + DWORD idx = id; HRESULT hres; - if(id == DISPID_STARTENUM && !own_only) { - hres = fill_protrefs(obj); + if(id == DISPID_STARTENUM || idx >= obj->prop_cnt) { + hres = (enum_type == JSDISP_ENUM_ALL) ? fill_protrefs(obj) : fill_props(obj); if(FAILED(hres)) return hres; + if(id == DISPID_STARTENUM) + idx = 0; + if(idx >= obj->prop_cnt) + return S_FALSE; } - if(id + 1 < 0 || id+1 >= obj->prop_cnt) - return S_FALSE; - - for(iter = &obj->props[id + 1]; iter < obj->props + obj->prop_cnt; iter++) { - if(!iter->name || iter->type == PROP_DELETED) + for(iter = &obj->props[idx]; iter < obj->props + obj->prop_cnt; iter++) { + if(iter->type == PROP_EXTERN) { + dispex_prop_t *prop; + hres = find_external_prop(obj, iter->name, FALSE, iter, &prop); + if(FAILED(hres) || prop != iter) + iter->type = PROP_DELETED; + } + if(iter->type == PROP_DELETED) continue; - if(own_only && iter->type == PROP_PROTREF) + if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF) continue; - if(!(get_flags(obj, iter) & PROPF_ENUMERABLE)) + if(enum_type != JSDISP_ENUM_OWN && !(get_flags(obj, iter) & PROPF_ENUMERABLE)) continue; *ret = prop_to_id(obj, iter); return S_OK; } + if(obj->ctx->html_mode) + return jsdisp_next_prop(obj, prop_to_id(obj, iter - 1), enum_type, ret); + return S_FALSE; } @@ -1589,9 +3127,9 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL return E_OUTOFMEMORY; } - hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop); + hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, NULL, &prop); if(prop) { - hres = delete_prop(prop, ret); + hres = delete_prop(jsdisp, prop, ret); }else { *ret = TRUE; hres = S_OK; @@ -1636,7 +3174,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name(obj, string_hash(name), name, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; @@ -1648,10 +3186,11 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: + case PROP_EXTERN: desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) { - hres = prop_get(obj, prop, &desc->value); + hres = prop_get(obj, to_disp(obj), prop, &desc->value); if(FAILED(hres)) return hres; } @@ -1679,10 +3218,13 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name(obj, string_hash(name), name, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &prop); if(FAILED(hres)) return hres; + if((!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) && !obj->extensible) + return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name); + if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0))) return E_OUTOFMEMORY; @@ -1708,20 +3250,20 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t return S_OK; } - TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name), + TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(name), prop->flags, desc->flags, desc->mask); if(!(prop->flags & PROPF_CONFIGURABLE)) { if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE)) || ((desc->mask & PROPF_ENUMERABLE) && ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE)))) - return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); } if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { if(prop->type == PROP_ACCESSOR) { if(!(prop->flags & PROPF_CONFIGURABLE)) - return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); if(prop->u.accessor.getter) jsdisp_release(prop->u.accessor.getter); if(prop->u.accessor.setter) @@ -1736,7 +3278,7 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t }else { if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) { if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE)) - return throw_type_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); + return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); if(desc->explicit_value) { if(prop->type == PROP_JSVAL) { BOOL eq; @@ -1744,7 +3286,7 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t if(FAILED(hres)) return hres; if(!eq) - return throw_type_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); + return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); }else { FIXME("redefinition of property type %d\n", prop->type); } @@ -1753,8 +3295,14 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t if(desc->explicit_value) { if(prop->type == PROP_JSVAL) jsval_release(prop->u.val); - else + else { + if(prop->type == PROP_EXTERN && obj->builtin_info->prop_delete) { + hres = obj->builtin_info->prop_delete(obj, prop->u.id); + if(FAILED(hres)) + return hres; + } prop->type = PROP_JSVAL; + } hres = jsval_copy(desc->value, &prop->u.val); if(FAILED(hres)) { prop->u.val = jsval_undefined(); @@ -1765,7 +3313,7 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t }else if(desc->explicit_getter || desc->explicit_setter) { if(prop->type != PROP_ACCESSOR) { if(!(prop->flags & PROPF_CONFIGURABLE)) - return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); if(prop->type == PROP_JSVAL) jsval_release(prop->u.val); prop->type = PROP_ACCESSOR; @@ -1773,7 +3321,7 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t }else if(!(prop->flags & PROPF_CONFIGURABLE)) { if((desc->explicit_getter && desc->getter != prop->u.accessor.getter) || (desc->explicit_setter && desc->setter != prop->u.accessor.setter)) - return throw_type_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); } if(desc->explicit_getter) { @@ -1804,3 +3352,247 @@ HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned f prop_desc.value = value; return jsdisp_define_property(obj, name, &prop_desc); } + +HRESULT jsdisp_change_prototype(jsdisp_t *obj, jsdisp_t *proto) +{ + jsdisp_t *iter; + DWORD i; + + if(obj->prototype == proto) + return S_OK; + if(!obj->extensible) + return JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE; + + for(iter = proto; iter; iter = iter->prototype) + if(iter == obj) + return JS_E_CYCLIC_PROTO_VALUE; + + if(obj->prototype) { + for(i = 0; i < obj->prop_cnt; i++) + if(obj->props[i].type == PROP_PROTREF) + obj->props[i].type = PROP_DELETED; + jsdisp_release(obj->prototype); + } + + obj->prototype = proto; + if(proto) + jsdisp_addref(proto); + return S_OK; +} + +static void set_prop_flags(jsdisp_t *obj, dispex_prop_t *prop, UINT32 flags) +{ + if(prop->type == PROP_EXTERN && obj->builtin_info->prop_config) { + HRESULT hres = obj->builtin_info->prop_config(obj, prop->u.id, flags); + if(hres != S_OK) + return; + } + prop->flags = (prop->flags & ~PROPF_PUBLIC_MASK) | flags; +} + +void jsdisp_freeze(jsdisp_t *obj, BOOL seal) +{ + unsigned int i; + + fill_props(obj); + for(i = 0; i < obj->prop_cnt; i++) { + unsigned int mask = PROPF_CONFIGURABLE; + if(!seal && obj->props[i].type == PROP_JSVAL) + mask |= PROPF_WRITABLE; + set_prop_flags(obj, &obj->props[i], obj->props[i].flags & PROPF_PUBLIC_MASK & ~mask); + } + + obj->extensible = FALSE; +} + +BOOL jsdisp_is_frozen(jsdisp_t *obj, BOOL sealed) +{ + unsigned int i; + + if(obj->extensible) + return FALSE; + fill_props(obj); + + for(i = 0; i < obj->prop_cnt; i++) { + if(obj->props[i].type == PROP_JSVAL || obj->props[i].type == PROP_EXTERN) { + if(!sealed && (obj->props[i].flags & PROPF_WRITABLE)) + return FALSE; + }else if(obj->props[i].type != PROP_ACCESSOR) + continue; + if(obj->props[i].flags & PROPF_CONFIGURABLE) + return FALSE; + } + + return TRUE; +} + +HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r) +{ + dispex_prop_t *prop = get_prop(obj, id); + + if(!prop) + return DISP_E_MEMBERNOTFOUND; + + *r = jsstr_alloc(prop->name); + return *r ? S_OK : E_OUTOFMEMORY; +} + +typedef struct { + jsdisp_t jsdisp; + IWineJSDispatchHost *host_iface; +} HostObject; + +static inline HostObject *HostObject_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, HostObject, jsdisp); +} + +static ULONG HostObject_addref(jsdisp_t *jsdisp) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + return IWineJSDispatchHost_AddRef(This->host_iface); +} + +static ULONG HostObject_release(jsdisp_t *jsdisp) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + return IWineJSDispatchHost_Release(This->host_iface); +} + +static HRESULT HostObject_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + + return IWineJSDispatchHost_LookupProperty(This->host_iface, name, flags, desc); +} + +static HRESULT HostObject_prop_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + EXCEPINFO ei = { 0 }; + VARIANT v; + HRESULT hres; + + V_VT(&v) = VT_EMPTY; + hres = IWineJSDispatchHost_GetProperty(This->host_iface, idx, jsdisp->ctx->lcid, &v, &ei, + &jsdisp->ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(jsdisp->ctx, &ei); + if(FAILED(hres)) + return hres; + + hres = variant_to_jsval(jsdisp->ctx, &v, r); + VariantClear(&v); + return hres; +} + +static HRESULT HostObject_prop_put(jsdisp_t *jsdisp, unsigned idx, jsval_t v) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + EXCEPINFO ei = { 0 }; + VARIANT var; + HRESULT hres; + + hres = jsval_to_variant(v, &var); + if(FAILED(hres)) + return hres; + + hres = IWineJSDispatchHost_SetProperty(This->host_iface, idx, jsdisp->ctx->lcid, &var, &ei, + &jsdisp->ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(jsdisp->ctx, &ei); + VariantClear(&var); + return hres; +} + +static HRESULT HostObject_next_prop(jsdisp_t *jsdisp, unsigned id, struct property_info *desc) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + + return IWineJSDispatchHost_NextProperty(This->host_iface, id, desc); +} + +static HRESULT HostObject_prop_delete(jsdisp_t *jsdisp, unsigned id) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + + return IWineJSDispatchHost_DeleteProperty(This->host_iface, id); +} + +static HRESULT HostObject_prop_config(jsdisp_t *jsdisp, unsigned id, unsigned flags) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + + return IWineJSDispatchHost_ConfigureProperty(This->host_iface, id, flags); +} + +static HRESULT HostObject_to_string(jsdisp_t *jsdisp, jsstr_t **ret) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + BSTR str; + HRESULT hres; + + hres = IWineJSDispatchHost_ToString(This->host_iface, &str); + if(FAILED(hres)) + return hres; + + *ret = jsstr_alloc(str); + SysFreeString(str); + return *ret ? S_OK : E_OUTOFMEMORY; +} + +static const builtin_info_t HostObject_info = { + .class = JSCLASS_HOST, + .addref = HostObject_addref, + .release = HostObject_release, + .lookup_prop = HostObject_lookup_prop, + .prop_get = HostObject_prop_get, + .prop_put = HostObject_prop_put, + .next_prop = HostObject_next_prop, + .prop_delete = HostObject_prop_delete, + .prop_config = HostObject_prop_config, + .to_string = HostObject_to_string, +}; + +HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWineJSDispatch *prototype_iface, + UINT32 flags, IWineJSDispatch **ret) +{ + HostObject *host_obj; + jsdisp_t *prototype; + HRESULT hres; + + if(!(host_obj = calloc(1, sizeof(*host_obj)))) + return E_OUTOFMEMORY; + + if(prototype_iface) + prototype = impl_from_IWineJSDispatch(prototype_iface); + else + prototype = ctx->object_prototype; + hres = init_dispex(&host_obj->jsdisp, ctx, &HostObject_info, prototype); + if(FAILED(hres)) { + free(host_obj); + return hres; + } + + host_obj->host_iface = host_iface; + if(flags & HOSTOBJ_CONSTRUCTOR) + host_obj->jsdisp.is_constructor = TRUE; + *ret = &host_obj->jsdisp.IWineJSDispatch_iface; + return S_OK; +} + +IWineJSDispatchHost *get_host_dispatch(IDispatch *disp) +{ + IWineJSDispatchHost *ret; + HostObject *host_obj; + jsdisp_t *jsdisp; + + if(!(jsdisp = to_jsdisp(disp))) + return NULL; + if(jsdisp->builtin_info != &HostObject_info) + return NULL; + + host_obj = HostObject_from_jsdisp(jsdisp); + IWineJSDispatchHost_GetOuterDispatch(host_obj->host_iface, &ret); + return ret; +} diff --git a/dll/win32/jscript/engine.c b/dll/win32/jscript/engine.c index 4d11db981eb..7938b129ad6 100644 --- a/dll/win32/jscript/engine.c +++ b/dll/win32/jscript/engine.c @@ -31,14 +31,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); -static const WCHAR booleanW[] = {'b','o','o','l','e','a','n',0}; -static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0}; -static const WCHAR numberW[] = {'n','u','m','b','e','r',0}; -static const WCHAR objectW[] = {'o','b','j','e','c','t',0}; -static const WCHAR stringW[] = {'s','t','r','i','n','g',0}; -static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0}; -static const WCHAR unknownW[] = {'u','n','k','n','o','w','n',0}; - struct _except_frame_t { unsigned stack_top; scope_chain_t *scope; @@ -66,25 +58,12 @@ typedef struct { } u; } exprval_t; +static const size_t stack_size = 0x40000; + static HRESULT stack_push(script_ctx_t *ctx, jsval_t v) { - if(!ctx->stack_size) { - ctx->stack = heap_alloc(16*sizeof(*ctx->stack)); - if(!ctx->stack) - return E_OUTOFMEMORY; - ctx->stack_size = 16; - }else if(ctx->stack_size == ctx->stack_top) { - jsval_t *new_stack; - - new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*new_stack)); - if(!new_stack) { - jsval_release(v); - return E_OUTOFMEMORY; - } - - ctx->stack = new_stack; - ctx->stack_size *= 2; - } + if(ctx->stack_top == stack_size) + return JS_E_STACK_OVERFLOW; ctx->stack[ctx->stack_top++] = v; return S_OK; @@ -156,8 +135,6 @@ static HRESULT stack_pop_object(script_ctx_t *ctx, IDispatch **r) v = stack_pop(ctx); if(is_object_instance(v)) { - if(!get_object(v)) - return throw_type_error(ctx, JS_E_OBJECT_REQUIRED, NULL); *r = get_object(v); return S_OK; } @@ -172,7 +149,7 @@ static inline HRESULT stack_pop_int(script_ctx_t *ctx, INT *r) return to_int32(ctx, stack_pop(ctx), r); } -static inline HRESULT stack_pop_uint(script_ctx_t *ctx, DWORD *r) +static inline HRESULT stack_pop_uint(script_ctx_t *ctx, UINT32 *r) { return to_uint32(ctx, stack_pop(ctx), r); } @@ -189,6 +166,23 @@ static inline BSTR local_name(call_frame_t *frame, int ref) return ref < 0 ? frame->function->params[-ref-1] : frame->function->variables[ref].name; } +static jsval_t *get_detached_var_ref(scope_chain_t *scope, const WCHAR *name) +{ + struct vars_buffer *detached_vars = scope->detached_vars; + local_ref_t *ref; + + if(!detached_vars) + return NULL; + ref = lookup_local(detached_vars->func_code, name, scope->scope_index); + return ref && ref->ref < 0 ? &detached_vars->var[-ref->ref - 1] : NULL; +} + +static HRESULT get_detached_var_dispid(scope_chain_t *scope, const WCHAR *name, DISPID *id) +{ + jsval_t *var_ref = get_detached_var_ref(scope, name); + return var_ref ? jsdisp_get_idx_id(&scope->dispex, var_ref - scope->detached_vars->var, id) : DISP_E_UNKNOWNNAME; +} + /* Steals input reference even on failure. */ static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val) { @@ -196,7 +190,10 @@ static HRESULT stack_push_exprval(script_ctx_t *ctx, exprval_t *val) switch(val->type) { case EXPRVAL_JSVAL: - assert(0); + hres = stack_push(ctx, jsval_null()); + if(SUCCEEDED(hres)) + hres = stack_push(ctx, val->u.val); + return hres; case EXPRVAL_IDREF: hres = stack_push(ctx, jsval_disp(val->u.idref.disp)); if(SUCCEEDED(hres)) @@ -227,30 +224,58 @@ static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r) switch(jsval_type(v)) { case JSV_NUMBER: { call_frame_t *frame = ctx->call_ctx; + scope_chain_t *scope; unsigned off = get_number(v); if(!frame->base_scope->frame && off >= frame->arguments_off) { + jsdisp_t *jsobj; DISPID id; BSTR name; - HRESULT hres; + HRESULT hres = E_FAIL; /* Got stack reference in deoptimized code. Need to convert it back to variable object reference. */ assert(off < frame->variables_off + frame->function->var_cnt); - name = off >= frame->variables_off - ? frame->function->variables[off - frame->variables_off].name - : frame->function->params[off - frame->arguments_off]; - hres = jsdisp_get_id(ctx->call_ctx->base_scope->jsobj, name, 0, &id); - if(FAILED(hres)) { - r->type = EXPRVAL_INVALID; - r->u.hres = hres; - return FALSE; + if (off >= frame->variables_off) + { + name = frame->function->variables[off - frame->variables_off].name; + scope = frame->scope; + } + else + { + name = frame->function->params[off - frame->arguments_off]; + scope = frame->base_scope; } - *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(frame->base_scope->jsobj)); + while (1) + { + hres = get_detached_var_dispid(scope, name, &id); + if (hres != DISP_E_UNKNOWNNAME) + { + if (FAILED(hres)) + { + r->type = EXPRVAL_INVALID; + r->u.hres = hres; + return FALSE; + } + jsobj = &scope->dispex; + break; + } + if ((jsobj = to_jsdisp(scope->obj)) && SUCCEEDED(hres = jsdisp_get_id(jsobj, name, 0, &id))) + break; + if (scope == frame->base_scope) + { + r->type = EXPRVAL_INVALID; + r->u.hres = hres; + return FALSE; + } + scope = scope->next; + } + + *stack_top_ref(ctx, n+1) = jsval_obj(jsdisp_addref(jsobj)); *stack_top_ref(ctx, n) = jsval_number(id); r->type = EXPRVAL_IDREF; - r->u.idref.disp = frame->base_scope->obj; + r->u.idref.disp = to_disp(jsobj); r->u.idref.id = id; return TRUE; } @@ -270,6 +295,10 @@ static BOOL stack_topn_exprval(script_ctx_t *ctx, unsigned n, exprval_t *r) assert(is_number(stack_topn(ctx, n))); r->u.hres = get_number(stack_topn(ctx, n)); return FALSE; + case JSV_NULL: + r->type = EXPRVAL_JSVAL; + r->u.val = stack_topn(ctx, n); + return TRUE; default: assert(0); return FALSE; @@ -293,6 +322,9 @@ static HRESULT exprval_propput(script_ctx_t *ctx, exprval_t *ref, jsval_t v) } case EXPRVAL_IDREF: return disp_propput(ctx, ref->u.idref.disp, ref->u.idref.id, v); + case EXPRVAL_JSVAL: + WARN("ignoring an attempt to set value reference\n"); + return S_OK; default: assert(0); return E_FAIL; @@ -306,6 +338,8 @@ static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r) return jsval_copy(ctx->stack[ref->u.off], r); case EXPRVAL_IDREF: return disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, r); + case EXPRVAL_JSVAL: + return jsval_copy(ref->u.val, r); default: assert(0); return E_FAIL; @@ -314,19 +348,48 @@ static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r) static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + jsdisp_t *jsdisp; + HRESULT hres; + jsval_t v; + switch(ref->type) { case EXPRVAL_STACK_REF: { - jsval_t v = ctx->stack[ref->u.off]; + v = ctx->stack[ref->u.off]; if(!is_object_instance(v)) { FIXME("invoke %s\n", debugstr_jsval(v)); return E_FAIL; } - return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r); + return disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r); } case EXPRVAL_IDREF: + /* ECMA-262 3rd Edition 11.2.3.7 / ECMA-262 5.1 Edition 11.2.3.6 * + * Don't treat scope object props as PropertyReferences. */ + if((jsdisp = to_jsdisp(ref->u.idref.disp)) && jsdisp->builtin_info->class == JSCLASS_NONE) { + hres = disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, &v); + if(FAILED(hres)) + return hres; + if(!is_object_instance(v)) { + FIXME("invoke %s\n", debugstr_jsval(v)); + hres = E_FAIL; + }else { + hres = disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r); + } + jsval_release(v); + return hres; + } return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r); + case EXPRVAL_JSVAL: { + IDispatch *obj; + + hres = to_object(ctx, ref->u.val, &obj); + if(SUCCEEDED(hres)) { + hres = disp_call_value(ctx, obj, jsval_undefined(), flags, argc, argv, r); + IDispatch_Release(obj); + } + return hres; + } default: assert(0); return E_FAIL; @@ -376,9 +439,9 @@ static inline void exprval_set_exception(exprval_t *val, HRESULT hres) static inline void exprval_set_disp_ref(exprval_t *ref, IDispatch *obj, DISPID id) { ref->type = EXPRVAL_IDREF; -#ifdef __REACTOS__ /* FIXME: Inspect */ - IDispatch_AddRef(obj); +#ifdef __REACTOS__ ref->u.idref.disp = obj; + IDispatch_AddRef(obj); #else IDispatch_AddRef(ref->u.idref.disp = obj); #endif @@ -398,21 +461,127 @@ static inline void clear_acc(script_ctx_t *ctx) ctx->acc = jsval_undefined(); } -static HRESULT scope_push(scope_chain_t *scope, jsdisp_t *jsobj, IDispatch *obj, scope_chain_t **ret) +static inline scope_chain_t *scope_from_dispex(jsdisp_t *dispex) +{ + return CONTAINING_RECORD(dispex, scope_chain_t, dispex); +} + +static void scope_destructor(jsdisp_t *dispex) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + if(scope->detached_vars) { + struct vars_buffer *vars = scope->detached_vars; + unsigned i, cnt = vars->argc; + + release_bytecode(vars->func_code->bytecode); + for(i = 0; i < cnt; i++) + jsval_release(vars->var[i]); + free(vars); + } + + if(scope->next) + scope_release(scope->next); + + if(scope->obj) + IDispatch_Release(scope->obj); +} + +static HRESULT scope_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) +{ + scope_chain_t *scope = scope_from_dispex(jsdisp); + + return jsdisp_index_lookup(&scope->dispex, name, scope->detached_vars->argc, desc); +} + +static HRESULT scope_prop_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + return jsval_copy(scope->detached_vars->var[idx], r); +} + +static HRESULT scope_prop_put(jsdisp_t *dispex, unsigned idx, jsval_t val) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + jsval_t copy, *ref; + HRESULT hres; + + hres = jsval_copy(val, ©); + if(FAILED(hres)) + return hres; + + ref = &scope->detached_vars->var[idx]; + jsval_release(*ref); + *ref = copy; + return S_OK; +} + +static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + jsdisp_t *jsobj; + HRESULT hres; + + if(scope->detached_vars) { + struct vars_buffer *vars = scope->detached_vars; + unsigned i, cnt = vars->argc; + + for(i = 0; i < cnt; i++) { + hres = gc_process_linked_val(gc_ctx, op, dispex, &vars->var[i]); + if(FAILED(hres)) + return hres; + } + } + + if(scope->next) { + hres = gc_process_linked_obj(gc_ctx, op, dispex, &scope->next->dispex, (void**)&scope->next); + if(FAILED(hres)) + return hres; + } + + if(op == GC_TRAVERSE_UNLINK) { + IDispatch *obj = scope->obj; + if(obj) { + scope->obj = NULL; + IDispatch_Release(obj); + } + return S_OK; + } + + return scope->obj && (jsobj = to_jsdisp(scope->obj)) ? gc_process_linked_obj(gc_ctx, op, dispex, jsobj, (void**)&scope->obj) : S_OK; +} + +static const builtin_info_t scope_info = { + JSCLASS_NONE, + .destructor = scope_destructor, + .lookup_prop = scope_lookup_prop, + .prop_get = scope_prop_get, + .prop_put = scope_prop_put, + .gc_traverse = scope_gc_traverse +}; + +static HRESULT scope_push(script_ctx_t *ctx, scope_chain_t *scope, IDispatch *obj, scope_chain_t **ret) { scope_chain_t *new_scope; + HRESULT hres; - new_scope = heap_alloc(sizeof(scope_chain_t)); + new_scope = calloc(1, sizeof(scope_chain_t)); if(!new_scope) return E_OUTOFMEMORY; - new_scope->ref = 1; + hres = init_dispex(&new_scope->dispex, ctx, &scope_info, NULL); + if(FAILED(hres)) { + free(new_scope); + return hres; + } - IDispatch_AddRef(obj); - new_scope->jsobj = jsobj; + if (obj) + IDispatch_AddRef(obj); new_scope->obj = obj; new_scope->frame = NULL; new_scope->next = scope ? scope_addref(scope) : NULL; + new_scope->scope_index = 0; *ret = new_scope; return S_OK; @@ -427,25 +596,6 @@ static void scope_pop(scope_chain_t **scope) scope_release(tmp); } -void clear_ei(script_ctx_t *ctx) -{ - memset(&ctx->ei.ei, 0, sizeof(ctx->ei.ei)); - jsval_release(ctx->ei.val); - ctx->ei.val = jsval_undefined(); -} - -void scope_release(scope_chain_t *scope) -{ - if(--scope->ref) - return; - - if(scope->next) - scope_release(scope->next); - - IDispatch_Release(scope->obj); - heap_free(scope); -} - static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, BSTR name_bstr, DWORD flags, DISPID *id) { IDispatchEx *dispex; @@ -453,12 +603,9 @@ static HRESULT disp_get_id(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name BSTR bstr; HRESULT hres; - jsdisp = iface_to_jsdisp(disp); - if(jsdisp) { - hres = jsdisp_get_id(jsdisp, name, flags, id); - jsdisp_release(jsdisp); - return hres; - } + jsdisp = to_jsdisp(disp); + if(jsdisp) + return jsdisp_get_id(jsdisp, name, flags, id); if(name_bstr) { bstr = name_bstr; @@ -499,14 +646,20 @@ static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret) return S_OK; } - hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1); - if(FAILED(hres)) - return hres; + unk1 = (IUnknown *)get_host_dispatch(disp1); + if(!unk1) { + hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1); + if(FAILED(hres)) + return hres; + } - hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2); - if(FAILED(hres)) { - IUnknown_Release(unk1); - return hres; + unk2 = (IUnknown *)get_host_dispatch(disp2); + if(!unk2) { + hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2); + if(FAILED(hres)) { + IUnknown_Release(unk1); + return hres; + } } if(unk1 == unk2) { @@ -535,10 +688,7 @@ HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret) TRACE("\n"); if(type != jsval_type(rval)) { - if(is_null_instance(lval)) - *ret = is_null_instance(rval); - else - *ret = FALSE; + *ret = FALSE; return S_OK; } @@ -559,20 +709,99 @@ HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret) *ret = !get_bool(lval) == !get_bool(rval); break; case JSV_VARIANT: - FIXME("VARIANT not implemented\n"); - return E_NOTIMPL; + WARN("VARIANT type, returning false\n"); + *ret = FALSE; + return S_OK; } return S_OK; } +static HRESULT alloc_detached_vars(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope) +{ + function_code_t *func = frame->function; + unsigned i, argc; + + argc = (scope == frame->base_scope) ? max(frame->argc, func->param_cnt) : 0; + if(!argc) + return S_OK; + + if(!(scope->detached_vars = malloc(FIELD_OFFSET(struct vars_buffer, var[argc])))) + return E_OUTOFMEMORY; + scope->detached_vars->argc = argc; + scope->detached_vars->func_code = func; + bytecode_addref(func->bytecode); + + for(i = 0; i < argc; i++) { + scope->detached_vars->var[i] = ctx->stack[frame->arguments_off + i]; + ctx->stack[frame->arguments_off + i] = jsval_undefined(); + } + + return S_OK; +} + +static HRESULT detach_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope) +{ + function_code_t *func = frame->function; + unsigned int i, index; + jsdisp_t *jsobj; + HRESULT hres; + + if (!scope->frame) + return S_OK; + + assert(scope->frame == frame); + scope->frame = NULL; + + hres = alloc_detached_vars(ctx, frame, scope); + if (FAILED(hres)) + return hres; + + if (!scope->obj) + { + if (FAILED(hres = create_dispex(ctx, NULL, NULL, &jsobj))) + return hres; + scope->obj = to_disp(jsobj); + } + else + jsobj = as_jsdisp(scope->obj); + + if (scope == frame->base_scope && func->name && func->local_ref == INVALID_LOCAL_REF && + ctx->version >= SCRIPTLANGUAGEVERSION_ES5) + jsdisp_propput_name(jsobj, func->name, jsval_obj(frame->function_instance)); + + index = scope->scope_index; + for(i = 0; i < frame->function->local_scopes[index].locals_cnt; i++) + { + WCHAR *name = frame->function->local_scopes[index].locals[i].name; + int ref = frame->function->local_scopes[index].locals[i].ref; + + if (ref < 0) + continue; + if (FAILED(hres = jsdisp_propput_name(jsobj, name, ctx->stack[local_off(frame, ref)]))) + return hres; + if (scope != frame->base_scope && frame->function->variables[ref].func_id != -1 + && FAILED(hres = jsdisp_propput_name(frame->variable_obj, name, ctx->stack[local_off(frame, ref)]))) + return hres; + } + return S_OK; +} + +static HRESULT detach_scope_chain(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t *scope) +{ + HRESULT hres; + + if (scope != frame->base_scope && FAILED(hres = detach_scope_chain(ctx, frame, scope->next))) + return hres; + return detach_scope(ctx, frame, scope); +} + /* * Transfers local variables from stack to variable object. * It's slow, so we want to avoid it as much as possible. */ static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BOOL from_release) { - unsigned i; HRESULT hres; if(!frame->base_scope || !frame->base_scope->frame) @@ -581,7 +810,7 @@ static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BO TRACE("detaching %p\n", frame); assert(frame == frame->base_scope->frame); - assert(frame->variable_obj == frame->base_scope->jsobj); + assert(to_disp(frame->variable_obj) == frame->base_scope->obj); if(!from_release && !frame->arguments_obj) { hres = setup_arguments_object(ctx, frame); @@ -589,16 +818,8 @@ static HRESULT detach_variable_object(script_ctx_t *ctx, call_frame_t *frame, BO return hres; } - frame->base_scope->frame = NULL; - - for(i = 0; i < frame->function->locals_cnt; i++) { - hres = jsdisp_propput_name(frame->variable_obj, frame->function->locals[i].name, - ctx->stack[local_off(frame, frame->function->locals[i].ref)]); - if(FAILED(hres)) - return hres; - } - - return S_OK; + TRACE("detaching scope chain %p, frame %p.\n", ctx->call_ctx->scope, frame); + return detach_scope_chain(ctx, frame, ctx->call_ctx->scope); } static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t *ret) @@ -607,7 +828,7 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t DISPID id; HRESULT hres; - for(item = ctx->named_items; item; item = item->next) { + LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { if(item->flags & SCRIPTITEM_GLOBALMEMBERS) { hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id); if(SUCCEEDED(hres)) { @@ -621,14 +842,30 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t return FALSE; } +IDispatch *lookup_global_host(script_ctx_t *ctx) +{ + IDispatch *disp = NULL; + named_item_t *item; + + LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { + if(!(item->flags & SCRIPTITEM_GLOBALMEMBERS)) continue; + disp = item->disp; + break; + } + if(!disp) disp = to_disp(ctx->global); + + return disp; +} + static int __cdecl local_ref_cmp(const void *key, const void *ref) { return wcscmp((const WCHAR*)key, ((const local_ref_t*)ref)->name); } -local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier) +local_ref_t *lookup_local(const function_code_t *function, const WCHAR *identifier, unsigned int scope) { - return bsearch(identifier, function->locals, function->locals_cnt, sizeof(*function->locals), local_ref_cmp); + return bsearch(identifier, function->local_scopes[scope].locals, function->local_scopes[scope].locals_cnt, + sizeof(*function->local_scopes[scope].locals), local_ref_cmp); } /* ECMA-262 3rd Edition 10.1.4 */ @@ -645,8 +882,7 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re for(scope = ctx->call_ctx->scope; scope; scope = scope->next) { if(scope->frame) { function_code_t *func = scope->frame->function; - local_ref_t *ref = lookup_local(func, identifier); - static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0}; + local_ref_t *ref = lookup_local(func, identifier, scope->scope_index); if(ref) { ret->type = EXPRVAL_STACK_REF; @@ -655,21 +891,51 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re return S_OK; } - if(!wcscmp(identifier, argumentsW)) { + if(!wcscmp(identifier, L"arguments")) { hres = detach_variable_object(ctx, scope->frame, FALSE); if(FAILED(hres)) return hres; } + + /* ECMA-262 5.1 Edition 13 */ + if(func->name && ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && + func->local_ref == INVALID_LOCAL_REF && !wcscmp(identifier, func->name)) { + TRACE("returning a function from scope chain\n"); + ret->type = EXPRVAL_JSVAL; + ret->u.val = jsval_obj(jsdisp_addref(scope->frame->function_instance)); + return S_OK; + } + }else if((hres = get_detached_var_dispid(scope, identifier, &id)) != DISP_E_UNKNOWNNAME) { + if(SUCCEEDED(hres)) + exprval_set_disp_ref(ret, to_disp(&scope->dispex), id); + return hres; } - if(scope->jsobj) - hres = jsdisp_get_id(scope->jsobj, identifier, fdexNameImplicit, &id); - else - hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id); + + if (!scope->obj) + continue; + + hres = disp_get_id(ctx, scope->obj, identifier, identifier, fdexNameImplicit, &id); if(SUCCEEDED(hres)) { exprval_set_disp_ref(ret, scope->obj, id); return S_OK; } } + + item = ctx->call_ctx->bytecode->named_item; + if(item) { + hres = jsdisp_get_id(item->script_obj, identifier, 0, &id); + if(SUCCEEDED(hres)) { + exprval_set_disp_ref(ret, to_disp(item->script_obj), id); + return S_OK; + } + if(!(item->flags & SCRIPTITEM_CODEONLY)) { + hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id); + if(SUCCEEDED(hres)) { + exprval_set_disp_ref(ret, item->disp, id); + return S_OK; + } + } + } } hres = jsdisp_get_id(ctx->global, identifier, 0, &id); @@ -678,34 +944,12 @@ static HRESULT identifier_eval(script_ctx_t *ctx, BSTR identifier, exprval_t *re return S_OK; } - for(item = ctx->named_items; item; item = item->next) { - if((item->flags & SCRIPTITEM_ISVISIBLE) && !wcscmp(item->name, identifier)) { - if(!item->disp) { - IUnknown *unk; - - if(!ctx->site) - break; - - hres = IActiveScriptSite_GetItemInfo(ctx->site, identifier, - SCRIPTINFO_IUNKNOWN, &unk, NULL); - if(FAILED(hres)) { - WARN("GetItemInfo failed: %08x\n", hres); - break; - } - - hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp); - IUnknown_Release(unk); - if(FAILED(hres)) { - WARN("object does not implement IDispatch\n"); - break; - } - } - - IDispatch_AddRef(item->disp); - ret->type = EXPRVAL_JSVAL; - ret->u.val = jsval_disp(item->disp); - return S_OK; - } + item = lookup_named_item(ctx, identifier, SCRIPTITEM_ISVISIBLE); + if(item) { + IDispatch_AddRef(item->disp); + ret->type = EXPRVAL_JSVAL; + ret->u.val = jsval_disp(item->disp); + return S_OK; } if(lookup_global_members(ctx, identifier, ret)) @@ -772,7 +1016,7 @@ static HRESULT interp_forin(script_ctx_t *ctx) id = get_number(stack_top(ctx)); if(!stack_topn_exprval(ctx, 1, &prop_ref)) { - FIXME("invalid ref: %08x\n", prop_ref.u.hres); + FIXME("invalid ref: %08lx\n", prop_ref.u.hres); return E_FAIL; } @@ -817,8 +1061,78 @@ static HRESULT interp_forin(script_ctx_t *ctx) return S_OK; } +static HRESULT scope_init_locals(script_ctx_t *ctx) +{ + call_frame_t *frame = ctx->call_ctx; + unsigned int i, off, index; + scope_chain_t *scope; + BOOL detached_vars; + jsdisp_t *jsobj; + HRESULT hres; + + scope = frame->scope; + index = scope->scope_index; + detached_vars = !(frame->base_scope && frame->base_scope->frame); + + if (!detached_vars) + { + assert(frame->base_scope->frame == frame); + frame->scope->frame = ctx->call_ctx; + } + else if (!scope->obj) + { + if (FAILED(hres = create_dispex(ctx, NULL, NULL, &jsobj))) + return hres; + scope->obj = to_disp(jsobj); + } + else + jsobj = as_jsdisp(scope->obj); + + for(i = 0; i < frame->function->local_scopes[index].locals_cnt; i++) + { + WCHAR *name = frame->function->local_scopes[index].locals[i].name; + int ref = frame->function->local_scopes[index].locals[i].ref; + jsdisp_t *func_obj; + jsval_t val; + + if (frame->function->variables[ref].func_id != -1) + { + TRACE("function %s %d\n", debugstr_w(name), i); + + if (FAILED(hres = create_source_function(ctx, frame->bytecode, frame->function->funcs + + frame->function->variables[ref].func_id, ctx->call_ctx->scope, &func_obj))) + return hres; + val = jsval_obj(func_obj); + if (detached_vars && FAILED(hres = jsdisp_propput_name(frame->variable_obj, name, jsval_obj(func_obj)))) + { + jsdisp_release(func_obj); + return hres; + } + } + else + { + val = jsval_undefined(); + } + + if (detached_vars) + { + hres = jsdisp_propput_name(jsobj, name, val); + jsval_release(val); + if (FAILED(hres)) + return hres; + } + else + { + off = local_off(frame, ref); + jsval_release(ctx->stack[off]); + ctx->stack[off] = val; + } + } + return S_OK; +} + /* ECMA-262 3rd Edition 12.10 */ -static HRESULT interp_push_scope(script_ctx_t *ctx) +static HRESULT interp_push_with_scope(script_ctx_t *ctx) { IDispatch *disp; jsval_t v; @@ -832,16 +1146,41 @@ static HRESULT interp_push_scope(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = scope_push(ctx->call_ctx->scope, to_jsdisp(disp), disp, &ctx->call_ctx->scope); + hres = scope_push(ctx, ctx->call_ctx->scope, disp, &ctx->call_ctx->scope); IDispatch_Release(disp); return hres; } +/* ECMA-262 10th Edition 13.3.1 */ +static HRESULT interp_push_block_scope(script_ctx_t *ctx) +{ + unsigned int scope_index = get_op_uint(ctx, 0); + call_frame_t *frame = ctx->call_ctx; + HRESULT hres; + + TRACE("scope_index %u.\n", scope_index); + + hres = scope_push(ctx, ctx->call_ctx->scope, NULL, &frame->scope); + + if (FAILED(hres) || !scope_index) + return hres; + + frame->scope->scope_index = scope_index; + + return scope_init_locals(ctx); +} + /* ECMA-262 3rd Edition 12.10 */ static HRESULT interp_pop_scope(script_ctx_t *ctx) { TRACE("\n"); + if(ctx->call_ctx->scope->dispex.ref > 1) { + HRESULT hres = detach_variable_object(ctx, ctx->call_ctx, FALSE); + if(FAILED(hres)) + ERR("Failed to detach variable object: %08lx\n", hres); + } + scope_pop(&ctx->call_ctx->scope); return S_OK; } @@ -871,13 +1210,48 @@ static HRESULT interp_case(script_ctx_t *ctx) return S_OK; } +static void set_error_value(script_ctx_t *ctx, jsval_t value) +{ + jsexcept_t *ei = ctx->ei; + jsdisp_t *obj; + + reset_ei(ei); + ei->error = JS_E_EXCEPTION_THROWN; + ei->valid_value = TRUE; + ei->value = value; + + if(is_object_instance(value) && (obj = to_jsdisp(get_object(value)))) { + UINT32 number; + jsstr_t *str; + jsval_t v; + HRESULT hres; + + /* FIXME: We should check if object is an error instance */ + + hres = jsdisp_propget_name(obj, L"number", &v); + if(SUCCEEDED(hres)) { + hres = to_uint32(ctx, v, &number); + if(SUCCEEDED(hres)) + ei->error = FAILED(number) ? number : E_FAIL; + jsval_release(v); + } + + hres = jsdisp_propget_name(obj, L"description", &v); + if(SUCCEEDED(hres)) { + hres = to_string(ctx, v, &str); + if(SUCCEEDED(hres)) + ei->message = str; + jsval_release(v); + } + } +} + /* ECMA-262 3rd Edition 12.13 */ static HRESULT interp_throw(script_ctx_t *ctx) { TRACE("\n"); - jsval_release(ctx->ei.val); - ctx->ei.val = stack_pop(ctx); + set_error_value(ctx, stack_pop(ctx)); return DISP_E_EXCEPTION; } @@ -885,9 +1259,9 @@ static HRESULT interp_throw_ref(script_ctx_t *ctx) { const HRESULT arg = get_op_uint(ctx, 0); - TRACE("%08x\n", arg); + TRACE("%08lx\n", arg); - return throw_reference_error(ctx, arg, NULL); + return arg; } static HRESULT interp_throw_type(script_ctx_t *ctx) @@ -896,10 +1270,10 @@ static HRESULT interp_throw_type(script_ctx_t *ctx) jsstr_t *str = get_op_str(ctx, 1); const WCHAR *ptr; - TRACE("%08x %s\n", hres, debugstr_jsstr(str)); + TRACE("%08lx %s\n", hres, debugstr_jsstr(str)); ptr = jsstr_flatten(str); - return ptr ? throw_type_error(ctx, hres, ptr) : E_OUTOFMEMORY; + return ptr ? throw_error(ctx, hres, ptr) : E_OUTOFMEMORY; } /* ECMA-262 3rd Edition 12.14 */ @@ -912,7 +1286,7 @@ static HRESULT interp_push_except(script_ctx_t *ctx) TRACE("\n"); - except = heap_alloc(sizeof(*except)); + except = malloc(sizeof(*except)); if(!except) return E_OUTOFMEMORY; @@ -940,7 +1314,7 @@ static HRESULT interp_pop_except(script_ctx_t *ctx) finally_off = except->finally_off; frame->except_frame = except->next; - heap_free(except); + free(except); if(finally_off) { HRESULT hres; @@ -973,7 +1347,7 @@ static HRESULT interp_end_finally(script_ctx_t *ctx) if(!get_bool(v)) { TRACE("passing exception\n"); - ctx->ei.val = stack_pop(ctx); + set_error_value(ctx, stack_pop(ctx)); return DISP_E_EXCEPTION; } @@ -998,7 +1372,7 @@ static HRESULT interp_enter_catch(script_ctx_t *ctx) hres = jsdisp_propput_name(scope_obj, ident, v); jsval_release(v); if(SUCCEEDED(hres)) - hres = scope_push(ctx->call_ctx->scope, scope_obj, to_disp(scope_obj), &ctx->call_ctx->scope); + hres = scope_push(ctx, ctx->call_ctx->scope, to_disp(scope_obj), &ctx->call_ctx->scope); jsdisp_release(scope_obj); return hres; } @@ -1132,7 +1506,7 @@ static HRESULT interp_memberid(script_ctx_t *ctx) exprval_set_exception(&ref, JS_E_INVALID_PROPERTY); hres = S_OK; }else { - ERR("failed %08x\n", hres); + ERR("failed %08lx\n", hres); return hres; } } @@ -1150,7 +1524,7 @@ static HRESULT interp_refval(script_ctx_t *ctx) TRACE("\n"); if(!stack_topn_exprval(ctx, 0, &ref)) - return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL); + return JS_E_ILLEGAL_ASSIGN; hres = exprval_propget(ctx, &ref, &v); if(FAILED(hres)) @@ -1172,14 +1546,12 @@ static HRESULT interp_new(script_ctx_t *ctx) /* NOTE: Should use to_object here */ if(is_null(constr)) - return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); - else if(!is_object_instance(constr)) - return throw_type_error(ctx, JS_E_INVALID_ACTION, NULL); - else if(!get_object(constr)) - return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL); + return is_null_disp(constr) ? JS_E_INVALID_PROPERTY : JS_E_OBJECT_EXPECTED; + if(!is_object_instance(constr)) + return JS_E_INVALID_ACTION; clear_acc(ctx); - return disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, + return disp_call_value(ctx, get_object(constr), jsval_undefined(), DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, argc, stack_args(ctx, argc), &ctx->acc); } @@ -1194,10 +1566,10 @@ static HRESULT interp_call(script_ctx_t *ctx) obj = stack_topn(ctx, argn); if(!is_object_instance(obj)) - return throw_type_error(ctx, JS_E_INVALID_PROPERTY, NULL); + return JS_E_INVALID_PROPERTY; clear_acc(ctx); - return disp_call_value(ctx, get_object(obj), NULL, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, + return disp_call_value(ctx, get_object(obj), jsval_undefined(), DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL); } @@ -1211,22 +1583,65 @@ static HRESULT interp_call_member(script_ctx_t *ctx) TRACE("%d %d\n", argn, do_ret); if(!stack_topn_exprval(ctx, argn, &ref)) - return throw_type_error(ctx, ref.u.hres, NULL); + return ref.u.hres; clear_acc(ctx); return exprval_call(ctx, &ref, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL); } +/* ECMA-262 5th Edition 15.1.2.1.1 */ +static HRESULT interp_call_eval(script_ctx_t *ctx) +{ + const unsigned argn = get_op_uint(ctx, 0); + const int do_ret = get_op_int(ctx, 1); + HRESULT hres = S_OK; + exprval_t exprval; + jsdisp_t *jsdisp; + BSTR identifier; + jsval_t v; + + TRACE("%d %d\n", argn, do_ret); + + identifier = SysAllocString(L"eval"); + hres = identifier_eval(ctx, identifier, &exprval); + SysFreeString(identifier); + if(FAILED(hres)) + return hres; + + clear_acc(ctx); + hres = exprval_propget(ctx, &exprval, &v); + if(SUCCEEDED(hres)) { + if(is_object_instance(v) && (jsdisp = to_jsdisp(get_object(v))) && jsdisp->ctx == ctx && is_builtin_eval_func(jsdisp)) + hres = builtin_eval(ctx, ctx->call_ctx, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, + argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL); + else + hres = exprval_call(ctx, &exprval, DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, + argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL); + jsval_release(v); + } + exprval_release(&exprval); + return hres; +} + /* ECMA-262 3rd Edition 11.1.1 */ static HRESULT interp_this(script_ctx_t *ctx) { - call_frame_t *frame = ctx->call_ctx; + IDispatch *this_obj = ctx->call_ctx->this_obj; TRACE("\n"); - IDispatch_AddRef(frame->this_obj); - return stack_push(ctx, jsval_disp(frame->this_obj)); + if(!this_obj) { + named_item_t *item = ctx->call_ctx->bytecode->named_item; + + if(item) + this_obj = (item->flags & SCRIPTITEM_CODEONLY) ? to_disp(item->script_obj) : item->disp; + else + this_obj = lookup_global_host(ctx); + } + + IDispatch_AddRef(this_obj); + return stack_push(ctx, jsval_disp(this_obj)); } static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigned flags) @@ -1239,16 +1654,21 @@ static HRESULT interp_identifier_ref(script_ctx_t *ctx, BSTR identifier, unsigne return hres; if(exprval.type == EXPRVAL_INVALID && (flags & fdexNameEnsure)) { + jsdisp_t *script_obj = ctx->global; DISPID id; - hres = jsdisp_get_id(ctx->global, identifier, fdexNameEnsure, &id); + if(ctx->call_ctx->bytecode->named_item) + script_obj = ctx->call_ctx->bytecode->named_item->script_obj; + + hres = jsdisp_get_id(script_obj, identifier, fdexNameEnsure, &id); if(FAILED(hres)) return hres; - exprval_set_disp_ref(&exprval, to_disp(ctx->global), id); + exprval_set_disp_ref(&exprval, to_disp(script_obj), id); } - if(exprval.type == EXPRVAL_JSVAL || exprval.type == EXPRVAL_INVALID) { + if(exprval.type == EXPRVAL_INVALID || + (exprval.type == EXPRVAL_JSVAL && ctx->version < SCRIPTLANGUAGEVERSION_ES5)) { WARN("invalid ref\n"); exprval_release(&exprval); exprval_set_exception(&exprval, JS_E_OBJECT_EXPECTED); @@ -1268,7 +1688,7 @@ static HRESULT identifier_value(script_ctx_t *ctx, BSTR identifier) return hres; if(exprval.type == EXPRVAL_INVALID) - return throw_type_error(ctx, exprval.u.hres, identifier); + return throw_error(ctx, exprval.u.hres, identifier); hres = exprval_to_value(ctx, &exprval, &v); if(FAILED(hres)) @@ -1284,7 +1704,7 @@ static HRESULT interp_local_ref(script_ctx_t *ctx) call_frame_t *frame = ctx->call_ctx; exprval_t ref; - TRACE("%d\n", arg); + TRACE("%s\n", debugstr_w(local_name(frame, arg))); if(!frame->base_scope || !frame->base_scope->frame) return interp_identifier_ref(ctx, local_name(frame, arg), flags); @@ -1301,15 +1721,16 @@ static HRESULT interp_local(script_ctx_t *ctx) jsval_t copy; HRESULT hres; - TRACE("%d: %s\n", arg, debugstr_w(local_name(frame, arg))); - - if(!frame->base_scope || !frame->base_scope->frame) + if(!frame->base_scope || !frame->base_scope->frame) { + TRACE("%s\n", debugstr_w(local_name(frame, arg))); return identifier_value(ctx, local_name(frame, arg)); + } hres = jsval_copy(ctx->stack[local_off(frame, arg)], ©); if(FAILED(hres)) return hres; + TRACE("%s: %s\n", debugstr_w(local_name(frame, arg)), debugstr_jsval(copy)); return stack_push(ctx, copy); } @@ -1428,7 +1849,7 @@ static HRESULT interp_carray_set(script_ctx_t *ctx) array = stack_top(ctx); assert(is_object_instance(array)); - hres = jsdisp_propput_idx(iface_to_jsdisp(get_object(array)), index, value); + hres = jsdisp_propput_idx(to_jsdisp(get_object(array)), index, value); jsval_release(value); return hres; } @@ -1475,7 +1896,7 @@ static HRESULT interp_obj_prop(script_ctx_t *ctx) jsdisp_t *func; assert(is_object_instance(val)); - func = iface_to_jsdisp(get_object(val)); + func = to_jsdisp(get_object(val)); desc.mask = desc.flags; if(type == PROPERTY_DEFINITION_GETTER) { @@ -1487,7 +1908,6 @@ static HRESULT interp_obj_prop(script_ctx_t *ctx) } hres = jsdisp_define_property(obj, name, &desc); - jsdisp_release(func); } jsval_release(val); @@ -1603,12 +2023,10 @@ static HRESULT interp_instanceof(script_ctx_t *ctx) BOOL ret = FALSE; HRESULT hres; - static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0}; - v = stack_pop(ctx); - if(!is_object_instance(v) || !get_object(v)) { + if(!is_object_instance(v)) { jsval_release(v); - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + return JS_E_FUNCTION_EXPECTED; } obj = iface_to_jsdisp(get_object(v)); @@ -1618,10 +2036,10 @@ static HRESULT interp_instanceof(script_ctx_t *ctx) return E_FAIL; } - if(is_class(obj, JSCLASS_FUNCTION)) { - hres = jsdisp_propget_name(obj, prototypeW, &prot); + if(obj->is_constructor) { + hres = jsdisp_propget_name(obj, L"prototype", &prot); }else { - hres = throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + hres = JS_E_FUNCTION_EXPECTED; } jsdisp_release(obj); if(FAILED(hres)) @@ -1629,17 +2047,16 @@ static HRESULT interp_instanceof(script_ctx_t *ctx) v = stack_pop(ctx); - if(is_object_instance(prot)) { + if(is_null_disp(v)) + hres = JS_E_OBJECT_EXPECTED; + else if(is_object_instance(prot)) { if(is_object_instance(v)) - tmp = iface_to_jsdisp(get_object(v)); + tmp = to_jsdisp(get_object(v)); for(iter = tmp; !ret && iter; iter = iter->prototype) { hres = disp_cmp(get_object(prot), to_disp(iter), &ret); if(FAILED(hres)) break; } - - if(tmp) - jsdisp_release(tmp); }else { FIXME("prototype is not an object\n"); hres = E_FAIL; @@ -1666,9 +2083,9 @@ static HRESULT interp_in(script_ctx_t *ctx) TRACE("\n"); obj = stack_pop(ctx); - if(!is_object_instance(obj) || !get_object(obj)) { + if(!is_object_instance(obj)) { jsval_release(obj); - return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); + return JS_E_OBJECT_EXPECTED; } v = stack_pop(ctx); @@ -1693,21 +2110,27 @@ static HRESULT interp_in(script_ctx_t *ctx) } /* ECMA-262 3rd Edition 11.6.1 */ -static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t *ret) +static HRESULT interp_add(script_ctx_t *ctx) { - jsval_t r, l; + jsval_t l, r, lval, rval, ret; HRESULT hres; + rval = stack_pop(ctx); + lval = stack_pop(ctx); + + TRACE("%s + %s\n", debugstr_jsval(lval), debugstr_jsval(rval)); + hres = to_primitive(ctx, lval, &l, NO_HINT); + if(SUCCEEDED(hres)) { + hres = to_primitive(ctx, rval, &r, NO_HINT); + if(FAILED(hres)) + jsval_release(l); + } + jsval_release(lval); + jsval_release(rval); if(FAILED(hres)) return hres; - hres = to_primitive(ctx, rval, &r, NO_HINT); - if(FAILED(hres)) { - jsval_release(l); - return hres; - } - if(is_string(l) || is_string(r)) { jsstr_t *lstr, *rstr = NULL; @@ -1720,7 +2143,7 @@ static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t * ret_str = jsstr_concat(lstr, rstr); if(ret_str) - *ret = jsval_string(ret_str); + ret = jsval_string(ret_str); else hres = E_OUTOFMEMORY; } @@ -1735,29 +2158,12 @@ static HRESULT add_eval(script_ctx_t *ctx, jsval_t lval, jsval_t rval, jsval_t * if(SUCCEEDED(hres)) { hres = to_number(ctx, r, &nr); if(SUCCEEDED(hres)) - *ret = jsval_number(nl+nr); + ret = jsval_number(nl+nr); } } jsval_release(r); jsval_release(l); - return hres; -} - -/* ECMA-262 3rd Edition 11.6.1 */ -static HRESULT interp_add(script_ctx_t *ctx) -{ - jsval_t l, r, ret; - HRESULT hres; - - r = stack_pop(ctx); - l = stack_pop(ctx); - - TRACE("%s + %s\n", debugstr_jsval(l), debugstr_jsval(r)); - - hres = add_eval(ctx, l, r, &ret); - jsval_release(l); - jsval_release(r); if(FAILED(hres)) return hres; @@ -1928,30 +2334,29 @@ static HRESULT typeof_string(jsval_t v, const WCHAR **ret) { switch(jsval_type(v)) { case JSV_UNDEFINED: - *ret = undefinedW; + *ret = L"undefined"; break; case JSV_NULL: - *ret = objectW; + *ret = L"object"; break; case JSV_OBJECT: { jsdisp_t *dispex; - if(get_object(v) && (dispex = iface_to_jsdisp(get_object(v)))) { - *ret = is_class(dispex, JSCLASS_FUNCTION) ? functionW : objectW; - jsdisp_release(dispex); + if((dispex = to_jsdisp(get_object(v)))) { + *ret = is_class(dispex, JSCLASS_FUNCTION) ? L"function" : L"object"; }else { - *ret = objectW; + *ret = L"object"; } break; } case JSV_STRING: - *ret = stringW; + *ret = L"string"; break; case JSV_NUMBER: - *ret = numberW; + *ret = L"number"; break; case JSV_BOOL: - *ret = booleanW; + *ret = L"boolean"; break; case JSV_VARIANT: FIXME("unhandled variant %s\n", debugstr_variant(get_variant(v))); @@ -1977,7 +2382,7 @@ static HRESULT interp_typeofid(script_ctx_t *ctx) hres = exprval_propget(ctx, &ref, &v); exprval_release(&ref); if(FAILED(hres)) - return stack_push_string(ctx, unknownW); + return stack_push_string(ctx, L"unknown"); hres = typeof_string(v, &ret); jsval_release(v); @@ -2079,7 +2484,7 @@ static HRESULT interp_postinc(script_ctx_t *ctx) TRACE("%d\n", arg); if(!stack_pop_exprval(ctx, &ref)) - return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); + return JS_E_OBJECT_EXPECTED; hres = exprval_propget(ctx, &ref, &v); if(SUCCEEDED(hres)) { @@ -2110,7 +2515,7 @@ static HRESULT interp_preinc(script_ctx_t *ctx) TRACE("%d\n", arg); if(!stack_pop_exprval(ctx, &ref)) - return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); + return JS_E_OBJECT_EXPECTED; hres = exprval_propget(ctx, &ref, &v); if(SUCCEEDED(hres)) { @@ -2136,12 +2541,6 @@ static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval))) return jsval_strict_equal(lval, rval, ret); - /* FIXME: NULL disps should be handled in more general way */ - if(is_object_instance(lval) && !get_object(lval)) - return equal_values(ctx, jsval_null(), rval, ret); - if(is_object_instance(rval) && !get_object(rval)) - return equal_values(ctx, lval, jsval_null(), ret); - if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) { *ret = TRUE; return S_OK; @@ -2453,7 +2852,7 @@ static HRESULT interp_neg(script_ctx_t *ctx) /* ECMA-262 3rd Edition 11.7.1 */ static HRESULT interp_lshift(script_ctx_t *ctx) { - DWORD r; + UINT32 r; INT l; HRESULT hres; @@ -2471,7 +2870,7 @@ static HRESULT interp_lshift(script_ctx_t *ctx) /* ECMA-262 3rd Edition 11.7.2 */ static HRESULT interp_rshift(script_ctx_t *ctx) { - DWORD r; + UINT32 r; INT l; HRESULT hres; @@ -2489,7 +2888,7 @@ static HRESULT interp_rshift(script_ctx_t *ctx) /* ECMA-262 3rd Edition 11.7.3 */ static HRESULT interp_rshift2(script_ctx_t *ctx) { - DWORD r, l; + UINT32 r, l; HRESULT hres; hres = stack_pop_uint(ctx, &r); @@ -2503,6 +2902,25 @@ static HRESULT interp_rshift2(script_ctx_t *ctx) return stack_push(ctx, jsval_number(l >> (r&0x1f))); } +/* ECMA-262 3rd Edition 9.8 */ +static HRESULT interp_to_string(script_ctx_t *ctx) +{ + jsstr_t *str; + jsval_t v; + HRESULT hres; + + v = stack_pop(ctx); + TRACE("%s\n", debugstr_jsval(v)); + hres = to_string(ctx, v, &str); + jsval_release(v); + if(FAILED(hres)) { + WARN("failed %08lx\n", hres); + return hres; + } + + return stack_push(ctx, jsval_string(str)); +} + /* ECMA-262 3rd Edition 11.13.1 */ static HRESULT interp_assign(script_ctx_t *ctx) { @@ -2516,7 +2934,7 @@ static HRESULT interp_assign(script_ctx_t *ctx) if(!stack_pop_exprval(ctx, &ref)) { jsval_release(v); - return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL); + return JS_E_ILLEGAL_ASSIGN; } hres = exprval_propput(ctx, &ref, v); @@ -2529,6 +2947,41 @@ static HRESULT interp_assign(script_ctx_t *ctx) return stack_push(ctx, v); } +/* ECMA-262 3rd Edition 11.13.1 */ +static HRESULT interp_set_member(script_ctx_t *ctx) +{ + jsval_t objv, namev, value; + const WCHAR *name; + IDispatch *obj; + HRESULT hres; + + value = stack_pop(ctx); + namev = stack_pop(ctx); + assert(is_string(namev)); + objv = stack_pop(ctx); + + TRACE("%s.%s = %s\n", debugstr_jsval(objv), debugstr_jsval(namev), debugstr_jsval(value)); + + hres = to_object(ctx, objv, &obj); + jsval_release(objv); + if(SUCCEEDED(hres) && !(name = jsstr_flatten(get_string(namev)))) { + IDispatch_Release(obj); + hres = E_OUTOFMEMORY; + } + if(SUCCEEDED(hres)) { + hres = disp_propput_name(ctx, obj, name, value); + IDispatch_Release(obj); + jsstr_release(get_string(namev)); + } + if(FAILED(hres)) { + WARN("failed %08lx\n", hres); + jsval_release(value); + return hres; + } + + return stack_push(ctx, value); +} + /* JScript extension */ static HRESULT interp_assign_call(script_ctx_t *ctx) { @@ -2540,7 +2993,7 @@ static HRESULT interp_assign_call(script_ctx_t *ctx) TRACE("%u\n", argc); if(!stack_topn_exprval(ctx, argc+1, &ref)) - return throw_reference_error(ctx, JS_E_ILLEGAL_ASSIGN, NULL); + return JS_E_ILLEGAL_ASSIGN; hres = exprval_call(ctx, &ref, DISPATCH_PROPERTYPUT, argc+1, stack_args(ctx, argc+1), NULL); if(FAILED(hres)) @@ -2666,14 +3119,14 @@ static void pop_call_frame(script_ctx_t *ctx) assert(frame->scope == frame->base_scope); /* If current scope will be kept alive, we need to transfer local variables to its variable object. */ - if(frame->scope && frame->scope->ref > 1) { + if(frame->scope && frame->scope->dispex.ref > 1) { HRESULT hres = detach_variable_object(ctx, frame, TRUE); if(FAILED(hres)) - ERR("Failed to detach variable object: %08x\n", hres); + ERR("Failed to detach variable object: %08lx\n", hres); } if(frame->arguments_obj) - detach_arguments_object(frame->arguments_obj); + detach_arguments_object(frame); if(frame->scope) scope_release(frame->scope); @@ -2691,19 +3144,19 @@ static void pop_call_frame(script_ctx_t *ctx) IDispatch_Release(frame->this_obj); jsval_release(frame->ret); release_bytecode(frame->bytecode); - heap_free(frame); + free(frame); } static void print_backtrace(script_ctx_t *ctx) { - unsigned depth = 0, i; + unsigned depth = 0, i, line, char_pos; call_frame_t *frame; for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { WARN("%u\t", depth); depth++; - if(frame->this_obj && frame->this_obj != to_disp(ctx->global) && frame->this_obj != ctx->host_global) + if(frame->this_obj) WARN("%p->", frame->this_obj); WARN("%s(", frame->function->name ? debugstr_w(frame->function->name) : "[unnamed]"); if(frame->base_scope && frame->base_scope->frame) { @@ -2717,7 +3170,8 @@ static void print_backtrace(script_ctx_t *ctx) }else { WARN("[detached frame]"); } - WARN(")\n"); + line = get_location_line(frame->bytecode, frame->bytecode->instrs[frame->ip].loc, &char_pos); + WARN(") context %s line %u char %u\n", wine_dbgstr_longlong(frame->bytecode->source_context), line, char_pos); if(!(frame->flags & EXEC_RETURN_TO_INTERP)) { WARN("%u\t[native code]\n", depth); @@ -2729,6 +3183,7 @@ static void print_backtrace(script_ctx_t *ctx) static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) { except_frame_t *except_frame; + jsexcept_t *ei = ctx->ei; call_frame_t *frame; jsval_t except_val; unsigned catch_off; @@ -2738,13 +3193,11 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) jsdisp_t *error_obj; jsval_t msg; - static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0}; - - WARN("Exception %08x %s", exception_hres, debugstr_jsval(ctx->ei.val)); - if(jsval_type(ctx->ei.val) == JSV_OBJECT) { - error_obj = to_jsdisp(get_object(ctx->ei.val)); + WARN("Exception %08lx %s", exception_hres, debugstr_jsval(ei->valid_value ? ei->value : jsval_undefined())); + if(ei->valid_value && jsval_type(ei->value) == JSV_OBJECT) { + error_obj = to_jsdisp(get_object(ei->value)); if(error_obj) { - hres = jsdisp_propget_name(error_obj, messageW, &msg); + hres = jsdisp_propget_name(error_obj, L"message", &msg); if(SUCCEEDED(hres)) { WARN(" (message %s)", debugstr_jsval(msg)); jsval_release(msg); @@ -2756,7 +3209,12 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) print_backtrace(ctx); } - for(frame = ctx->call_ctx; !frame->except_frame; frame = ctx->call_ctx) { + frame = ctx->call_ctx; + if(exception_hres != DISP_E_EXCEPTION) + throw_error(ctx, exception_hres, NULL); + set_error_location(ei, frame->bytecode, frame->bytecode->instrs[frame->ip].loc, IDS_RUNTIME_ERROR, NULL); + + while(!frame->except_frame) { DWORD flags; while(frame->scope != frame->base_scope) @@ -2767,7 +3225,8 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) flags = frame->flags; pop_call_frame(ctx); if(!(flags & EXEC_RETURN_TO_INTERP)) - return exception_hres; + return DISP_E_EXCEPTION; + frame = ctx->call_ctx; } except_frame = frame->except_frame; @@ -2780,18 +3239,24 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) scope_pop(&frame->scope); frame->ip = catch_off ? catch_off : except_frame->finally_off; - if(catch_off) assert(frame->bytecode->instrs[frame->ip].op == OP_enter_catch); + assert(!catch_off || frame->bytecode->instrs[frame->ip].op == OP_enter_catch); - except_val = ctx->ei.val; - ctx->ei.val = jsval_undefined(); - clear_ei(ctx); + if(ei->valid_value) { + except_val = ctx->ei->value; + ei->valid_value = FALSE; + }else { + jsdisp_t *err; + if(!(err = create_builtin_error(ctx))) + return E_OUTOFMEMORY; + except_val = jsval_obj(err); + } /* keep current except_frame if we're entering catch block with finally block associated */ if(catch_off && except_frame->finally_off) { except_frame->catch_off = 0; }else { frame->except_frame = except_frame->next; - heap_free(except_frame); + free(except_frame); } hres = stack_push(ctx, except_val); @@ -2866,10 +3331,10 @@ static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdis disp = get_object(v); hres = IDispatch_QueryInterface(disp, &IID_IBindEventHandler, (void**)&target); if(SUCCEEDED(hres)) { - hres = IBindEventHandler_BindHandler(target, func->name, (IDispatch*)&func_obj->IDispatchEx_iface); + hres = IBindEventHandler_BindHandler(target, func->name, to_disp(func_obj)); IBindEventHandler_Release(target); if(FAILED(hres)) - WARN("BindEvent failed: %08x\n", hres); + WARN("BindEvent failed: %08lx\n", hres); }else { FIXME("No IBindEventHandler, not yet supported binding\n"); } @@ -2926,14 +3391,16 @@ static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t frame->pop_variables = i; - hres = scope_push(scope_chain, variable_object, to_disp(variable_object), &scope); + hres = scope_push(ctx, scope_chain, to_disp(variable_object), &scope); if(FAILED(hres)) { stack_popn(ctx, ctx->stack_top - orig_stack); return hres; } for(i = 0; i < frame->function->func_cnt; i++) { - if(frame->function->funcs[i].name && !frame->function->funcs[i].event_target) { + if(frame->function->funcs[i].local_ref != INVALID_LOCAL_REF + && !frame->function->funcs[i].scope_index) + { jsdisp_t *func_obj; unsigned off; @@ -2956,18 +3423,43 @@ static HRESULT setup_scope(script_ctx_t *ctx, call_frame_t *frame, scope_chain_t } HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, function_code_t *function, scope_chain_t *scope, - IDispatch *this_obj, jsdisp_t *function_instance, jsdisp_t *variable_obj, unsigned argc, jsval_t *argv, jsval_t *r) + IDispatch *this_obj, jsdisp_t *function_instance, unsigned argc, jsval_t *argv, jsval_t *r) { + jsdisp_t *variable_obj; call_frame_t *frame; unsigned i; HRESULT hres; + if(!ctx->stack) { + ctx->stack = malloc(stack_size * sizeof(*ctx->stack)); + if(!ctx->stack) + return E_OUTOFMEMORY; + } + + if(bytecode->named_item) { + if(!bytecode->named_item->script_obj) { + hres = create_named_item_script_obj(ctx, bytecode->named_item); + if(FAILED(hres)) return hres; + } + } + + if(!ctx->ei->enter_notified) { + ctx->ei->enter_notified = TRUE; + IActiveScriptSite_OnEnterScript(ctx->site); + } + for(i = 0; i < function->func_cnt; i++) { jsdisp_t *func_obj; if(!function->funcs[i].event_target) continue; + if (function->funcs[i].scope_index) + { + /* TODO: Add tests and handle in interp_push_scope(). */ + FIXME("Event target with scope index are not properly handled.\n"); + } + hres = create_source_function(ctx, bytecode, function->funcs+i, scope, &func_obj); if(FAILED(hres)) return hres; @@ -2978,49 +3470,72 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi return hres; } + if((flags & EXEC_EVAL) && scope) { + variable_obj = jsdisp_addref(ctx->call_ctx->variable_obj); + }else if(!(flags & (EXEC_GLOBAL | EXEC_EVAL))) { + hres = create_dispex(ctx, NULL, NULL, &variable_obj); + if(FAILED(hres)) return hres; + }else if(bytecode->named_item) { + variable_obj = jsdisp_addref(bytecode->named_item->script_obj); + }else { + variable_obj = jsdisp_addref(ctx->global); + } + if(flags & (EXEC_GLOBAL | EXEC_EVAL)) { + named_item_t *item = bytecode->named_item; + DISPID id; + for(i=0; i < function->var_cnt; i++) { TRACE("[%d] %s %d\n", i, debugstr_w(function->variables[i].name), function->variables[i].func_id); if(function->variables[i].func_id != -1) { jsdisp_t *func_obj; + if (function->funcs[function->variables[i].func_id].scope_index && flags & EXEC_EVAL) + { + /* TODO: Add tests and handle in interp_push_scope(). */ + FIXME("Functions with scope index inside eval() are not properly handled.\n"); + } + hres = create_source_function(ctx, bytecode, function->funcs+function->variables[i].func_id, scope, &func_obj); if(FAILED(hres)) - return hres; + goto fail; hres = jsdisp_propput_name(variable_obj, function->variables[i].name, jsval_obj(func_obj)); jsdisp_release(func_obj); - }else if(!(flags & EXEC_GLOBAL) || !lookup_global_members(ctx, function->variables[i].name, NULL)) { - DISPID id = 0; - - hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id); - if(FAILED(hres)) - return hres; + continue; } + + if(item && !(item->flags & SCRIPTITEM_CODEONLY) + && SUCCEEDED(disp_get_id(ctx, item->disp, function->variables[i].name, function->variables[i].name, 0, &id))) + continue; + + if(!item && (flags & EXEC_GLOBAL) && lookup_global_members(ctx, function->variables[i].name, NULL)) + continue; + + hres = jsdisp_get_id(variable_obj, function->variables[i].name, fdexNameEnsure, &id); + if(FAILED(hres)) + goto fail; } } - /* ECMA-262 3rd Edition 11.2.3.7 */ if(this_obj) { - jsdisp_t *jsthis; + jsdisp_t *jsthis = to_jsdisp(this_obj); - jsthis = iface_to_jsdisp(this_obj); - if(jsthis) { - if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE) - this_obj = NULL; - jsdisp_release(jsthis); - } + if(jsthis && jsthis->builtin_info->class == JSCLASS_GLOBAL) + this_obj = NULL; } - if(ctx->call_ctx && (flags & EXEC_EVAL)) { + if(scope && (flags & EXEC_EVAL)) { hres = detach_variable_object(ctx, ctx->call_ctx, FALSE); if(FAILED(hres)) - return hres; + goto fail; } - frame = heap_alloc_zero(sizeof(*frame)); - if(!frame) - return E_OUTOFMEMORY; + frame = calloc(1, sizeof(*frame)); + if(!frame) { + hres = E_OUTOFMEMORY; + goto fail; + } frame->function = function; frame->ret = jsval_undefined(); @@ -3031,8 +3546,8 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi hres = setup_scope(ctx, frame, scope, variable_obj, argc, argv); if(FAILED(hres)) { release_bytecode(frame->bytecode); - heap_free(frame); - return hres; + free(frame); + goto fail; } }else if(scope) { frame->base_scope = frame->scope = scope_addref(scope); @@ -3040,19 +3555,16 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi frame->ip = function->instr_off; frame->stack_base = ctx->stack_top; - if(this_obj) + if(this_obj) { frame->this_obj = this_obj; - else if(ctx->host_global) - frame->this_obj = ctx->host_global; - else - frame->this_obj = to_disp(ctx->global); - IDispatch_AddRef(frame->this_obj); + IDispatch_AddRef(frame->this_obj); + } if(function_instance) frame->function_instance = jsdisp_addref(function_instance); frame->flags = flags; - frame->variable_obj = jsdisp_addref(variable_obj); + frame->variable_obj = variable_obj; frame->prev_frame = ctx->call_ctx; ctx->call_ctx = frame; @@ -3068,4 +3580,8 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi } return enter_bytecode(ctx, r); + +fail: + jsdisp_release(variable_obj); + return hres; } diff --git a/dll/win32/jscript/engine.h b/dll/win32/jscript/engine.h index 0920f6f1d5f..1aecf59036c 100644 --- a/dll/win32/jscript/engine.h +++ b/dll/win32/jscript/engine.h @@ -27,6 +27,7 @@ X(bool, 1, ARG_INT, 0) \ X(bneg, 1, 0,0) \ X(call, 1, ARG_UINT, ARG_UINT) \ + X(call_eval, 1, ARG_UINT, ARG_UINT) \ X(call_member,1, ARG_UINT, ARG_UINT) \ X(carray, 1, ARG_UINT, 0) \ X(carray_set, 1, ARG_UINT, 0) \ @@ -77,7 +78,8 @@ X(preinc, 1, ARG_INT, 0) \ X(push_acc, 1, 0,0) \ X(push_except,1, ARG_ADDR, ARG_UINT) \ - X(push_scope, 1, 0,0) \ + X(push_block_scope, 1, ARG_UINT, 0) \ + X(push_with_scope, 1, 0,0) \ X(regexp, 1, ARG_STR, ARG_UINT) \ X(rshift, 1, 0,0) \ X(rshift2, 1, 0,0) \ @@ -92,8 +94,10 @@ X(typeofident,1, 0,0) \ X(refval, 1, 0,0) \ X(ret, 0, ARG_UINT, 0) \ + X(set_member, 1, 0,0) \ X(setret, 1, 0,0) \ X(sub, 1, 0,0) \ + X(to_string, 1, 0,0) \ X(undefined, 1, 0,0) \ X(void, 1, 0,0) \ X(xor, 1, 0,0) @@ -105,6 +109,8 @@ OP_LIST OP_LAST } jsop_t; +typedef struct _bytecode_t bytecode_t; + typedef union { BSTR bstr; LONG lng; @@ -125,6 +131,7 @@ typedef enum { typedef struct { jsop_t op; + unsigned loc; union { instr_arg_t arg[2]; double dbl; @@ -142,6 +149,13 @@ typedef struct { int ref; } local_ref_t; +#define INVALID_LOCAL_REF 0x7fffffff + +typedef struct { + unsigned locals_cnt; + local_ref_t *locals; +} local_ref_scopes_t; + typedef struct _function_code_t { BSTR name; int local_ref; @@ -163,21 +177,30 @@ typedef struct _function_code_t { unsigned param_cnt; BSTR *params; - unsigned locals_cnt; - local_ref_t *locals; + local_ref_scopes_t *local_scopes; + unsigned local_scope_count; + + unsigned int scope_index; /* index of scope in the parent function where the function is defined */ + + bytecode_t *bytecode; } function_code_t; -local_ref_t *lookup_local(const function_code_t*,const WCHAR*) DECLSPEC_HIDDEN; +IDispatch *lookup_global_host(script_ctx_t*); +local_ref_t *lookup_local(const function_code_t*,const WCHAR*,unsigned int); -typedef struct _bytecode_t { +struct _bytecode_t { LONG ref; + BOOL is_persistent; instr_t *instrs; heap_pool_t heap; function_code_t global_code; + named_item_t *named_item; WCHAR *source; + UINT64 source_context; + unsigned start_line; BSTR *bstr_pool; unsigned bstr_pool_size; @@ -187,11 +210,13 @@ typedef struct _bytecode_t { unsigned str_pool_size; unsigned str_cnt; - struct _bytecode_t *next; -} bytecode_t; + struct list entry; +}; -HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,BOOL,BOOL,bytecode_t**) DECLSPEC_HIDDEN; -void release_bytecode(bytecode_t*) DECLSPEC_HIDDEN; +HRESULT compile_script(script_ctx_t*,const WCHAR*,UINT64,unsigned,const WCHAR*,const WCHAR*,BOOL,BOOL,named_item_t*,bytecode_t**); +void release_bytecode(bytecode_t*); + +unsigned get_location_line(bytecode_t *code, unsigned loc, unsigned *char_pos); static inline bytecode_t *bytecode_addref(bytecode_t *code) { @@ -199,22 +224,54 @@ static inline bytecode_t *bytecode_addref(bytecode_t *code) return code; } +struct vars_buffer { + function_code_t *func_code; + unsigned argc; + jsval_t var[]; +}; + typedef struct _scope_chain_t { - LONG ref; - jsdisp_t *jsobj; + jsdisp_t dispex; IDispatch *obj; + unsigned int scope_index; + struct vars_buffer *detached_vars; struct _call_frame_t *frame; struct _scope_chain_t *next; } scope_chain_t; -void scope_release(scope_chain_t*) DECLSPEC_HIDDEN; - static inline scope_chain_t *scope_addref(scope_chain_t *scope) { - scope->ref++; + jsdisp_addref(&scope->dispex); return scope; } +static inline void scope_release(scope_chain_t *scope) +{ + jsdisp_release(&scope->dispex); +} + +struct _jsexcept_t { + HRESULT error; + + BOOL valid_value; + jsval_t value; + + jsstr_t *source; + jsstr_t *message; + jsstr_t *line; + + bytecode_t *code; + unsigned loc; + + BOOL enter_notified; + jsexcept_t *prev; +}; + +void enter_script(script_ctx_t*,jsexcept_t*); +HRESULT leave_script(script_ctx_t*,HRESULT); +void reset_ei(jsexcept_t*); +void set_error_location(jsexcept_t*,bytecode_t*,unsigned,unsigned,jsstr_t*); + typedef struct _except_frame_t except_frame_t; struct _parser_ctx_t; @@ -251,8 +308,8 @@ typedef struct _call_frame_t { #define EXEC_EVAL 0x0008 HRESULT exec_source(script_ctx_t*,DWORD,bytecode_t*,function_code_t*,scope_chain_t*,IDispatch*, - jsdisp_t*,jsdisp_t*,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; + jsdisp_t*,unsigned,jsval_t*,jsval_t*); -HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT setup_arguments_object(script_ctx_t*,call_frame_t*) DECLSPEC_HIDDEN; -void detach_arguments_object(jsdisp_t*) DECLSPEC_HIDDEN; +HRESULT create_source_function(script_ctx_t*,bytecode_t*,function_code_t*,scope_chain_t*,jsdisp_t**); +HRESULT setup_arguments_object(script_ctx_t*,call_frame_t*); +void detach_arguments_object(call_frame_t*); diff --git a/dll/win32/jscript/enumerator.c b/dll/win32/jscript/enumerator.c index 5f5b135cb50..1f57f6b5173 100644 --- a/dll/win32/jscript/enumerator.c +++ b/dll/win32/jscript/enumerator.c @@ -33,27 +33,18 @@ typedef struct { BOOL atend; } EnumeratorInstance; -static const WCHAR atEndW[] = {'a','t','E','n','d',0}; -static const WCHAR itemW[] = {'i','t','e','m',0}; -static const WCHAR moveFirstW[] = {'m','o','v','e','F','i','r','s','t',0}; -static const WCHAR moveNextW[] = {'m','o','v','e','N','e','x','t',0}; - static inline EnumeratorInstance *enumerator_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, EnumeratorInstance, dispex); } -static inline EnumeratorInstance *enumerator_from_vdisp(vdisp_t *vdisp) +static inline EnumeratorInstance *enumerator_this(jsval_t vthis) { - return enumerator_from_jsdisp(vdisp->u.jsdisp); + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_ENUMERATOR)) ? enumerator_from_jsdisp(jsdisp) : NULL; } -static inline EnumeratorInstance *enumerator_this(vdisp_t *jsthis) -{ - return is_vclass(jsthis, JSCLASS_ENUMERATOR) ? enumerator_from_vdisp(jsthis) : NULL; -} - -static inline HRESULT enumvar_get_next_item(EnumeratorInstance *This) +static inline HRESULT enumvar_get_next_item(EnumeratorInstance *This, script_ctx_t *ctx) { HRESULT hres; VARIANT nextitem; @@ -69,7 +60,7 @@ static inline HRESULT enumvar_get_next_item(EnumeratorInstance *This) hres = IEnumVARIANT_Next(This->enumvar, 1, &nextitem, NULL); if (hres == S_OK) { - hres = variant_to_jsval(&nextitem, &This->item); + hres = variant_to_jsval(ctx, &nextitem, &This->item); VariantClear(&nextitem); if (FAILED(hres)) { @@ -93,17 +84,23 @@ static void Enumerator_destructor(jsdisp_t *dispex) TRACE("\n"); + if(This->enumvar) + IEnumVARIANT_Release(This->enumvar); jsval_release(This->item); - heap_free(dispex); } -static HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Enumerator_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + return gc_process_linked_val(gc_ctx, op, dispex, &enumerator_from_jsdisp(dispex)->item); +} + +static HRESULT Enumerator_atEnd(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { EnumeratorInstance *This; - if (!(This = enumerator_this(jsthis))) - return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL); + if (!(This = enumerator_this(vthis))) + return JS_E_ENUMERATOR_EXPECTED; TRACE("%d\n", This->atend); @@ -112,20 +109,20 @@ static HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, return S_OK; } -static HRESULT Enumerator_item(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Enumerator_item(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { EnumeratorInstance *This; TRACE("\n"); - if (!(This = enumerator_this(jsthis))) - return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL); + if (!(This = enumerator_this(vthis))) + return JS_E_ENUMERATOR_EXPECTED; return r ? jsval_copy(This->item, r) : S_OK; } -static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { EnumeratorInstance *This; @@ -133,8 +130,8 @@ static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla TRACE("\n"); - if (!(This = enumerator_this(jsthis))) - return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL); + if (!(This = enumerator_this(vthis))) + return JS_E_ENUMERATOR_EXPECTED; if (This->enumvar) { @@ -143,7 +140,7 @@ static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla return hres; This->atend = FALSE; - hres = enumvar_get_next_item(This); + hres = enumvar_get_next_item(This, ctx); if(FAILED(hres)) return hres; } @@ -153,7 +150,7 @@ static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla return S_OK; } -static HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Enumerator_moveNext(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { EnumeratorInstance *This; @@ -161,12 +158,12 @@ static HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag TRACE("\n"); - if (!(This = enumerator_this(jsthis))) - return throw_type_error(ctx, JS_E_ENUMERATOR_EXPECTED, NULL); + if (!(This = enumerator_this(vthis))) + return JS_E_ENUMERATOR_EXPECTED; if (This->enumvar) { - hres = enumvar_get_next_item(This); + hres = enumvar_get_next_item(This, ctx); if (FAILED(hres)) return hres; } @@ -177,28 +174,22 @@ static HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag } static const builtin_prop_t Enumerator_props[] = { - {atEndW, Enumerator_atEnd, PROPF_METHOD}, - {itemW, Enumerator_item, PROPF_METHOD}, - {moveFirstW, Enumerator_moveFirst, PROPF_METHOD}, - {moveNextW, Enumerator_moveNext, PROPF_METHOD}, + {L"atEnd", Enumerator_atEnd, PROPF_METHOD}, + {L"item", Enumerator_item, PROPF_METHOD}, + {L"moveFirst", Enumerator_moveFirst, PROPF_METHOD}, + {L"moveNext", Enumerator_moveNext, PROPF_METHOD}, }; static const builtin_info_t Enumerator_info = { - JSCLASS_ENUMERATOR, - {NULL, NULL, 0}, - ARRAY_SIZE(Enumerator_props), - Enumerator_props, - NULL, - NULL + .class = JSCLASS_ENUMERATOR, + .props_cnt = ARRAY_SIZE(Enumerator_props), + .props = Enumerator_props, }; static const builtin_info_t EnumeratorInst_info = { - JSCLASS_ENUMERATOR, - {NULL, NULL, 0, NULL}, - 0, - NULL, - Enumerator_destructor, - NULL + .class = JSCLASS_ENUMERATOR, + .destructor = Enumerator_destructor, + .gc_traverse = Enumerator_gc_traverse }; static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret) @@ -206,7 +197,7 @@ static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, E EnumeratorInstance *enumerator; HRESULT hres; - enumerator = heap_alloc_zero(sizeof(EnumeratorInstance)); + enumerator = calloc(1, sizeof(EnumeratorInstance)); if(!enumerator) return E_OUTOFMEMORY; @@ -218,7 +209,7 @@ static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, E if(FAILED(hres)) { - heap_free(enumerator); + free(enumerator); return hres; } @@ -249,11 +240,11 @@ static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **re /* Try to get a IEnumVARIANT by _NewEnum */ VariantInit(&varresult); hres = IDispatch_Invoke(obj, DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL, - DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL); + DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL); if (FAILED(hres)) { WARN("Enumerator: no DISPID_NEWENUM.\n"); - return E_INVALIDARG; + return JS_E_OBJECT_NOT_COLLECTION; } if ((V_VT(&varresult) == VT_DISPATCH) || (V_VT(&varresult) == VT_UNKNOWN)) @@ -264,7 +255,7 @@ static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **re else { FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult)); - hres = E_INVALIDARG; + hres = JS_E_OBJECT_NOT_COLLECTION; } VariantClear(&varresult); if (FAILED(hres)) @@ -281,7 +272,7 @@ static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **re enumerator->enumvar = enumvar; enumerator->atend = !enumvar; - hres = enumvar_get_next_item(enumerator); + hres = enumvar_get_next_item(enumerator, ctx); if (FAILED(hres)) { jsdisp_release(&enumerator->dispex); @@ -292,7 +283,7 @@ static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **re return S_OK; } -static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *obj; @@ -303,13 +294,14 @@ static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD fl switch(flags) { case DISPATCH_CONSTRUCT: { if (argc > 1) - return throw_syntax_error(ctx, JS_E_INVALIDARG, NULL); + return JS_E_INVALIDARG; hres = create_enumerator(ctx, (argc == 1) ? &argv[0] : 0, &obj); if(FAILED(hres)) return hres; - *r = jsval_obj(obj); + if(r) *r = jsval_obj(obj); + else jsdisp_release(obj); break; } default: @@ -321,27 +313,21 @@ static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD fl } static const builtin_info_t EnumeratorConstr_info = { - JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, - 0, - NULL, - NULL, - NULL + .class = JSCLASS_FUNCTION, + .call = Function_value, }; HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) { EnumeratorInstance *enumerator; HRESULT hres; - static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0}; hres = alloc_enumerator(ctx, object_prototype, &enumerator); if(FAILED(hres)) return hres; - hres = create_builtin_constructor(ctx, EnumeratorConstr_value, - EnumeratorW, &EnumeratorConstr_info, - PROPF_CONSTR|7, &enumerator->dispex, ret); + hres = create_builtin_constructor(ctx, EnumeratorConstr_value, L"Enumerator", + &EnumeratorConstr_info, PROPF_CONSTR|7, &enumerator->dispex, ret); jsdisp_release(&enumerator->dispex); return hres; diff --git a/dll/win32/jscript/error.c b/dll/win32/jscript/error.c index fcdeddbfd90..441b116c1c7 100644 --- a/dll/win32/jscript/error.c +++ b/dll/win32/jscript/error.c @@ -22,38 +22,37 @@ #endif #include +#include +#include #include "jscript.h" +#include "engine.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(jscript); -static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0}; -static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0}; -static const WCHAR nameW[] = {'n','a','m','e',0}; -static const WCHAR numberW[] = {'n','u','m','b','e','r',0}; -static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; - /* ECMA-262 3rd Edition 15.11.4.4 */ -static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, +static HRESULT Error_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - jsdisp_t *jsthis; jsstr_t *name = NULL, *msg = NULL, *ret = NULL; + jsdisp_t *jsthis = NULL; jsval_t v; HRESULT hres; - static const WCHAR object_errorW[] = {'[','o','b','j','e','c','t',' ','E','r','r','o','r',']',0}; - TRACE("\n"); - jsthis = get_jsdisp(vthis); + if(is_object_instance(vthis)) + jsthis = to_jsdisp(get_object(vthis)); + else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) + return JS_E_OBJECT_EXPECTED; + if(!jsthis || ctx->version < 2) { if(r) { jsstr_t *str; - str = jsstr_alloc(object_errorW); + str = jsstr_alloc(L"[object Error]"); if(!str) return E_OUTOFMEMORY; *r = jsval_string(str); @@ -61,7 +60,7 @@ static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, return S_OK; } - hres = jsdisp_propget_name(jsthis, nameW, &v); + hres = jsdisp_propget_name(jsthis, L"name", &v); if(FAILED(hres)) return hres; @@ -72,7 +71,7 @@ static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, return hres; } - hres = jsdisp_propget_name(jsthis, messageW, &v); + hres = jsdisp_propget_name(jsthis, L"message", &v); if(SUCCEEDED(hres)) { if(!is_undefined(v)) { hres = to_string(ctx, v, &msg); @@ -103,7 +102,7 @@ static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, ret = msg; msg = NULL; }else { - ret = jsstr_alloc(object_errorW); + ret = jsstr_alloc(L"[object Error]"); } } @@ -123,14 +122,14 @@ static HRESULT Error_toString(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, return S_OK; } -static HRESULT Error_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT Error_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); switch(flags) { case INVOKE_FUNC: - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + return JS_E_FUNCTION_EXPECTED; default: FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; @@ -140,25 +139,19 @@ static HRESULT Error_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, } static const builtin_prop_t Error_props[] = { - {toStringW, Error_toString, PROPF_METHOD} + {L"toString", Error_toString, PROPF_METHOD} }; static const builtin_info_t Error_info = { - JSCLASS_ERROR, - {NULL, Error_value, 0}, - ARRAY_SIZE(Error_props), - Error_props, - NULL, - NULL + .class = JSCLASS_ERROR, + .call = Error_value, + .props_cnt = ARRAY_SIZE(Error_props), + .props = Error_props, }; static const builtin_info_t ErrorInst_info = { - JSCLASS_ERROR, - {NULL, Error_value, 0}, - 0, - NULL, - NULL, - NULL + .class = JSCLASS_ERROR, + .call = Error_value, }; static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype, @@ -167,7 +160,7 @@ static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype, jsdisp_t *err; HRESULT hres; - err = heap_alloc_zero(sizeof(*err)); + err = calloc(1, sizeof(*err)); if(!err) return E_OUTOFMEMORY; @@ -177,7 +170,7 @@ static HRESULT alloc_error(script_ctx_t *ctx, jsdisp_t *prototype, hres = init_dispex_from_constr(err, ctx, &ErrorInst_info, constr ? constr : ctx->error_constr); if(FAILED(hres)) { - heap_free(err); + free(err); return hres; } @@ -195,18 +188,18 @@ static HRESULT create_error(script_ctx_t *ctx, jsdisp_t *constr, if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(err, numberW, PROPF_WRITABLE | PROPF_CONFIGURABLE, + hres = jsdisp_define_data_property(err, L"number", PROPF_WRITABLE | PROPF_CONFIGURABLE, jsval_number((INT)number)); if(FAILED(hres)) { jsdisp_release(err); return hres; } - hres = jsdisp_define_data_property(err, messageW, + hres = jsdisp_define_data_property(err, L"message", PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, jsval_string(msg)); if(SUCCEEDED(hres)) - hres = jsdisp_define_data_property(err, descriptionW, PROPF_WRITABLE | PROPF_CONFIGURABLE, + hres = jsdisp_define_data_property(err, L"description", PROPF_WRITABLE | PROPF_CONFIGURABLE, jsval_string(msg)); if(FAILED(hres)) { jsdisp_release(err); @@ -269,56 +262,56 @@ static HRESULT error_constr(script_ctx_t *ctx, WORD flags, unsigned argc, jsval_ } } -static HRESULT ErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT ErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->error_constr); } -static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT EvalErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->eval_error_constr); } -static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT RangeErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->range_error_constr); } -static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT ReferenceErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->reference_error_constr); } -static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT RegExpErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->regexp_error_constr); } -static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT SyntaxErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->syntax_error_constr); } -static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT TypeErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); return error_constr(ctx, flags, argc, argv, r, ctx->type_error_constr); } -static HRESULT URIErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, +static HRESULT URIErrorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); @@ -327,16 +320,8 @@ static HRESULT URIErrorConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) { - static const WCHAR ErrorW[] = {'E','r','r','o','r',0}; - static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0}; - static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0}; - static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0}; - static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0}; - static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0}; - static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0}; - static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0}; - static const WCHAR *names[] = {ErrorW, EvalErrorW, RangeErrorW, - ReferenceErrorW, RegExpErrorW, SyntaxErrorW, TypeErrorW, URIErrorW}; + static const WCHAR *names[] = {L"Error", L"EvalError", L"RangeError", + L"ReferenceError", L"RegExpError", L"SyntaxError", L"TypeError", L"URIError"}; jsdisp_t **constr_addr[] = {&ctx->error_constr, &ctx->eval_error_constr, &ctx->range_error_constr, &ctx->reference_error_constr, &ctx->regexp_error_constr, &ctx->syntax_error_constr, &ctx->type_error_constr, @@ -361,7 +346,7 @@ HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) return E_OUTOFMEMORY; } - hres = jsdisp_define_data_property(err, nameW, PROPF_WRITABLE | PROPF_CONFIGURABLE, + hres = jsdisp_define_data_property(err, L"name", PROPF_WRITABLE | PROPF_CONFIGURABLE, jsval_string(str)); jsstr_release(str); if(SUCCEEDED(hres)) @@ -376,73 +361,178 @@ HRESULT init_error_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) return S_OK; } -static HRESULT throw_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str, jsdisp_t *constr) +static jsstr_t *format_error_message(HRESULT error, const WCHAR *arg) { - WCHAR buf[1024], *pos = NULL; - jsdisp_t *err; - jsstr_t *msg; - HRESULT hres; + size_t len, arg_len = 0; + const WCHAR *res, *pos; + WCHAR *buf, *p; + jsstr_t *r; if(!is_jscript_error(error)) - return error; + return jsstr_empty(); - buf[0] = '\0'; - LoadStringW(jscript_hinstance, HRESULT_CODE(error), buf, ARRAY_SIZE(buf)); + len = LoadStringW(jscript_hinstance, HRESULT_CODE(error), (WCHAR*)&res, 0); - if(str) pos = wcschr(buf, '|'); - if(pos) { - int len = lstrlenW(str); - memmove(pos+len, pos+1, (lstrlenW(pos+1)+1)*sizeof(WCHAR)); - memcpy(pos, str, len*sizeof(WCHAR)); + pos = wmemchr(res, '|', len); + if(pos && arg) + arg_len = lstrlenW(arg); + r = jsstr_alloc_buf(len + arg_len - (pos ? 1 : 0), &buf); + if(!r) + return jsstr_empty(); + + p = buf; + if(pos > res) { + memcpy(p, res, (pos - res) * sizeof(WCHAR)); + p += pos - res; + } + pos = pos ? pos + 1 : res; + if(arg_len) { + memcpy(p, arg, arg_len * sizeof(WCHAR)); + p += arg_len; + } + if(pos != res + len) + memcpy(p, pos, (res + len - pos) * sizeof(WCHAR)); + return r; +} + +HRESULT throw_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) +{ + jsexcept_t *ei = ctx->ei; + TRACE("%08lx\n", error); + reset_ei(ei); + ei->error = error; + if(str) + ei->message = format_error_message(error, str); + return DISP_E_EXCEPTION; +} + +void handle_dispatch_exception(script_ctx_t *ctx, EXCEPINFO *ei) +{ + TRACE("%08lx %s %s\n", ei->scode, debugstr_w(ei->bstrSource), debugstr_w(ei->bstrDescription)); + + reset_ei(ctx->ei); + if(ei->pfnDeferredFillIn) + ei->pfnDeferredFillIn(ei); + ctx->ei->error = (SUCCEEDED(ei->scode) || ei->scode == DISP_E_EXCEPTION) ? E_FAIL : ei->scode; + if(ei->bstrSource) + ctx->ei->source = jsstr_alloc_len(ei->bstrSource, SysStringLen(ei->bstrSource)); + if(ei->bstrDescription) + ctx->ei->message = jsstr_alloc_len(ei->bstrDescription, SysStringLen(ei->bstrDescription)); + SysFreeString(ei->bstrSource); + SysFreeString(ei->bstrDescription); + SysFreeString(ei->bstrHelpFile); +} + +void set_error_location(jsexcept_t *ei, bytecode_t *code, unsigned loc, unsigned source_id, jsstr_t *line) +{ + if(is_jscript_error(ei->error)) { + if(!ei->source) { + const WCHAR *res; + size_t len; + + len = LoadStringW(jscript_hinstance, source_id, (WCHAR*)&res, 0); + ei->source = jsstr_alloc_len(res, len); + } + if(!ei->message) + ei->message = format_error_message(ei->error, NULL); } - WARN("%s\n", debugstr_w(buf)); + TRACE("source %s in %s\n", debugstr_w(code->source + loc), debugstr_w(code->source)); - msg = jsstr_alloc(buf); - if(!msg) - return E_OUTOFMEMORY; - - hres = create_error(ctx, constr, error, msg, &err); - jsstr_release(msg); - if(FAILED(hres)) - return hres; - - jsval_release(ctx->ei.val); - ctx->ei.val = jsval_obj(err); - return error; + ei->code = bytecode_addref(code); + ei->loc = loc; + if(line) + ei->line = jsstr_addref(line); } -HRESULT throw_generic_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) +jsdisp_t *create_builtin_error(script_ctx_t *ctx) { - return throw_error(ctx, error, str, ctx->error_constr); -} + jsdisp_t *constr = ctx->error_constr, *r; + jsexcept_t *ei = ctx->ei; + HRESULT hres; -HRESULT throw_range_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) -{ - return throw_error(ctx, error, str, ctx->range_error_constr); -} + assert(FAILED(ei->error) && ei->error != DISP_E_EXCEPTION); -HRESULT throw_reference_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) -{ - return throw_error(ctx, error, str, ctx->reference_error_constr); -} + if(is_jscript_error(ei->error)) { + switch(ei->error) { + case JS_E_SYNTAX: + case JS_E_MISSING_SEMICOLON: + case JS_E_MISSING_LBRACKET: + case JS_E_MISSING_RBRACKET: + case JS_E_EXPECTED_IDENTIFIER: + case JS_E_EXPECTED_ASSIGN: + case JS_E_INVALID_CHAR: + case JS_E_UNTERMINATED_STRING: + case JS_E_MISPLACED_RETURN: + case JS_E_INVALID_BREAK: + case JS_E_INVALID_CONTINUE: + case JS_E_LABEL_REDEFINED: + case JS_E_LABEL_NOT_FOUND: + case JS_E_EXPECTED_CCEND: + case JS_E_DISABLED_CC: + case JS_E_EXPECTED_AT: + case JS_E_UNEXPECTED_QUANTIFIER: + constr = ctx->syntax_error_constr; + break; -HRESULT throw_regexp_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) -{ - return throw_error(ctx, error, str, ctx->regexp_error_constr); -} + case JS_E_TO_PRIMITIVE: + case JS_E_INVALIDARG: + case JS_E_OBJECT_REQUIRED: + case JS_E_INVALID_PROPERTY: + case JS_E_INVALID_ACTION: + case JS_E_MISSING_ARG: + case JS_E_OBJECT_NOT_COLLECTION: + case JS_E_FUNCTION_EXPECTED: + case JS_E_DATE_EXPECTED: + case JS_E_NUMBER_EXPECTED: + case JS_E_OBJECT_EXPECTED: + case JS_E_UNDEFINED_VARIABLE: + case JS_E_BOOLEAN_EXPECTED: + case JS_E_VBARRAY_EXPECTED: + case JS_E_INVALID_DELETE: + case JS_E_JSCRIPT_EXPECTED: + case JS_E_ENUMERATOR_EXPECTED: + case JS_E_REGEXP_EXPECTED: + case JS_E_ARRAY_EXPECTED: + case JS_E_CYCLIC_PROTO_VALUE: + case JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE: + case JS_E_OBJECT_NONEXTENSIBLE: + case JS_E_NONCONFIGURABLE_REDEFINED: + case JS_E_NONWRITABLE_MODIFIED: + case JS_E_NOT_DATAVIEW: + case JS_E_DATAVIEW_NO_ARGUMENT: + case JS_E_WRONG_THIS: + case JS_E_KEY_NOT_OBJECT: + case JS_E_ARRAYBUFFER_EXPECTED: + case JS_E_PROP_DESC_MISMATCH: + case JS_E_INVALID_WRITABLE_PROP_DESC: + constr = ctx->type_error_constr; + break; -HRESULT throw_syntax_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) -{ - return throw_error(ctx, error, str, ctx->syntax_error_constr); -} + case JS_E_SUBSCRIPT_OUT_OF_RANGE: + case JS_E_FRACTION_DIGITS_OUT_OF_RANGE: + case JS_E_PRECISION_OUT_OF_RANGE: + case JS_E_INVALID_LENGTH: + case JS_E_DATAVIEW_INVALID_ACCESS: + case JS_E_DATAVIEW_INVALID_OFFSET: + constr = ctx->range_error_constr; + break; -HRESULT throw_type_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) -{ - return throw_error(ctx, error, str, ctx->type_error_constr); -} + case JS_E_ILLEGAL_ASSIGN: + constr = ctx->reference_error_constr; + break; -HRESULT throw_uri_error(script_ctx_t *ctx, HRESULT error, const WCHAR *str) -{ - return throw_error(ctx, error, str, ctx->uri_error_constr); + case JS_E_REGEXP_SYNTAX: + constr = ctx->regexp_error_constr; + break; + + case JS_E_INVALID_URI_CODING: + case JS_E_INVALID_URI_CHAR: + constr = ctx->uri_error_constr; + break; + } + } + + hres = create_error(ctx, constr, ei->error, ei->message ? ei->message : jsstr_empty(), &r); + return SUCCEEDED(hres) ? r : NULL; } diff --git a/dll/win32/jscript/function.c b/dll/win32/jscript/function.c index 7a44f5092b8..5330bbae21f 100644 --- a/dll/win32/jscript/function.c +++ b/dll/win32/jscript/function.c @@ -35,9 +35,11 @@ typedef struct { } FunctionInstance; struct _function_vtbl_t { - HRESULT (*call)(script_ctx_t*,FunctionInstance*,IDispatch*,unsigned,unsigned,jsval_t*,jsval_t*); + HRESULT (*call)(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,unsigned,jsval_t*,jsval_t*); HRESULT (*toString)(FunctionInstance*,jsstr_t**); + function_code_t* (*get_code)(FunctionInstance*); void (*destructor)(FunctionInstance*); + HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,FunctionInstance*); }; typedef struct { @@ -56,34 +58,47 @@ typedef struct { typedef struct { FunctionInstance function; FunctionInstance *target; - IDispatch *this; + jsval_t this; unsigned argc; jsval_t args[1]; } BindFunction; +typedef struct { + FunctionInstance function; + const WCHAR *name; + UINT32 id; + UINT32 iid; + UINT32 flags; +} HostFunction; + +typedef struct { + FunctionInstance function; + IWineJSDispatchHost *host_iface; +} HostConstructor; + typedef struct { jsdisp_t jsdisp; - InterpretedFunction *function; jsval_t *buf; - call_frame_t *frame; + scope_chain_t *scope; unsigned argc; } ArgumentsInstance; -static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,IDispatch*,unsigned,jsval_t*,jsdisp_t**r); +static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,jsval_t*,jsdisp_t**r); + +static HRESULT no_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *function) +{ + return S_OK; +} static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, FunctionInstance, dispex); } -static inline FunctionInstance *function_from_vdisp(vdisp_t *vdisp) +static inline FunctionInstance *function_this(jsval_t vthis) { - return function_from_jsdisp(vdisp->u.jsdisp); -} - -static inline FunctionInstance *function_this(vdisp_t *jsthis) -{ - return is_vclass(jsthis, JSCLASS_FUNCTION) ? function_from_vdisp(jsthis) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_FUNCTION)) ? function_from_jsdisp(jsdisp) : NULL; } static inline ArgumentsInstance *arguments_from_jsdisp(jsdisp_t *jsdisp) @@ -91,16 +106,7 @@ static inline ArgumentsInstance *arguments_from_jsdisp(jsdisp_t *jsdisp) return CONTAINING_RECORD(jsdisp, ArgumentsInstance, jsdisp); } -static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0}; - -static const WCHAR lengthW[] = {'l','e','n','g','t','h',0}; -static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; -static const WCHAR applyW[] = {'a','p','p','l','y',0}; -static const WCHAR bindW[] = {'b','i','n','d',0}; -static const WCHAR callW[] = {'c','a','l','l',0}; -static const WCHAR argumentsW[] = {'a','r','g','u','m','e','n','t','s',0}; - -static HRESULT Arguments_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Arguments_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FIXME("\n"); @@ -117,76 +123,137 @@ static void Arguments_destructor(jsdisp_t *jsdisp) unsigned i; for(i = 0; i < arguments->argc; i++) jsval_release(arguments->buf[i]); - heap_free(arguments->buf); + free(arguments->buf); } - jsdisp_release(&arguments->function->function.dispex); - heap_free(arguments); + if(arguments->scope) + scope_release(arguments->scope); } -static unsigned Arguments_idx_length(jsdisp_t *jsdisp) +static HRESULT Arguments_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - return arguments->argc; + return jsdisp_index_lookup(&arguments->jsdisp, name, arguments->argc, desc); +} + +static HRESULT Arguments_next_prop(jsdisp_t *jsdisp, unsigned id, struct property_info *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + return jsdisp_next_index(&arguments->jsdisp, arguments->argc, id, desc); } static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) { if(arguments->buf) return arguments->buf + idx; - if(arguments->frame->base_scope->frame || idx >= arguments->frame->function->param_cnt) - return arguments->jsdisp.ctx->stack + arguments->frame->arguments_off + idx; - return NULL; + if(!arguments->scope->detached_vars) + return arguments->jsdisp.ctx->stack + arguments->scope->frame->arguments_off + idx; + return arguments->scope->detached_vars->var + idx; } -static HRESULT Arguments_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) +static HRESULT Arguments_prop_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - jsval_t *ref; TRACE("%p[%u]\n", arguments, idx); - if((ref = get_argument_ref(arguments, idx))) - return jsval_copy(*ref, r); - - /* FIXME: Accessing by name won't work for duplicated argument names */ - return jsdisp_propget_name(arguments->frame->base_scope->jsobj, - arguments->function->func_code->params[idx], r); + return jsval_copy(*get_argument_ref(arguments, idx), r); } -static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) +static HRESULT Arguments_prop_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - jsval_t *ref; + jsval_t copy, *ref; HRESULT hres; TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); - if((ref = get_argument_ref(arguments, idx))) { - jsval_t copy; - hres = jsval_copy(val, ©); - if(FAILED(hres)) - return hres; + hres = jsval_copy(val, ©); + if(FAILED(hres)) + return hres; - jsval_release(*ref); - *ref = copy; - return S_OK; - } - - /* FIXME: Accessing by name won't work for duplicated argument names */ - return jsdisp_propput_name(arguments->frame->base_scope->jsobj, - arguments->function->func_code->params[idx], val); + ref = get_argument_ref(arguments, idx); + jsval_release(*ref); + *ref = copy; + return S_OK; } +static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *jsdisp) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + HRESULT hres; + unsigned i; + + if(arguments->buf) { + for(i = 0; i < arguments->argc; i++) { + hres = gc_process_linked_val(gc_ctx, op, jsdisp, &arguments->buf[i]); + if(FAILED(hres)) + return hres; + } + } + + if(arguments->scope) { + hres = gc_process_linked_obj(gc_ctx, op, jsdisp, &arguments->scope->dispex, (void**)&arguments->scope); + if(FAILED(hres)) + return hres; + } + + return S_OK; +} + +static HRESULT Arguments_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsthis); + call_frame_t *frame; + HRESULT hres; + + TRACE("\n"); + + for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { + if(frame->arguments_obj == &arguments->jsdisp) { + frame = frame->prev_frame; + if(!frame || !frame->function_instance) + break; + if(!frame->arguments_obj) { + hres = setup_arguments_object(ctx, frame); + if(FAILED(hres)) + return hres; + } + *r = jsval_obj(jsdisp_addref(frame->arguments_obj)); + return S_OK; + } + } + + *r = jsval_null(); + return S_OK; +} + +static const builtin_prop_t Arguments_props[] = { + {L"caller", NULL, 0, Arguments_get_caller}, +}; + static const builtin_info_t Arguments_info = { - JSCLASS_ARGUMENTS, - {NULL, Arguments_value, 0}, - 0, NULL, - Arguments_destructor, - NULL, - Arguments_idx_length, - Arguments_idx_get, - Arguments_idx_put + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .props_cnt = ARRAY_SIZE(Arguments_props), + .props = Arguments_props, + .destructor = Arguments_destructor, + .lookup_prop = Arguments_lookup_prop, + .next_prop = Arguments_next_prop, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .gc_traverse = Arguments_gc_traverse +}; + +static const builtin_info_t Arguments_ES5_info = { + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .destructor = Arguments_destructor, + .lookup_prop = Arguments_lookup_prop, + .next_prop = Arguments_next_prop, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .gc_traverse = Arguments_gc_traverse }; HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) @@ -194,29 +261,26 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) ArgumentsInstance *args; HRESULT hres; - static const WCHAR caleeW[] = {'c','a','l','l','e','e',0}; - - args = heap_alloc_zero(sizeof(*args)); + args = calloc(1, sizeof(*args)); if(!args) return E_OUTOFMEMORY; - hres = init_dispex_from_constr(&args->jsdisp, ctx, &Arguments_info, ctx->object_constr); + hres = init_dispex_from_constr(&args->jsdisp, ctx, ctx->version < SCRIPTLANGUAGEVERSION_ES5 ? &Arguments_info : &Arguments_ES5_info, ctx->object_constr); if(FAILED(hres)) { - heap_free(args); + free(args); return hres; } - args->function = (InterpretedFunction*)function_from_jsdisp(jsdisp_addref(frame->function_instance)); args->argc = frame->argc; - args->frame = frame; + args->scope = scope_addref(frame->base_scope); - hres = jsdisp_define_data_property(&args->jsdisp, lengthW, PROPF_WRITABLE | PROPF_CONFIGURABLE, + hres = jsdisp_define_data_property(&args->jsdisp, L"length", PROPF_WRITABLE | PROPF_CONFIGURABLE, jsval_number(args->argc)); if(SUCCEEDED(hres)) - hres = jsdisp_define_data_property(&args->jsdisp, caleeW, PROPF_WRITABLE | PROPF_CONFIGURABLE, - jsval_obj(&args->function->function.dispex)); + hres = jsdisp_define_data_property(&args->jsdisp, L"callee", PROPF_WRITABLE | PROPF_CONFIGURABLE, + jsval_obj(frame->function_instance)); if(SUCCEEDED(hres)) - hres = jsdisp_propput(frame->base_scope->jsobj, argumentsW, PROPF_WRITABLE, jsval_obj(&args->jsdisp)); + hres = jsdisp_propput(as_jsdisp(frame->base_scope->obj), L"arguments", PROPF_WRITABLE, TRUE, jsval_obj(&args->jsdisp)); if(FAILED(hres)) { jsdisp_release(&args->jsdisp); return hres; @@ -226,51 +290,75 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) return S_OK; } -void detach_arguments_object(jsdisp_t *args_disp) +void detach_arguments_object(call_frame_t *frame) { - ArgumentsInstance *arguments = arguments_from_jsdisp(args_disp); - call_frame_t *frame = arguments->frame; - const BOOL on_stack = frame->base_scope->frame == frame; - HRESULT hres; + ArgumentsInstance *arguments = arguments_from_jsdisp(frame->arguments_obj); + scope_chain_t *scope = arguments->scope; + const BOOL on_stack = scope->frame == frame; + jsdisp_t *jsobj = as_jsdisp(scope->obj); /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have * their own arguments property, it's impossible to use prototype's one during name lookup */ - jsdisp_propput_name(frame->base_scope->jsobj, argumentsW, jsval_undefined()); - arguments->frame = NULL; + jsdisp_propput_name(jsobj, L"arguments", jsval_undefined()); /* Don't bother coppying arguments if call frame holds the last reference. */ - if(arguments->jsdisp.ref > 1) { - arguments->buf = heap_alloc(arguments->argc * sizeof(*arguments->buf)); + if(arguments->jsdisp.ref > 1 && !arguments->jsdisp.ctx->html_mode) { + arguments->buf = malloc(arguments->argc * sizeof(*arguments->buf)); if(arguments->buf) { + const jsval_t *args = on_stack ? arguments->jsdisp.ctx->stack + frame->arguments_off : scope->detached_vars->var; int i; for(i = 0; i < arguments->argc ; i++) { - if(on_stack || i >= frame->function->param_cnt) - hres = jsval_copy(arguments->jsdisp.ctx->stack[frame->arguments_off + i], arguments->buf+i); - else - hres = jsdisp_propget_name(frame->base_scope->jsobj, frame->function->params[i], arguments->buf+i); - if(FAILED(hres)) + if(FAILED(jsval_copy(args[i], &arguments->buf[i]))) arguments->buf[i] = jsval_undefined(); } }else { ERR("out of memory\n"); arguments->argc = 0; } + + arguments->scope = NULL; + scope_release(scope); } - jsdisp_release(frame->arguments_obj); + jsdisp_release(&arguments->jsdisp); } -HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +HRESULT Function_invoke(jsdisp_t *func_this, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; - TRACE("func %p this %p\n", func_this, jsthis); + TRACE("func %p this %s\n", func_this, debugstr_jsval(vthis)); assert(is_class(func_this, JSCLASS_FUNCTION)); function = function_from_jsdisp(func_this); - return function->vtbl->call(function->dispex.ctx, function, jsthis, flags, argc, argv, r); + if(function->dispex.ctx->state == SCRIPTSTATE_UNINITIALIZED || function->dispex.ctx->state == SCRIPTSTATE_CLOSED) { + WARN("Script engine state does not allow running code.\n"); + return E_UNEXPECTED; + } + + return function->vtbl->call(function->dispex.ctx, function, vthis, flags, argc, argv, r); +} + +static HRESULT Function_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + FunctionInstance *function = function_from_jsdisp(jsthis); + call_frame_t *frame; + + TRACE("%p\n", jsthis); + + for(frame = ctx->call_ctx; frame; frame = frame->prev_frame) { + if(frame->function_instance == &function->dispex) { + if(!frame->prev_frame || !frame->prev_frame->function_instance) + break; + *r = jsval_obj(jsdisp_addref(frame->prev_frame->function_instance)); + return S_OK; + } + } + + *r = jsval_null(); + return S_OK; } static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) @@ -281,7 +369,31 @@ static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t return S_OK; } -static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT native_function_string(const WCHAR *name, jsstr_t **ret) +{ + DWORD name_len; + jsstr_t *str; + WCHAR *ptr; + + static const WCHAR native_prefixW[] = L"\nfunction "; + static const WCHAR native_suffixW[] = L"() {\n [native code]\n}\n"; + + name_len = name ? lstrlenW(name) : 0; + str = jsstr_alloc_buf(ARRAY_SIZE(native_prefixW) + ARRAY_SIZE(native_suffixW) + name_len - 2, &ptr); + if(!str) + return E_OUTOFMEMORY; + + memcpy(ptr, native_prefixW, sizeof(native_prefixW)); + ptr += ARRAY_SIZE(native_prefixW) - 1; + memcpy(ptr, name, name_len * sizeof(WCHAR)); + ptr += name_len; + memcpy(ptr, native_suffixW, sizeof(native_suffixW)); + + *ret = str; + return S_OK; +} + +static HRESULT Function_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; @@ -290,8 +402,8 @@ static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, TRACE("\n"); - if(!(function = function_this(jsthis))) - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + if(!(function = function_this(vthis))) + return JS_E_FUNCTION_EXPECTED; hres = function->vtbl->toString(function, &str); if(FAILED(hres)) @@ -307,10 +419,10 @@ static HRESULT Function_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *argc, jsval_t **ret) { jsval_t *argv, val; - DWORD length, i; + UINT32 length, i; HRESULT hres; - hres = jsdisp_propget_name(arg_array, lengthW, &val); + hres = jsdisp_propget_name(arg_array, L"length", &val); if(FAILED(hres)) return hres; @@ -319,7 +431,7 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a if(FAILED(hres)) return hres; - argv = heap_alloc(length * sizeof(*argv)); + argv = malloc(length * sizeof(*argv)); if(!argv) return E_OUTOFMEMORY; @@ -330,7 +442,7 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a }else if(FAILED(hres)) { while(i--) jsval_release(argv[i]); - heap_free(argv); + free(argv); return hres; } } @@ -340,24 +452,32 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a return S_OK; } -static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + jsval_t this_val = jsval_undefined(); FunctionInstance *function; jsval_t *args = NULL; unsigned i, cnt = 0; - IDispatch *this_obj = NULL; HRESULT hres = S_OK; TRACE("\n"); - if(!(function = function_this(jsthis)) && (jsthis->flags & VDISP_JSDISP)) - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + if(is_null_disp(vthis)) + return JS_E_OBJECT_REQUIRED; + if(!is_object_instance(vthis) || (!(function = function_this(vthis)) && to_jsdisp(get_object(vthis)))) + return JS_E_FUNCTION_EXPECTED; if(argc) { - if(!is_undefined(argv[0]) && !is_null(argv[0])) { + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(argv[0]) && !is_null(argv[0])) { + IDispatch *this_obj; hres = to_object(ctx, argv[0], &this_obj); if(FAILED(hres)) return hres; + this_val = jsval_disp(this_obj); + }else { + hres = jsval_copy(argv[0], &this_val); + if(FAILED(hres)) + return hres; } } @@ -384,10 +504,10 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un if(SUCCEEDED(hres)) { if(function) { - hres = function->vtbl->call(ctx, function, this_obj, flags, cnt, args, r); + hres = function->vtbl->call(ctx, function, this_val, flags, cnt, args, r); }else { jsval_t res; - hres = disp_call_value(ctx, jsthis->u.disp, this_obj, DISPATCH_METHOD, cnt, args, &res); + hres = disp_call_value(ctx, get_object(vthis), this_val, DISPATCH_METHOD, cnt, args, &res); if(SUCCEEDED(hres)) { if(r) *r = res; @@ -397,67 +517,76 @@ static HRESULT Function_apply(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un } } - if(this_obj) - IDispatch_Release(this_obj); + jsval_release(this_val); for(i=0; i < cnt; i++) jsval_release(args[i]); - heap_free(args); + free(args); return hres; } -static HRESULT Function_call(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + jsval_t this_val = jsval_undefined(); FunctionInstance *function; - IDispatch *this_obj = NULL; unsigned cnt = 0; HRESULT hres; TRACE("\n"); - if(!(function = function_this(jsthis))) - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + if(is_null_disp(vthis)) + return JS_E_OBJECT_REQUIRED; + if(!(function = function_this(vthis))) + return JS_E_FUNCTION_EXPECTED; if(argc) { - if(!is_undefined(argv[0]) && !is_null(argv[0])) { + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(argv[0]) && !is_null(argv[0])) { + IDispatch *this_obj; hres = to_object(ctx, argv[0], &this_obj); if(FAILED(hres)) return hres; + this_val = jsval_disp(this_obj); + }else { + hres = jsval_copy(argv[0], &this_val); + if(FAILED(hres)) + return hres; } - cnt = argc-1; } - hres = function->vtbl->call(ctx, function, this_obj, flags, cnt, argv + 1, r); + hres = function->vtbl->call(ctx, function, this_val, flags, cnt, argv + 1, r); - if(this_obj) - IDispatch_Release(this_obj); + jsval_release(this_val); return hres; } -static HRESULT Function_bind(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT Function_bind(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + jsval_t bound_this = jsval_undefined(); FunctionInstance *function; jsdisp_t *new_function; HRESULT hres; TRACE("\n"); - if(!(function = function_this(jsthis))) - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + if(!(function = function_this(vthis))) + return JS_E_FUNCTION_EXPECTED; if(argc < 1) { - FIXME("no this argument\n"); - return E_NOTIMPL; + argc = 1; + }else if(is_null(argv[0])) { + bound_this = argv[0]; + }else if(!is_undefined(argv[0])) { + IDispatch *obj; + hres = to_object(ctx, argv[0], &obj); + if(FAILED(hres)) + return hres; + bound_this = jsval_disp(obj); } - if(!is_object_instance(argv[0]) || !get_object(argv[0])) { - FIXME("%s is not an object instance\n", debugstr_jsval(argv[0])); - return E_NOTIMPL; - } - - hres = create_bind_function(ctx, function, get_object(argv[0]), argc - 1, argv + 1, &new_function); + hres = create_bind_function(ctx, function, bound_this, argc - 1, argv + 1, &new_function); + jsval_release(bound_this); if(FAILED(hres)) return hres; @@ -468,20 +597,19 @@ static HRESULT Function_bind(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, uns return S_OK; } -HRESULT Function_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +HRESULT Function_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FunctionInstance *function; TRACE("\n"); - if(!is_vclass(jsthis, JSCLASS_FUNCTION)) { + if(!(function = function_this(vthis))) { ERR("dispex is not a function\n"); return E_FAIL; } - function = function_from_jsdisp(jsthis->u.jsdisp); - return function->vtbl->call(ctx, function, NULL, flags, argc, argv, r); + return function->vtbl->call(ctx, function, vthis, flags, argc, argv, r); } HRESULT Function_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) @@ -524,43 +652,60 @@ static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval return S_OK; } +function_code_t *Function_get_code(jsdisp_t *jsthis) +{ + FunctionInstance *function; + + assert(is_class(jsthis, JSCLASS_FUNCTION)); + function = function_from_jsdisp(jsthis); + + return function->vtbl->get_code(function); +} + static void Function_destructor(jsdisp_t *dispex) { FunctionInstance *function = function_from_jsdisp(dispex); function->vtbl->destructor(function); - heap_free(function); +} + +static HRESULT Function_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + FunctionInstance *function = function_from_jsdisp(dispex); + return function->vtbl->gc_traverse(gc_ctx, op, function); } static const builtin_prop_t Function_props[] = { - {applyW, Function_apply, PROPF_METHOD|2}, - {argumentsW, NULL, 0, Function_get_arguments}, - {bindW, Function_bind, PROPF_METHOD|PROPF_ES5|1}, - {callW, Function_call, PROPF_METHOD|1}, - {lengthW, NULL, 0, Function_get_length}, - {toStringW, Function_toString, PROPF_METHOD} + {L"apply", Function_apply, PROPF_METHOD|2}, + {L"arguments", NULL, PROPF_HTML, Function_get_arguments}, + {L"bind", Function_bind, PROPF_METHOD|PROPF_ES5|1}, + {L"call", Function_call, PROPF_METHOD|1}, + {L"caller", NULL, PROPF_HTML, Function_get_caller}, + {L"length", NULL, 0, Function_get_length}, + {L"toString", Function_toString, PROPF_METHOD} }; static const builtin_info_t Function_info = { - JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, - ARRAY_SIZE(Function_props), - Function_props, - Function_destructor, - NULL + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(Function_props), + .props = Function_props, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse }; static const builtin_prop_t FunctionInst_props[] = { - {argumentsW, NULL, 0, Function_get_arguments}, - {lengthW, NULL, 0, Function_get_length} + {L"arguments", NULL, 0, Function_get_arguments}, + {L"caller", NULL, PROPF_HTML, Function_get_caller}, + {L"length", NULL, 0, Function_get_length} }; static const builtin_info_t FunctionInst_info = { - JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, - ARRAY_SIZE(FunctionInst_props), - FunctionInst_props, - Function_destructor, - NULL + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(FunctionInst_props), + .props = FunctionInst_props, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse }; static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_info, const function_vtbl_t *vtbl, size_t size, @@ -569,7 +714,7 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_ FunctionInstance *function; HRESULT hres; - function = heap_alloc_zero(size); + function = calloc(1, size); if(!function) return E_OUTOFMEMORY; @@ -580,7 +725,7 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_ else hres = init_dispex_from_constr(&function->dispex, ctx, &FunctionInst_info, ctx->function_constr); if(FAILED(hres)) { - heap_free(function); + free(function); return hres; } @@ -592,50 +737,25 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_ return S_OK; } -static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_disp, unsigned flags, +static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { NativeFunction *function = (NativeFunction*)func; - vdisp_t vthis; - HRESULT hres; - if(this_disp) - set_disp(&vthis, this_disp); - else if(ctx->host_global) - set_disp(&vthis, ctx->host_global); - else - set_jsdisp(&vthis, ctx->global); - - hres = function->proc(ctx, &vthis, flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r); - - vdisp_release(&vthis); - return hres; + if((flags & DISPATCH_CONSTRUCT) && !(function->function.flags & PROPF_CONSTR)) + return JS_E_INVALID_ACTION; + return function->proc(ctx, vthis, flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r); } static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret) { NativeFunction *function = (NativeFunction*)func; - DWORD name_len; - jsstr_t *str; - WCHAR *ptr; + return native_function_string(function->name, ret); +} - static const WCHAR native_prefixW[] = {'\n','f','u','n','c','t','i','o','n',' '}; - static const WCHAR native_suffixW[] = - {'(',')',' ','{','\n',' ',' ',' ',' ','[','n','a','t','i','v','e',' ','c','o','d','e',']','\n','}','\n'}; - - name_len = function->name ? lstrlenW(function->name) : 0; - str = jsstr_alloc_buf(ARRAY_SIZE(native_prefixW) + ARRAY_SIZE(native_suffixW) + name_len, &ptr); - if(!str) - return E_OUTOFMEMORY; - - memcpy(ptr, native_prefixW, sizeof(native_prefixW)); - ptr += ARRAY_SIZE(native_prefixW); - memcpy(ptr, function->name, name_len*sizeof(WCHAR)); - ptr += name_len; - memcpy(ptr, native_suffixW, sizeof(native_suffixW)); - - *ret = str; - return S_OK; +static function_code_t *NativeFunction_get_code(FunctionInstance *function) +{ + return NULL; } static void NativeFunction_destructor(FunctionInstance *function) @@ -645,7 +765,9 @@ static void NativeFunction_destructor(FunctionInstance *function) static const function_vtbl_t NativeFunctionVtbl = { NativeFunction_call, NativeFunction_toString, - NativeFunction_destructor + NativeFunction_get_code, + NativeFunction_destructor, + no_gc_traverse }; HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name, @@ -654,15 +776,18 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, NativeFunction *function; HRESULT hres; + if(!ctx->function_constr) + return E_UNEXPECTED; + hres = create_function(ctx, builtin_info, &NativeFunctionVtbl, sizeof(NativeFunction), flags, FALSE, NULL, (void**)&function); if(FAILED(hres)) return hres; if(builtin_info) - hres = jsdisp_define_data_property(&function->function.dispex, lengthW, 0, + hres = jsdisp_define_data_property(&function->function.dispex, L"length", 0, jsval_number(function->function.length)); if(SUCCEEDED(hres)) - hres = jsdisp_define_data_property(&function->function.dispex, prototypeW, 0, jsval_obj(prototype)); + hres = jsdisp_define_data_property(&function->function.dispex, L"prototype", 0, prototype ? jsval_obj(prototype) : jsval_null()); if(FAILED(hres)) { jsdisp_release(&function->function.dispex); return hres; @@ -677,9 +802,7 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, static HRESULT set_constructor_prop(script_ctx_t *ctx, jsdisp_t *constr, jsdisp_t *prot) { - static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r',0}; - - return jsdisp_define_data_property(prot, constructorW, PROPF_WRITABLE | PROPF_CONFIGURABLE, + return jsdisp_define_data_property(prot, L"constructor", PROPF_WRITABLE | PROPF_CONFIGURABLE, jsval_obj(constr)); } @@ -703,41 +826,85 @@ HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_pro return S_OK; } -static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, +/* + * Create the actual prototype on demand, since it is a circular ref, which prevents the vast + * majority of functions from being released quickly, leading to unnecessary scope detach. + */ +static HRESULT InterpretedFunction_get_prototype(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + jsdisp_t *prototype; + HRESULT hres; + + hres = create_object(ctx, NULL, &prototype); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(jsthis, L"prototype", PROPF_WRITABLE, jsval_obj(prototype)); + if(SUCCEEDED(hres)) + hres = set_constructor_prop(ctx, jsthis, prototype); + if(FAILED(hres)) { + jsdisp_release(prototype); + return hres; + } + + *r = jsval_obj(prototype); + return S_OK; +} + +static HRESULT InterpretedFunction_set_prototype(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) +{ + return jsdisp_define_data_property(jsthis, L"prototype", PROPF_WRITABLE, value); +} + +static const builtin_prop_t InterpretedFunction_props[] = { + {L"arguments", NULL, 0, Function_get_arguments}, + {L"caller", NULL, PROPF_HTML, Function_get_caller}, + {L"length", NULL, 0, Function_get_length}, + {L"prototype", NULL, 0, InterpretedFunction_get_prototype, InterpretedFunction_set_prototype} +}; + +static const builtin_info_t InterpretedFunction_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(InterpretedFunction_props), + .props = InterpretedFunction_props, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse +}; + +static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { InterpretedFunction *function = (InterpretedFunction*)func; - jsdisp_t *var_disp, *new_obj = NULL; + IDispatch *this_obj = NULL; DWORD exec_flags = 0; + jsdisp_t *new_obj; HRESULT hres; TRACE("%p\n", function); - if(ctx->state == SCRIPTSTATE_UNINITIALIZED || ctx->state == SCRIPTSTATE_CLOSED) { - WARN("Script engine state does not allow running code.\n"); - return E_UNEXPECTED; - } - if(flags & DISPATCH_CONSTRUCT) { hres = create_object(ctx, &function->function.dispex, &new_obj); if(FAILED(hres)) return hres; this_obj = to_disp(new_obj); + }else if(is_object_instance(vthis)) { + this_obj = get_object(vthis); + IDispatch_AddRef(this_obj); + }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(vthis) && !is_null(vthis)) { + hres = to_object(ctx, vthis, &this_obj); + if(FAILED(hres)) + return hres; } if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) exec_flags |= EXEC_RETURN_TO_INTERP; if(flags & DISPATCH_CONSTRUCT) exec_flags |= EXEC_CONSTRUCTOR; - - hres = create_dispex(ctx, NULL, NULL, &var_disp); - if(SUCCEEDED(hres)) - hres = exec_source(ctx, exec_flags, function->code, function->func_code, function->scope_chain, this_obj, - &function->function.dispex, var_disp, argc, argv, r); - if(new_obj) - jsdisp_release(new_obj); - - jsdisp_release(var_disp); + hres = exec_source(ctx, exec_flags, function->code, function->func_code, function->scope_chain, this_obj, + &function->function.dispex, argc, argv, r); + if(this_obj) + IDispatch_Release(this_obj); return hres; } @@ -749,6 +916,13 @@ static HRESULT InterpretedFunction_toString(FunctionInstance *func, jsstr_t **re return *ret ? S_OK : E_OUTOFMEMORY; } +static function_code_t *InterpretedFunction_get_code(FunctionInstance *func) +{ + InterpretedFunction *function = (InterpretedFunction*)func; + + return function->func_code; +} + static void InterpretedFunction_destructor(FunctionInstance *func) { InterpretedFunction *function = (InterpretedFunction*)func; @@ -758,34 +932,32 @@ static void InterpretedFunction_destructor(FunctionInstance *func) scope_release(function->scope_chain); } +static HRESULT InterpretedFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) +{ + InterpretedFunction *function = (InterpretedFunction*)func; + + if(!function->scope_chain) + return S_OK; + return gc_process_linked_obj(gc_ctx, op, &function->function.dispex, &function->scope_chain->dispex, + (void**)&function->scope_chain); +} + static const function_vtbl_t InterpretedFunctionVtbl = { InterpretedFunction_call, InterpretedFunction_toString, - InterpretedFunction_destructor + InterpretedFunction_get_code, + InterpretedFunction_destructor, + InterpretedFunction_gc_traverse }; HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_code_t *func_code, scope_chain_t *scope_chain, jsdisp_t **ret) { InterpretedFunction *function; - jsdisp_t *prototype; HRESULT hres; - hres = create_object(ctx, NULL, &prototype); - if(FAILED(hres)) - return hres; - - hres = create_function(ctx, NULL, &InterpretedFunctionVtbl, sizeof(InterpretedFunction), PROPF_CONSTR, - FALSE, NULL, (void**)&function); - if(SUCCEEDED(hres)) { - hres = jsdisp_define_data_property(&function->function.dispex, prototypeW, PROPF_WRITABLE, - jsval_obj(prototype)); - if(SUCCEEDED(hres)) - hres = set_constructor_prop(ctx, &function->function.dispex, prototype); - if(FAILED(hres)) - jsdisp_release(&function->function.dispex); - } - jsdisp_release(prototype); + hres = create_function(ctx, &InterpretedFunction_info, &InterpretedFunctionVtbl, sizeof(InterpretedFunction), + PROPF_CONSTR, FALSE, NULL, (void**)&function); if(FAILED(hres)) return hres; @@ -803,7 +975,267 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod return S_OK; } -static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, +static const builtin_info_t HostFunction_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse +}; + +static HRESULT HostFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + HostFunction *function = (HostFunction*)func; + VARIANT buf[6], retv; + DISPPARAMS dp = { .cArgs = argc, .rgvarg = buf }; + IWineJSDispatchHost *obj; + EXCEPINFO ei = { 0 }; + IDispatch *this_obj; + HRESULT hres = S_OK; + unsigned i; + + if(flags & DISPATCH_CONSTRUCT) + return E_UNEXPECTED; + + if(is_object_instance(vthis)) + this_obj = get_object(vthis); + else if(is_undefined(vthis) || is_null(vthis)) + this_obj = lookup_global_host(ctx); + else + return E_UNEXPECTED; + + obj = get_host_dispatch(this_obj); + if(!obj) { + TRACE("no host dispatch\n"); + return E_UNEXPECTED; + } + + if(argc > ARRAYSIZE(buf) && !(dp.rgvarg = malloc(argc * sizeof(*dp.rgvarg)))) { + IWineJSDispatchHost_Release(obj); + return E_OUTOFMEMORY; + } + + for(i = 0; i < argc; i++) { + hres = jsval_to_variant(argv[i], &dp.rgvarg[dp.cArgs - i - 1]); + if(FAILED(hres)) + break; + } + + if(SUCCEEDED(hres)) { + V_VT(&retv) = VT_EMPTY; + hres = IWineJSDispatchHost_CallFunction(obj, function->id, function->iid, function->flags, &dp, + r ? &retv : NULL, &ei, &ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(ctx, &ei); + if(SUCCEEDED(hres) && r) { + hres = variant_to_jsval(ctx, &retv, r); + VariantClear(&retv); + } + } + + while(i--) + VariantClear(&dp.rgvarg[dp.cArgs - i - 1]); + if(dp.rgvarg != buf) + free(dp.rgvarg); + IWineJSDispatchHost_Release(obj); + return hres; +} + +static HRESULT HostFunction_toString(FunctionInstance *func, jsstr_t **ret) +{ + HostFunction *function = (HostFunction*)func; + return native_function_string(function->name, ret); +} + +static function_code_t *HostFunction_get_code(FunctionInstance *function) +{ + return NULL; +} + +static void HostFunction_destructor(FunctionInstance *func) +{ +} + +static HRESULT HostFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) +{ + return S_OK; +} + +static const function_vtbl_t HostFunctionVtbl = { + HostFunction_call, + HostFunction_toString, + HostFunction_get_code, + HostFunction_destructor, + HostFunction_gc_traverse +}; + +HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc, DWORD flags, jsdisp_t **ret) +{ + HostFunction *function; + HRESULT hres; + + if(!ctx->function_constr) + return E_UNEXPECTED; + + hres = create_function(ctx, &HostFunction_info, &HostFunctionVtbl, sizeof(HostFunction), PROPF_METHOD, + FALSE, NULL, (void**)&function); + if(FAILED(hres)) + return hres; + + function->name = desc->name; + function->id = desc->id; + function->iid = desc->iid; + function->flags = flags; + *ret = &function->function.dispex; + return S_OK; +} + +static ULONG HostConstructor_addref(jsdisp_t *jsdisp) +{ + HostConstructor *constr = (HostConstructor*)jsdisp; + return IWineJSDispatchHost_AddRef(constr->host_iface); +} + +static ULONG HostConstructor_release(jsdisp_t *jsdisp) +{ + HostConstructor *constr = (HostConstructor*)jsdisp; + return IWineJSDispatchHost_Release(constr->host_iface); +} + +static HRESULT HostConstructor_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) +{ + HostConstructor *constr = (HostConstructor*)jsdisp; + HRESULT hres = IWineJSDispatchHost_LookupProperty(constr->host_iface, name, flags, desc); + assert(hres != S_OK || (desc->flags & PROPF_METHOD)); /* external properties are not allowed */ + return hres; +} + +static const builtin_info_t HostConstructor_info = { + .class = JSCLASS_FUNCTION, + .addref = HostConstructor_addref, + .release = HostConstructor_release, + .call = Function_value, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse, + .lookup_prop = HostConstructor_lookup_prop, +}; + +static HRESULT HostConstructor_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + HostConstructor *function = (HostConstructor*)func; + VARIANT buf[6], ret; + DISPPARAMS dp = { .cArgs = argc, .rgvarg = buf }; + EXCEPINFO ei = { 0 }; + HRESULT hres = S_OK; + unsigned i; + + flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; + if(argc > ARRAYSIZE(buf) && !(dp.rgvarg = malloc(argc * sizeof(*dp.rgvarg)))) + return E_OUTOFMEMORY; + + for(i = 0; i < argc; i++) { + hres = jsval_to_variant(argv[i], &dp.rgvarg[dp.cArgs - i - 1]); + if(FAILED(hres)) + break; + } + + if(SUCCEEDED(hres)) { + V_VT(&ret) = VT_EMPTY; + hres = IWineJSDispatchHost_Construct(function->host_iface, ctx->lcid, flags, &dp, &ret, &ei, + &ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(ctx, &ei); + if(SUCCEEDED(hres) && r) { + hres = variant_to_jsval(ctx, &ret, r); + VariantClear(&ret); + } + } + + while(i--) + VariantClear(&dp.rgvarg[dp.cArgs - i - 1]); + if(dp.rgvarg != buf) + free(dp.rgvarg); + return hres; +} + +static HRESULT HostConstructor_toString(FunctionInstance *function, jsstr_t **ret) +{ + *ret = jsstr_alloc(L"\nfunction() {\n [native code]\n}\n"); + return *ret ? S_OK : E_OUTOFMEMORY; +} + +static function_code_t *HostConstructor_get_code(FunctionInstance *function) +{ + return NULL; +} + +static void HostConstructor_destructor(FunctionInstance *func) +{ +} + +static HRESULT HostConstructor_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) +{ + return S_OK; +} + +static const function_vtbl_t HostConstructorVtbl = { + HostConstructor_call, + HostConstructor_toString, + HostConstructor_get_code, + HostConstructor_destructor, + HostConstructor_gc_traverse +}; + +HRESULT init_host_constructor(script_ctx_t *ctx, IWineJSDispatchHost *host_constr, IWineJSDispatch *prototype, + IWineJSDispatch **ret) +{ + HostConstructor *function; + HRESULT hres; + + hres = create_function(ctx, &HostConstructor_info, &HostConstructorVtbl, sizeof(*function), PROPF_METHOD, + FALSE, NULL, (void**)&function); + if(FAILED(hres)) + return hres; + function->host_iface = host_constr; + + hres = jsdisp_define_data_property(&function->function.dispex, L"prototype", PROPF_WRITABLE | PROPF_CONFIGURABLE, + jsval_disp((IDispatch *)prototype)); + if(FAILED(hres)) { + IWineJSDispatch_Free(&function->function.dispex.IWineJSDispatch_iface); + return hres; + } + + *ret = &function->function.dispex.IWineJSDispatch_iface; + return S_OK; +} + +static HRESULT BindFunction_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + return JS_E_INVALID_ACTION; +} + +static HRESULT BindFunction_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + return JS_E_INVALID_ACTION; +} + +static const builtin_prop_t BindFunction_props[] = { + {L"arguments", NULL, 0, BindFunction_get_arguments}, + {L"caller", NULL, 0, BindFunction_get_caller}, + {L"length", NULL, 0, Function_get_length} +}; + +static const builtin_info_t BindFunction_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(BindFunction_props), + .props = BindFunction_props, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse +}; + +static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { BindFunction *function = (BindFunction*)func; @@ -815,7 +1247,7 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDis call_argc = function->argc + argc; if(call_argc) { - call_args = heap_alloc(function->argc * sizeof(*function->args)); + call_args = malloc(call_argc * sizeof(*call_args)); if(!call_args) return E_OUTOFMEMORY; @@ -827,21 +1259,21 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDis hres = function->target->vtbl->call(ctx, function->target, function->this, flags, call_argc, call_args, r); - heap_free(call_args); + free(call_args); return hres; } static HRESULT BindFunction_toString(FunctionInstance *function, jsstr_t **ret) { - static const WCHAR native_functionW[] = - {'\n','f','u','n','c','t','i','o','n','(',')',' ','{','\n', - ' ',' ',' ',' ','[','n','a','t','i','v','e',' ','c','o','d','e',']','\n', - '}','\n',0}; - - *ret = jsstr_alloc(native_functionW); + *ret = jsstr_alloc(L"\nfunction() {\n [native code]\n}\n"); return *ret ? S_OK : E_OUTOFMEMORY; } +static function_code_t *BindFunction_get_code(FunctionInstance *function) +{ + return NULL; +} + static void BindFunction_destructor(FunctionInstance *func) { BindFunction *function = (BindFunction*)func; @@ -851,23 +1283,45 @@ static void BindFunction_destructor(FunctionInstance *func) for(i = 0; i < function->argc; i++) jsval_release(function->args[i]); - jsdisp_release(&function->target->dispex); - IDispatch_Release(function->this); + if(function->target) + jsdisp_release(&function->target->dispex); + jsval_release(function->this); +} + +static HRESULT BindFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) +{ + BindFunction *function = (BindFunction*)func; + HRESULT hres; + unsigned i; + + for(i = 0; i < function->argc; i++) { + hres = gc_process_linked_val(gc_ctx, op, &function->function.dispex, &function->args[i]); + if(FAILED(hres)) + return hres; + } + + hres = gc_process_linked_obj(gc_ctx, op, &function->function.dispex, &function->target->dispex, (void**)&function->target); + if(FAILED(hres)) + return hres; + + return gc_process_linked_val(gc_ctx, op, &function->function.dispex, &function->this); } static const function_vtbl_t BindFunctionVtbl = { BindFunction_call, BindFunction_toString, - BindFunction_destructor + BindFunction_get_code, + BindFunction_destructor, + BindFunction_gc_traverse }; -static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, IDispatch *bound_this, unsigned argc, +static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, jsval_t bound_this, unsigned argc, jsval_t *argv, jsdisp_t **ret) { BindFunction *function; HRESULT hres; - hres = create_function(ctx, NULL, &BindFunctionVtbl, FIELD_OFFSET(BindFunction, args[argc]), PROPF_METHOD, + hres = create_function(ctx, &BindFunction_info, &BindFunctionVtbl, FIELD_OFFSET(BindFunction, args[argc]), PROPF_METHOD, FALSE, NULL, (void**)&function); if(FAILED(hres)) return hres; @@ -875,7 +1329,11 @@ static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, jsdisp_addref(&target->dispex); function->target = target; - IDispatch_AddRef(function->this = bound_this); + hres = jsval_copy(bound_this, &function->this); + if(FAILED(hres)) { + jsdisp_release(&function->function.dispex); + return hres; + } for(function->argc = 0; function->argc < argc; function->argc++) { hres = jsval_copy(argv[function->argc], function->args + function->argc); @@ -901,12 +1359,12 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg int j = 0; HRESULT hres = S_OK; - static const WCHAR function_anonymousW[] = {'f','u','n','c','t','i','o','n',' ','a','n','o','n','y','m','o','u','s','('}; - static const WCHAR function_beginW[] = {')',' ','{','\n'}; - static const WCHAR function_endW[] = {'\n','}',0}; + static const WCHAR function_anonymousW[] = L"function anonymous("; + static const WCHAR function_beginW[] = L") {\n"; + static const WCHAR function_endW[] = L"\n}"; if(argc) { - params = heap_alloc(argc*sizeof(*params)); + params = malloc(argc*sizeof(*params)); if(!params) return E_OUTOFMEMORY; @@ -921,11 +1379,11 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg } if(SUCCEEDED(hres)) { - len += ARRAY_SIZE(function_anonymousW) + ARRAY_SIZE(function_beginW) + ARRAY_SIZE(function_endW); - str = heap_alloc(len*sizeof(WCHAR)); + len += ARRAY_SIZE(function_anonymousW) + ARRAY_SIZE(function_beginW) + ARRAY_SIZE(function_endW) - 2; + str = malloc(len*sizeof(WCHAR)); if(str) { memcpy(str, function_anonymousW, sizeof(function_anonymousW)); - ptr = str + ARRAY_SIZE(function_anonymousW); + ptr = str + ARRAY_SIZE(function_anonymousW) - 1; if(argc > 1) { while(1) { ptr += jsstr_flush(params[j], ptr); @@ -936,7 +1394,7 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg } } memcpy(ptr, function_beginW, sizeof(function_beginW)); - ptr += ARRAY_SIZE(function_beginW); + ptr += ARRAY_SIZE(function_beginW) - 1; if(argc) ptr += jsstr_flush(params[argc-1], ptr); memcpy(ptr, function_endW, sizeof(function_endW)); @@ -949,12 +1407,13 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg while(i) jsstr_release(params[--i]); - heap_free(params); + free(params); if(FAILED(hres)) return hres; - hres = compile_script(ctx, str, NULL, NULL, FALSE, FALSE, &code); - heap_free(str); + hres = compile_script(ctx, str, 0, 0, NULL, NULL, FALSE, FALSE, + ctx->call_ctx ? ctx->call_ctx->bytecode->named_item : NULL, &code); + free(str); if(FAILED(hres)) return hres; @@ -973,7 +1432,7 @@ static HRESULT construct_function(script_ctx_t *ctx, unsigned argc, jsval_t *arg return S_OK; } -static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT FunctionConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { HRESULT hres; @@ -989,7 +1448,8 @@ static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla if(FAILED(hres)) return hres; - *r = jsval_disp(ret); + if(r) *r = jsval_disp(ret); + else IDispatch_Release(ret); break; } default: @@ -1000,34 +1460,38 @@ static HRESULT FunctionConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla return S_OK; } -static HRESULT FunctionProt_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT FunctionProt_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FIXME("\n"); return E_NOTIMPL; } +BOOL is_builtin_eval_func(jsdisp_t *jsdisp) +{ + return is_class(jsdisp, JSCLASS_FUNCTION) && function_from_jsdisp(jsdisp)->vtbl == &NativeFunctionVtbl && + ((NativeFunction*)function_from_jsdisp(jsdisp))->proc == JSGlobal_eval; +} + HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) { NativeFunction *prot, *constr; HRESULT hres; - static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0}; - hres = create_function(ctx, &Function_info, &NativeFunctionVtbl, sizeof(NativeFunction), PROPF_CONSTR, TRUE, object_prototype, (void**)&prot); if(FAILED(hres)) return hres; prot->proc = FunctionProt_value; - prot->name = prototypeW; + prot->name = L"prototype"; hres = create_function(ctx, &FunctionInst_info, &NativeFunctionVtbl, sizeof(NativeFunction), PROPF_CONSTR|1, TRUE, &prot->function.dispex, (void**)&constr); if(SUCCEEDED(hres)) { constr->proc = FunctionConstr_value; - constr->name = FunctionW; - hres = jsdisp_define_data_property(&constr->function.dispex, prototypeW, 0, jsval_obj(&prot->function.dispex)); + constr->name = L"Function"; + hres = jsdisp_define_data_property(&constr->function.dispex, L"prototype", 0, jsval_obj(&prot->function.dispex)); if(SUCCEEDED(hres)) hres = set_constructor_prop(ctx, &constr->function.dispex, &prot->function.dispex); if(FAILED(hres)) diff --git a/dll/win32/jscript/global.c b/dll/win32/jscript/global.c index 24c4eebf1db..dcfbd45f6c7 100644 --- a/dll/win32/jscript/global.c +++ b/dll/win32/jscript/global.c @@ -31,52 +31,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); -static const WCHAR NaNW[] = {'N','a','N',0}; -static const WCHAR InfinityW[] = {'I','n','f','i','n','i','t','y',0}; -static const WCHAR ArrayW[] = {'A','r','r','a','y',0}; -static const WCHAR BooleanW[] = {'B','o','o','l','e','a','n',0}; -static const WCHAR DateW[] = {'D','a','t','e',0}; -static const WCHAR ErrorW[] = {'E','r','r','o','r',0}; -static const WCHAR EvalErrorW[] = {'E','v','a','l','E','r','r','o','r',0}; -static const WCHAR RangeErrorW[] = {'R','a','n','g','e','E','r','r','o','r',0}; -static const WCHAR ReferenceErrorW[] = {'R','e','f','e','r','e','n','c','e','E','r','r','o','r',0}; -static const WCHAR SyntaxErrorW[] = {'S','y','n','t','a','x','E','r','r','o','r',0}; -static const WCHAR TypeErrorW[] = {'T','y','p','e','E','r','r','o','r',0}; -static const WCHAR URIErrorW[] = {'U','R','I','E','r','r','o','r',0}; -static const WCHAR FunctionW[] = {'F','u','n','c','t','i','o','n',0}; -static const WCHAR NumberW[] = {'N','u','m','b','e','r',0}; -static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0}; -static const WCHAR StringW[] = {'S','t','r','i','n','g',0}; -static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0}; -static const WCHAR RegExpErrorW[] = {'R','e','g','E','x','p','E','r','r','o','r',0}; -static const WCHAR ActiveXObjectW[] = {'A','c','t','i','v','e','X','O','b','j','e','c','t',0}; -static const WCHAR VBArrayW[] = {'V','B','A','r','r','a','y',0}; -static const WCHAR EnumeratorW[] = {'E','n','u','m','e','r','a','t','o','r',0}; -static const WCHAR escapeW[] = {'e','s','c','a','p','e',0}; -static const WCHAR evalW[] = {'e','v','a','l',0}; -static const WCHAR isNaNW[] = {'i','s','N','a','N',0}; -static const WCHAR isFiniteW[] = {'i','s','F','i','n','i','t','e',0}; -static const WCHAR parseIntW[] = {'p','a','r','s','e','I','n','t',0}; -static const WCHAR parseFloatW[] = {'p','a','r','s','e','F','l','o','a','t',0}; -static const WCHAR unescapeW[] = {'u','n','e','s','c','a','p','e',0}; -static const WCHAR _GetObjectW[] = {'G','e','t','O','b','j','e','c','t',0}; -static const WCHAR ScriptEngineW[] = {'S','c','r','i','p','t','E','n','g','i','n','e',0}; -static const WCHAR ScriptEngineMajorVersionW[] = - {'S','c','r','i','p','t','E','n','g','i','n','e','M','a','j','o','r','V','e','r','s','i','o','n',0}; -static const WCHAR ScriptEngineMinorVersionW[] = - {'S','c','r','i','p','t','E','n','g','i','n','e','M','i','n','o','r','V','e','r','s','i','o','n',0}; -static const WCHAR ScriptEngineBuildVersionW[] = - {'S','c','r','i','p','t','E','n','g','i','n','e','B','u','i','l','d','V','e','r','s','i','o','n',0}; -static const WCHAR CollectGarbageW[] = {'C','o','l','l','e','c','t','G','a','r','b','a','g','e',0}; -static const WCHAR MathW[] = {'M','a','t','h',0}; -static const WCHAR JSONW[] = {'J','S','O','N',0}; -static const WCHAR encodeURIW[] = {'e','n','c','o','d','e','U','R','I',0}; -static const WCHAR decodeURIW[] = {'d','e','c','o','d','e','U','R','I',0}; -static const WCHAR encodeURIComponentW[] = {'e','n','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0}; -static const WCHAR decodeURIComponentW[] = {'d','e','c','o','d','e','U','R','I','C','o','m','p','o','n','e','n','t',0}; - -static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0}; - static int uri_char_table[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00-0f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10-1f */ @@ -115,7 +69,7 @@ static WCHAR int_to_char(int i) return 'A'+i-10; } -static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_escape(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *ret_str, *str; @@ -180,10 +134,9 @@ static HRESULT JSGlobal_escape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u } /* ECMA-262 3rd Edition 15.1.2.1 */ -HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +HRESULT builtin_eval(script_ctx_t *ctx, call_frame_t *frame, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - call_frame_t *frame = ctx->call_ctx; DWORD exec_flags = EXEC_EVAL; bytecode_t *code; const WCHAR *src; @@ -208,10 +161,10 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a return E_OUTOFMEMORY; TRACE("parsing %s\n", debugstr_jsval(argv[0])); - hres = compile_script(ctx, src, NULL, NULL, TRUE, FALSE, &code); + hres = compile_script(ctx, src, 0, 0, NULL, NULL, TRUE, FALSE, frame ? frame->bytecode->named_item : NULL, &code); if(FAILED(hres)) { - WARN("parse (%s) failed: %08x\n", debugstr_jsval(argv[0]), hres); - return throw_syntax_error(ctx, hres, NULL); + WARN("parse (%s) failed: %08lx\n", debugstr_jsval(argv[0]), hres); + return hres; } if(!frame || (frame->flags & EXEC_GLOBAL)) @@ -219,12 +172,18 @@ HRESULT JSGlobal_eval(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned a if(flags & DISPATCH_JSCRIPT_CALLEREXECSSOURCE) exec_flags |= EXEC_RETURN_TO_INTERP; hres = exec_source(ctx, exec_flags, code, &code->global_code, frame ? frame->scope : NULL, - frame ? frame->this_obj : NULL, NULL, frame ? frame->variable_obj : ctx->global, 0, NULL, r); + frame ? frame->this_obj : NULL, NULL, 0, NULL, r); release_bytecode(code); return hres; } -static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +HRESULT JSGlobal_eval(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + return builtin_eval(ctx, ctx->version < SCRIPTLANGUAGEVERSION_ES5 ? ctx->call_ctx : NULL, flags, argc, argv, r); +} + +static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { BOOL ret = TRUE; @@ -247,7 +206,7 @@ static HRESULT JSGlobal_isNaN(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un return S_OK; } -static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { BOOL ret = FALSE; @@ -262,7 +221,7 @@ static HRESULT JSGlobal_isFinite(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, if(FAILED(hres)) return hres; - ret = is_finite(n); + ret = isfinite(n); } if(r) @@ -281,7 +240,7 @@ static INT char_to_int(WCHAR c) return 100; } -static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { BOOL neg = FALSE, empty = TRUE; @@ -364,7 +323,7 @@ static HRESULT JSGlobal_parseInt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, return S_OK; } -static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { LONGLONG d = 0, hlp; @@ -380,6 +339,8 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag return S_OK; } + TRACE("%s\n", debugstr_jsval(argv[0])); + hres = to_flat_string(ctx, argv[0], &val_str, &str); if(FAILED(hres)) return hres; @@ -393,10 +354,10 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag str++; } - if(iswdigit(*str)) + if(is_digit(*str)) ret_nan = FALSE; - while(iswdigit(*str)) { + while(is_digit(*str)) { hlp = d*10 + *(str++) - '0'; if(d>MAXLONGLONG/10 || hlp<0) { exp++; @@ -405,17 +366,17 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag else d = hlp; } - while(iswdigit(*str)) { + while(is_digit(*str)) { exp++; str++; } if(*str == '.') str++; - if(iswdigit(*str)) + if(is_digit(*str)) ret_nan = FALSE; - while(iswdigit(*str)) { + while(is_digit(*str)) { hlp = d*10 + *(str++) - '0'; if(d>MAXLONGLONG/10 || hlp<0) break; @@ -423,7 +384,7 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag d = hlp; exp--; } - while(iswdigit(*str)) + while(is_digit(*str)) str++; if(*str && !ret_nan && (*str=='e' || *str=='E')) { @@ -437,7 +398,7 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag str++; } - while(iswdigit(*str)) { + while(is_digit(*str)) { if(e>INT_MAX/10 || (e = e*10 + *str++ - '0')<0) e = INT_MAX; } @@ -463,13 +424,17 @@ static HRESULT JSGlobal_parseFloat(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag return S_OK; } +#if defined(__REACTOS__) && defined(__clang__) +static inline __attribute__((always_inline)) int hex_to_int(WCHAR wch) { +#else static inline int hex_to_int(const WCHAR wch) { +#endif if(towupper(wch)>='A' && towupper(wch)<='F') return towupper(wch)-'A'+10; - if(iswdigit(wch)) return wch-'0'; + if(is_digit(wch)) return wch-'0'; return -1; } -static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_unescape(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *ret_str, *str; @@ -539,24 +504,22 @@ static HRESULT JSGlobal_unescape(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, return S_OK; } -static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_GetObject(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { FIXME("\n"); return E_NOTIMPL; } -static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - static const WCHAR JScriptW[] = {'J','S','c','r','i','p','t',0}; - TRACE("\n"); if(r) { jsstr_t *ret; - ret = jsstr_alloc(JScriptW); + ret = jsstr_alloc(L"JScript"); if(!ret) return E_OUTOFMEMORY; @@ -566,7 +529,7 @@ static HRESULT JSGlobal_ScriptEngine(script_ctx_t *ctx, vdisp_t *jsthis, WORD fl return S_OK; } -static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); @@ -576,7 +539,7 @@ static HRESULT JSGlobal_ScriptEngineMajorVersion(script_ctx_t *ctx, vdisp_t *jst return S_OK; } -static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); @@ -586,7 +549,7 @@ static HRESULT JSGlobal_ScriptEngineMinorVersion(script_ctx_t *ctx, vdisp_t *jst return S_OK; } -static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); @@ -596,16 +559,13 @@ static HRESULT JSGlobal_ScriptEngineBuildVersion(script_ctx_t *ctx, vdisp_t *jst return S_OK; } -static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_CollectGarbage(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - static int once = 0; - if (!once++) - FIXME(": stub\n"); - return S_OK; + return gc_run(ctx); } -static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { const WCHAR *ptr, *uri; @@ -631,10 +591,10 @@ static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') { len++; }else { - i = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL)*3; + i = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL)*3; if(!i) { jsstr_release(str); - return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL); + return JS_E_INVALID_URI_CHAR; } len += i; @@ -651,7 +611,7 @@ static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags if(is_uri_unescaped(*ptr) || is_uri_reserved(*ptr) || *ptr == '#') { *rptr++ = *ptr; }else { - len = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL); + len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL); for(i=0; i> 4); @@ -670,7 +630,7 @@ static HRESULT JSGlobal_encodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags return S_OK; } -static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { const WCHAR *ptr, *uri; @@ -705,14 +665,14 @@ static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags val += hex_to_int(ptr[i*3+1])<<4; buf[i] = val; - res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, &out, 1); + res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, &out, 1); if(res) break; } if(!res) { jsstr_release(str); - return throw_uri_error(ctx, JS_E_INVALID_URI_CODING, NULL); + return JS_E_INVALID_URI_CODING; } ptr += i*3+2; @@ -736,7 +696,7 @@ static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags val += hex_to_int(ptr[i*3+1])<<4; buf[i] = val; - res = MultiByteToWideChar(CP_UTF8, 0, buf, i+1, ret, 1); + res = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buf, i+1, ret, 1); if(res) break; } @@ -756,7 +716,7 @@ static HRESULT JSGlobal_decodeURI(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags return S_OK; } -static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsstr_t *str, *ret_str; @@ -782,10 +742,10 @@ static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W if(is_uri_unescaped(*ptr)) len++; else { - size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, NULL, 0, NULL, NULL); + size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, NULL, 0, NULL, NULL); if(!size) { jsstr_release(str); - return throw_uri_error(ctx, JS_E_INVALID_URI_CHAR, NULL); + return JS_E_INVALID_URI_CHAR; } len += size*3; } @@ -801,7 +761,7 @@ static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W if(is_uri_unescaped(*ptr)) { *ret++ = *ptr; }else { - size = WideCharToMultiByte(CP_UTF8, 0, ptr, 1, buf, sizeof(buf), NULL, NULL); + size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, 1, buf, sizeof(buf), NULL, NULL); for(i=0; i> 4); @@ -820,7 +780,7 @@ static HRESULT JSGlobal_encodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W } /* ECMA-262 3rd Edition 15.1.3.2 */ -static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { const WCHAR *ptr, *uri; @@ -933,34 +893,56 @@ static HRESULT JSGlobal_decodeURIComponent(script_ctx_t *ctx, vdisp_t *jsthis, W } static const builtin_prop_t JSGlobal_props[] = { - {CollectGarbageW, JSGlobal_CollectGarbage, PROPF_METHOD}, - {_GetObjectW, JSGlobal_GetObject, PROPF_METHOD|2}, - {ScriptEngineW, JSGlobal_ScriptEngine, PROPF_METHOD}, - {ScriptEngineBuildVersionW, JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD}, - {ScriptEngineMajorVersionW, JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD}, - {ScriptEngineMinorVersionW, JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD}, - {decodeURIW, JSGlobal_decodeURI, PROPF_METHOD|1}, - {decodeURIComponentW, JSGlobal_decodeURIComponent, PROPF_METHOD|1}, - {encodeURIW, JSGlobal_encodeURI, PROPF_METHOD|1}, - {encodeURIComponentW, JSGlobal_encodeURIComponent, PROPF_METHOD|1}, - {escapeW, JSGlobal_escape, PROPF_METHOD|1}, - {evalW, JSGlobal_eval, PROPF_METHOD|1}, - {isFiniteW, JSGlobal_isFinite, PROPF_METHOD|1}, - {isNaNW, JSGlobal_isNaN, PROPF_METHOD|1}, - {parseFloatW, JSGlobal_parseFloat, PROPF_METHOD|1}, - {parseIntW, JSGlobal_parseInt, PROPF_METHOD|2}, - {unescapeW, JSGlobal_unescape, PROPF_METHOD|1} + {L"CollectGarbage", JSGlobal_CollectGarbage, PROPF_METHOD}, + {L"GetObject", JSGlobal_GetObject, PROPF_METHOD|2}, + {L"ScriptEngine", JSGlobal_ScriptEngine, PROPF_METHOD}, + {L"ScriptEngineBuildVersion", JSGlobal_ScriptEngineBuildVersion, PROPF_METHOD}, + {L"ScriptEngineMajorVersion", JSGlobal_ScriptEngineMajorVersion, PROPF_METHOD}, + {L"ScriptEngineMinorVersion", JSGlobal_ScriptEngineMinorVersion, PROPF_METHOD}, + {L"decodeURI", JSGlobal_decodeURI, PROPF_METHOD|1}, + {L"decodeURIComponent", JSGlobal_decodeURIComponent, PROPF_METHOD|1}, + {L"encodeURI", JSGlobal_encodeURI, PROPF_METHOD|1}, + {L"encodeURIComponent", JSGlobal_encodeURIComponent, PROPF_METHOD|1}, + {L"escape", JSGlobal_escape, PROPF_METHOD|1}, + {L"eval", JSGlobal_eval, PROPF_METHOD|1}, + {L"isFinite", JSGlobal_isFinite, PROPF_METHOD|1}, + {L"isNaN", JSGlobal_isNaN, PROPF_METHOD|1}, + {L"parseFloat", JSGlobal_parseFloat, PROPF_METHOD|1}, + {L"parseInt", JSGlobal_parseInt, PROPF_METHOD|2}, + {L"unescape", JSGlobal_unescape, PROPF_METHOD|1} }; static const builtin_info_t JSGlobal_info = { - JSCLASS_GLOBAL, - {NULL, NULL, 0}, - ARRAY_SIZE(JSGlobal_props), - JSGlobal_props, - NULL, - NULL + .class = JSCLASS_GLOBAL, + .props_cnt = ARRAY_SIZE(JSGlobal_props), + .props = JSGlobal_props, }; +static HRESULT init_object_prototype_accessors(script_ctx_t *ctx, jsdisp_t *object_prototype) +{ + property_desc_t desc; + HRESULT hres = S_OK; + + /* __proto__ is an actual accessor on native, despite being a builtin */ + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES6) { + desc.flags = PROPF_CONFIGURABLE; + desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = desc.explicit_setter = TRUE; + desc.explicit_value = FALSE; + + hres = create_builtin_function(ctx, Object_get_proto_, NULL, NULL, PROPF_METHOD, NULL, &desc.getter); + if(SUCCEEDED(hres)) { + hres = create_builtin_function(ctx, Object_set_proto_, NULL, NULL, PROPF_METHOD|1, NULL, &desc.setter); + if(SUCCEEDED(hres)) { + hres = jsdisp_define_property(object_prototype, L"__proto__", &desc); + jsdisp_release(desc.setter); + } + jsdisp_release(desc.getter); + } + } + return hres; +} + static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) { HRESULT hres; @@ -969,7 +951,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, FunctionW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Function", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->function_constr)); if(FAILED(hres)) return hres; @@ -978,7 +960,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, ObjectW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Object", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->object_constr)); if(FAILED(hres)) return hres; @@ -987,7 +969,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, ArrayW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Array", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->array_constr)); if(FAILED(hres)) return hres; @@ -996,7 +978,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, BooleanW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Boolean", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->bool_constr)); if(FAILED(hres)) return hres; @@ -1005,7 +987,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, DateW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Date", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->date_constr)); if(FAILED(hres)) return hres; @@ -1014,7 +996,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, EnumeratorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Enumerator", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->enumerator_constr)); if(FAILED(hres)) return hres; @@ -1023,42 +1005,42 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, ErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Error", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, EvalErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"EvalError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->eval_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, RangeErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"RangeError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->range_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, ReferenceErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"ReferenceError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->reference_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, RegExpErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"RegExpError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->regexp_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, SyntaxErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"SyntaxError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->syntax_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, TypeErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"TypeError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->type_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, URIErrorW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"URIError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->uri_error_constr)); if(FAILED(hres)) return hres; @@ -1067,7 +1049,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, NumberW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Number", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->number_constr)); if(FAILED(hres)) return hres; @@ -1076,7 +1058,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, RegExpW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"RegExp", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->regexp_constr)); if(FAILED(hres)) return hres; @@ -1085,7 +1067,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, StringW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"String", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->string_constr)); if(FAILED(hres)) return hres; @@ -1094,7 +1076,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, VBArrayW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"VBArray", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->vbarray_constr)); if(FAILED(hres)) return hres; @@ -1105,7 +1087,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) HRESULT init_global(script_ctx_t *ctx) { unsigned const_flags = ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? 0 : PROPF_WRITABLE; - jsdisp_t *math, *object_prototype, *constr; + jsdisp_t *math, *constr; HRESULT hres; if(ctx->global) @@ -1115,12 +1097,15 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = create_object_prototype(ctx, &object_prototype); + hres = create_object_prototype(ctx, &ctx->object_prototype); if(FAILED(hres)) return hres; - hres = init_constructors(ctx, object_prototype); - jsdisp_release(object_prototype); + hres = init_constructors(ctx, ctx->object_prototype); + if(FAILED(hres)) + return hres; + + hres = init_object_prototype_accessors(ctx, ctx->object_prototype); if(FAILED(hres)) return hres; @@ -1128,7 +1113,7 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, MathW, PROPF_WRITABLE, jsval_obj(math)); + hres = jsdisp_define_data_property(ctx->global, L"Math", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(math)); jsdisp_release(math); if(FAILED(hres)) return hres; @@ -1140,7 +1125,7 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, JSONW, PROPF_WRITABLE, jsval_obj(json)); + hres = jsdisp_define_data_property(ctx->global, L"JSON", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(json)); jsdisp_release(json); if(FAILED(hres)) return hres; @@ -1150,20 +1135,27 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, ActiveXObjectW, PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"ActiveXObject", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(constr)); jsdisp_release(constr); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, undefinedW, const_flags, jsval_undefined()); + hres = jsdisp_define_data_property(ctx->global, L"undefined", const_flags, jsval_undefined()); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, NaNW, const_flags, jsval_number(NAN)); + hres = jsdisp_define_data_property(ctx->global, L"NaN", const_flags, jsval_number(NAN)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, InfinityW, const_flags, jsval_number(INFINITY)); - return hres; + hres = jsdisp_define_data_property(ctx->global, L"Infinity", const_flags, jsval_number(INFINITY)); + if(FAILED(hres)) + return hres; + + hres = init_arraybuf_constructors(ctx); + if(FAILED(hres)) + return hres; + + return init_set_constructor(ctx); } diff --git a/dll/win32/jscript/guid.c b/dll/win32/jscript/guid.c new file mode 100644 index 00000000000..081e0f0482d --- /dev/null +++ b/dll/win32/jscript/guid.c @@ -0,0 +1,15 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS + +#include +#include +#include +#include +#include +#include + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/dll/win32/jscript/jscript.c b/dll/win32/jscript/jscript.c index 75eef39e355..c42109b4143 100644 --- a/dll/win32/jscript/jscript.c +++ b/dll/win32/jscript/jscript.c @@ -47,42 +47,61 @@ typedef struct { IActiveScriptProperty IActiveScriptProperty_iface; IObjectSafety IObjectSafety_iface; IVariantChangeType IVariantChangeType_iface; + IWineJScript IWineJScript_iface; LONG ref; DWORD safeopt; + struct thread_data *thread_data; script_ctx_t *ctx; - LONG thread_id; LCID lcid; DWORD version; BOOL html_mode; BOOL is_encode; + BOOL is_initialized; IActiveScriptSite *site; - bytecode_t *queue_head; - bytecode_t *queue_tail; + struct list persistent_code; + struct list queued_code; } JScript; +typedef struct { + IActiveScriptError IActiveScriptError_iface; + LONG ref; + jsexcept_t ei; +} JScriptError; + void script_release(script_ctx_t *ctx) { if(--ctx->ref) return; jsval_release(ctx->acc); - clear_ei(ctx); if(ctx->cc) release_cc(ctx->cc); heap_pool_free(&ctx->tmp_heap); if(ctx->last_match) jsstr_release(ctx->last_match); assert(!ctx->stack_top); - heap_free(ctx->stack); + free(ctx->stack); ctx->jscaller->ctx = NULL; IServiceProvider_Release(&ctx->jscaller->IServiceProvider_iface); - heap_free(ctx); + release_thread_data(ctx->thread_data); + free(ctx); +} + +static void script_globals_release(script_ctx_t *ctx) +{ + unsigned i; + for(i = 0; i < ARRAY_SIZE(ctx->global_objects); i++) { + if(ctx->global_objects[i]) { + jsdisp_release(ctx->global_objects[i]); + ctx->global_objects[i] = NULL; + } + } } static void change_state(JScript *This, SCRIPTSTATE state) @@ -102,66 +121,340 @@ static inline BOOL is_started(script_ctx_t *ctx) || ctx->state == SCRIPTSTATE_DISCONNECTED; } -static HRESULT exec_global_code(JScript *This, bytecode_t *code) +HRESULT create_named_item_script_obj(script_ctx_t *ctx, named_item_t *item) { - HRESULT hres; + static const builtin_info_t disp_info = { .class = JSCLASS_GLOBAL }; + return create_dispex(ctx, &disp_info, NULL, &item->script_obj); +} - IActiveScriptSite_OnEnterScript(This->site); +static void release_named_item_script_obj(named_item_t *item) +{ + if(!item->script_obj) return; - clear_ei(This->ctx); - hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL); + jsdisp_release(item->script_obj); + item->script_obj = NULL; +} - IActiveScriptSite_OnLeaveScript(This->site); - return hres; +static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *item) +{ + IUnknown *unk; + HRESULT hr; + + if(!site) + return E_UNEXPECTED; + + hr = IActiveScriptSite_GetItemInfo(site, item->name, SCRIPTINFO_IUNKNOWN, &unk, NULL); + if(FAILED(hr)) { + WARN("GetItemInfo failed: %08lx\n", hr); + return hr; + } + + hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp); + IUnknown_Release(unk); + if(FAILED(hr)) { + WARN("object does not implement IDispatch\n"); + return hr; + } + + return S_OK; +} + +named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *item_name, unsigned flags) +{ + named_item_t *item; + HRESULT hr; + + LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { + if((item->flags & flags) == flags && !wcscmp(item->name, item_name)) { + if(!item->script_obj && !(item->flags & SCRIPTITEM_GLOBALMEMBERS)) { + hr = create_named_item_script_obj(ctx, item); + if(FAILED(hr)) return NULL; + } + + if(!item->disp && (flags || !(item->flags & SCRIPTITEM_CODEONLY))) { + hr = retrieve_named_item_disp(ctx->site, item); + if(FAILED(hr)) continue; + } + + return item; + } + } + + return NULL; +} + +void release_named_item(named_item_t *item) +{ + if(--item->ref) return; + + free(item->name); + free(item); +} + +static inline JScriptError *impl_from_IActiveScriptError(IActiveScriptError *iface) +{ + return CONTAINING_RECORD(iface, JScriptError, IActiveScriptError_iface); +} + +static HRESULT WINAPI JScriptError_QueryInterface(IActiveScriptError *iface, REFIID riid, void **ppv) +{ + JScriptError *This = impl_from_IActiveScriptError(iface); + + if(IsEqualGUID(riid, &IID_IUnknown)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IActiveScriptError_iface; + }else if(IsEqualGUID(riid, &IID_IActiveScriptError)) { + TRACE("(%p)->(IID_IActiveScriptError %p)\n", This, ppv); + *ppv = &This->IActiveScriptError_iface; + }else { + FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI JScriptError_AddRef(IActiveScriptError *iface) +{ + JScriptError *This = impl_from_IActiveScriptError(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI JScriptError_Release(IActiveScriptError *iface) +{ + JScriptError *This = impl_from_IActiveScriptError(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + reset_ei(&This->ei); + free(This); + } + + return ref; +} + +static HRESULT WINAPI JScriptError_GetExceptionInfo(IActiveScriptError *iface, EXCEPINFO *excepinfo) +{ + JScriptError *This = impl_from_IActiveScriptError(iface); + + TRACE("(%p)->(%p)\n", This, excepinfo); + + if(!excepinfo) + return E_POINTER; + + memset(excepinfo, 0, sizeof(*excepinfo)); + excepinfo->scode = This->ei.error; + if(This->ei.source) + jsstr_to_bstr(This->ei.source, &excepinfo->bstrSource); + if(This->ei.message) + jsstr_to_bstr(This->ei.message, &excepinfo->bstrDescription); + return S_OK; +} + +static HRESULT WINAPI JScriptError_GetSourcePosition(IActiveScriptError *iface, DWORD *source_context, ULONG *line, LONG *character) +{ + JScriptError *This = impl_from_IActiveScriptError(iface); + bytecode_t *code = This->ei.code; + unsigned line_pos, char_pos; + + TRACE("(%p)->(%p %p %p)\n", This, source_context, line, character); + + if(!This->ei.code) { + FIXME("unknown position\n"); + return E_FAIL; + } + + if(source_context) + *source_context = This->ei.code->source_context; + if(!line && !character) + return S_OK; + + line_pos = get_location_line(code, This->ei.loc, &char_pos); + if(line) + *line = line_pos; + if(character) + *character = char_pos; + return S_OK; +} + +static HRESULT WINAPI JScriptError_GetSourceLineText(IActiveScriptError *iface, BSTR *source) +{ + JScriptError *This = impl_from_IActiveScriptError(iface); + + TRACE("(%p)->(%p)\n", This, source); + + if(!source) + return E_POINTER; + + if(!This->ei.line) { + *source = NULL; + return E_FAIL; + } + + return jsstr_to_bstr(This->ei.line, source); +} + +static const IActiveScriptErrorVtbl JScriptErrorVtbl = { + JScriptError_QueryInterface, + JScriptError_AddRef, + JScriptError_Release, + JScriptError_GetExceptionInfo, + JScriptError_GetSourcePosition, + JScriptError_GetSourceLineText +}; + +void reset_ei(jsexcept_t *ei) +{ + ei->error = S_OK; + if(ei->valid_value) { + jsval_release(ei->value); + ei->valid_value = FALSE; + } + if(ei->code) { + release_bytecode(ei->code); + ei->code = NULL; + ei->loc = 0; + } + if(ei->source) { + jsstr_release(ei->source); + ei->source = NULL; + } + if(ei->message) { + jsstr_release(ei->message); + ei->message = NULL; + } + if(ei->line) { + jsstr_release(ei->line); + ei->line = NULL; + } +} + +void enter_script(script_ctx_t *ctx, jsexcept_t *ei) +{ + memset(ei, 0, sizeof(*ei)); + ei->prev = ctx->ei; + ctx->ei = ei; + TRACE("ctx %p ei %p prev %p\n", ctx, ei, ei->prev); +} + +HRESULT leave_script(script_ctx_t *ctx, HRESULT result) +{ + jsexcept_t *ei = ctx->ei; + BOOL enter_notified = ei->enter_notified; + JScriptError *error; + + TRACE("ctx %p ei %p prev %p\n", ctx, ei, ei->prev); + + ctx->ei = ei->prev; + if(result == DISP_E_EXCEPTION) { + result = ei->error; + }else { + reset_ei(ei); + ei->error = result; + } + if(FAILED(result)) { + WARN("%08lx\n", result); + if(ctx->site && (error = malloc(sizeof(*error)))) { + HRESULT hres; + + error->IActiveScriptError_iface.lpVtbl = &JScriptErrorVtbl; + error->ref = 1; + error->ei = *ei; + memset(ei, 0, sizeof(*ei)); + + hres = IActiveScriptSite_OnScriptError(ctx->site, &error->IActiveScriptError_iface); + IActiveScriptError_Release(&error->IActiveScriptError_iface); + if(hres == S_OK) + result = SCRIPT_E_REPORTED; + } + } + if(enter_notified && ctx->site) + IActiveScriptSite_OnLeaveScript(ctx->site); + reset_ei(ei); + return result; } static void clear_script_queue(JScript *This) { - bytecode_t *iter, *iter2; - - if(!This->queue_head) - return; - - iter = This->queue_head; - while(iter) { - iter2 = iter->next; - iter->next = NULL; - release_bytecode(iter); - iter = iter2; + while(!list_empty(&This->queued_code)) + { + bytecode_t *iter = LIST_ENTRY(list_head(&This->queued_code), bytecode_t, entry); + list_remove(&iter->entry); + if (iter->is_persistent) + list_add_tail(&This->persistent_code, &iter->entry); + else + release_bytecode(iter); } +} - This->queue_head = This->queue_tail = NULL; +static void clear_persistent_code_list(JScript *This) +{ + while(!list_empty(&This->persistent_code)) + { + bytecode_t *iter = LIST_ENTRY(list_head(&This->persistent_code), bytecode_t, entry); + list_remove(&iter->entry); + release_bytecode(iter); + } +} + +static void release_persistent_script_objs(JScript *This) +{ + bytecode_t *iter; + + LIST_FOR_EACH_ENTRY(iter, &This->persistent_code, bytecode_t, entry) + if(iter->named_item) + release_named_item_script_obj(iter->named_item); +} + +static void release_named_item_list(JScript *This) +{ + while(!list_empty(&This->ctx->named_items)) { + named_item_t *iter = LIST_ENTRY(list_head(&This->ctx->named_items), named_item_t, entry); + list_remove(&iter->entry); + release_named_item(iter); + } +} + +static HRESULT exec_global_code(script_ctx_t *ctx, bytecode_t *code, jsval_t *r) +{ + IServiceProvider *prev_caller = ctx->jscaller->caller; + HRESULT hres; + + ctx->jscaller->caller = SP_CALLER_UNINITIALIZED; + hres = exec_source(ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, r); + ctx->jscaller->caller = prev_caller; + return hres; } static void exec_queued_code(JScript *This) { bytecode_t *iter; + jsexcept_t ei; + HRESULT hres = S_OK; - for(iter = This->queue_head; iter; iter = iter->next) - exec_global_code(This, iter); + LIST_FOR_EACH_ENTRY(iter, &This->queued_code, bytecode_t, entry) { + enter_script(This->ctx, &ei); + hres = exec_global_code(This->ctx, iter, NULL); + leave_script(This->ctx, hres); + if(FAILED(hres)) + break; + } clear_script_queue(This); } -static HRESULT set_ctx_site(JScript *This) -{ - HRESULT hres; - - This->ctx->lcid = This->lcid; - - hres = init_global(This->ctx); - if(FAILED(hres)) - return hres; - - IActiveScriptSite_AddRef(This->site); - This->ctx->site = This->site; - - change_state(This, SCRIPTSTATE_INITIALIZED); - return S_OK; -} - static void decrease_state(JScript *This, SCRIPTSTATE state) { + named_item_t *item, *item_next; + if(This->ctx) { switch(This->ctx->state) { case SCRIPTSTATE_CONNECTED: @@ -179,26 +472,22 @@ static void decrease_state(JScript *This, SCRIPTSTATE state) return; /* FALLTHROUGH */ case SCRIPTSTATE_INITIALIZED: - if(This->ctx->host_global) { - IDispatch_Release(This->ctx->host_global); - This->ctx->host_global = NULL; - } + clear_script_queue(This); + release_persistent_script_objs(This); - if(This->ctx->named_items) { - named_item_t *iter, *iter2; - - iter = This->ctx->named_items; - while(iter) { - iter2 = iter->next; - - if(iter->disp) - IDispatch_Release(iter->disp); - heap_free(iter->name); - heap_free(iter); - iter = iter2; + LIST_FOR_EACH_ENTRY_SAFE(item, item_next, &This->ctx->named_items, named_item_t, entry) + { + if(item->disp) + { + IDispatch_Release(item->disp); + item->disp = NULL; + } + release_named_item_script_obj(item); + if(!(item->flags & SCRIPTITEM_ISPERSISTENT)) + { + list_remove(&item->entry); + release_named_item(item); } - - This->ctx->named_items = NULL; } if(This->ctx->secmgr) { @@ -211,10 +500,9 @@ static void decrease_state(JScript *This, SCRIPTSTATE state) This->ctx->site = NULL; } - if(This->ctx->global) { - jsdisp_release(This->ctx->global); - This->ctx->global = NULL; - } + script_globals_release(This->ctx); + gc_run(This->ctx); + /* FALLTHROUGH */ case SCRIPTSTATE_UNINITIALIZED: change_state(This, state); @@ -231,8 +519,10 @@ static void decrease_state(JScript *This, SCRIPTSTATE state) FIXME("NULL ctx\n"); } - if(state == SCRIPTSTATE_UNINITIALIZED) - This->thread_id = 0; + if((state == SCRIPTSTATE_UNINITIALIZED || state == SCRIPTSTATE_CLOSED) && This->thread_data) { + release_thread_data(This->thread_data); + This->thread_data = NULL; + } if(This->site) { IActiveScriptSite_Release(This->site); @@ -278,7 +568,7 @@ static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface) AXSite *This = impl_from_IServiceProvider(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -288,14 +578,14 @@ static ULONG WINAPI AXSite_Release(IServiceProvider *iface) AXSite *This = impl_from_IServiceProvider(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { if(This->sp) IServiceProvider_Release(This->sp); - heap_free(This); + free(This); } return ref; @@ -329,10 +619,10 @@ IUnknown *create_ax_site(script_ctx_t *ctx) hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp); if(FAILED(hres)) { - TRACE("Could not get IServiceProvider iface: %08x\n", hres); + TRACE("Could not get IServiceProvider iface: %08lx\n", hres); } - ret = heap_alloc(sizeof(AXSite)); + ret = malloc(sizeof(AXSite)); if(!ret) { IServiceProvider_Release(sp); return NULL; @@ -380,6 +670,9 @@ static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid, }else if(IsEqualGUID(riid, &IID_IVariantChangeType)) { TRACE("(%p)->(IID_IVariantChangeType %p)\n", This, ppv); *ppv = &This->IVariantChangeType_iface; + }else if(IsEqualGUID(riid, &IID_IWineJScript)) { + TRACE("(%p)->(IID_IWineJScript %p)\n", This, ppv); + *ppv = &This->IWineJScript_iface; } if(*ppv) { @@ -396,7 +689,7 @@ static ULONG WINAPI JScript_AddRef(IActiveScript *iface) JScript *This = impl_from_IActiveScript(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -406,7 +699,7 @@ static ULONG WINAPI JScript_Release(IActiveScript *iface) JScript *This = impl_from_IActiveScript(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", iface, ref); + TRACE("(%p) ref=%ld\n", iface, ref); if(!ref) { if(This->ctx && This->ctx->state != SCRIPTSTATE_CLOSED) @@ -415,7 +708,9 @@ static ULONG WINAPI JScript_Release(IActiveScript *iface) This->ctx->active_script = NULL; script_release(This->ctx); } - heap_free(This); + if(This->thread_data) + release_thread_data(This->thread_data); + free(This); unlock_module(); } @@ -426,6 +721,8 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { JScript *This = impl_from_IActiveScript(iface); + struct thread_data *thread_data; + named_item_t *item; LCID lcid; HRESULT hres; @@ -437,8 +734,54 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, if(This->site) return E_UNEXPECTED; - if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0)) + if(!(thread_data = get_thread_data())) + return E_OUTOFMEMORY; + + if(InterlockedCompareExchangePointer((void**)&This->thread_data, thread_data, NULL)) { + release_thread_data(thread_data); return E_UNEXPECTED; + } + + if(!This->ctx) { + script_ctx_t *ctx = calloc(1, sizeof(script_ctx_t)); + if(!ctx) + return E_OUTOFMEMORY; + + ctx->ref = 1; + ctx->state = SCRIPTSTATE_UNINITIALIZED; + ctx->active_script = &This->IActiveScript_iface; + ctx->safeopt = This->safeopt; + ctx->version = This->version; + ctx->html_mode = This->html_mode; + ctx->acc = jsval_undefined(); + list_init(&ctx->named_items); + heap_pool_init(&ctx->tmp_heap); + + hres = create_jscaller(ctx); + if(FAILED(hres)) { + free(ctx); + return hres; + } + + thread_data->ref++; + ctx->thread_data = thread_data; + ctx->last_match = jsstr_empty(); + + This->ctx = ctx; + } + + /* Retrieve new dispatches for persistent named items */ + LIST_FOR_EACH_ENTRY(item, &This->ctx->named_items, named_item_t, entry) + { + if(!item->disp) + { + hres = retrieve_named_item_disp(pass, item); + if(FAILED(hres)) return hres; + } + + /* For some reason, CODEONLY flag is lost in re-initialized scripts */ + item->flags &= ~SCRIPTITEM_CODEONLY; + } This->site = pass; IActiveScriptSite_AddRef(This->site); @@ -447,7 +790,18 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, if(hres == S_OK) This->lcid = lcid; - return This->ctx ? set_ctx_site(This) : S_OK; + This->ctx->lcid = This->lcid; + + hres = init_global(This->ctx); + if(FAILED(hres)) + return hres; + + IActiveScriptSite_AddRef(This->site); + This->ctx->site = This->site; + + if(This->is_initialized) + change_state(This, SCRIPTSTATE_INITIALIZED); + return S_OK; } static HRESULT WINAPI JScript_GetScriptSite(IActiveScript *iface, REFIID riid, @@ -464,7 +818,7 @@ static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE s TRACE("(%p)->(%d)\n", This, ss); - if(This->thread_id && GetCurrentThreadId() != This->thread_id) + if(This->thread_data && This->thread_data->thread_id != GetCurrentThreadId()) return E_UNEXPECTED; if(ss == SCRIPTSTATE_UNINITIALIZED) { @@ -472,16 +826,17 @@ static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE s return E_UNEXPECTED; decrease_state(This, SCRIPTSTATE_UNINITIALIZED); + list_move_tail(&This->queued_code, &This->persistent_code); return S_OK; } - if(!This->ctx) + if(!This->is_initialized || !This->ctx) return E_UNEXPECTED; switch(ss) { case SCRIPTSTATE_STARTED: case SCRIPTSTATE_CONNECTED: /* FIXME */ - if(This->ctx->state == SCRIPTSTATE_CLOSED) + if(This->ctx->state == SCRIPTSTATE_UNINITIALIZED || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED; exec_queued_code(This); @@ -507,7 +862,7 @@ static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE * if(!pssState) return E_POINTER; - if(This->thread_id && This->thread_id != GetCurrentThreadId()) + if(This->thread_data && This->thread_data->thread_id != GetCurrentThreadId()) return E_UNEXPECTED; *pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED; @@ -520,10 +875,12 @@ static HRESULT WINAPI JScript_Close(IActiveScript *iface) TRACE("(%p)->()\n", This); - if(This->thread_id && This->thread_id != GetCurrentThreadId()) + if(This->thread_data && This->thread_data->thread_id != GetCurrentThreadId()) return E_UNEXPECTED; decrease_state(This, SCRIPTSTATE_CLOSED); + clear_persistent_code_list(This); + release_named_item_list(This); return S_OK; } @@ -535,9 +892,9 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, IDispatch *disp = NULL; HRESULT hres; - TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags); + TRACE("(%p)->(%s %lx)\n", This, debugstr_w(pstrName), dwFlags); - if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED) + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED; if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) { @@ -545,7 +902,7 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL); if(FAILED(hres)) { - WARN("GetItemInfo failed: %08x\n", hres); + WARN("GetItemInfo failed: %08lx\n", hres); return hres; } @@ -555,33 +912,28 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, WARN("object does not implement IDispatch\n"); return hres; } - - if(This->ctx->host_global) - IDispatch_Release(This->ctx->host_global); - IDispatch_AddRef(disp); - This->ctx->host_global = disp; } - item = heap_alloc(sizeof(*item)); + item = malloc(sizeof(*item)); if(!item) { if(disp) IDispatch_Release(disp); return E_OUTOFMEMORY; } + item->ref = 1; item->disp = disp; item->flags = dwFlags; - item->name = heap_strdupW(pstrName); + item->script_obj = NULL; + item->name = wcsdup(pstrName); if(!item->name) { if(disp) IDispatch_Release(disp); - heap_free(item); + free(item); return E_OUTOFMEMORY; } - item->next = This->ctx->named_items; - This->ctx->named_items = item; - + list_add_tail(&This->ctx->named_items, &item->entry); return S_OK; } @@ -597,18 +949,26 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR IDispatch **ppdisp) { JScript *This = impl_from_IActiveScript(iface); + jsdisp_t *script_obj; - TRACE("(%p)->(%p)\n", This, ppdisp); + TRACE("(%p)->(%s %p)\n", This, debugstr_w(pstrItemName), ppdisp); if(!ppdisp) return E_POINTER; - if(This->thread_id != GetCurrentThreadId() || !This->ctx->global) { + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || !This->ctx->global) { *ppdisp = NULL; return E_UNEXPECTED; } - *ppdisp = to_disp(This->ctx->global); + script_obj = This->ctx->global; + if(pstrItemName) { + named_item_t *item = lookup_named_item(This->ctx, pstrItemName, 0); + if(!item) return E_INVALIDARG; + if(item->script_obj) script_obj = item->script_obj; + } + + *ppdisp = to_disp(script_obj); IDispatch_AddRef(*ppdisp); return S_OK; } @@ -697,43 +1057,16 @@ static ULONG WINAPI JScriptParse_Release(IActiveScriptParse *iface) static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface) { JScript *This = impl_from_IActiveScriptParse(iface); - script_ctx_t *ctx; - HRESULT hres; TRACE("(%p)\n", This); - if(This->ctx) + if(This->is_initialized) return E_UNEXPECTED; + This->is_initialized = TRUE; - ctx = heap_alloc_zero(sizeof(script_ctx_t)); - if(!ctx) - return E_OUTOFMEMORY; - - ctx->ref = 1; - ctx->state = SCRIPTSTATE_UNINITIALIZED; - ctx->active_script = &This->IActiveScript_iface; - ctx->safeopt = This->safeopt; - ctx->version = This->version; - ctx->html_mode = This->html_mode; - ctx->ei.val = jsval_undefined(); - ctx->acc = jsval_undefined(); - heap_pool_init(&ctx->tmp_heap); - - hres = create_jscaller(ctx); - if(FAILED(hres)) { - heap_free(ctx); - return hres; - } - - ctx->last_match = jsstr_empty(); - - ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL); - if(ctx) { - script_release(ctx); - return E_UNEXPECTED; - } - - return This->site ? set_ctx_site(This) : S_OK; + if(This->site) + change_state(This, SCRIPTSTATE_INITIALIZED); + return S_OK; } static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface, @@ -743,7 +1076,7 @@ static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface, BSTR *pbstrName, EXCEPINFO *pexcepinfo) { JScript *This = impl_from_IActiveScriptParse(iface); - FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName), + FIXME("(%p)->(%s %s %s %s %s %s %s %lu %lx %p %p)\n", This, debugstr_w(pstrDefaultName), debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName), debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo); @@ -756,53 +1089,63 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface, DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo) { JScript *This = impl_from_IActiveScriptParse(iface); + named_item_t *item = NULL; bytecode_t *code; + jsexcept_t ei; HRESULT hres; - TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode), + TRACE("(%p)->(%s %s %p %s %s %lu %lx %p %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo); - if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED; - hres = compile_script(This->ctx, pstrCode, NULL, pstrDelimiter, (dwFlags & SCRIPTTEXT_ISEXPRESSION) != 0, - This->is_encode, &code); + if(pstrItemName) { + item = lookup_named_item(This->ctx, pstrItemName, 0); + if(!item) { + WARN("Unknown context %s\n", debugstr_w(pstrItemName)); + return E_INVALIDARG; + } + if(!item->script_obj) item = NULL; + } + + enter_script(This->ctx, &ei); + hres = compile_script(This->ctx, pstrCode, dwSourceContextCookie, ulStartingLine, NULL, pstrDelimiter, + (dwFlags & SCRIPTTEXT_ISEXPRESSION) != 0, This->is_encode, item, &code); if(FAILED(hres)) - return hres; + return leave_script(This->ctx, hres); if(dwFlags & SCRIPTTEXT_ISEXPRESSION) { jsval_t r; - IActiveScriptSite_OnEnterScript(This->site); - - clear_ei(This->ctx); - hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, &r); + hres = exec_global_code(This->ctx, code, &r); if(SUCCEEDED(hres)) { if(pvarResult) hres = jsval_to_variant(r, pvarResult); jsval_release(r); } - IActiveScriptSite_OnLeaveScript(This->site); - return hres; + return leave_script(This->ctx, hres); } + code->is_persistent = (dwFlags & SCRIPTTEXT_ISPERSISTENT) != 0; + /* * Although pvarResult is not really used without SCRIPTTEXT_ISEXPRESSION flag, if it's not NULL, * script is executed immediately, even if it's not in started state yet. */ if(!pvarResult && !is_started(This->ctx)) { - if(This->queue_tail) - This->queue_tail = This->queue_tail->next = code; + list_add_tail(&This->queued_code, &code->entry); + }else { + hres = exec_global_code(This->ctx, code, NULL); + if(code->is_persistent) + list_add_tail(&This->persistent_code, &code->entry); else - This->queue_head = This->queue_tail = code; - return S_OK; + release_bytecode(code); } - hres = exec_global_code(This, code); - release_bytecode(code); - if(FAILED(hres)) + if(FAILED(hres = leave_script(This->ctx, hres))) return hres; if(pvarResult) @@ -848,25 +1191,38 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp) { JScript *This = impl_from_IActiveScriptParseProcedure2(iface); + named_item_t *item = NULL; bytecode_t *code; jsdisp_t *dispex; + jsexcept_t ei; HRESULT hres; - TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams), + TRACE("(%p)->(%s %s %s %s %p %s %s %lu %lx %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams), debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp); - if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) + if(!This->thread_data || This->thread_data->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED) return E_UNEXPECTED; - hres = compile_script(This->ctx, pstrCode, pstrFormalParams, pstrDelimiter, FALSE, This->is_encode, &code); - if(FAILED(hres)) { - WARN("Parse failed %08x\n", hres); - return hres; + if(pstrItemName) { + item = lookup_named_item(This->ctx, pstrItemName, 0); + if(!item) { + WARN("Unknown context %s\n", debugstr_w(pstrItemName)); + return E_INVALIDARG; + } + if(!item->script_obj) item = NULL; } - hres = create_source_function(This->ctx, code, &code->global_code, NULL, &dispex); + enter_script(This->ctx, &ei); + hres = compile_script(This->ctx, pstrCode, dwSourceContextCookie, ulStartingLineNumber, pstrFormalParams, + pstrDelimiter, FALSE, This->is_encode, item, &code); + if(FAILED(hres)) + return leave_script(This->ctx, hres); + + hres = create_source_function(This->ctx, code, &code->global_code, NULL, &dispex); release_bytecode(code); + + hres = leave_script(This->ctx, hres); if(FAILED(hres)) return hres; @@ -908,7 +1264,7 @@ static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface, VARIANT *pvarIndex, VARIANT *pvarValue) { JScript *This = impl_from_IActiveScriptProperty(iface); - FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue); + FIXME("(%p)->(%lx %p %p)\n", This, dwProperty, pvarIndex, pvarValue); return E_NOTIMPL; } @@ -917,7 +1273,7 @@ static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, { JScript *This = impl_from_IActiveScriptProperty(iface); - TRACE("(%p)->(%x %s %s)\n", This, dwProperty, debugstr_variant(pvarIndex), debugstr_variant(pvarValue)); + TRACE("(%p)->(%lx %s %s)\n", This, dwProperty, debugstr_variant(pvarIndex), debugstr_variant(pvarValue)); if(pvarIndex) FIXME("unsupported pvarIndex\n"); @@ -934,7 +1290,7 @@ static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, This->html_mode = (V_I4(pvarValue) & SCRIPTLANGUAGEVERSION_HTML) != 0; break; default: - FIXME("Unimplemented property %x\n", dwProperty); + FIXME("Unimplemented property %lx\n", dwProperty); return E_NOTIMPL; } @@ -995,7 +1351,7 @@ static HRESULT WINAPI JScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *ifa { JScript *This = impl_from_IObjectSafety(iface); - TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions); + TRACE("(%p)->(%s %lx %lx)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions); if(dwOptionSetMask & ~SUPPORTED_OPTIONS) return E_FAIL; @@ -1038,17 +1394,20 @@ static ULONG WINAPI VariantChangeType_Release(IVariantChangeType *iface) static HRESULT WINAPI VariantChangeType_ChangeType(IVariantChangeType *iface, VARIANT *dst, VARIANT *src, LCID lcid, VARTYPE vt) { JScript *This = impl_from_IVariantChangeType(iface); + jsexcept_t ei; VARIANT res; HRESULT hres; - TRACE("(%p)->(%p %p%s %x %d)\n", This, dst, src, debugstr_variant(src), lcid, vt); + TRACE("(%p)->(%p %s %lx %s)\n", This, dst, debugstr_variant(src), lcid, debugstr_vt(vt)); if(!This->ctx) { FIXME("Object uninitialized\n"); return E_UNEXPECTED; } + enter_script(This->ctx, &ei); hres = variant_change_type(This->ctx, &res, src, vt); + hres = leave_script(This->ctx, hres); if(FAILED(hres)) return hres; @@ -1069,12 +1428,57 @@ static const IVariantChangeTypeVtbl VariantChangeTypeVtbl = { VariantChangeType_ChangeType }; +static inline JScript *impl_from_IWineJScript(IWineJScript *iface) +{ + return CONTAINING_RECORD(iface, JScript, IWineJScript_iface); +} + +static HRESULT WINAPI WineJScript_QueryInterface(IWineJScript *iface, REFIID riid, void **ppv) +{ + JScript *This = impl_from_IWineJScript(iface); + return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv); +} + +static ULONG WINAPI WineJScript_AddRef(IWineJScript *iface) +{ + JScript *This = impl_from_IWineJScript(iface); + return IActiveScript_AddRef(&This->IActiveScript_iface); +} + +static ULONG WINAPI WineJScript_Release(IWineJScript *iface) +{ + JScript *This = impl_from_IWineJScript(iface); + return IActiveScript_Release(&This->IActiveScript_iface); +} + +static HRESULT WINAPI WineJScript_InitHostObject(IWineJScript *iface, IWineJSDispatchHost *host_obj, + IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret) +{ + JScript *This = impl_from_IWineJScript(iface); + return init_host_object(This->ctx, host_obj, prototype, flags, ret); +} + +static HRESULT WINAPI WineJScript_InitHostConstructor(IWineJScript *iface, IWineJSDispatchHost *constr, + IWineJSDispatch *prototype, IWineJSDispatch **ret) +{ + JScript *This = impl_from_IWineJScript(iface); + return init_host_constructor(This->ctx, constr, prototype, ret); +} + +static const IWineJScriptVtbl WineJScriptVtbl = { + WineJScript_QueryInterface, + WineJScript_AddRef, + WineJScript_Release, + WineJScript_InitHostObject, + WineJScript_InitHostConstructor, +}; + HRESULT create_jscript_object(BOOL is_encode, REFIID riid, void **ppv) { JScript *ret; HRESULT hres; - ret = heap_alloc_zero(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; @@ -1086,9 +1490,12 @@ HRESULT create_jscript_object(BOOL is_encode, REFIID riid, void **ppv) ret->IActiveScriptProperty_iface.lpVtbl = &JScriptPropertyVtbl; ret->IObjectSafety_iface.lpVtbl = &JScriptSafetyVtbl; ret->IVariantChangeType_iface.lpVtbl = &VariantChangeTypeVtbl; + ret->IWineJScript_iface.lpVtbl = &WineJScriptVtbl; ret->ref = 1; ret->safeopt = INTERFACE_USES_DISPEX; ret->is_encode = is_encode; + list_init(&ret->persistent_code); + list_init(&ret->queued_code); hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv); IActiveScript_Release(&ret->IActiveScript_iface); diff --git a/dll/win32/jscript/jscript.h b/dll/win32/jscript/jscript.h index a16744776c5..113e301e912 100644 --- a/dll/win32/jscript/jscript.h +++ b/dll/win32/jscript/jscript.h @@ -28,16 +28,17 @@ #include "winbase.h" #include "winuser.h" #ifdef __REACTOS__ -#include "winnls.h" +#include #endif #include "ole2.h" #include "dispex.h" #include "activscp.h" +#include "jsdisp.h" #include "resource.h" -#include "wine/heap.h" #include "wine/list.h" +#include "wine/rbtree.h" /* * This is Wine jscript extension for ES5 compatible mode. Native IE9+ implements @@ -47,12 +48,14 @@ #define SCRIPTLANGUAGEVERSION_HTML 0x400 /* - * This is Wine jscript extension for ES5 compatible mode. Allowed only in HTML mode. + * This is Wine jscript extension for ES5 and ES6 compatible mode. Allowed only in HTML mode. */ #define SCRIPTLANGUAGEVERSION_ES5 0x102 +#define SCRIPTLANGUAGEVERSION_ES6 0x103 typedef struct _jsval_t jsval_t; typedef struct _jsstr_t jsstr_t; +typedef struct _jsexcept_t jsexcept_t; typedef struct _script_ctx_t script_ctx_t; typedef struct _dispex_prop_t dispex_prop_t; typedef struct _property_desc_t property_desc_t; @@ -66,46 +69,26 @@ typedef struct { struct list custom_blocks; } heap_pool_t; -void heap_pool_init(heap_pool_t*) DECLSPEC_HIDDEN; -void *heap_pool_alloc(heap_pool_t*,DWORD) __WINE_ALLOC_SIZE(2) DECLSPEC_HIDDEN; -void *heap_pool_grow(heap_pool_t*,void*,DWORD,DWORD) DECLSPEC_HIDDEN; -void heap_pool_clear(heap_pool_t*) DECLSPEC_HIDDEN; -void heap_pool_free(heap_pool_t*) DECLSPEC_HIDDEN; -heap_pool_t *heap_pool_mark(heap_pool_t*) DECLSPEC_HIDDEN; - -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (lstrlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} +void heap_pool_init(heap_pool_t*); +void *heap_pool_alloc(heap_pool_t*,DWORD) __WINE_ALLOC_SIZE(2); +void *heap_pool_grow(heap_pool_t*,void*,DWORD,DWORD); +void heap_pool_clear(heap_pool_t*); +void heap_pool_free(heap_pool_t*); +heap_pool_t *heap_pool_mark(heap_pool_t*); typedef struct jsdisp_t jsdisp_t; -extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN; +extern HINSTANCE jscript_hinstance ; +HRESULT get_dispatch_typeinfo(ITypeInfo**); -#define PROPF_ARGMASK 0x00ff -#define PROPF_METHOD 0x0100 -#define PROPF_CONSTR 0x0200 - -#define PROPF_ENUMERABLE 0x0400 -#define PROPF_WRITABLE 0x0800 -#define PROPF_CONFIGURABLE 0x1000 #define PROPF_ALL (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE) +#define PROPF_ARGMASK 0x000000ff #define PROPF_VERSION_MASK 0x01ff0000 #define PROPF_VERSION_SHIFT 16 #define PROPF_HTML (SCRIPTLANGUAGEVERSION_HTML << PROPF_VERSION_SHIFT) #define PROPF_ES5 ((SCRIPTLANGUAGEVERSION_HTML|SCRIPTLANGUAGEVERSION_ES5) << PROPF_VERSION_SHIFT) +#define PROPF_ES6 ((SCRIPTLANGUAGEVERSION_HTML|SCRIPTLANGUAGEVERSION_ES6) << PROPF_VERSION_SHIFT) /* * This is our internal dispatch flag informing calee that it's called directly from interpreter. @@ -132,80 +115,61 @@ typedef enum { JSCLASS_STRING, JSCLASS_ARGUMENTS, JSCLASS_VBARRAY, - JSCLASS_JSON + JSCLASS_JSON, + JSCLASS_ARRAYBUFFER, + JSCLASS_DATAVIEW, + JSCLASS_MAP, + JSCLASS_SET, + JSCLASS_WEAKMAP, + JSCLASS_HOST, } jsclass_t; -jsdisp_t *iface_to_jsdisp(IDispatch*) DECLSPEC_HIDDEN; +jsdisp_t *iface_to_jsdisp(IDispatch*); -typedef struct { - union { - IDispatch *disp; - IDispatchEx *dispex; - jsdisp_t *jsdisp; - } u; - DWORD flags; -} vdisp_t; - -#define VDISP_DISPEX 0x0001 -#define VDISP_JSDISP 0x0002 - -static inline void vdisp_release(vdisp_t *vdisp) -{ - IDispatch_Release(vdisp->u.disp); -} - -static inline BOOL is_jsdisp(vdisp_t *vdisp) -{ - return (vdisp->flags & VDISP_JSDISP) != 0; -} - -static inline BOOL is_dispex(vdisp_t *vdisp) -{ - return (vdisp->flags & VDISP_DISPEX) != 0; -} - -static inline void set_jsdisp(vdisp_t *vdisp, jsdisp_t *jsdisp) -{ - vdisp->u.jsdisp = jsdisp; - vdisp->flags = VDISP_JSDISP | VDISP_DISPEX; - IDispatch_AddRef(vdisp->u.disp); -} - -static inline void set_disp(vdisp_t *vdisp, IDispatch *disp) -{ - IDispatchEx *dispex; - jsdisp_t *jsdisp; - HRESULT hres; - - jsdisp = iface_to_jsdisp(disp); - if(jsdisp) { - vdisp->u.jsdisp = jsdisp; - vdisp->flags = VDISP_JSDISP | VDISP_DISPEX; - return; - } - - hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); - if(SUCCEEDED(hres)) { - vdisp->u.dispex = dispex; - vdisp->flags = VDISP_DISPEX; - return; - } - - IDispatch_AddRef(disp); - vdisp->u.disp = disp; - vdisp->flags = 0; -} - -static inline jsdisp_t *get_jsdisp(vdisp_t *vdisp) -{ - return is_jsdisp(vdisp) ? vdisp->u.jsdisp : NULL; -} - -typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*); +typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); typedef HRESULT (*builtin_getter_t)(script_ctx_t*,jsdisp_t*,jsval_t*); typedef HRESULT (*builtin_setter_t)(script_ctx_t*,jsdisp_t*,jsval_t); -HRESULT builtin_set_const(script_ctx_t*,jsdisp_t*,jsval_t) DECLSPEC_HIDDEN; +HRESULT builtin_set_const(script_ctx_t*,jsdisp_t*,jsval_t); + +struct thread_data { + LONG ref; + LONG thread_id; + + BOOL gc_is_unlinking; + DWORD gc_last_tick; + + struct list objects; + struct rb_tree weak_refs; +}; + +struct thread_data *get_thread_data(void); +void release_thread_data(struct thread_data*); + +typedef struct named_item_t { + jsdisp_t *script_obj; + IDispatch *disp; + unsigned ref; + DWORD flags; + LPWSTR name; + + struct list entry; +} named_item_t; + +struct gc_ctx; + +enum gc_traverse_op { + GC_TRAVERSE_UNLINK, + GC_TRAVERSE_SPECULATIVELY, + GC_TRAVERSE +}; + +HRESULT create_named_item_script_obj(script_ctx_t*,named_item_t*); +named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned); +void release_named_item(named_item_t*); +HRESULT gc_run(script_ctx_t*); +HRESULT gc_process_linked_obj(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*,jsdisp_t*,void**); +HRESULT gc_process_linked_val(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*,jsval_t*); typedef struct { const WCHAR *name; @@ -217,21 +181,33 @@ typedef struct { typedef struct { jsclass_t class; - builtin_prop_t value_prop; + builtin_invoke_t call; DWORD props_cnt; const builtin_prop_t *props; void (*destructor)(jsdisp_t*); + ULONG (*addref)(jsdisp_t*); + ULONG (*release)(jsdisp_t*); void (*on_put)(jsdisp_t*,const WCHAR*); - unsigned (*idx_length)(jsdisp_t*); - HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*); - HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t); + HRESULT (*lookup_prop)(jsdisp_t*,const WCHAR*,unsigned,struct property_info*); + HRESULT (*next_prop)(jsdisp_t*,unsigned,struct property_info*); + HRESULT (*prop_get)(jsdisp_t*,unsigned,jsval_t*); + HRESULT (*prop_put)(jsdisp_t*,unsigned,jsval_t); + HRESULT (*prop_delete)(jsdisp_t*,unsigned); + HRESULT (*prop_config)(jsdisp_t*,unsigned,unsigned); + HRESULT (*to_string)(jsdisp_t*,jsstr_t**); + HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*); } builtin_info_t; struct jsdisp_t { - IDispatchEx IDispatchEx_iface; + IWineJSDispatch IWineJSDispatch_iface; LONG ref; + BOOLEAN has_weak_refs; + BOOLEAN extensible; + BOOLEAN gc_marked; + BOOLEAN is_constructor; + DWORD buf_size; DWORD prop_cnt; dispex_prop_t *props; @@ -240,99 +216,94 @@ struct jsdisp_t { jsdisp_t *prototype; const builtin_info_t *builtin_info; + struct list entry; }; static inline IDispatch *to_disp(jsdisp_t *jsdisp) { - return (IDispatch*)&jsdisp->IDispatchEx_iface; + return (IDispatch *)&jsdisp->IWineJSDispatch_iface; } -jsdisp_t *as_jsdisp(IDispatch*) DECLSPEC_HIDDEN; -jsdisp_t *to_jsdisp(IDispatch*) DECLSPEC_HIDDEN; -void jsdisp_free(jsdisp_t*) DECLSPEC_HIDDEN; - -#ifndef TRACE_REFCNT - -/* - * We do a lot of refcount calls during script execution, so having an inline - * version is a nice perf win. Define TRACE_REFCNT macro when debugging - * refcount bugs to have traces. Also, since jsdisp_t is not thread safe anyways, - * there is no point in using atomic operations. - */ -static inline jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp) +static inline IDispatchEx *to_dispex(jsdisp_t *jsdisp) { - jsdisp->ref++; - return jsdisp; + return (IDispatchEx *)&jsdisp->IWineJSDispatch_iface; } -static inline void jsdisp_release(jsdisp_t *jsdisp) -{ - if(!--jsdisp->ref) - jsdisp_free(jsdisp); -} +jsdisp_t *as_jsdisp(IDispatch*); +jsdisp_t *to_jsdisp(IDispatch*); +IWineJSDispatchHost *get_host_dispatch(IDispatch*); -#else +jsdisp_t *jsdisp_addref(jsdisp_t*); +ULONG jsdisp_release(jsdisp_t*); -jsdisp_t *jsdisp_addref(jsdisp_t*) DECLSPEC_HIDDEN; -void jsdisp_release(jsdisp_t*) DECLSPEC_HIDDEN; +enum jsdisp_enum_type { + JSDISP_ENUM_ALL, + JSDISP_ENUM_OWN, + JSDISP_ENUM_OWN_ENUMERABLE +}; -#endif +HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**); +HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); +HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); +HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,UINT32,IWineJSDispatch**); +HRESULT init_host_constructor(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch**); -HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; -HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; - -HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT disp_call_value(script_ctx_t*,IDispatch*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_call_value(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,jsval_t*) DECLSPEC_HIDDEN; -HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,jsval_t) DECLSPEC_HIDDEN; -HRESULT jsdisp_propget(jsdisp_t*,DISPID,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_propput(jsdisp_t*,const WCHAR*,DWORD,jsval_t) DECLSPEC_HIDDEN; -HRESULT jsdisp_propput_name(jsdisp_t*,const WCHAR*,jsval_t) DECLSPEC_HIDDEN; -HRESULT jsdisp_propput_idx(jsdisp_t*,DWORD,jsval_t) DECLSPEC_HIDDEN; -HRESULT jsdisp_propget_name(jsdisp_t*,LPCWSTR,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_get_idx(jsdisp_t*,DWORD,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*) DECLSPEC_HIDDEN; -HRESULT disp_delete(IDispatch*,DISPID,BOOL*) DECLSPEC_HIDDEN; -HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*) DECLSPEC_HIDDEN; -HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD) DECLSPEC_HIDDEN; -HRESULT jsdisp_get_own_property(jsdisp_t*,const WCHAR*,BOOL,property_desc_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_define_property(jsdisp_t*,const WCHAR*,property_desc_t*) DECLSPEC_HIDDEN; -HRESULT jsdisp_define_data_property(jsdisp_t*,const WCHAR*,unsigned,jsval_t) DECLSPEC_HIDDEN; -HRESULT jsdisp_next_prop(jsdisp_t*,DISPID,BOOL,DISPID*) DECLSPEC_HIDDEN; +HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT disp_call_value_with_caller(script_ctx_t*,IDispatch*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); +HRESULT jsdisp_call_value(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,jsval_t*); +HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,jsval_t); +HRESULT disp_propput_name(script_ctx_t*,IDispatch*,const WCHAR*,jsval_t); +HRESULT jsdisp_propget(jsdisp_t*,DISPID,jsval_t*); +HRESULT jsdisp_propput(jsdisp_t*,const WCHAR*,DWORD,BOOL,jsval_t); +HRESULT jsdisp_propput_name(jsdisp_t*,const WCHAR*,jsval_t); +HRESULT jsdisp_propput_idx(jsdisp_t*,DWORD,jsval_t); +HRESULT jsdisp_propget_name(jsdisp_t*,LPCWSTR,jsval_t*); +HRESULT jsdisp_get_idx(jsdisp_t*,DWORD,jsval_t*); +HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*); +HRESULT jsdisp_get_idx_id(jsdisp_t*,DWORD,DISPID*); +HRESULT disp_delete(IDispatch*,DISPID,BOOL*); +HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*); +HRESULT jsdisp_index_lookup(jsdisp_t*,const WCHAR*,unsigned,struct property_info*); +HRESULT jsdisp_next_index(jsdisp_t*,unsigned,unsigned,struct property_info*); +HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD); +HRESULT jsdisp_get_own_property(jsdisp_t*,const WCHAR*,BOOL,property_desc_t*); +HRESULT jsdisp_define_property(jsdisp_t*,const WCHAR*,property_desc_t*); +HRESULT jsdisp_define_data_property(jsdisp_t*,const WCHAR*,unsigned,jsval_t); +HRESULT jsdisp_next_prop(jsdisp_t*,DISPID,enum jsdisp_enum_type,DISPID*); +HRESULT jsdisp_get_prop_name(jsdisp_t*,DISPID,jsstr_t**); +HRESULT jsdisp_change_prototype(jsdisp_t*,jsdisp_t*); +void jsdisp_freeze(jsdisp_t*,BOOL); +BOOL jsdisp_is_frozen(jsdisp_t*,BOOL); HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, - jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; + jsdisp_t*,jsdisp_t**); HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, - jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; + jsdisp_t*,jsdisp_t**); +HRESULT create_host_function(script_ctx_t*,const struct property_info*,DWORD,jsdisp_t**); +HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); -HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT Function_get_value(script_ctx_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN; -#define DEFAULT_FUNCTION_VALUE {NULL, Function_value,0, Function_get_value} +HRESULT Function_value(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT Function_get_value(script_ctx_t*,jsdisp_t*,jsval_t*); +struct _function_code_t *Function_get_code(jsdisp_t*); -HRESULT throw_eval_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_generic_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_range_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_reference_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_regexp_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_syntax_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_type_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -HRESULT throw_uri_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; +HRESULT throw_error(script_ctx_t*,HRESULT,const WCHAR*); +jsdisp_t *create_builtin_error(script_ctx_t *ctx); +void handle_dispatch_exception(script_ctx_t *ctx, EXCEPINFO *ei); -HRESULT create_object(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_math(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_array(script_ctx_t*,DWORD,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_regexp(script_ctx_t*,jsstr_t*,DWORD,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_regexp_var(script_ctx_t*,jsval_t,jsval_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_string(script_ctx_t*,jsstr_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_bool(script_ctx_t*,BOOL,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_number(script_ctx_t*,double,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_vbarray(script_ctx_t*,SAFEARRAY*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_json(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; +HRESULT create_object(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_math(script_ctx_t*,jsdisp_t**); +HRESULT create_array(script_ctx_t*,DWORD,jsdisp_t**); +HRESULT create_regexp(script_ctx_t*,jsstr_t*,DWORD,jsdisp_t**); +HRESULT create_regexp_var(script_ctx_t*,jsval_t,jsval_t*,jsdisp_t**); +HRESULT create_string(script_ctx_t*,jsstr_t*,jsdisp_t**); +HRESULT create_bool(script_ctx_t*,BOOL,jsdisp_t**); +HRESULT create_number(script_ctx_t*,double,jsdisp_t**); +HRESULT create_vbarray(script_ctx_t*,SAFEARRAY*,jsdisp_t**); +HRESULT create_json(script_ctx_t*,jsdisp_t**); typedef enum { NO_HINT, @@ -340,32 +311,32 @@ typedef enum { HINT_NUMBER } hint_t; -HRESULT to_primitive(script_ctx_t*,jsval_t,jsval_t*, hint_t) DECLSPEC_HIDDEN; -HRESULT to_boolean(jsval_t,BOOL*) DECLSPEC_HIDDEN; -HRESULT to_number(script_ctx_t*,jsval_t,double*) DECLSPEC_HIDDEN; -HRESULT to_integer(script_ctx_t*,jsval_t,double*) DECLSPEC_HIDDEN; -HRESULT to_int32(script_ctx_t*,jsval_t,INT*) DECLSPEC_HIDDEN; -HRESULT to_uint32(script_ctx_t*,jsval_t,UINT32*) DECLSPEC_HIDDEN; -HRESULT to_string(script_ctx_t*,jsval_t,jsstr_t**) DECLSPEC_HIDDEN; -HRESULT to_flat_string(script_ctx_t*,jsval_t,jsstr_t**,const WCHAR**) DECLSPEC_HIDDEN; -HRESULT to_object(script_ctx_t*,jsval_t,IDispatch**) DECLSPEC_HIDDEN; +HRESULT to_primitive(script_ctx_t*,jsval_t,jsval_t*, hint_t); +HRESULT to_boolean(jsval_t,BOOL*); +HRESULT to_number(script_ctx_t*,jsval_t,double*); +HRESULT to_integer(script_ctx_t*,jsval_t,double*); +HRESULT to_int32(script_ctx_t*,jsval_t,INT*); +HRESULT to_long(script_ctx_t*,jsval_t,LONG*); +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**); -HRESULT jsval_strict_equal(jsval_t,jsval_t,BOOL*) DECLSPEC_HIDDEN; +HRESULT jsval_strict_equal(jsval_t,jsval_t,BOOL*); -HRESULT variant_change_type(script_ctx_t*,VARIANT*,VARIANT*,VARTYPE) DECLSPEC_HIDDEN; +HRESULT variant_change_type(script_ctx_t*,VARIANT*,VARIANT*,VARTYPE); +HRESULT variant_date_to_number(double,double*); +HRESULT variant_date_to_string(script_ctx_t*,double,jsstr_t**); -HRESULT decode_source(WCHAR*) DECLSPEC_HIDDEN; +HRESULT decode_source(WCHAR*); -HRESULT double_to_string(double,jsstr_t**) DECLSPEC_HIDDEN; -BOOL is_finite(double) DECLSPEC_HIDDEN; +HRESULT double_to_string(double,jsstr_t**); +WCHAR *idx_to_str(DWORD,WCHAR*); -typedef struct named_item_t { - IDispatch *disp; - DWORD flags; - LPWSTR name; - - struct named_item_t *next; -} named_item_t; +static inline BOOL is_digit(WCHAR c) +{ + return '0' <= c && c <= '9'; +} typedef struct _cc_var_t cc_var_t; @@ -373,7 +344,9 @@ typedef struct { cc_var_t *vars; } cc_ctx_t; -void release_cc(cc_ctx_t*) DECLSPEC_HIDDEN; +void release_cc(cc_ctx_t*); + +#define SP_CALLER_UNINITIALIZED ((IServiceProvider*)IntToPtr(-1)) typedef struct { IServiceProvider IServiceProvider_iface; @@ -381,6 +354,7 @@ typedef struct { LONG ref; script_ctx_t *ctx; + IServiceProvider *caller; } JSCaller; #include "jsval.h" @@ -396,24 +370,25 @@ struct _property_desc_t { jsdisp_t *setter; }; -typedef struct { - EXCEPINFO ei; - jsval_t val; -} jsexcept_t; - typedef struct { unsigned index; unsigned length; } match_result_t; +struct weak_refs_entry { + struct rb_entry entry; + struct list list; +}; + struct _script_ctx_t { LONG ref; SCRIPTSTATE state; IActiveScript *active_script; + struct thread_data *thread_data; struct _call_frame_t *call_ctx; - named_item_t *named_items; + struct list named_items; IActiveScriptSite *site; IInternetHostSecurityManager *secmgr; DWORD safeopt; @@ -422,14 +397,11 @@ struct _script_ctx_t { LCID lcid; cc_ctx_t *cc; JSCaller *jscaller; - jsexcept_t ei; + jsexcept_t *ei; heap_pool_t tmp_heap; - IDispatch *host_global; - jsval_t *stack; - unsigned stack_size; unsigned stack_top; jsval_t acc; @@ -438,53 +410,75 @@ struct _script_ctx_t { DWORD last_match_index; DWORD last_match_length; - jsdisp_t *global; - jsdisp_t *function_constr; - jsdisp_t *array_constr; - jsdisp_t *bool_constr; - jsdisp_t *date_constr; - jsdisp_t *enumerator_constr; - jsdisp_t *error_constr; - jsdisp_t *eval_error_constr; - jsdisp_t *range_error_constr; - jsdisp_t *reference_error_constr; - jsdisp_t *regexp_error_constr; - jsdisp_t *syntax_error_constr; - jsdisp_t *type_error_constr; - jsdisp_t *uri_error_constr; - jsdisp_t *number_constr; - jsdisp_t *object_constr; - jsdisp_t *regexp_constr; - jsdisp_t *string_constr; - jsdisp_t *vbarray_constr; + union { + struct { + jsdisp_t *global; + jsdisp_t *function_constr; + jsdisp_t *array_constr; + jsdisp_t *bool_constr; + jsdisp_t *date_constr; + jsdisp_t *enumerator_constr; + jsdisp_t *error_constr; + jsdisp_t *eval_error_constr; + jsdisp_t *range_error_constr; + jsdisp_t *reference_error_constr; + jsdisp_t *regexp_error_constr; + jsdisp_t *syntax_error_constr; + jsdisp_t *type_error_constr; + jsdisp_t *uri_error_constr; + jsdisp_t *number_constr; + jsdisp_t *object_constr; + jsdisp_t *object_prototype; + jsdisp_t *regexp_constr; + jsdisp_t *string_constr; + jsdisp_t *vbarray_constr; + jsdisp_t *arraybuf_constr; + jsdisp_t *dataview_constr; + jsdisp_t *map_prototype; + jsdisp_t *set_prototype; + jsdisp_t *weakmap_prototype; + }; + jsdisp_t *global_objects[25]; + }; }; +C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); -void script_release(script_ctx_t*) DECLSPEC_HIDDEN; -void clear_ei(script_ctx_t*) DECLSPEC_HIDDEN; +struct weakmap_entry { + struct rb_entry entry; + jsdisp_t *key; + jsval_t value; + jsdisp_t *weakmap; + struct list weak_refs_entry; +}; +void remove_weakmap_entry(struct weakmap_entry*); + +void script_release(script_ctx_t*); static inline void script_addref(script_ctx_t *ctx) { ctx->ref++; } -HRESULT init_global(script_ctx_t*) DECLSPEC_HIDDEN; -HRESULT init_function_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN; -HRESULT create_object_prototype(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; +HRESULT init_global(script_ctx_t*); +HRESULT init_function_constr(script_ctx_t*,jsdisp_t*); +HRESULT create_object_prototype(script_ctx_t*,jsdisp_t**); +HRESULT init_set_constructor(script_ctx_t*); +HRESULT init_arraybuf_constructors(script_ctx_t*); -HRESULT create_activex_constr(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_bool_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_date_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT init_error_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN; -HRESULT create_enumerator_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_number_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_object_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_regexp_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_string_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT create_vbarray_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; +HRESULT create_activex_constr(script_ctx_t*,jsdisp_t**); +HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_bool_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_date_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT init_error_constr(script_ctx_t*,jsdisp_t*); +HRESULT create_enumerator_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_number_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_object_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_regexp_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_string_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); +HRESULT create_vbarray_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**); -IUnknown *create_ax_site(script_ctx_t*) DECLSPEC_HIDDEN; -HRESULT create_jscaller(script_ctx_t*) DECLSPEC_HIDDEN; +IUnknown *create_ax_site(script_ctx_t*); +HRESULT create_jscaller(script_ctx_t*); #define REM_CHECK_GLOBAL 0x0001 #define REM_RESET_INDEX 0x0002 @@ -492,25 +486,25 @@ HRESULT create_jscaller(script_ctx_t*) DECLSPEC_HIDDEN; #define REM_ALLOC_RESULT 0x0008 #define REM_NO_PARENS 0x0010 struct match_state_t; -HRESULT regexp_match_next(script_ctx_t*,jsdisp_t*,DWORD,jsstr_t*,struct match_state_t**) DECLSPEC_HIDDEN; -HRESULT parse_regexp_flags(const WCHAR*,DWORD,DWORD*) DECLSPEC_HIDDEN; -HRESULT regexp_string_match(script_ctx_t*,jsdisp_t*,jsstr_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT regexp_match_next(script_ctx_t*,jsdisp_t*,DWORD,jsstr_t*,struct match_state_t**); +HRESULT parse_regexp_flags(const WCHAR*,DWORD,DWORD*); +HRESULT regexp_string_match(script_ctx_t*,jsdisp_t*,jsstr_t*,jsval_t*); -BOOL bool_obj_value(jsdisp_t*) DECLSPEC_HIDDEN; -unsigned array_get_length(jsdisp_t*) DECLSPEC_HIDDEN; +BOOL bool_obj_value(jsdisp_t*); +unsigned array_get_length(jsdisp_t*); +HRESULT localize_number(script_ctx_t*,DOUBLE,BOOL,jsstr_t**); -HRESULT JSGlobal_eval(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; +BOOL is_builtin_eval_func(jsdisp_t*); +HRESULT builtin_eval(script_ctx_t*,struct _call_frame_t*,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT JSGlobal_eval(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT Object_get_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT Object_set_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); static inline BOOL is_class(jsdisp_t *jsdisp, jsclass_t class) { return jsdisp->builtin_info->class == class; } -static inline BOOL is_vclass(vdisp_t *vdisp, jsclass_t class) -{ - return is_jsdisp(vdisp) && is_class(vdisp->u.jsdisp, class); -} - static inline BOOL is_int32(double d) { return INT32_MIN <= d && d <= INT32_MAX && (double)(int)d == d; @@ -521,16 +515,24 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) return ((ctx->version & 0xff) << 28) | flags; } -#define MAKE_JSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_JSCRIPT, code) +static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_t vthis, WORD flags, unsigned argc, + jsval_t *argv, jsval_t *r) +{ + return disp_call_value_with_caller(ctx, disp, vthis, flags, argc, argv, r, &ctx->jscaller->IServiceProvider_iface); +} + +#define MAKE_JSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, code) #define JS_E_TO_PRIMITIVE MAKE_JSERROR(IDS_TO_PRIMITIVE) #define JS_E_INVALIDARG MAKE_JSERROR(IDS_INVALID_CALL_ARG) #define JS_E_SUBSCRIPT_OUT_OF_RANGE MAKE_JSERROR(IDS_SUBSCRIPT_OUT_OF_RANGE) +#define JS_E_STACK_OVERFLOW MAKE_JSERROR(IDS_STACK_OVERFLOW) #define JS_E_OBJECT_REQUIRED MAKE_JSERROR(IDS_OBJECT_REQUIRED) #define JS_E_CANNOT_CREATE_OBJ MAKE_JSERROR(IDS_CREATE_OBJ_ERROR) #define JS_E_INVALID_PROPERTY MAKE_JSERROR(IDS_NO_PROPERTY) #define JS_E_INVALID_ACTION MAKE_JSERROR(IDS_UNSUPPORTED_ACTION) #define JS_E_MISSING_ARG MAKE_JSERROR(IDS_ARG_NOT_OPT) +#define JS_E_OBJECT_NOT_COLLECTION MAKE_JSERROR(IDS_OBJECT_NOT_COLLECTION) #define JS_E_SYNTAX MAKE_JSERROR(IDS_SYNTAX_ERROR) #define JS_E_MISSING_SEMICOLON MAKE_JSERROR(IDS_SEMICOLON) #define JS_E_MISSING_LBRACKET MAKE_JSERROR(IDS_LBRACKET) @@ -557,29 +559,42 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_VBARRAY_EXPECTED MAKE_JSERROR(IDS_NOT_VBARRAY) #define JS_E_INVALID_DELETE MAKE_JSERROR(IDS_INVALID_DELETE) #define JS_E_JSCRIPT_EXPECTED MAKE_JSERROR(IDS_JSCRIPT_EXPECTED) -#define JS_E_ENUMERATOR_EXPECTED MAKE_JSERROR(IDS_NOT_ENUMERATOR) +#define JS_E_ENUMERATOR_EXPECTED MAKE_JSERROR(IDS_ENUMERATOR_EXPECTED) +#define JS_E_REGEXP_EXPECTED MAKE_JSERROR(IDS_REGEXP_EXPECTED) #define JS_E_REGEXP_SYNTAX MAKE_JSERROR(IDS_REGEXP_SYNTAX_ERROR) +#define JS_E_UNEXPECTED_QUANTIFIER MAKE_JSERROR(IDS_UNEXPECTED_QUANTIFIER) +#define JS_E_EXCEPTION_THROWN MAKE_JSERROR(IDS_EXCEPTION_THROWN) #define JS_E_INVALID_URI_CODING MAKE_JSERROR(IDS_URI_INVALID_CODING) #define JS_E_INVALID_URI_CHAR MAKE_JSERROR(IDS_URI_INVALID_CHAR) #define JS_E_FRACTION_DIGITS_OUT_OF_RANGE MAKE_JSERROR(IDS_FRACTION_DIGITS_OUT_OF_RANGE) #define JS_E_PRECISION_OUT_OF_RANGE MAKE_JSERROR(IDS_PRECISION_OUT_OF_RANGE) #define JS_E_INVALID_LENGTH MAKE_JSERROR(IDS_INVALID_LENGTH) #define JS_E_ARRAY_EXPECTED MAKE_JSERROR(IDS_ARRAY_EXPECTED) +#define JS_E_CYCLIC_PROTO_VALUE MAKE_JSERROR(IDS_CYCLIC_PROTO_VALUE) +#define JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE MAKE_JSERROR(IDS_CREATE_FOR_NONEXTENSIBLE) +#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_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) +#define JS_E_DATAVIEW_INVALID_OFFSET MAKE_JSERROR(IDS_DATAVIEW_INVALID_OFFSET) +#define JS_E_WRONG_THIS MAKE_JSERROR(IDS_WRONG_THIS) +#define JS_E_KEY_NOT_OBJECT MAKE_JSERROR(IDS_KEY_NOT_OBJECT) +#define JS_E_ARRAYBUFFER_EXPECTED MAKE_JSERROR(IDS_ARRAYBUFFER_EXPECTED) #define JS_E_PROP_DESC_MISMATCH MAKE_JSERROR(IDS_PROP_DESC_MISMATCH) #define JS_E_INVALID_WRITABLE_PROP_DESC MAKE_JSERROR(IDS_INVALID_WRITABLE_PROP_DESC) static inline BOOL is_jscript_error(HRESULT hres) { - return HRESULT_FACILITY(hres) == FACILITY_JSCRIPT; + return HRESULT_FACILITY(hres) == FACILITY_CONTROL; } -const char *debugstr_jsval(const jsval_t) DECLSPEC_HIDDEN; +const char *debugstr_jsval(const jsval_t); -HRESULT create_jscript_object(BOOL,REFIID,void**) DECLSPEC_HIDDEN; +HRESULT create_jscript_object(BOOL,REFIID,void**); -extern LONG module_ref DECLSPEC_HIDDEN; +extern LONG module_ref ; static inline void lock_module(void) { diff --git a/dll/win32/jscript/jscript_classes.rgs b/dll/win32/jscript/jscript_classes.rgs deleted file mode 100644 index ae671fcd273..00000000000 --- a/dll/win32/jscript/jscript_classes.rgs +++ /dev/null @@ -1,36 +0,0 @@ -HKCR -{ - NoRemove Interface - { - } - NoRemove CLSID - { - '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}' = s 'JScript Language' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } - ProgId = s 'JScript' - } - '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}' = s 'JScript Language Authoring' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } - ProgId = s 'JScript Author' - } - '{F414C262-6AC0-11CF-B6D1-00AA00BBBB58}' = s 'JScript Language Encoding' - { - InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } - ProgId = s 'JScript.Encode' - } - } - 'JScript' = s 'JScript Language' - { - CLSID = s '{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}' - } - 'JScript Author' = s 'JScript Language Authoring' - { - CLSID = s '{F414C261-6AC0-11CF-B6D1-00AA00BBBB58}' - } - 'JScript.Encode' = s 'JScript Language Encoding' - { - CLSID = s '{F414C262-6AC0-11CF-B6D1-00AA00BBBB58}' - } -} diff --git a/dll/win32/jscript/jscript_main.c b/dll/win32/jscript/jscript_main.c index 9f9f4121f7f..6ccab362051 100644 --- a/dll/win32/jscript/jscript_main.c +++ b/dll/win32/jscript/jscript_main.c @@ -27,6 +27,7 @@ #include "mshtmhst.h" #include "rpcproxy.h" #include "jscript_classes.h" +#include "jsdisp.h" #include "wine/debug.h" @@ -37,6 +38,65 @@ LONG module_ref = 0; DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); HINSTANCE jscript_hinstance; +static DWORD jscript_tls; +static ITypeInfo *dispatch_typeinfo; + +static int weak_refs_compare(const void *key, const struct rb_entry *entry) +{ + const struct weak_refs_entry *weak_refs_entry = RB_ENTRY_VALUE(entry, const struct weak_refs_entry, entry); + ULONG_PTR a = (ULONG_PTR)key, b = (ULONG_PTR)LIST_ENTRY(weak_refs_entry->list.next, struct weakmap_entry, weak_refs_entry)->key; + return (a > b) - (a < b); +} + +struct thread_data *get_thread_data(void) +{ + struct thread_data *thread_data = TlsGetValue(jscript_tls); + + if(!thread_data) { + thread_data = calloc(1, sizeof(struct thread_data)); + if(!thread_data) + return NULL; + thread_data->thread_id = GetCurrentThreadId(); + list_init(&thread_data->objects); + rb_init(&thread_data->weak_refs, weak_refs_compare); + TlsSetValue(jscript_tls, thread_data); + } + + thread_data->ref++; + return thread_data; +} + +void release_thread_data(struct thread_data *thread_data) +{ + if(--thread_data->ref) + return; + + free(thread_data); + TlsSetValue(jscript_tls, NULL); +} + +HRESULT get_dispatch_typeinfo(ITypeInfo **out) +{ + ITypeInfo *typeinfo; + ITypeLib *typelib; + HRESULT hr; + + if (!dispatch_typeinfo) + { + hr = LoadRegTypeLib(&IID_StdOle, STDOLE_MAJORVERNUM, STDOLE_MINORVERNUM, STDOLE_LCID, &typelib); + if (FAILED(hr)) return hr; + + hr = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IDispatch, &typeinfo); + ITypeLib_Release(typelib); + if (FAILED(hr)) return hr; + + if (InterlockedCompareExchangePointer((void**)&dispatch_typeinfo, typeinfo, NULL)) + ITypeInfo_Release(typeinfo); + } + + *out = dispatch_typeinfo; + return S_OK; +} static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { @@ -134,18 +194,22 @@ static IClassFactory JScriptEncodeFactory = { &JScriptEncodeFactoryVtbl }; */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) { - TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpv); + TRACE("(%p %ld %p)\n", hInstDLL, fdwReason, lpv); switch(fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstDLL); jscript_hinstance = hInstDLL; - if(!init_strings()) + jscript_tls = TlsAlloc(); + if(jscript_tls == TLS_OUT_OF_INDEXES || !init_strings()) return FALSE; break; case DLL_PROCESS_DETACH: if (lpv) break; + if (dispatch_typeinfo) ITypeInfo_Release(dispatch_typeinfo); + if(jscript_tls != TLS_OUT_OF_INDEXES) TlsFree(jscript_tls); free_strings(); + break; } return TRUE; @@ -175,25 +239,7 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) */ HRESULT WINAPI DllCanUnloadNow(void) { - TRACE("() ref=%d\n", module_ref); + TRACE("() ref=%ld\n", module_ref); return module_ref ? S_FALSE : S_OK; } - -/*********************************************************************** - * DllRegisterServer (jscript.@) - */ -HRESULT WINAPI DllRegisterServer(void) -{ - TRACE("()\n"); - return __wine_register_resources(jscript_hinstance); -} - -/*********************************************************************** - * DllUnregisterServer (jscript.@) - */ -HRESULT WINAPI DllUnregisterServer(void) -{ - TRACE("()\n"); - return __wine_unregister_resources(jscript_hinstance); -} diff --git a/dll/win32/jscript/jsdisp.idl b/dll/win32/jscript/jsdisp.idl new file mode 100644 index 00000000000..5f1384bce78 --- /dev/null +++ b/dll/win32/jscript/jsdisp.idl @@ -0,0 +1,87 @@ +/* + * Copyright 2024 Gabriel Ivăncescu for CodeWeavers + * Copyright 2024 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma makedep header + +import "dispex.idl"; + +struct property_info +{ + UINT32 id; + UINT32 flags; + const WCHAR *name; + UINT32 index; + UINT32 iid; +}; + +const unsigned int PROPF_METHOD = 0x0100; +const unsigned int PROPF_CONSTR = 0x0200; + +const unsigned int PROPF_ENUMERABLE = 0x0400; +const unsigned int PROPF_WRITABLE = 0x0800; +const unsigned int PROPF_CONFIGURABLE = 0x1000; + +const unsigned int PROPF_PUBLIC_MASK = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; + +const unsigned int HOSTOBJ_CONSTRUCTOR = 0x0001; + +interface IWineJSDispatchHost; + +[ + object, + uuid(d359f2fe-5531-741b-a41a-5cf92edc971c), + local +] +interface IWineJSDispatch : IDispatchEx +{ + void Free(); + HRESULT GetPropertyFlags(DISPID id, UINT32 *ret); + HRESULT GetScriptGlobal(IWineJSDispatchHost **ret); +} + +[ + object, + uuid(b1ebc544-6644-40c6-97f6-ccd9cc32bfba), + local +] +interface IWineJSDispatchHost : IDispatchEx +{ + HRESULT GetJSDispatch(IWineJSDispatch **ret); + HRESULT LookupProperty(const WCHAR *name, DWORD flags, struct property_info *desc); + HRESULT NextProperty(DISPID id, struct property_info *desc); + HRESULT GetProperty(DISPID id, LCID lcid, VARIANT *r, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT SetProperty(DISPID id, LCID lcid, VARIANT *v, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT DeleteProperty(DISPID id); + HRESULT ConfigureProperty(DISPID id, UINT32 flags); + HRESULT CallFunction(DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT Construct(LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT GetOuterDispatch(IWineJSDispatchHost **ret); + HRESULT ToString(BSTR *str); +} + +[ + object, + uuid(d359f2fe-5531-741b-a41a-5cf92edc971d), + local +] +interface IWineJScript : IUnknown +{ + HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret); + HRESULT InitHostConstructor(IWineJSDispatchHost *constr, IWineJSDispatch *prototype, IWineJSDispatch **ret); +} diff --git a/dll/win32/jscript/jsglobal.rgs b/dll/win32/jscript/jsglobal.rgs deleted file mode 100644 index 42c1a80164f..00000000000 --- a/dll/win32/jscript/jsglobal.rgs +++ /dev/null @@ -1,146 +0,0 @@ -HKCR -{ - NoRemove Typelib - { - NoRemove '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' - { - '1.0' = s 'JSGlobal' - { - '0' { win32 = s '%MODULE%' } - FLAGS = s '0' - } - } - } - NoRemove Interface - { - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B086}' = s 'GlobalObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B087}' = s 'DateObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B088}' = s 'MathObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B089}' = s 'NumberObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B090}' = s 'RegExpObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B091}' = s 'StringObj' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B092}' = s 'ArrayInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B093}' = s 'FunctionInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B094}' = s 'StringInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B095}' = s 'BoolInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B096}' = s 'NumberInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B097}' = s 'ObjectInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B098}' = s 'DateInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B099}' = s 'RegExpInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B09A}' = s 'ErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B09B}' = s 'EvalErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B09C}' = s 'RangeErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B09D}' = s 'ReferenceErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B09E}' = s 'SyntaxErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B09F}' = s 'TypeErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - '{3EEF9758-35FC-11D1-8CE4-00C04FC2B0A0}' = s 'URIErrorInstance' - { - ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}' - ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}' - TypeLib = s '{3EEF9759-35FC-11D1-8CE4-00C04FC2B085}' { val Version = s '1.0' } - } - } - NoRemove CLSID - { - } -} diff --git a/dll/win32/jscript/json.c b/dll/win32/jscript/json.c index 608237f32a9..a0db7a20565 100644 --- a/dll/win32/jscript/json.c +++ b/dll/win32/jscript/json.c @@ -16,6 +16,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifdef __REACTOS__ +#include +#include +#endif + #include #include @@ -26,15 +31,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); -static const WCHAR parseW[] = {'p','a','r','s','e',0}; -static const WCHAR stringifyW[] = {'s','t','r','i','n','g','i','f','y',0}; - -static const WCHAR nullW[] = {'n','u','l','l',0}; -static const WCHAR trueW[] = {'t','r','u','e',0}; -static const WCHAR falseW[] = {'f','a','l','s','e',0}; - -static const WCHAR toJSONW[] = {'t','o','J','S','O','N',0}; - typedef struct { const WCHAR *ptr; const WCHAR *end; @@ -66,6 +62,77 @@ static BOOL is_keyword(json_parse_ctx_t *ctx, const WCHAR *keyword) return TRUE; } +static BOOL unescape_json_string(WCHAR *str, size_t *len) +{ + WCHAR *pd, *p, c, *end = str + *len; + int i; + + pd = p = str; + while(p < end) { + if(*p != '\\') { + *pd++ = *p++; + continue; + } + + if(++p == end) + return FALSE; + + switch(*p) { + case '\"': + case '\\': + case '/': + c = *p; + break; + case 'b': + c = '\b'; + break; + case 't': + c = '\t'; + break; + case 'n': + c = '\n'; + break; + case 'f': + c = '\f'; + break; + case 'r': + c = '\r'; + break; + case 'u': + if(p + 4 >= end) + return FALSE; + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c = i << 12; + + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c += i << 8; + + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c += i << 4; + + i = hex_to_int(*++p); + if(i == -1) + return FALSE; + c += i; + break; + default: + return FALSE; + } + + *pd++ = c; + p++; + } + + *len = pd - str; + return TRUE; +} + /* ECMA-262 5.1 Edition 15.12.1.1 */ static HRESULT parse_json_string(json_parse_ctx_t *ctx, WCHAR **r) { @@ -83,16 +150,16 @@ static HRESULT parse_json_string(json_parse_ctx_t *ctx, WCHAR **r) } len = ctx->ptr-ptr; - buf = heap_alloc((len+1)*sizeof(WCHAR)); + buf = malloc((len+1)*sizeof(WCHAR)); if(!buf) return E_OUTOFMEMORY; if(len) memcpy(buf, ptr, len*sizeof(WCHAR)); - if(!unescape(buf, &len)) { - FIXME("unescape failed\n"); - heap_free(buf); - return E_FAIL; + if(!(ctx->ctx->html_mode ? unescape_json_string(buf, &len) : unescape(buf, &len))) { + WARN("unescape failed\n"); + free(buf); + return JS_E_INVALID_CHAR; } buf[len] = 0; @@ -110,19 +177,19 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) /* JSONNullLiteral */ case 'n': - if(!is_keyword(ctx, nullW)) + if(!is_keyword(ctx, L"null")) break; *r = jsval_null(); return S_OK; /* JSONBooleanLiteral */ case 't': - if(!is_keyword(ctx, trueW)) + if(!is_keyword(ctx, L"true")) break; *r = jsval_bool(TRUE); return S_OK; case 'f': - if(!is_keyword(ctx, falseW)) + if(!is_keyword(ctx, L"false")) break; *r = jsval_bool(FALSE); return S_OK; @@ -153,7 +220,7 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) if(skip_spaces(ctx) != ':') { FIXME("missing ':'\n"); - heap_free(prop_name); + free(prop_name); break; } @@ -163,7 +230,7 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) hres = jsdisp_propput_name(obj, prop_name, val); jsval_release(val); } - heap_free(prop_name); + free(prop_name); if(FAILED(hres)) break; @@ -195,7 +262,7 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) /* FIXME: avoid reallocation */ str = jsstr_alloc(string); - heap_free(string); + free(string); if(!str) return E_OUTOFMEMORY; @@ -260,7 +327,7 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) skip_spaces(ctx); } - if(*ctx->ptr == '0' && ctx->ptr + 1 < ctx->end && iswdigit(ctx->ptr[1])) + if(*ctx->ptr == '0' && ctx->ptr + 1 < ctx->end && is_digit(ctx->ptr[1])) break; hres = parse_decimal(&ctx->ptr, ctx->end, &n); @@ -276,20 +343,106 @@ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) return E_FAIL; } +struct transform_json_object_ctx +{ + script_ctx_t *ctx; + IDispatch *reviver; + HRESULT hres; +}; + +static jsval_t transform_json_object(struct transform_json_object_ctx *proc_ctx, jsdisp_t *holder, jsstr_t *name) +{ + jsval_t res, args[2]; + const WCHAR *str; + + if(!(str = jsstr_flatten(name))) + proc_ctx->hres = E_OUTOFMEMORY; + else + proc_ctx->hres = jsdisp_propget_name(holder, str, &args[1]); + if(FAILED(proc_ctx->hres)) + return jsval_undefined(); + + if(is_object_instance(args[1])) { + jsdisp_t *obj = to_jsdisp(get_object(args[1])); + jsstr_t *jsstr; + DISPID id; + BOOL b; + + if(!obj) { + FIXME("non-JS obj in JSON object: %p\n", get_object(args[1])); + proc_ctx->hres = E_NOTIMPL; + goto ret; + }else if(is_class(obj, JSCLASS_ARRAY)) { + unsigned i, length = array_get_length(obj); + WCHAR buf[14], *buf_end; + + buf_end = buf + ARRAY_SIZE(buf) - 1; + *buf_end-- = 0; + for(i = 0; i < length; i++) { + str = idx_to_str(i, buf_end); + if(!(jsstr = jsstr_alloc(str))) { + proc_ctx->hres = E_OUTOFMEMORY; + goto ret; + } + res = transform_json_object(proc_ctx, obj, jsstr); + jsstr_release(jsstr); + if(is_undefined(res)) { + if(FAILED(proc_ctx->hres)) + goto ret; + if(FAILED(jsdisp_get_id(obj, str, 0, &id))) + continue; + proc_ctx->hres = disp_delete(to_disp(obj), id, &b); + }else { + proc_ctx->hres = jsdisp_define_data_property(obj, str, PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, res); + jsval_release(res); + } + if(FAILED(proc_ctx->hres)) + goto ret; + } + }else { + id = DISPID_STARTENUM; + for(;;) { + proc_ctx->hres = jsdisp_next_prop(obj, id, JSDISP_ENUM_OWN_ENUMERABLE, &id); + if(proc_ctx->hres == S_FALSE) + break; + if(FAILED(proc_ctx->hres) || FAILED(proc_ctx->hres = jsdisp_get_prop_name(obj, id, &jsstr))) + goto ret; + res = transform_json_object(proc_ctx, obj, jsstr); + if(is_undefined(res)) { + if(SUCCEEDED(proc_ctx->hres)) + proc_ctx->hres = disp_delete(to_disp(obj), id, &b); + }else { + if(!(str = jsstr_flatten(jsstr))) + proc_ctx->hres = E_OUTOFMEMORY; + else + proc_ctx->hres = jsdisp_define_data_property(obj, str, PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, res); + jsval_release(res); + } + jsstr_release(jsstr); + if(FAILED(proc_ctx->hres)) + goto ret; + } + } + } + + args[0] = jsval_string(name); + proc_ctx->hres = disp_call_value(proc_ctx->ctx, proc_ctx->reviver, jsval_obj(holder), + DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); +ret: + jsval_release(args[1]); + return FAILED(proc_ctx->hres) ? jsval_undefined() : res; +} + /* ECMA-262 5.1 Edition 15.12.2 */ -static HRESULT JSON_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT JSON_parse(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { json_parse_ctx_t parse_ctx; const WCHAR *buf; + jsdisp_t *root; jsstr_t *str; jsval_t ret; HRESULT hres; - if(argc != 1) { - FIXME("Unsupported args\n"); - return E_INVALIDARG; - } - hres = to_flat_string(ctx, argv[0], &str, &buf); if(FAILED(hres)) return hres; @@ -300,14 +453,36 @@ static HRESULT JSON_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsign parse_ctx.end = buf + jsstr_length(str); parse_ctx.ctx = ctx; hres = parse_json_value(&parse_ctx, &ret); + if(SUCCEEDED(hres) && skip_spaces(&parse_ctx)) { + FIXME("syntax error\n"); + jsval_release(ret); + hres = E_FAIL; + } jsstr_release(str); if(FAILED(hres)) return hres; - if(skip_spaces(&parse_ctx)) { - FIXME("syntax error\n"); + /* FIXME: check IsCallable */ + if(argc > 1 && is_object_instance(argv[1])) { + hres = create_object(ctx, NULL, &root); + if(FAILED(hres)) { + jsval_release(ret); + return hres; + } + hres = jsdisp_define_data_property(root, L"", PROPF_WRITABLE | PROPF_ENUMERABLE | PROPF_CONFIGURABLE, ret); jsval_release(ret); - return E_FAIL; + + if(SUCCEEDED(hres)) { + struct transform_json_object_ctx proc_ctx = { ctx, get_object(argv[1]), S_OK }; + + str = jsstr_empty(); + ret = transform_json_object(&proc_ctx, root, str); + jsstr_release(str); + hres = proc_ctx.hres; + } + jsdisp_release(root); + if(FAILED(hres)) + return hres; } if(r) @@ -329,19 +504,21 @@ typedef struct { size_t stack_size; WCHAR gap[11]; /* according to the spec, it's no longer than 10 chars */ + + jsdisp_t *replacer; } stringify_ctx_t; static BOOL stringify_push_obj(stringify_ctx_t *ctx, jsdisp_t *obj) { if(!ctx->stack_size) { - ctx->stack = heap_alloc(4*sizeof(*ctx->stack)); + ctx->stack = malloc(4*sizeof(*ctx->stack)); if(!ctx->stack) return FALSE; ctx->stack_size = 4; }else if(ctx->stack_top == ctx->stack_size) { jsdisp_t **new_stack; - new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack)); + new_stack = realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack)); if(!new_stack) return FALSE; ctx->stack = new_stack; @@ -370,7 +547,7 @@ static BOOL is_on_stack(stringify_ctx_t *ctx, jsdisp_t *obj) static BOOL append_string_len(stringify_ctx_t *ctx, const WCHAR *str, size_t len) { if(!ctx->buf_size) { - ctx->buf = heap_alloc(len*2*sizeof(WCHAR)); + ctx->buf = malloc(len*2*sizeof(WCHAR)); if(!ctx->buf) return FALSE; ctx->buf_size = len*2; @@ -379,7 +556,7 @@ static BOOL append_string_len(stringify_ctx_t *ctx, const WCHAR *str, size_t len size_t new_size; new_size = ctx->buf_size * 2 + len; - new_buf = heap_realloc(ctx->buf, new_size*sizeof(WCHAR)); + new_buf = realloc(ctx->buf, new_size*sizeof(WCHAR)); if(!new_buf) return FALSE; ctx->buf = new_buf; @@ -413,7 +590,7 @@ static HRESULT maybe_to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *r) jsdisp_t *obj; HRESULT hres; - if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp(get_object(val)))) + if(!is_object_instance(val) || !(obj = iface_to_jsdisp(get_object(val)))) return jsval_copy(val, r); if(is_class(obj, JSCLASS_NUMBER)) { @@ -479,9 +656,8 @@ static HRESULT json_quote(stringify_ctx_t *ctx, const WCHAR *ptr, size_t len) break; default: if(*ptr < ' ') { - static const WCHAR formatW[] = {'\\','u','%','0','4','x',0}; WCHAR buf[7]; - swprintf(buf, formatW, *ptr); + swprintf(buf, ARRAY_SIZE(buf), L"\\u%04x", *ptr); if(!append_string(ctx, buf)) return E_OUTOFMEMORY; }else { @@ -500,13 +676,13 @@ static inline BOOL is_callable(jsdisp_t *obj) return is_class(obj, JSCLASS_FUNCTION); } -static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val); +static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *name); /* ECMA-262 5.1 Edition 15.12.3 (abstract operation JA) */ static HRESULT stringify_array(stringify_ctx_t *ctx, jsdisp_t *obj) { unsigned length, i, j; - jsval_t val; + WCHAR name[16]; HRESULT hres; if(is_on_stack(ctx, obj)) { @@ -536,19 +712,12 @@ static HRESULT stringify_array(stringify_ctx_t *ctx, jsdisp_t *obj) } } - hres = jsdisp_get_idx(obj, i, &val); - if(SUCCEEDED(hres)) { - hres = stringify(ctx, val); - if(FAILED(hres)) - return hres; - if(hres == S_FALSE && !append_string(ctx, nullW)) - return E_OUTOFMEMORY; - }else if(hres == DISP_E_UNKNOWNNAME) { - if(!append_string(ctx, nullW)) - return E_OUTOFMEMORY; - }else { + _itow(i, name, ARRAY_SIZE(name)); + hres = stringify(ctx, obj, name); + if(FAILED(hres)) return hres; - } + if(hres == S_FALSE && !append_string(ctx, L"null")) + return E_OUTOFMEMORY; } if((length && *ctx->gap && !append_char(ctx, '\n')) || !append_char(ctx, ']')) @@ -562,7 +731,6 @@ static HRESULT stringify_array(stringify_ctx_t *ctx, jsdisp_t *obj) static HRESULT stringify_object(stringify_ctx_t *ctx, jsdisp_t *obj) { DISPID dispid = DISPID_STARTENUM; - jsval_t val = jsval_undefined(); unsigned prop_cnt = 0, i; size_t stepback; BSTR prop_name; @@ -579,15 +747,7 @@ static HRESULT stringify_object(stringify_ctx_t *ctx, jsdisp_t *obj) if(!append_char(ctx, '{')) return E_OUTOFMEMORY; - while((hres = IDispatchEx_GetNextDispID(&obj->IDispatchEx_iface, fdexEnumDefault, dispid, &dispid)) == S_OK) { - jsval_release(val); - hres = jsdisp_propget(obj, dispid, &val); - if(FAILED(hres)) - return hres; - - if(is_undefined(val)) - continue; - + while((hres = IDispatchEx_GetNextDispID(to_dispex(obj), fdexEnumDefault, dispid, &dispid)) == S_OK) { stepback = ctx->buf_len; if(prop_cnt && !append_char(ctx, ',')) { @@ -609,23 +769,25 @@ static HRESULT stringify_object(stringify_ctx_t *ctx, jsdisp_t *obj) } } - hres = IDispatchEx_GetMemberName(&obj->IDispatchEx_iface, dispid, &prop_name); + hres = IDispatchEx_GetMemberName(to_dispex(obj), dispid, &prop_name); if(FAILED(hres)) - break; + return hres; hres = json_quote(ctx, prop_name, SysStringLen(prop_name)); - SysFreeString(prop_name); - if(FAILED(hres)) - break; - - if(!append_char(ctx, ':') || (*ctx->gap && !append_char(ctx, ' '))) { - hres = E_OUTOFMEMORY; - break; + if(FAILED(hres)) { + SysFreeString(prop_name); + return hres; } - hres = stringify(ctx, val); + if(!append_char(ctx, ':') || (*ctx->gap && !append_char(ctx, ' '))) { + SysFreeString(prop_name); + return E_OUTOFMEMORY; + } + + hres = stringify(ctx, obj, prop_name); + SysFreeString(prop_name); if(FAILED(hres)) - break; + return hres; if(hres == S_FALSE) { ctx->buf_len = stepback; @@ -634,9 +796,6 @@ static HRESULT stringify_object(stringify_ctx_t *ctx, jsdisp_t *obj) prop_cnt++; } - jsval_release(val); - if(FAILED(hres)) - return hres; if(prop_cnt && *ctx->gap) { if(!append_char(ctx, '\n')) @@ -658,38 +817,62 @@ static HRESULT stringify_object(stringify_ctx_t *ctx, jsdisp_t *obj) } /* ECMA-262 5.1 Edition 15.12.3 (abstract operation Str) */ -static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val) +static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *name) { - jsval_t value; + jsval_t value, v; HRESULT hres; - if(is_object_instance(val) && get_object(val)) { + hres = jsdisp_propget_name(object, name, &value); + if(FAILED(hres)) + return hres == DISP_E_UNKNOWNNAME ? S_FALSE : hres; + + if(is_object_instance(value)) { jsdisp_t *obj; DISPID id; - obj = iface_to_jsdisp(get_object(val)); - if(!obj) + obj = to_jsdisp(get_object(value)); + if(!obj) { + jsval_release(value); return S_FALSE; + } - hres = jsdisp_get_id(obj, toJSONW, 0, &id); - jsdisp_release(obj); + hres = jsdisp_get_id(obj, L"toJSON", 0, &id); if(hres == S_OK) FIXME("Use toJSON.\n"); } - /* FIXME: Support replacer replacer. */ + if(ctx->replacer) { + jsstr_t *name_str; + jsval_t args[2]; + if(!(name_str = jsstr_alloc(name))) { + jsval_release(value); + return E_OUTOFMEMORY; + } + args[0] = jsval_string(name_str); + args[1] = value; + hres = jsdisp_call_value(ctx->replacer, jsval_obj(object), DISPATCH_METHOD, ARRAY_SIZE(args), args, &v); + jsstr_release(name_str); + jsval_release(value); + if(FAILED(hres)) + return hres; + value = v; + } - hres = maybe_to_primitive(ctx->ctx, val, &value); + v = value; + hres = maybe_to_primitive(ctx->ctx, v, &value); + jsval_release(v); if(FAILED(hres)) return hres; switch(jsval_type(value)) { case JSV_NULL: - if(!append_string(ctx, nullW)) + if(is_null_disp(value)) + hres = S_FALSE; + else if(!append_string(ctx, L"null")) hres = E_OUTOFMEMORY; break; case JSV_BOOL: - if(!append_string(ctx, get_bool(value) ? trueW : falseW)) + if(!append_string(ctx, get_bool(value) ? L"true" : L"false")) hres = E_OUTOFMEMORY; break; case JSV_STRING: { @@ -703,7 +886,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val) } case JSV_NUMBER: { double n = get_number(value); - if(is_finite(n)) { + if(isfinite(n)) { const WCHAR *ptr; jsstr_t *str; @@ -717,7 +900,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val) hres = ptr && !append_string_len(ctx, ptr, jsstr_length(str)) ? E_OUTOFMEMORY : S_OK; jsstr_release(str); }else { - if(!append_string(ctx, nullW)) + if(!append_string(ctx, L"null")) hres = E_OUTOFMEMORY; } break; @@ -753,9 +936,10 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsval_t val) } /* ECMA-262 5.1 Edition 15.12.3 */ -static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +static HRESULT JSON_stringify(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - stringify_ctx_t stringify_ctx = {ctx, NULL,0,0, NULL,0,0, {0}}; + stringify_ctx_t stringify_ctx = { ctx }; + jsdisp_t *obj = NULL, *replacer; HRESULT hres; TRACE("\n"); @@ -766,9 +950,13 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un return S_OK; } - if(argc >= 2 && is_object_instance(argv[1])) { - FIXME("Replacer %s not yet supported\n", debugstr_jsval(argv[1])); - return E_NOTIMPL; + if(argc >= 2 && is_object_instance(argv[1]) && (replacer = to_jsdisp(get_object(argv[1])))) { + if(is_callable(replacer)) { + stringify_ctx.replacer = jsdisp_addref(replacer); + }else if(is_class(replacer, JSCLASS_ARRAY)) { + FIXME("Array replacer not yet supported\n"); + return E_NOTIMPL; + } } if(argc >= 3) { @@ -776,7 +964,7 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un hres = maybe_to_primitive(ctx, argv[2], &space_val); if(FAILED(hres)) - return hres; + goto fail; if(is_number(space_val)) { double n = get_number(space_val); @@ -800,7 +988,12 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un jsval_release(space_val); } - hres = stringify(&stringify_ctx, argv[0]); + if(FAILED(hres = create_object(ctx, NULL, &obj))) + goto fail; + if(FAILED(hres = jsdisp_propput_name(obj, L"", argv[0]))) + goto fail; + + hres = stringify(&stringify_ctx, obj, L""); if(SUCCEEDED(hres) && r) { assert(!stringify_ctx.stack_top); @@ -815,23 +1008,25 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, un } } - heap_free(stringify_ctx.buf); - heap_free(stringify_ctx.stack); +fail: + if(obj) + jsdisp_release(obj); + if(stringify_ctx.replacer) + jsdisp_release(stringify_ctx.replacer); + free(stringify_ctx.buf); + free(stringify_ctx.stack); return hres; } static const builtin_prop_t JSON_props[] = { - {parseW, JSON_parse, PROPF_METHOD|2}, - {stringifyW, JSON_stringify, PROPF_METHOD|3} + {L"parse", JSON_parse, PROPF_METHOD|2}, + {L"stringify", JSON_stringify, PROPF_METHOD|3} }; static const builtin_info_t JSON_info = { - JSCLASS_JSON, - {NULL, NULL, 0}, - ARRAY_SIZE(JSON_props), - JSON_props, - NULL, - NULL + .class = JSCLASS_JSON, + .props_cnt = ARRAY_SIZE(JSON_props), + .props = JSON_props, }; HRESULT create_json(script_ctx_t *ctx, jsdisp_t **ret) @@ -839,13 +1034,13 @@ HRESULT create_json(script_ctx_t *ctx, jsdisp_t **ret) jsdisp_t *json; HRESULT hres; - json = heap_alloc_zero(sizeof(*json)); + json = calloc(1, sizeof(*json)); if(!json) return E_OUTOFMEMORY; hres = init_dispex_from_constr(json, ctx, &JSON_info, ctx->object_constr); if(FAILED(hres)) { - heap_free(json); + free(json); return hres; } diff --git a/dll/win32/jscript/jsregexp.c b/dll/win32/jscript/jsregexp.c index d4ee506f03b..979f994ee55 100644 --- a/dll/win32/jscript/jsregexp.c +++ b/dll/win32/jscript/jsregexp.c @@ -34,38 +34,15 @@ typedef struct { jsval_t last_index_val; } RegExpInstance; -static const WCHAR sourceW[] = {'s','o','u','r','c','e',0}; -static const WCHAR globalW[] = {'g','l','o','b','a','l',0}; -static const WCHAR ignoreCaseW[] = {'i','g','n','o','r','e','C','a','s','e',0}; -static const WCHAR multilineW[] = {'m','u','l','t','i','l','i','n','e',0}; -static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0}; -static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; -static const WCHAR execW[] = {'e','x','e','c',0}; -static const WCHAR testW[] = {'t','e','s','t',0}; - -static const WCHAR leftContextW[] = - {'l','e','f','t','C','o','n','t','e','x','t',0}; -static const WCHAR rightContextW[] = - {'r','i','g','h','t','C','o','n','t','e','x','t',0}; - -static const WCHAR idx1W[] = {'$','1',0}; -static const WCHAR idx2W[] = {'$','2',0}; -static const WCHAR idx3W[] = {'$','3',0}; -static const WCHAR idx4W[] = {'$','4',0}; -static const WCHAR idx5W[] = {'$','5',0}; -static const WCHAR idx6W[] = {'$','6',0}; -static const WCHAR idx7W[] = {'$','7',0}; -static const WCHAR idx8W[] = {'$','8',0}; -static const WCHAR idx9W[] = {'$','9',0}; - static inline RegExpInstance *regexp_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, RegExpInstance, dispex); } -static inline RegExpInstance *regexp_from_vdisp(vdisp_t *vdisp) +static inline RegExpInstance *regexp_this(jsval_t vthis) { - return regexp_from_jsdisp(vdisp->u.jsdisp); + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_REGEXP)) ? regexp_from_jsdisp(jsdisp) : NULL; } static void set_last_index(RegExpInstance *This, DWORD last_index) @@ -172,7 +149,7 @@ HRESULT regexp_match_next(script_ctx_t *ctx, jsdisp_t *dispex, heap_pool_clear(mark); if(hres != S_OK && (rem_flags & REM_ALLOC_RESULT)) { - heap_free(match); + free(match); *ret = NULL; } @@ -216,11 +193,11 @@ static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, if(ret) { match_result_t *old_ret = ret; - ret = heap_realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t)); + ret = realloc(old_ret, (ret_size <<= 1) * sizeof(match_result_t)); if(!ret) - heap_free(old_ret); + free(old_ret); }else { - ret = heap_alloc((ret_size=4) * sizeof(match_result_t)); + ret = malloc((ret_size=4) * sizeof(match_result_t)); } if(!ret) { hres = E_OUTOFMEMORY; @@ -231,6 +208,9 @@ static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, ret[i].index = result->cp - str - result->match_len; ret[i++].length = result->match_len; + if (result->match_len == 0) + result->cp++; + if(!gflag && !(This->jsregexp->flags & REG_GLOB)) { hres = S_OK; break; @@ -239,7 +219,7 @@ static HRESULT regexp_match(script_ctx_t *ctx, jsdisp_t *dispex, jsstr_t *jsstr, heap_pool_clear(mark); if(FAILED(hres)) { - heap_free(ret); + free(ret); return hres; } @@ -286,10 +266,8 @@ static INT index_from_val(script_ctx_t *ctx, jsval_t v) HRESULT hres; hres = to_number(ctx, v, &n); - if(FAILED(hres)) { - clear_ei(ctx); /* FIXME: Move ignoring exceptions to to_primitive */ + if(FAILED(hres)) return 0; - } n = floor(n); return is_int32(n) ? n : 0; @@ -320,7 +298,7 @@ static HRESULT RegExp_set_lastIndex(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t return S_OK; } -static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT RegExp_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { RegExpInstance *regexp; @@ -330,12 +308,11 @@ static HRESULT RegExp_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, u TRACE("\n"); - if(!is_vclass(jsthis, JSCLASS_REGEXP)) { - FIXME("Not a RegExp\n"); - return E_NOTIMPL; + if(!(regexp = regexp_this(vthis))) { + WARN("Not a RegExp\n"); + return JS_E_REGEXP_EXPECTED; } - regexp = regexp_from_vdisp(jsthis); if(!r) return S_OK; @@ -378,11 +355,6 @@ static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str, DWORD i; HRESULT hres = S_OK; - static const WCHAR indexW[] = {'i','n','d','e','x',0}; - static const WCHAR inputW[] = {'i','n','p','u','t',0}; - static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0}; - static const WCHAR zeroW[] = {'0',0}; - input = jsstr_flatten(input_str); if(!input) return E_OUTOFMEMORY; @@ -392,31 +364,36 @@ static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str, return hres; for(i=0; i < result->paren_count; i++) { - if(result->parens[i].index != -1) - str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length); - else - str = jsstr_empty(); - if(!str) { - hres = E_OUTOFMEMORY; - break; + jsval_t val; + + if(result->parens[i].index != -1) { + if(!(str = jsstr_substr(input_str, result->parens[i].index, result->parens[i].length))) { + hres = E_OUTOFMEMORY; + break; + } + val = jsval_string(str); + }else if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + val = jsval_string(jsstr_empty()); + }else { + val = jsval_undefined(); } - hres = jsdisp_propput_idx(array, i+1, jsval_string(str)); - jsstr_release(str); + hres = jsdisp_propput_idx(array, i+1, val); + jsval_release(val); if(FAILED(hres)) break; } while(SUCCEEDED(hres)) { - hres = jsdisp_propput_name(array, indexW, jsval_number(result->cp-input-result->match_len)); + hres = jsdisp_propput_name(array, L"index", jsval_number(result->cp-input-result->match_len)); if(FAILED(hres)) break; - hres = jsdisp_propput_name(array, lastIndexW, jsval_number(result->cp-input)); + hres = jsdisp_propput_name(array, L"lastIndex", jsval_number(result->cp-input)); if(FAILED(hres)) break; - hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr_addref(input_str))); + hres = jsdisp_propput_name(array, L"input", jsval_string(input_str)); if(FAILED(hres)) break; @@ -425,7 +402,7 @@ static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str, hres = E_OUTOFMEMORY; break; } - hres = jsdisp_propput_name(array, zeroW, jsval_string(str)); + hres = jsdisp_propput_name(array, L"0", jsval_string(str)); jsstr_release(str); break; } @@ -439,7 +416,7 @@ static HRESULT create_match_array(script_ctx_t *ctx, jsstr_t *input_str, return S_OK; } -static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg, +static HRESULT run_exec(script_ctx_t *ctx, jsval_t vthis, jsval_t arg, jsstr_t **input, match_state_t **result, BOOL *ret) { RegExpInstance *regexp; @@ -449,13 +426,11 @@ static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg, jsstr_t *jsstr; HRESULT hres; - if(!is_vclass(jsthis, JSCLASS_REGEXP)) { - FIXME("Not a RegExp\n"); - return E_NOTIMPL; + if(!(regexp = regexp_this(vthis))) { + WARN("Not a RegExp\n"); + return JS_E_REGEXP_EXPECTED; } - regexp = regexp_from_vdisp(jsthis); - hres = to_flat_string(ctx, arg, &jsstr, &string); if(FAILED(hres)) return hres; @@ -494,7 +469,7 @@ static HRESULT run_exec(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t arg, return S_OK; } -static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT RegExp_exec(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { match_state_t *match; @@ -507,7 +482,7 @@ static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsig mark = heap_pool_mark(&ctx->tmp_heap); - hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b); + hres = run_exec(ctx, vthis, argc ? argv[0] : jsval_string(jsstr_empty()), &string, &match, &b); if(FAILED(hres)) { heap_pool_clear(mark); return hres; @@ -530,7 +505,7 @@ static HRESULT RegExp_exec(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsig return hres; } -static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT RegExp_test(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { match_state_t *match; @@ -542,7 +517,7 @@ static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsig TRACE("\n"); mark = heap_pool_mark(&ctx->tmp_heap); - hres = run_exec(ctx, jsthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b); + hres = run_exec(ctx, vthis, argc ? argv[0] : jsval_string(undef_str = jsstr_undefined()), NULL, &match, &b); heap_pool_clear(mark); if(!argc) jsstr_release(undef_str); @@ -554,14 +529,14 @@ static HRESULT RegExp_test(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsig return S_OK; } -static HRESULT RegExp_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT RegExp_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); switch(flags) { case INVOKE_FUNC: - return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL); + return JS_E_FUNCTION_EXPECTED; default: FIXME("unimplemented flags %x\n", flags); return E_NOTIMPL; @@ -578,52 +553,56 @@ static void RegExp_destructor(jsdisp_t *dispex) regexp_destroy(This->jsregexp); jsval_release(This->last_index_val); jsstr_release(This->str); - heap_free(This); +} + +static HRESULT RegExp_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + return gc_process_linked_val(gc_ctx, op, dispex, ®exp_from_jsdisp(dispex)->last_index_val); } static const builtin_prop_t RegExp_props[] = { - {execW, RegExp_exec, PROPF_METHOD|1}, - {globalW, NULL,0, RegExp_get_global}, - {ignoreCaseW, NULL,0, RegExp_get_ignoreCase}, - {lastIndexW, NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex}, - {multilineW, NULL,0, RegExp_get_multiline}, - {sourceW, NULL,0, RegExp_get_source}, - {testW, RegExp_test, PROPF_METHOD|1}, - {toStringW, RegExp_toString, PROPF_METHOD} + {L"exec", RegExp_exec, PROPF_METHOD|1}, + {L"global", NULL,0, RegExp_get_global}, + {L"ignoreCase", NULL,0, RegExp_get_ignoreCase}, + {L"lastIndex", NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex}, + {L"multiline", NULL,0, RegExp_get_multiline}, + {L"source", NULL,0, RegExp_get_source}, + {L"test", RegExp_test, PROPF_METHOD|1}, + {L"toString", RegExp_toString, PROPF_METHOD} }; static const builtin_info_t RegExp_info = { - JSCLASS_REGEXP, - {NULL, RegExp_value, 0}, - ARRAY_SIZE(RegExp_props), - RegExp_props, - RegExp_destructor, - NULL + .class = JSCLASS_REGEXP, + .call = RegExp_value, + .props_cnt = ARRAY_SIZE(RegExp_props), + .props = RegExp_props, + .destructor = RegExp_destructor, + .gc_traverse = RegExp_gc_traverse }; static const builtin_prop_t RegExpInst_props[] = { - {globalW, NULL,0, RegExp_get_global}, - {ignoreCaseW, NULL,0, RegExp_get_ignoreCase}, - {lastIndexW, NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex}, - {multilineW, NULL,0, RegExp_get_multiline}, - {sourceW, NULL,0, RegExp_get_source} + {L"global", NULL,0, RegExp_get_global}, + {L"ignoreCase", NULL,0, RegExp_get_ignoreCase}, + {L"lastIndex", NULL,0, RegExp_get_lastIndex, RegExp_set_lastIndex}, + {L"multiline", NULL,0, RegExp_get_multiline}, + {L"source", NULL,0, RegExp_get_source} }; static const builtin_info_t RegExpInst_info = { - JSCLASS_REGEXP, - {NULL, RegExp_value, 0}, - ARRAY_SIZE(RegExpInst_props), - RegExpInst_props, - RegExp_destructor, - NULL + .class = JSCLASS_REGEXP, + .call = RegExp_value, + .props_cnt = ARRAY_SIZE(RegExpInst_props), + .props = RegExpInst_props, + .destructor = RegExp_destructor, + .gc_traverse = RegExp_gc_traverse }; -static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegExpInstance **ret) +static HRESULT alloc_regexp(script_ctx_t *ctx, jsstr_t *str, jsdisp_t *object_prototype, RegExpInstance **ret) { RegExpInstance *regexp; HRESULT hres; - regexp = heap_alloc_zero(sizeof(RegExpInstance)); + regexp = calloc(1, sizeof(RegExpInstance)); if(!regexp) return E_OUTOFMEMORY; @@ -633,10 +612,13 @@ static HRESULT alloc_regexp(script_ctx_t *ctx, jsdisp_t *object_prototype, RegEx hres = init_dispex_from_constr(®exp->dispex, ctx, &RegExpInst_info, ctx->regexp_constr); if(FAILED(hres)) { - heap_free(regexp); + free(regexp); return hres; } + regexp->str = jsstr_addref(str); + regexp->last_index_val = jsval_number(0); + *ret = regexp; return S_OK; } @@ -651,20 +633,17 @@ HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **r if(!str) return E_OUTOFMEMORY; - TRACE("%s %x\n", debugstr_wn(str, jsstr_length(src)), flags); + TRACE("%s %lx\n", debugstr_wn(str, jsstr_length(src)), flags); - hres = alloc_regexp(ctx, NULL, ®exp); + hres = alloc_regexp(ctx, src, NULL, ®exp); if(FAILED(hres)) return hres; - regexp->str = jsstr_addref(src); - regexp->last_index_val = jsval_number(0); - regexp->jsregexp = regexp_new(ctx, &ctx->tmp_heap, str, jsstr_length(regexp->str), flags, FALSE); if(!regexp->jsregexp) { WARN("regexp_new failed\n"); jsdisp_release(®exp->dispex); - return E_FAIL; + return DISP_E_EXCEPTION; } *ret = ®exp->dispex; @@ -673,66 +652,57 @@ HRESULT create_regexp(script_ctx_t *ctx, jsstr_t *src, DWORD flags, jsdisp_t **r HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg, jsdisp_t **ret) { - unsigned flags, opt_len = 0; + DWORD flags = 0; const WCHAR *opt = NULL; jsstr_t *src; - HRESULT hres; + HRESULT hres = S_OK; if(is_object_instance(src_arg)) { jsdisp_t *obj; - obj = iface_to_jsdisp(get_object(src_arg)); + obj = to_jsdisp(get_object(src_arg)); if(obj) { if(is_class(obj, JSCLASS_REGEXP)) { RegExpInstance *regexp = regexp_from_jsdisp(obj); hres = create_regexp(ctx, regexp->str, regexp->jsregexp->flags, ret); - jsdisp_release(obj); return hres; } - - jsdisp_release(obj); } } - if(!is_string(src_arg)) { - FIXME("src_arg = %s\n", debugstr_jsval(src_arg)); - return E_NOTIMPL; - } - - src = get_string(src_arg); - - if(flags_arg) { - jsstr_t *opt_str; - - if(!is_string(*flags_arg)) { - FIXME("unimplemented for %s\n", debugstr_jsval(*flags_arg)); - return E_NOTIMPL; - } - - opt_str = get_string(*flags_arg); - opt = jsstr_flatten(opt_str); - if(!opt) - return E_OUTOFMEMORY; - opt_len = jsstr_length(opt_str); - } - - hres = parse_regexp_flags(opt, opt_len, &flags); + if(is_undefined(src_arg)) + src = jsstr_empty(); + else + hres = to_string(ctx, src_arg, &src); if(FAILED(hres)) return hres; - return create_regexp(ctx, src, flags, ret); + if(flags_arg && !is_undefined(*flags_arg)) { + jsstr_t *opt_str; + + hres = to_string(ctx, *flags_arg, &opt_str); + if(SUCCEEDED(hres)) { + opt = jsstr_flatten(opt_str); + if(opt) + hres = parse_regexp_flags(opt, jsstr_length(opt_str), &flags); + else + hres = E_OUTOFMEMORY; + jsstr_release(opt_str); + } + } + + if(SUCCEEDED(hres)) + hres = create_regexp(ctx, src, flags, ret); + jsstr_release(src); + return hres; } HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsval_t *r) { - static const WCHAR indexW[] = {'i','n','d','e','x',0}; - static const WCHAR inputW[] = {'i','n','p','u','t',0}; - static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0}; - RegExpInstance *regexp = regexp_from_jsdisp(re); match_result_t *match_result; - unsigned match_cnt, i; + DWORD match_cnt, i; const WCHAR *str; jsdisp_t *array; HRESULT hres; @@ -787,8 +757,10 @@ HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsv } hres = create_array(ctx, match_cnt, &array); - if(FAILED(hres)) + if(FAILED(hres)) { + free(match_result); return hres; + } for(i=0; i < match_cnt; i++) { jsstr_t *tmp_str; @@ -806,20 +778,20 @@ HRESULT regexp_string_match(script_ctx_t *ctx, jsdisp_t *re, jsstr_t *jsstr, jsv } while(SUCCEEDED(hres)) { - hres = jsdisp_propput_name(array, indexW, jsval_number(match_result[match_cnt-1].index)); + hres = jsdisp_propput_name(array, L"index", jsval_number(match_result[match_cnt-1].index)); if(FAILED(hres)) break; - hres = jsdisp_propput_name(array, lastIndexW, + hres = jsdisp_propput_name(array, L"lastIndex", jsval_number(match_result[match_cnt-1].index + match_result[match_cnt-1].length)); if(FAILED(hres)) break; - hres = jsdisp_propput_name(array, inputW, jsval_string(jsstr)); + hres = jsdisp_propput_name(array, L"input", jsval_string(jsstr)); break; } - heap_free(match_result); + free(match_result); if(SUCCEEDED(hres) && r) *r = jsval_obj(array); @@ -923,7 +895,7 @@ static HRESULT RegExpConstr_get_rightContext(script_ctx_t *ctx, jsdisp_t *jsthis return S_OK; } -static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, +static HRESULT RegExpConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { TRACE("\n"); @@ -932,21 +904,16 @@ static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags case DISPATCH_METHOD: if(argc) { if(is_object_instance(argv[0])) { - jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0])); + jsdisp_t *jsdisp = to_jsdisp(get_object(argv[0])); if(jsdisp) { if(is_class(jsdisp, JSCLASS_REGEXP)) { - if(argc > 1 && !is_undefined(argv[1])) { - jsdisp_release(jsdisp); - return throw_regexp_error(ctx, JS_E_REGEXP_SYNTAX, NULL); - } + if(argc > 1 && !is_undefined(argv[1])) + return JS_E_REGEXP_SYNTAX; if(r) - *r = jsval_obj(jsdisp); - else - jsdisp_release(jsdisp); + *r = jsval_obj(jsdisp_addref(jsdisp)); return S_OK; } - jsdisp_release(jsdisp); } } } @@ -955,12 +922,7 @@ static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags jsdisp_t *ret; HRESULT hres; - if(!argc) { - FIXME("no args\n"); - return E_NOTIMPL; - } - - hres = create_regexp_var(ctx, argv[0], argc > 1 ? argv+1 : NULL, &ret); + hres = create_regexp_var(ctx, argc ? argv[0] : jsval_undefined(), argc > 1 ? argv+1 : NULL, &ret); if(FAILED(hres)) return hres; @@ -979,40 +941,38 @@ static HRESULT RegExpConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags } static const builtin_prop_t RegExpConstr_props[] = { - {idx1W, NULL,0, RegExpConstr_get_idx1, builtin_set_const}, - {idx2W, NULL,0, RegExpConstr_get_idx2, builtin_set_const}, - {idx3W, NULL,0, RegExpConstr_get_idx3, builtin_set_const}, - {idx4W, NULL,0, RegExpConstr_get_idx4, builtin_set_const}, - {idx5W, NULL,0, RegExpConstr_get_idx5, builtin_set_const}, - {idx6W, NULL,0, RegExpConstr_get_idx6, builtin_set_const}, - {idx7W, NULL,0, RegExpConstr_get_idx7, builtin_set_const}, - {idx8W, NULL,0, RegExpConstr_get_idx8, builtin_set_const}, - {idx9W, NULL,0, RegExpConstr_get_idx9, builtin_set_const}, - {leftContextW, NULL,0, RegExpConstr_get_leftContext, builtin_set_const}, - {rightContextW, NULL,0, RegExpConstr_get_rightContext, builtin_set_const} + {L"$1", NULL,0, RegExpConstr_get_idx1, builtin_set_const}, + {L"$2", NULL,0, RegExpConstr_get_idx2, builtin_set_const}, + {L"$3", NULL,0, RegExpConstr_get_idx3, builtin_set_const}, + {L"$4", NULL,0, RegExpConstr_get_idx4, builtin_set_const}, + {L"$5", NULL,0, RegExpConstr_get_idx5, builtin_set_const}, + {L"$6", NULL,0, RegExpConstr_get_idx6, builtin_set_const}, + {L"$7", NULL,0, RegExpConstr_get_idx7, builtin_set_const}, + {L"$8", NULL,0, RegExpConstr_get_idx8, builtin_set_const}, + {L"$9", NULL,0, RegExpConstr_get_idx9, builtin_set_const}, + {L"leftContext", NULL,0, RegExpConstr_get_leftContext, builtin_set_const}, + {L"rightContext", NULL,0, RegExpConstr_get_rightContext, builtin_set_const} }; static const builtin_info_t RegExpConstr_info = { - JSCLASS_FUNCTION, - DEFAULT_FUNCTION_VALUE, - ARRAY_SIZE(RegExpConstr_props), - RegExpConstr_props, - NULL, - NULL + .class = JSCLASS_FUNCTION, + .call = Function_value, + .props_cnt = ARRAY_SIZE(RegExpConstr_props), + .props = RegExpConstr_props, }; HRESULT create_regexp_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret) { + jsstr_t *str = jsstr_empty(); RegExpInstance *regexp; HRESULT hres; - static const WCHAR RegExpW[] = {'R','e','g','E','x','p',0}; - - hres = alloc_regexp(ctx, object_prototype, ®exp); + hres = alloc_regexp(ctx, str, object_prototype, ®exp); + jsstr_release(str); if(FAILED(hres)) return hres; - hres = create_builtin_constructor(ctx, RegExpConstr_value, RegExpW, &RegExpConstr_info, + hres = create_builtin_constructor(ctx, RegExpConstr_value, L"RegExp", &RegExpConstr_info, PROPF_CONSTR|2, ®exp->dispex, ret); jsdisp_release(®exp->dispex); diff --git a/dll/win32/jscript/jsstr.c b/dll/win32/jscript/jsstr.c index 6a39c4c3dcc..76ded2528bb 100644 --- a/dll/win32/jscript/jsstr.c +++ b/dll/win32/jscript/jsstr.c @@ -45,7 +45,7 @@ void jsstr_free(jsstr_t *str) { switch(jsstr_tag(str)) { case JSSTR_HEAP: - heap_free(jsstr_as_heap(str)->buf); + free(jsstr_as_heap(str)->buf); break; case JSSTR_ROPE: { jsstr_rope_t *rope = jsstr_as_rope(str); @@ -57,7 +57,7 @@ void jsstr_free(jsstr_t *str) break; } - heap_free(str); + free(str); } static inline void jsstr_init(jsstr_t *str, unsigned len, jsstr_tag_t tag) @@ -73,7 +73,7 @@ jsstr_t *jsstr_alloc_buf(unsigned len, WCHAR **buf) if(len > JSSTR_MAX_LENGTH) return NULL; - ret = heap_alloc(FIELD_OFFSET(jsstr_inline_t, buf[len+1])); + ret = malloc(FIELD_OFFSET(jsstr_inline_t, buf[len+1])); if(!ret) return NULL; @@ -120,8 +120,11 @@ void jsstr_extract(jsstr_t *str, unsigned off, unsigned len, WCHAR *buf) memcpy(buf, jsstr_as_heap(str)->buf+off, len*sizeof(WCHAR)); return; case JSSTR_ROPE: +#ifdef __REACTOS__ jsstr_rope_extract(jsstr_as_rope(str), off, len, buf); - return; +#else + return jsstr_rope_extract(jsstr_as_rope(str), off, len, buf); +#endif } } @@ -235,7 +238,7 @@ jsstr_t *jsstr_concat(jsstr_t *str1, jsstr_t *str2) if(len1+len2 > JSSTR_MAX_LENGTH) return NULL; - rope = heap_alloc(sizeof(*rope)); + rope = malloc(sizeof(*rope)); if(!rope) return NULL; @@ -263,7 +266,7 @@ const WCHAR *jsstr_rope_flatten(jsstr_rope_t *str) { WCHAR *buf; - buf = heap_alloc((jsstr_length(&str->str)+1) * sizeof(WCHAR)); + buf = malloc((jsstr_length(&str->str)+1) * sizeof(WCHAR)); if(!buf) return NULL; @@ -300,22 +303,29 @@ jsstr_t *jsstr_null_bstr(void) return jsstr_addref(null_bstr_str); } -BOOL is_null_bstr(jsstr_t *str) +HRESULT jsstr_to_bstr(jsstr_t *str, BSTR *r) { - return str == null_bstr_str; + if(str == null_bstr_str) { + *r = NULL; + return S_OK; + } + + if(!(*r = SysAllocStringLen(NULL, jsstr_length(str)))) + return E_OUTOFMEMORY; + + jsstr_flush(str, *r); + return S_OK; } BOOL init_strings(void) { - static const WCHAR NaNW[] = { 'N','a','N',0 }; - static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0}; WCHAR *ptr; if(!(empty_str = jsstr_alloc_buf(0, &ptr))) return FALSE; - if(!(nan_str = jsstr_alloc(NaNW))) + if(!(nan_str = jsstr_alloc(L"NaN"))) return FALSE; - if(!(undefined_str = jsstr_alloc(undefinedW))) + if(!(undefined_str = jsstr_alloc(L"undefined"))) return FALSE; if(!(null_bstr_str = jsstr_alloc_buf(0, &ptr))) return FALSE; diff --git a/dll/win32/jscript/jsstr.h b/dll/win32/jscript/jsstr.h index e55fef23584..ecc87d5d916 100644 --- a/dll/win32/jscript/jsstr.h +++ b/dll/win32/jscript/jsstr.h @@ -33,9 +33,6 @@ * * In the future more layouts and transformations may be added. */ - -#pragma once - struct _jsstr_t { unsigned length_flags; unsigned ref; @@ -82,7 +79,7 @@ static inline BOOL jsstr_is_rope(jsstr_t *str) typedef struct { jsstr_t str; - WCHAR buf[1]; + WCHAR buf[]; } jsstr_inline_t; typedef struct { @@ -97,15 +94,15 @@ typedef struct { unsigned depth; } jsstr_rope_t; -jsstr_t *jsstr_alloc_len(const WCHAR*,unsigned) DECLSPEC_HIDDEN; -jsstr_t *jsstr_alloc_buf(unsigned,WCHAR**) DECLSPEC_HIDDEN; +jsstr_t *jsstr_alloc_len(const WCHAR*,unsigned); +jsstr_t *jsstr_alloc_buf(unsigned,WCHAR**); static inline jsstr_t *jsstr_alloc(const WCHAR *str) { return jsstr_alloc_len(str, lstrlenW(str)); } -void jsstr_free(jsstr_t*) DECLSPEC_HIDDEN; +void jsstr_free(jsstr_t*); static inline void jsstr_release(jsstr_t *str) { @@ -134,7 +131,7 @@ static inline jsstr_rope_t *jsstr_as_rope(jsstr_t *str) return CONTAINING_RECORD(str, jsstr_rope_t, str); } -const WCHAR *jsstr_rope_flatten(jsstr_rope_t*) DECLSPEC_HIDDEN; +const WCHAR *jsstr_rope_flatten(jsstr_rope_t*); static inline const WCHAR *jsstr_flatten(jsstr_t *str) { @@ -143,7 +140,7 @@ static inline const WCHAR *jsstr_flatten(jsstr_t *str) : jsstr_rope_flatten(jsstr_as_rope(str)); } -void jsstr_extract(jsstr_t*,unsigned,unsigned,WCHAR*) DECLSPEC_HIDDEN; +void jsstr_extract(jsstr_t*,unsigned,unsigned,WCHAR*); static inline unsigned jsstr_flush(jsstr_t *str, WCHAR *buf) { @@ -171,23 +168,23 @@ static inline jsstr_t *jsstr_substr(jsstr_t *str, unsigned off, unsigned len) return ret; } -int jsstr_cmp(jsstr_t*,jsstr_t*) DECLSPEC_HIDDEN; +int jsstr_cmp(jsstr_t*,jsstr_t*); static inline BOOL jsstr_eq(jsstr_t *left, jsstr_t *right) { return jsstr_length(left) == jsstr_length(right) && !jsstr_cmp(left, right); } -jsstr_t *jsstr_concat(jsstr_t*,jsstr_t*) DECLSPEC_HIDDEN; +jsstr_t *jsstr_concat(jsstr_t*,jsstr_t*); -jsstr_t *jsstr_nan(void) DECLSPEC_HIDDEN; -jsstr_t *jsstr_empty(void) DECLSPEC_HIDDEN; -jsstr_t *jsstr_undefined(void) DECLSPEC_HIDDEN; +jsstr_t *jsstr_nan(void); +jsstr_t *jsstr_empty(void); +jsstr_t *jsstr_undefined(void); -jsstr_t *jsstr_null_bstr(void) DECLSPEC_HIDDEN; -BOOL is_null_bstr(jsstr_t*) DECLSPEC_HIDDEN; +jsstr_t *jsstr_null_bstr(void); +HRESULT jsstr_to_bstr(jsstr_t *str, BSTR *r); -BOOL init_strings(void) DECLSPEC_HIDDEN; -void free_strings(void) DECLSPEC_HIDDEN; +BOOL init_strings(void); +void free_strings(void); -const char *debugstr_jsstr(jsstr_t*) DECLSPEC_HIDDEN; +const char *debugstr_jsstr(jsstr_t*); diff --git a/dll/win32/jscript/jsutils.c b/dll/win32/jscript/jsutils.c index 33a61c2d856..74ffe44c754 100644 --- a/dll/win32/jscript/jsutils.c +++ b/dll/win32/jscript/jsutils.c @@ -55,11 +55,6 @@ const char *debugstr_jsval(const jsval_t v) return NULL; } -BOOL is_finite(double n) -{ - return !isnan(n) && !isinf(n); -} - #define MIN_BLOCK_SIZE 128 #define ARENA_FREE_FILLER 0xaa @@ -81,12 +76,12 @@ void *heap_pool_alloc(heap_pool_t *heap, DWORD size) if(!heap->block_cnt) { if(!heap->blocks) { - heap->blocks = heap_alloc(sizeof(void*)); + heap->blocks = malloc(sizeof(void*)); if(!heap->blocks) return NULL; } - tmp = heap_alloc(block_size(0)); + tmp = malloc(block_size(0)); if(!tmp) return NULL; @@ -102,12 +97,12 @@ void *heap_pool_alloc(heap_pool_t *heap, DWORD size) if(size <= block_size(heap->last_block+1)) { if(heap->last_block+1 == heap->block_cnt) { - tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*)); + tmp = realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*)); if(!tmp) return NULL; heap->blocks = tmp; - heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt)); + heap->blocks[heap->block_cnt] = malloc(block_size(heap->block_cnt)); if(!heap->blocks[heap->block_cnt]) return NULL; @@ -119,7 +114,7 @@ void *heap_pool_alloc(heap_pool_t *heap, DWORD size) return heap->blocks[heap->last_block]; } - list = heap_alloc(size + sizeof(struct list)); + list = malloc(size + sizeof(struct list)); if(!list) return NULL; @@ -152,7 +147,7 @@ void heap_pool_clear(heap_pool_t *heap) while((tmp = list_head(&heap->custom_blocks))) { list_remove(tmp); - heap_free(tmp); + free(tmp); } if(WARN_ON(heap)) { @@ -173,8 +168,8 @@ void heap_pool_free(heap_pool_t *heap) heap_pool_clear(heap); for(i=0; i < heap->block_cnt; i++) - heap_free(heap->blocks[i]); - heap_free(heap->blocks); + free(heap->blocks[i]); + free(heap->blocks); heap_pool_init(heap); } @@ -192,15 +187,14 @@ void jsval_release(jsval_t val) { switch(jsval_type(val)) { case JSV_OBJECT: - if(get_object(val)) - IDispatch_Release(get_object(val)); + IDispatch_Release(get_object(val)); break; case JSV_STRING: jsstr_release(get_string(val)); break; case JSV_VARIANT: VariantClear(get_variant(val)); - heap_free(get_variant(val)); + free(get_variant(val)); break; default: break; @@ -213,7 +207,7 @@ static HRESULT jsval_variant(jsval_t *val, VARIANT *var) HRESULT hres; __JSVAL_TYPE(*val) = JSV_VARIANT; - __JSVAL_VAR(*val) = v = heap_alloc(sizeof(VARIANT)); + __JSVAL_VAR(*val) = v = malloc(sizeof(VARIANT)); if(!v) { *val = jsval_undefined(); return E_OUTOFMEMORY; @@ -223,7 +217,7 @@ static HRESULT jsval_variant(jsval_t *val, VARIANT *var) hres = VariantCopy(v, var); if(FAILED(hres)) { *val = jsval_undefined(); - heap_free(v); + free(v); } return hres; } @@ -238,8 +232,7 @@ HRESULT jsval_copy(jsval_t v, jsval_t *r) *r = v; return S_OK; case JSV_OBJECT: - if(get_object(v)) - IDispatch_AddRef(get_object(v)); + IDispatch_AddRef(get_object(v)); *r = v; return S_OK; case JSV_STRING: { @@ -255,7 +248,7 @@ HRESULT jsval_copy(jsval_t v, jsval_t *r) return E_FAIL; } -HRESULT variant_to_jsval(VARIANT *var, jsval_t *r) +HRESULT variant_to_jsval(script_ctx_t *ctx, VARIANT *var, jsval_t *r) { if(V_VT(var) == (VT_VARIANT|VT_BYREF)) var = V_VARIANTREF(var); @@ -290,12 +283,33 @@ HRESULT variant_to_jsval(VARIANT *var, jsval_t *r) *r = jsval_string(str); return S_OK; } - case VT_DISPATCH: { - if(V_DISPATCH(var)) - IDispatch_AddRef(V_DISPATCH(var)); + case VT_DISPATCH: + if(!V_DISPATCH(var)) { + *r = ctx->html_mode ? jsval_null() : jsval_null_disp(); + return S_OK; + } + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) { + IWineJSDispatchHost *disp_host; + HRESULT hres; + hres = IDispatch_QueryInterface(V_DISPATCH(var), &IID_IWineJSDispatchHost, (void **)&disp_host); + if(SUCCEEDED(hres)) { + IWineJSDispatch *jsdisp_iface; + hres = IWineJSDispatchHost_GetJSDispatch(disp_host, &jsdisp_iface); + IWineJSDispatchHost_Release(disp_host); + if(SUCCEEDED(hres)) { + jsdisp_t *jsdisp = to_jsdisp((IDispatch *)jsdisp_iface); + if(jsdisp->ctx == ctx) { + *r = jsval_obj(jsdisp); + return S_OK; + }else { + jsdisp_release(jsdisp); + } + } + } + } + IDispatch_AddRef(V_DISPATCH(var)); *r = jsval_disp(V_DISPATCH(var)); return S_OK; - } case VT_I1: *r = jsval_number(V_I1(var)); return S_OK; @@ -324,6 +338,12 @@ HRESULT variant_to_jsval(VARIANT *var, jsval_t *r) case VT_R4: *r = jsval_number(V_R4(var)); return S_OK; + case VT_CY: + /* FIXME: Native converts VT_CY to a special kind number type, which is + * never converted to VT_I4 when it's converted back to VARIANT. */ + *r = jsval_number((double)V_CY(var).int64 / 10000.0); + WARN("VT_CY: %lf\n", get_number(*r)); + return S_OK; case VT_UNKNOWN: if(V_UNKNOWN(var)) { IDispatch *disp; @@ -335,7 +355,7 @@ HRESULT variant_to_jsval(VARIANT *var, jsval_t *r) return S_OK; } }else { - *r = jsval_disp(NULL); + *r = ctx->html_mode ? jsval_null() : jsval_null_disp(); return S_OK; } /* fall through */ @@ -351,29 +371,28 @@ HRESULT jsval_to_variant(jsval_t val, VARIANT *retv) V_VT(retv) = VT_EMPTY; return S_OK; case JSV_NULL: + if(get_bool(val)) { + V_VT(retv) = VT_DISPATCH; + V_DISPATCH(retv) = NULL; + return S_OK; + } V_VT(retv) = VT_NULL; return S_OK; - case JSV_OBJECT: + case JSV_OBJECT: { + IWineJSDispatchHost *host_disp = get_host_dispatch(get_object(val)); V_VT(retv) = VT_DISPATCH; - if(get_object(val)) - IDispatch_AddRef(get_object(val)); - V_DISPATCH(retv) = get_object(val); - return S_OK; - case JSV_STRING: { - jsstr_t *str = get_string(val); - - V_VT(retv) = VT_BSTR; - if(is_null_bstr(str)) { - V_BSTR(retv) = NULL; - }else { - V_BSTR(retv) = SysAllocStringLen(NULL, jsstr_length(str)); - if(V_BSTR(retv)) - jsstr_flush(str, V_BSTR(retv)); - else - return E_OUTOFMEMORY; + if(host_disp) { + V_DISPATCH(retv) = (IDispatch *)host_disp; + return S_OK; } + + V_DISPATCH(retv) = get_object(val); + IDispatch_AddRef(get_object(val)); return S_OK; } + case JSV_STRING: + V_VT(retv) = VT_BSTR; + return jsstr_to_bstr(get_string(val), &V_BSTR(retv)); case JSV_NUMBER: { double n = get_number(val); @@ -409,14 +428,6 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) DISPID id; HRESULT hres; - static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0}; - static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0}; - - if(!get_object(val)) { - *ret = jsval_null(); - return S_OK; - } - jsdisp = iface_to_jsdisp(get_object(val)); if(!jsdisp) return disp_propget(ctx, get_object(val), DISPID_VALUE, ret); @@ -426,7 +437,7 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) /* Native implementation doesn't throw TypeErrors, returns strange values */ - hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id); + hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? L"toString" : L"valueOf", 0, &id); if(SUCCEEDED(hres)) { hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); if(FAILED(hres)) { @@ -440,9 +451,12 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) }else { IDispatch_Release(get_object(prim)); } + }else if(hres != DISP_E_UNKNOWNNAME) { + jsdisp_release(jsdisp); + return hres; } - hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id); + hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? L"valueOf" : L"toString", 0, &id); if(SUCCEEDED(hres)) { hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, 0, NULL, &prim); if(FAILED(hres)) { @@ -456,12 +470,15 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) }else { IDispatch_Release(get_object(prim)); } + }else if(hres != DISP_E_UNKNOWNNAME) { + jsdisp_release(jsdisp); + return hres; } jsdisp_release(jsdisp); WARN("failed\n"); - return throw_type_error(ctx, JS_E_TO_PRIMITIVE, NULL); + return JS_E_TO_PRIMITIVE; } return jsval_copy(val, ret); @@ -477,7 +494,7 @@ HRESULT to_boolean(jsval_t val, BOOL *ret) *ret = FALSE; return S_OK; case JSV_OBJECT: - *ret = get_object(val) != NULL; + *ret = TRUE; return S_OK; case JSV_STRING: *ret = jsstr_length(get_string(val)) != 0; @@ -497,7 +514,11 @@ HRESULT to_boolean(jsval_t val, BOOL *ret) return E_FAIL; } +#if defined(__REACTOS__) && defined(__clang__) +static inline __attribute__((always_inline)) int hex_to_int(WCHAR c) +#else static int hex_to_int(WCHAR c) +#endif { if('0' <= c && c <= '9') return c-'0'; @@ -518,7 +539,7 @@ static HRESULT str_to_number(jsstr_t *str, double *ret) BOOL neg = FALSE; DOUBLE d = 0.0; - static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'}; + static const WCHAR infinityW[] = L"Infinity"; ptr = jsstr_flatten(str); if(!ptr) @@ -534,8 +555,8 @@ static HRESULT str_to_number(jsstr_t *str, double *ret) ptr++; } - if(!wcsncmp(ptr, infinityW, ARRAY_SIZE(infinityW))) { - ptr += ARRAY_SIZE(infinityW); + if(!wcsncmp(ptr, infinityW, ARRAY_SIZE(infinityW)-1)) { + ptr += ARRAY_SIZE(infinityW) - 1; while(*ptr && iswspace(*ptr)) ptr++; @@ -559,7 +580,7 @@ static HRESULT str_to_number(jsstr_t *str, double *ret) return S_OK; } - while(iswdigit(*ptr)) + while(is_digit(*ptr)) d = d*10 + (*ptr++ - '0'); if(*ptr == 'e' || *ptr == 'E') { @@ -574,7 +595,7 @@ static HRESULT str_to_number(jsstr_t *str, double *ret) ptr++; } - while(iswdigit(*ptr)) + while(is_digit(*ptr)) l = l*10 + (*ptr++ - '0'); if(eneg) l = -l; @@ -584,7 +605,7 @@ static HRESULT str_to_number(jsstr_t *str, double *ret) DOUBLE dec = 0.1; ptr++; - while(iswdigit(*ptr)) { + while(is_digit(*ptr)) { d += dec * (*ptr++ - '0'); dec *= 0.1; } @@ -635,9 +656,16 @@ HRESULT to_number(script_ctx_t *ctx, jsval_t val, double *ret) case JSV_BOOL: *ret = get_bool(val) ? 1 : 0; return S_OK; - case JSV_VARIANT: - FIXME("unimplemented for variant %s\n", debugstr_variant(get_variant(val))); - return E_NOTIMPL; + case JSV_VARIANT: { + const VARIANT *v = get_variant(val); + switch(V_VT(v)) { + case VT_DATE: + return variant_date_to_number(V_DATE(v), ret); + default: + FIXME("unimplemented for variant %s\n", debugstr_variant(v)); + return E_NOTIMPL; + } + } }; assert(0); @@ -661,79 +689,95 @@ HRESULT to_integer(script_ctx_t *ctx, jsval_t v, double *ret) return S_OK; } +static INT32 double_to_int32(double number) +{ + INT32 exp, result; + union { + double d; + INT64 n; + } bits; + + bits.d = number; + exp = ((INT32)(bits.n >> 52) & 0x7ff) - 0x3ff; + + /* If exponent < 0 there will be no bits to the left of the decimal point + * after rounding; if the exponent is > 83 then no bits of precision can be + * left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits + * of fractional precision). + * Note this case handles 0, -0, and all infinite, NaN & denormal values. */ + if(exp < 0 || exp > 83) + return 0; + + /* Select the appropriate 32-bits from the floating point mantissa. If the + * exponent is 52 then the bits we need to select are already aligned to the + * lowest bits of the 64-bit integer representation of the number, no need + * to shift. If the exponent is greater than 52 we need to shift the value + * left by (exp - 52), if the value is less than 52 we need to shift right + * accordingly. */ + result = (exp > 52) ? bits.n << (exp - 52) : bits.n >> (52 - exp); + + /* IEEE-754 double precision values are stored omitting an implicit 1 before + * the decimal point; we need to reinsert this now. We may also the shifted + * invalid bits into the result that are not a part of the mantissa (the sign + * and exponent bits from the floatingpoint representation); mask these out. */ + if(exp < 32) { + INT32 missing_one = 1 << exp; + result &= missing_one - 1; + result += missing_one; + } + + /* If the input value was negative (we could test either 'number' or 'bits', + * but testing 'bits' is likely faster) invert the result appropriately. */ + return bits.n < 0 ? -result : result; +} + /* ECMA-262 3rd Edition 9.5 */ HRESULT to_int32(script_ctx_t *ctx, jsval_t v, INT *ret) { double n; HRESULT hres; - const double p32 = (double)0xffffffff + 1; - hres = to_number(ctx, v, &n); if(FAILED(hres)) return hres; - if(is_finite(n)) - n = n > 0 ? fmod(n, p32) : -fmod(-n, p32); - else - n = 0; - - *ret = (UINT32)n; + *ret = double_to_int32(n); return S_OK; } +HRESULT to_long(script_ctx_t *ctx, jsval_t v, LONG *ret) +{ + return to_int32(ctx, v, (INT*)ret); +} + /* ECMA-262 3rd Edition 9.6 */ HRESULT to_uint32(script_ctx_t *ctx, jsval_t val, UINT32 *ret) { - INT32 n; + double n; HRESULT hres; - hres = to_int32(ctx, val, &n); - if(SUCCEEDED(hres)) - *ret = n; - return hres; -} + hres = to_number(ctx, val, &n); + if(FAILED(hres)) + return hres; -static jsstr_t *int_to_string(int i) -{ - WCHAR buf[12], *p; - BOOL neg = FALSE; - - if(!i) { - static const WCHAR zeroW[] = {'0',0}; - return jsstr_alloc(zeroW); - } - - if(i < 0) { - neg = TRUE; - i = -i; - } - - p = buf + ARRAY_SIZE(buf)-1; - *p-- = 0; - while(i) { - *p-- = i%10 + '0'; - i /= 10; - } - - if(neg) - *p = '-'; - else - p++; - - return jsstr_alloc(p); + *ret = double_to_int32(n); + return S_OK; } HRESULT double_to_string(double n, jsstr_t **str) { - static const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0}; - if(isnan(n)) { *str = jsstr_nan(); }else if(isinf(n)) { - *str = jsstr_alloc(n<0 ? InfinityW : InfinityW+1); + *str = jsstr_alloc(n<0 ? L"-Infinity" : L"Infinity"); }else if(is_int32(n)) { - *str = int_to_string(n); + WCHAR buf[12]; +#ifdef __REACTOS__ /* FIXME: Inspect */ + swprintf(buf, ARRAY_SIZE(buf), L"%d", (int)n); +#else + _ltow_s(n, buf, ARRAY_SIZE(buf), 10); +#endif + *str = jsstr_alloc(buf); }else { VARIANT strv, v; HRESULT hres; @@ -756,16 +800,12 @@ HRESULT double_to_string(double n, jsstr_t **str) /* ECMA-262 3rd Edition 9.8 */ HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str) { - static const WCHAR nullW[] = {'n','u','l','l',0}; - static const WCHAR trueW[] = {'t','r','u','e',0}; - static const WCHAR falseW[] = {'f','a','l','s','e',0}; - switch(jsval_type(val)) { case JSV_UNDEFINED: *str = jsstr_undefined(); return S_OK; case JSV_NULL: - *str = jsstr_alloc(nullW); + *str = jsstr_alloc(L"null"); break; case JSV_NUMBER: return double_to_string(get_number(val), str); @@ -785,11 +825,19 @@ HRESULT to_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str) return hres; } case JSV_BOOL: - *str = jsstr_alloc(get_bool(val) ? trueW : falseW); + *str = jsstr_alloc(get_bool(val) ? L"true" : L"false"); break; - default: - FIXME("unsupported %s\n", debugstr_jsval(val)); - return E_NOTIMPL; + default: { + const VARIANT *v = get_variant(val); + switch(V_VT(v)) + { + case VT_DATE: + return variant_date_to_string(ctx, V_DATE(v), str); + default: + FIXME("unsupported %s\n", debugstr_variant(v)); + return E_NOTIMPL; + } + } } return *str ? S_OK : E_OUTOFMEMORY; @@ -834,18 +882,8 @@ HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp) *disp = to_disp(dispex); break; case JSV_OBJECT: - if(get_object(val)) { - *disp = get_object(val); - IDispatch_AddRef(*disp); - }else { - jsdisp_t *obj; - - hres = create_object(ctx, NULL, &obj); - if(FAILED(hres)) - return hres; - - *disp = to_disp(obj); - } + *disp = get_object(val); + IDispatch_AddRef(*disp); break; case JSV_BOOL: hres = create_bool(ctx, get_bool(val), &dispex); @@ -854,10 +892,13 @@ HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp) *disp = to_disp(dispex); break; - case JSV_UNDEFINED: case JSV_NULL: + if(is_null_disp(val)) + return JS_E_OBJECT_REQUIRED; + /* fall through */ + case JSV_UNDEFINED: WARN("object expected\n"); - return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL); + return JS_E_OBJECT_EXPECTED; case JSV_VARIANT: switch(V_VT(get_variant(val))) { case VT_ARRAY|VT_VARIANT: @@ -880,14 +921,16 @@ HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp) HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt) { + jsexcept_t ei; jsval_t val; HRESULT hres; - clear_ei(ctx); - hres = variant_to_jsval(src, &val); + hres = variant_to_jsval(ctx, src, &val); if(FAILED(hres)) return hres; + enter_script(ctx, &ei); + switch(vt) { case VT_I2: case VT_I4: { @@ -940,16 +983,8 @@ HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTY if(FAILED(hres)) break; - if(is_null_bstr(str)) { - V_BSTR(dst) = NULL; - break; - } - - V_BSTR(dst) = SysAllocStringLen(NULL, jsstr_length(str)); - if(V_BSTR(dst)) - jsstr_flush(str, V_BSTR(dst)); - else - hres = E_OUTOFMEMORY; + hres = jsstr_to_bstr(str, &V_BSTR(dst)); + jsstr_release(str); break; } case VT_EMPTY: @@ -958,12 +993,23 @@ HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTY case VT_NULL: hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL; break; + case VT_UNKNOWN: + case VT_DISPATCH: + if(V_VT(src) != vt) + hres = E_NOTIMPL; + else { + IUnknown_AddRef(V_UNKNOWN(src)); + V_UNKNOWN(dst) = V_UNKNOWN(src); + hres = S_OK; + } + break; default: FIXME("vt %d not implemented\n", vt); hres = E_NOTIMPL; } jsval_release(val); + leave_script(ctx, hres); if(FAILED(hres)) return hres; @@ -1001,7 +1047,7 @@ static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface) JSCaller *This = impl_from_IServiceProvider(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); return ref; } @@ -1009,13 +1055,13 @@ static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface) static ULONG WINAPI JSCaller_Release(IServiceProvider *iface) { JSCaller *This = impl_from_IServiceProvider(iface); - LONG ref = InterlockedIncrement(&This->ref); + LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%d\n", This, ref); + TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { assert(!This->ctx); - heap_free(This); + free(This); } return ref; @@ -1026,6 +1072,22 @@ static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID gui { JSCaller *This = impl_from_IServiceProvider(iface); + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + TRACE("(%p)->(IID_IActiveScriptSite)\n", This); + if(This->ctx && This->ctx->site) + return IActiveScriptSite_QueryInterface(This->ctx->site, riid, ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + TRACE("(%p)->(SID_GetCaller)\n", This); + *ppv = NULL; + if(!This->caller) + return S_OK; + return (This->caller == SP_CALLER_UNINITIALIZED) ? E_NOINTERFACE : IServiceProvider_QueryInterface(This->caller, riid, ppv); + } + if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) { TRACE("(%p)->(SID_VariantConversion)\n", This); return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv); @@ -1048,13 +1110,14 @@ HRESULT create_jscaller(script_ctx_t *ctx) { JSCaller *ret; - ret = heap_alloc(sizeof(*ret)); + ret = malloc(sizeof(*ret)); if(!ret) return E_OUTOFMEMORY; ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; ret->ref = 1; ret->ctx = ctx; + ret->caller = SP_CALLER_UNINITIALIZED; ctx->jscaller = ret; return S_OK; diff --git a/dll/win32/jscript/jsval.h b/dll/win32/jscript/jsval.h index 963f59f6a08..16aacda7162 100644 --- a/dll/win32/jscript/jsval.h +++ b/dll/win32/jscript/jsval.h @@ -35,8 +35,8 @@ #endif #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 -/* NaN exponent and our 0x80000 marker */ -#define JSV_VAL(x) (0x7ff80000|x) +/* NaN exponent, quiet bit 0x80000 and our 0x10000 marker */ +#define JSV_VAL(x) (0x7ff90000|x) #else #define JSV_VAL(x) x #endif @@ -131,6 +131,15 @@ static inline jsval_t jsval_null(void) { jsval_t ret; __JSVAL_TYPE(ret) = JSV_NULL; + __JSVAL_BOOL(ret) = FALSE; + return ret; +} + +static inline jsval_t jsval_null_disp(void) +{ + jsval_t ret; + __JSVAL_TYPE(ret) = JSV_NULL; + __JSVAL_BOOL(ret) = TRUE; return ret; } @@ -150,10 +159,10 @@ static inline jsval_t jsval_number(double n) if((ret.u.s.tag & 0x7ff00000) == 0x7ff00000) { /* isinf */ if(ret.u.s.tag & 0xfffff) { - ret.u.s.tag = 0x7ff00000; + ret.u.s.tag = 0x7ff80000; ret.u.s.u.as_uintptr = ~0; }else if(ret.u.s.u.as_uintptr) { - ret.u.s.tag = 0x7ff00000; + ret.u.s.tag = 0x7ff80000; } } #else @@ -178,9 +187,9 @@ static inline BOOL is_null(jsval_t v) return __JSVAL_TYPE(v) == JSV_NULL; } -static inline BOOL is_null_instance(jsval_t v) +static inline BOOL is_null_disp(jsval_t v) { - return is_null(v) || (is_object_instance(v) && !__JSVAL_OBJ(v)); + return is_null(v) && __JSVAL_BOOL(v); } static inline BOOL is_string(jsval_t v) @@ -191,7 +200,7 @@ static inline BOOL is_string(jsval_t v) static inline BOOL is_number(jsval_t v) { #ifdef JSVAL_DOUBLE_LAYOUT_PTR32 - return (v.u.s.tag & 0x7ff80000) != 0x7ff80000; + return (v.u.s.tag & 0x7ff10000) != 0x7ff10000; #else return v.type == JSV_NUMBER; #endif @@ -241,9 +250,9 @@ static inline BOOL get_bool(jsval_t v) return __JSVAL_BOOL(v); } -HRESULT variant_to_jsval(VARIANT*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT jsval_to_variant(jsval_t,VARIANT*) DECLSPEC_HIDDEN; -void jsval_release(jsval_t) DECLSPEC_HIDDEN; -HRESULT jsval_copy(jsval_t,jsval_t*) DECLSPEC_HIDDEN; +HRESULT variant_to_jsval(script_ctx_t*,VARIANT*,jsval_t*); +HRESULT jsval_to_variant(jsval_t,VARIANT*); +void jsval_release(jsval_t); +HRESULT jsval_copy(jsval_t,jsval_t*); #endif diff --git a/dll/win32/jscript/lang/jscript_Da.rc b/dll/win32/jscript/lang/jscript_Da.rc index e373a0af9b6..c4f98931068 100644 --- a/dll/win32/jscript/lang/jscript_Da.rc +++ b/dll/win32/jscript/lang/jscript_Da.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Fejl ved konvertering af objekt til primitiv type" IDS_INVALID_CALL_ARG "Ugyldig procedure kald eller argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automations-serveren kan ikke oprette objektet" IDS_NO_PROPERTY "Objektet understøtter ikke denne egenskab eller metode" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argument ikke valgfrit" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Syntaksfejl" IDS_SEMICOLON "Forventet ';'" IDS_LBRACKET "Forventet '('" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScript objekt forventet" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Syntax fejl i regulært udtryk" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI, der skal kodes indeholder ugyldige tegn" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -63,7 +69,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Array længde skal være et endeligt positivt heltal" IDS_ARRAY_EXPECTED "Array objekt forventet" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_De.rc b/dll/win32/jscript/lang/jscript_De.rc index 967a39fcab4..b7634d6d97e 100644 --- a/dll/win32/jscript/lang/jscript_De.rc +++ b/dll/win32/jscript/lang/jscript_De.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Fehler beim Umwandeln des Objektes in einen Grundtyp" IDS_INVALID_CALL_ARG "Ungültiger Funktionsaufruf oder ungültiges Argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automatisierungsserver konnte das Objekt nicht erstellen" IDS_NO_PROPERTY "Das Objekt unterstützt diese Eigenschaft oder Methode nicht" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Dieses Argument ist nicht optional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Syntaxfehler" IDS_SEMICOLON "';' erwartet" IDS_LBRACKET "'(' erwartet" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScript-Objekt erwartet" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Syntaxfehler in regulärem Ausdruck" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "Zu verschlüsselnde URI enthält ungültige Zeichen" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Größe des Array muss eine endliche, positive Ganzzahl sein" IDS_ARRAY_EXPECTED "Array-Objekt erwartet" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_En.rc b/dll/win32/jscript/lang/jscript_En.rc index 0381b43e26b..16a1468e772 100644 --- a/dll/win32/jscript/lang/jscript_En.rc +++ b/dll/win32/jscript/lang/jscript_En.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Error converting object to primitive type" IDS_INVALID_CALL_ARG "Invalid procedure call or argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automation server can't create object" IDS_NO_PROPERTY "Object doesn't support this property or method" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argument not optional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Syntax error" IDS_SEMICOLON "Expected ';'" IDS_LBRACKET "Expected '('" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScript object expected" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Syntax error in regular expression" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI to be encoded contains invalid characters" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Array length must be a finite positive integer" IDS_ARRAY_EXPECTED "Array object expected" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Es.rc b/dll/win32/jscript/lang/jscript_Es.rc index 73cfe3b8f02..7e361592f4b 100644 --- a/dll/win32/jscript/lang/jscript_Es.rc +++ b/dll/win32/jscript/lang/jscript_Es.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Error al convertir objeto a tipo primitivo" IDS_INVALID_CALL_ARG "Llamada a procedimiento no válido o argumento" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Servidor de automatización no puede crear el objeto" IDS_NO_PROPERTY "El objeto no acepta esta propiedad o método" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argumento no opcional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Error de sintaxis" IDS_SEMICOLON "Esperado ';'" IDS_LBRACKET "Esperado '('" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Objeto JScript esperado" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Error de sintaxis en la expresion regular" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI a codificar contiene caracteres no válidos" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "La longitud del arreglo debe ser un entero positivo finito" IDS_ARRAY_EXPECTED "Objeto Arreglo esperado" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Fr.rc b/dll/win32/jscript/lang/jscript_Fr.rc index dc5abfde4df..48115a59b45 100644 --- a/dll/win32/jscript/lang/jscript_Fr.rc +++ b/dll/win32/jscript/lang/jscript_Fr.rc @@ -25,11 +25,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Erreur lors de la conversion de l'objet vers un type primitif" IDS_INVALID_CALL_ARG "Appel de procédure ou argument invalide" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Le serveur d'automatisation ne peut créer l'objet" IDS_NO_PROPERTY "Cet objet ne supporte pas cette propriété ou méthode" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argument non optionnel" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Erreur de syntaxe" IDS_SEMICOLON "« ; » attendu" IDS_LBRACKET "« ( » attendu" @@ -56,7 +58,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Objet JScript attendu" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Erreur de syntaxe dans l'expression rationnelle" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "L'URI à coder contient des caractères invalides" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -64,7 +70,21 @@ STRINGTABLE IDS_INVALID_LENGTH "La longueur d'un tableau doit être un entier positif" IDS_ARRAY_EXPECTED "Objet tableau attendu" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_He.rc b/dll/win32/jscript/lang/jscript_He.rc index b65b04c7ade..10e4ffe560f 100644 --- a/dll/win32/jscript/lang/jscript_He.rc +++ b/dll/win32/jscript/lang/jscript_He.rc @@ -25,11 +25,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Error converting object to primitive type" IDS_INVALID_CALL_ARG "Invalid procedure call or argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automation server can't create object" IDS_NO_PROPERTY "Object doesn't support this property or method" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argument not optional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "שגיאת תחביר" IDS_SEMICOLON "צפוי ';'" IDS_LBRACKET "צפוי '('" @@ -56,7 +58,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "אובייקט JScript היה צפוי" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Syntax error in regular expression" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI to be encoded contains invalid characters" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -64,7 +70,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Array length must be a finite positive integer" IDS_ARRAY_EXPECTED "אובייקט מערך היה צפוי" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Hu.rc b/dll/win32/jscript/lang/jscript_Hu.rc index 401ccd9ca15..a2d745df814 100644 --- a/dll/win32/jscript/lang/jscript_Hu.rc +++ b/dll/win32/jscript/lang/jscript_Hu.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Hiba az objektum primitív típusra való konvertálásánál" IDS_INVALID_CALL_ARG "Érvénytelen eljáráshívás vagy argmentum" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Az automatizáló (automation) kiszolgáló nem tud objektumot létrehozni" IDS_NO_PROPERTY "Az objektum nem támogatja ezt a tulajdonságot vagy metódust" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Az argumentum nem opcionális" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Szinttaktikai hiba" IDS_SEMICOLON "Hiányzó ';'" IDS_LBRACKET "Hiányzó '('" @@ -54,6 +56,8 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScript objektumot vártam" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Szinttaktikai hiba a reguláris kifejezésben" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "A kódolandó URI érvénytelen karaktereket tartalmaz" @@ -62,7 +66,21 @@ STRINGTABLE IDS_INVALID_LENGTH "A tömb hosszának egy véges pozitív egész számnak kell lennie" IDS_ARRAY_EXPECTED "Tömb objektumot vártam" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_It.rc b/dll/win32/jscript/lang/jscript_It.rc index 23fa96588a9..b6b79fd8f8e 100644 --- a/dll/win32/jscript/lang/jscript_It.rc +++ b/dll/win32/jscript/lang/jscript_It.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Errore nel convertire un oggetto ad un tipo primitivo" IDS_INVALID_CALL_ARG "Chiamata o argomento di procedura non valido" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Il server di automazione non può creare l'oggetto" IDS_NO_PROPERTY "L'oggetto non supporta questa proprietà o metodo" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argomento non opzionale" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Errore di sintassi" IDS_SEMICOLON "Richiesto ';'" IDS_LBRACKET "Richiesto '('" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Richiesto un oggetto JScript" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Errore di sintassi nell'espressione regolare" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "L'URI da codificare contiene caratteri non validi" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -63,7 +69,21 @@ STRINGTABLE IDS_INVALID_LENGTH "La lunghezza dell'array deve essere un intero finito e positivo" IDS_ARRAY_EXPECTED "Richiesto un oggetto array" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Ja.rc b/dll/win32/jscript/lang/jscript_Ja.rc index 415eaee49e3..e4693f021fc 100644 --- a/dll/win32/jscript/lang/jscript_Ja.rc +++ b/dll/win32/jscript/lang/jscript_Ja.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "オブジェクトを基本型に変換できません" IDS_INVALID_CALL_ARG "手続き呼び出しまたは引数が無効です" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "オートメーション サーバはオブジェクトを生成できません" IDS_NO_PROPERTY "オブジェクトはこのプロパティまたはメソッドをサポートしていません" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "引数は省略できません" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "文法エラー" IDS_SEMICOLON "';'を期待していました" IDS_LBRACKET "'('を期待していました" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScriptオブジェクトを期待していました" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "正規表現に文法誤りがあります" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "エンコードされるURIに無効な文字が含まれています" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -63,7 +69,21 @@ STRINGTABLE IDS_INVALID_LENGTH "配列の長さは有限の正整数でなければなりません" IDS_ARRAY_EXPECTED "配列オブジェクトを期待していました" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Ko.rc b/dll/win32/jscript/lang/jscript_Ko.rc index 59c39aadd3c..aa0ab9a25cf 100644 --- a/dll/win32/jscript/lang/jscript_Ko.rc +++ b/dll/win32/jscript/lang/jscript_Ko.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "객페를 기본 형식으로 변환하는 중에 에러 발생" IDS_INVALID_CALL_ARG "올바르지 않은 프로시져 호출이나 인수" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "자동화 서버가 객체를 만들 수 없습니다" IDS_NO_PROPERTY "객체는 이 속성이나 메소드를 지원하지 않습니다" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "인수는 옵션이 아닙니다" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "문법 에러" IDS_SEMICOLON "';' 가 필요합니다" IDS_LBRACKET "'(' 가 필요합니다" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScript 객체가 필요합니다" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "정규 표현식에 문법에러가 있습니다" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI 는 올바르지 않은 문자를 포함해서 인코딩되었습니다" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -63,7 +69,21 @@ STRINGTABLE IDS_INVALID_LENGTH "배열 길이는 반드시 한정된 양의 정수이어야 합니다" IDS_ARRAY_EXPECTED "배열 객체가 필요합니다" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Lt.rc b/dll/win32/jscript/lang/jscript_Lt.rc index b180923b213..80135187ba2 100644 --- a/dll/win32/jscript/lang/jscript_Lt.rc +++ b/dll/win32/jscript/lang/jscript_Lt.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Klaida keičiant objektą į primityvų tipą" IDS_INVALID_CALL_ARG "Netinkamas kreipinys į procedūrą ar argumentas" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automatizacijos serveriui nepavyko sukurti objekto" IDS_NO_PROPERTY "Objektas nepalaiko šios savybės ar metodo" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argumentas nėra neprivalomas" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Sintaksės klaida" IDS_SEMICOLON "Tikėtasi „;“" IDS_LBRACKET "Tikėtasi „(“" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Tikėtasi JScript objekto" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Sintaksės klaida reguliariajame reiškinyje" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "Koduotiname URI yra netinkamų simbolių" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Masyvo dydis turi būti teigiamas sveikasis skaičius" IDS_ARRAY_EXPECTED "Tikėtasi masyvo objekto" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Nl.rc b/dll/win32/jscript/lang/jscript_Nl.rc index d4fef4621c6..adca1b6b11a 100644 --- a/dll/win32/jscript/lang/jscript_Nl.rc +++ b/dll/win32/jscript/lang/jscript_Nl.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Fout bij het omzetten van het object naar een primitief type" IDS_INVALID_CALL_ARG "Ongeldige procedure-aanroep of argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automatiseringsserver kan het object niet creëren" IDS_NO_PROPERTY "Dit object ondersteunt deze eigenschap of methode niet" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argument is niet optioneel" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Syntax fout" IDS_SEMICOLON "';' verwacht" IDS_LBRACKET "'(' verwacht" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "JScript object verwacht" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Syntax fout in reguliere expressie" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "De te coderen URI bevat ongeldige tekens" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Array lengte moet een eindig, positief geheel getal zijn" IDS_ARRAY_EXPECTED "Array object verwacht" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_No.rc b/dll/win32/jscript/lang/jscript_No.rc index 1112371cfd9..90836407394 100644 --- a/dll/win32/jscript/lang/jscript_No.rc +++ b/dll/win32/jscript/lang/jscript_No.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Klarte ikke konvertere objekt til primitiv type" IDS_INVALID_CALL_ARG "Ugyldig funksjonskall eller argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Automatiseringstjeneren klarte ikke opprette objekt" IDS_NO_PROPERTY "Objektet støtter ikke denne egenskapen eller metoden" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argumentet er ikke valgfritt" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Syntaksfeil" IDS_SEMICOLON "Forventet ';'" IDS_LBRACKET "Forventet '('" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Forventet JScript-objekt" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Syntaksfeil i regulært uttrykk" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI'en som skulle kodes inneholder ugyldige tegn" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Rekkens lengde må være et endelig, positivt tall" IDS_ARRAY_EXPECTED "Forventet rekke-objekt" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Pl.rc b/dll/win32/jscript/lang/jscript_Pl.rc index f7201dd5302..0df8d01f386 100644 --- a/dll/win32/jscript/lang/jscript_Pl.rc +++ b/dll/win32/jscript/lang/jscript_Pl.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Błąd przy przekształcaniu obiektu do typu podstawowego" IDS_INVALID_CALL_ARG "Nieprawidłowe wywołanie procedury lub nieprawidłowy argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Indeks poza zakresem" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Wymagany jest obiekt" IDS_CREATE_OBJ_ERROR "Serwer automatyzacji nie może utworzyć obiektu" IDS_NO_PROPERTY "Obiekt nie obsługuje tej właściwości lub metody" IDS_UNSUPPORTED_ACTION "Obiekt nie obsługuje tej operacji" IDS_ARG_NOT_OPT "Argument nie jest opcjonalny" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Błąd składni" IDS_SEMICOLON "Oczekiwano znaku ':'" IDS_LBRACKET "Oczekiwano znaku '('" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Nie można usunąć '|'" IDS_NOT_VBARRAY "Oczekiwano obiektu typu VBArray" IDS_JSCRIPT_EXPECTED "Oczekiwano obiektu typu JScript" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Błąd składniowy w wyrażeniu zwykłym" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI do zdekodowania jest nieprawidłowy" IDS_URI_INVALID_CHAR "URI do zakodowania zawiera nieprawidłowe znaki" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Liczba miejsc po przecinku jest poza zakresem" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Długość tablicy musi być skończoną dodatnią liczbą całkowitą" IDS_ARRAY_EXPECTED "Oczekiwano obiektu tablicy" IDS_INVALID_WRITABLE_PROP_DESC "Atrybut 'writable' dotyczący deskryptora właściwości nie może mieć wartości 'true' dla tego obiektu" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Nie można ponownie zdefiniować niekonfigurowalnej właściwości '|'" IDS_NONWRITABLE_MODIFIED "Nie można zdefiniować niezapisywalnej właściwości '|'" + 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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Właściwość nie może mieć jednocześnie metod dostępu i wartości" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Pt.rc b/dll/win32/jscript/lang/jscript_Pt.rc index 5016e05f403..21dea47c678 100644 --- a/dll/win32/jscript/lang/jscript_Pt.rc +++ b/dll/win32/jscript/lang/jscript_Pt.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Erro ao converter objeto em tipo primitivo" IDS_INVALID_CALL_ARG "Argumento ou chamada de procedimento inválida" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "O servidor de automação não conseguiu criar o objeto" IDS_NO_PROPERTY "O objeto não suporta esta propriedade ou método" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argumento não opcional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Erro de sintaxe" IDS_SEMICOLON "';' esperado" IDS_LBRACKET "'(' esperado" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Objeto JScript esperado" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Erro de sintaxe na expressão regular" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI a ser codificado contém caracteres inválidos" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -63,9 +69,23 @@ STRINGTABLE IDS_INVALID_LENGTH "Tamanho do vetor tem que ser um inteiro finito positivo" IDS_ARRAY_EXPECTED "Objeto Array esperado" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE @@ -75,11 +95,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Erro ao converter objecto em tipo primitivo" IDS_INVALID_CALL_ARG "Argumento ou chamada de procedimento inválido" IDS_SUBSCRIPT_OUT_OF_RANGE "Inscrito fora do intervalo" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Objecto necessário" IDS_CREATE_OBJ_ERROR "O servidor de automação não conseguiu criar o objecto" IDS_NO_PROPERTY "O objecto não suporta esta propriedade ou método" IDS_UNSUPPORTED_ACTION "O objecto não suporta esta acção" IDS_ARG_NOT_OPT "Argumento não opcional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Erro de sintaxe" IDS_SEMICOLON "';' esperado" IDS_LBRACKET "'(' esperado" @@ -106,7 +128,11 @@ STRINGTABLE IDS_INVALID_DELETE "Não é possível excluir '|'" IDS_NOT_VBARRAY "Objecto VBArray esperado" IDS_JSCRIPT_EXPECTED "Objecto JScript esperado" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Erro de sintaxe na expressão regular" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "O URI a ser decodificado está incorrecto" IDS_URI_INVALID_CHAR "O URI a ser codificado contém caracteres inválidos" IDS_FRACTION_DIGITS_OUT_OF_RANGE "O número de dígitos da fracção está fora do intervalo" @@ -114,7 +140,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Tamanho do vector deverá ser um número inteiro positivo" IDS_ARRAY_EXPECTED "Objecto Array esperado" IDS_INVALID_WRITABLE_PROP_DESC "O atributo 'gravável' no descritor de propriedades não pode ser definido como 'true' neste objecto" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Não é possível redefinir a propriedade não configurável '|'" IDS_NONWRITABLE_MODIFIED "Não é possível modificar a propriedade não gravável '|'" + 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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "A propriedade não pode ter acessadores e um valor" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Ro.rc b/dll/win32/jscript/lang/jscript_Ro.rc index da3db3e404c..e9d8d3fa515 100644 --- a/dll/win32/jscript/lang/jscript_Ro.rc +++ b/dll/win32/jscript/lang/jscript_Ro.rc @@ -27,11 +27,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Eroare la convertirea obiectului la un tip primitiv" IDS_INVALID_CALL_ARG "Apel de procedură sau argument nevalid" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript în afara limitelor admise" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Obiect necesar" IDS_CREATE_OBJ_ERROR "Serverul de automatizare nu poate crea obiectul" IDS_NO_PROPERTY "Proprietatea sau metoda este neaplicabilă obiectului" IDS_UNSUPPORTED_ACTION "Acțiunea este neaplicabilă obiectului" IDS_ARG_NOT_OPT "Argumentul nu este opțional" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Eroare de sintaxă" IDS_SEMICOLON "Era așteptat „;”" IDS_LBRACKET "Era așteptat „(”" @@ -58,7 +60,11 @@ STRINGTABLE IDS_INVALID_DELETE "„|” nu poate fi șters" IDS_NOT_VBARRAY "Era așteptat un obiect de tip VBArray" IDS_JSCRIPT_EXPECTED "Era așteptat un obiect JScript" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Eroare de sintaxă în expresia regulată" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI ce urmează a fi decodificat nu este corect" IDS_URI_INVALID_CHAR "URI care trebuie codificat conține caractere nevalide" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Numărul cifrelor fracționare este în afara limitelor admise" @@ -66,7 +72,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Lungimea unei matrice trebuie să fie un număr întreg pozitiv" IDS_ARRAY_EXPECTED "Era așteptat un obiect matrice" IDS_INVALID_WRITABLE_PROP_DESC "„inscriptibil” de pe descriptorul de proprietate nu poate fi setat la „adevărat” pe acest obiect" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Nu se poate redefini proprietatea neconfigurabilă „|”" IDS_NONWRITABLE_MODIFIED "Nu se poate modifica proprietatea neinscriptibilă „|”" + 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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Proprietatea nu poate avea atât accesori, cât și o valoare" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Ru.rc b/dll/win32/jscript/lang/jscript_Ru.rc index 274e8a65968..ad2a47df884 100644 --- a/dll/win32/jscript/lang/jscript_Ru.rc +++ b/dll/win32/jscript/lang/jscript_Ru.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Ошибка конвертирования объекта в примитивный тип" IDS_INVALID_CALL_ARG "Недопустимый вызов или аргумент процедуры" IDS_SUBSCRIPT_OUT_OF_RANGE "Нижний индекс вне диапазона" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Требуется объект" IDS_CREATE_OBJ_ERROR "Сервер автоматизации не может создать объект" IDS_NO_PROPERTY "Объект не поддерживает это свойство или метод" IDS_UNSUPPORTED_ACTION "Объект не поддерживает это действие" IDS_ARG_NOT_OPT "Отсутствует обязательный аргумент" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Синтаксическая ошибка" IDS_SEMICOLON "Предполагается наличие ';'" IDS_LBRACKET "Предполагается наличие '('" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Не удается удалить '|'" IDS_NOT_VBARRAY "Предполагается наличие VBArray" IDS_JSCRIPT_EXPECTED "Предполагается наличие объекта 'JScript'" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Синтаксическая ошибка в регулярном выражении" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "Обнаружена недопустимая кодировка при попытке декодирования URI" IDS_URI_INVALID_CHAR "Обнаружен недопустимый знак при попытке кодирования URI" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Количество цифр дробной части числа вышла из диапазона" @@ -63,7 +69,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Длиной массива должно быть конечное положительное число" IDS_ARRAY_EXPECTED "Предполагается наличие объекта 'Array'" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Si.rc b/dll/win32/jscript/lang/jscript_Si.rc index b49e212bb22..e855224514a 100644 --- a/dll/win32/jscript/lang/jscript_Si.rc +++ b/dll/win32/jscript/lang/jscript_Si.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Napaka med spreminjanjem v primitivni tip" IDS_INVALID_CALL_ARG "Napačen klic postopka ali argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Avtomatizacijski server ne more ustvariti objekta" IDS_NO_PROPERTY "Objekt ne podpira atributa ali metode" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argument je obvezen" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Napačna sintaksa" IDS_SEMICOLON "Pričakujem ';'" IDS_LBRACKET "Pričakujem '('" @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Pričakujem JScript objekt" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Napačna sintaksa v regularnem izrazu" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI vsebuje neveljavne znake" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Dožina polja mora bit pozitivno celo število" IDS_ARRAY_EXPECTED "Pričakujem Array objekt" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Sq.rc b/dll/win32/jscript/lang/jscript_Sq.rc index 79a8407b12a..56d16bd47c1 100644 --- a/dll/win32/jscript/lang/jscript_Sq.rc +++ b/dll/win32/jscript/lang/jscript_Sq.rc @@ -26,11 +26,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Gabim ne konvertimin e subjektit te tipit primitiv" IDS_INVALID_CALL_ARG "Procedure a pavlefshme ne thirrje apo argument" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Serveri i Automatizuar nuk mund te krijoje objektin" IDS_NO_PROPERTY "Objekti nuk mbeshtet kete tipar apo metode" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Argumente jo opsionale" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "GAbim Sintaksi" IDS_SEMICOLON "Pritej ';'" IDS_LBRACKET "Pritej '('" @@ -57,7 +59,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Objekti JScript Pritej" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Gabim sintaksti ne shprehjen e rregullt" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI për tu koduar përmban shenja të pavlefshme" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -65,7 +71,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Gjatësia e një grupi duhet të jetë një numër i plotë pozitiv i caktuar" IDS_ARRAY_EXPECTED "Objekti Array Pritej" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Tr.rc b/dll/win32/jscript/lang/jscript_Tr.rc index 7deaae7739a..2cfbcd26ab8 100644 --- a/dll/win32/jscript/lang/jscript_Tr.rc +++ b/dll/win32/jscript/lang/jscript_Tr.rc @@ -23,11 +23,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Nesneyi ilk türe dönüştürmede hata." IDS_INVALID_CALL_ARG "Geçersiz yordam çağrısı ya da değişkeni." IDS_SUBSCRIPT_OUT_OF_RANGE "Alt indis aralık dışında." + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Nesne gerekli." IDS_CREATE_OBJ_ERROR "Otomasyon sunucusu nesne oluşturamıyor." IDS_NO_PROPERTY "Nesne bu özelliği/yöntemi desteklemiyor." IDS_UNSUPPORTED_ACTION "Nesne bu işlemi desteklemiyor." IDS_ARG_NOT_OPT "Değişken seçimlik değil." + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Söz dizimi hatası." IDS_SEMICOLON """;"" bekleniyordu." IDS_LBRACKET """("" bekleniyordu." @@ -54,7 +56,11 @@ STRINGTABLE IDS_INVALID_DELETE """|"" silinemez." IDS_NOT_VBARRAY "VBArray nesnesi bekleniyordu." IDS_JSCRIPT_EXPECTED "JScript nesnesi bekleniyordu." + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Düzenli deyişte söz dizimi hatası." + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "Çözülecek URI geçersiz." IDS_URI_INVALID_CHAR "Kodlanacak URI geçersiz karakterler içeriyor." IDS_FRACTION_DIGITS_OUT_OF_RANGE "Kesir basamaklarının sayısı aralık dışında." @@ -62,7 +68,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Dizi büyüklüğü bir sonlu artı tam sayı olmalı." IDS_ARRAY_EXPECTED "Dizi nesnesi bekleniyordu." IDS_INVALID_WRITABLE_PROP_DESC "Nesne açıklayıcısındaki 'yazılabilir' özelliği bu nesnede 'doğru' olarak ayarlanamaz." + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "'|' yapılandırılamayan nesnesi yeniden tanımlanamaz." IDS_NONWRITABLE_MODIFIED "'|' yazılamayan nesnesi değiştirilemez." + 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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Nesnenin aynı anda erişeni ve değeri olamaz." + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Uk.rc b/dll/win32/jscript/lang/jscript_Uk.rc index 90eb8189736..2da3d559010 100644 --- a/dll/win32/jscript/lang/jscript_Uk.rc +++ b/dll/win32/jscript/lang/jscript_Uk.rc @@ -24,11 +24,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "Помилка конвертування об'єкту в примітивний тип" IDS_INVALID_CALL_ARG "Невірний виклик процедури або аргумент" IDS_SUBSCRIPT_OUT_OF_RANGE "Subscript out of range" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "Object required" IDS_CREATE_OBJ_ERROR "Сервер автоматизації не може створити об'єкт" IDS_NO_PROPERTY "Об'єкт не підтримує цю властивість чи метод" IDS_UNSUPPORTED_ACTION "Object doesn't support this action" IDS_ARG_NOT_OPT "Відсутній обов'язковий аргумент" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "Синтаксична помилка" IDS_SEMICOLON "Очікується ';'" IDS_LBRACKET "Очікується '('" @@ -55,7 +57,11 @@ STRINGTABLE IDS_INVALID_DELETE "Cannot delete '|'" IDS_NOT_VBARRAY "VBArray object expected" IDS_JSCRIPT_EXPECTED "Очікується об'єкт JScript" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "Синтаксична помилка в регулярному виразі" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "URI to be decoded is incorrect" IDS_URI_INVALID_CHAR "URI, що буде закодований, містить неприпустимі символи" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" @@ -63,7 +69,21 @@ STRINGTABLE IDS_INVALID_LENGTH "Довжиною масиву повинне бути скінченне додатнє ціле число" IDS_ARRAY_EXPECTED "Очікується об'єкт Array" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lang/jscript_Zh.rc b/dll/win32/jscript/lang/jscript_Zh.rc index c2a11dc12a5..6cd5f5997dc 100644 --- a/dll/win32/jscript/lang/jscript_Zh.rc +++ b/dll/win32/jscript/lang/jscript_Zh.rc @@ -26,11 +26,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "将对象转换为原始类型的错误" IDS_INVALID_CALL_ARG "无效的过程调用或参数" IDS_SUBSCRIPT_OUT_OF_RANGE "下标超出范围" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "所需的对象" IDS_CREATE_OBJ_ERROR "自动化服务器不能创建对象" IDS_NO_PROPERTY "对象不支持此属性或方法" IDS_UNSUPPORTED_ACTION "对象不支持此操作" IDS_ARG_NOT_OPT "参数不可选" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "语法错误" IDS_SEMICOLON "预期 ';'" IDS_LBRACKET "预期 '('" @@ -57,7 +59,11 @@ STRINGTABLE IDS_INVALID_DELETE "不能删除 '|'" IDS_NOT_VBARRAY "VBArray 对象预期" IDS_JSCRIPT_EXPECTED "JScript 对象预期" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "正则表达式中的语法错误" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "被解码的 URI 不正确" IDS_URI_INVALID_CHAR "要编码的 URI 包含无效的字符" IDS_FRACTION_DIGITS_OUT_OF_RANGE "数字的小数部分的位数是超出范围" @@ -65,9 +71,23 @@ STRINGTABLE IDS_INVALID_LENGTH "数组长度必须为一个有限的正整数" IDS_ARRAY_EXPECTED "预期的数组对象" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + 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_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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL @@ -77,11 +97,13 @@ STRINGTABLE IDS_TO_PRIMITIVE "轉換物件到基本類型時發生錯誤" IDS_INVALID_CALL_ARG "無效的程序呼叫或引數" IDS_SUBSCRIPT_OUT_OF_RANGE "註標超出範圍" + IDS_STACK_OVERFLOW "Out of stack space" IDS_OBJECT_REQUIRED "需要物件" IDS_CREATE_OBJ_ERROR "自動作業伺服器無法建立物件" IDS_NO_PROPERTY "物件不支援這個屬性或方法" IDS_UNSUPPORTED_ACTION "物件不支援這個操作" IDS_ARG_NOT_OPT "這個" + IDS_OBJECT_NOT_COLLECTION "Object not a collection" IDS_SYNTAX_ERROR "語法錯誤" IDS_SEMICOLON "預期為 ';'" IDS_LBRACKET "預期為 '('" @@ -108,7 +130,11 @@ STRINGTABLE IDS_INVALID_DELETE "無法刪除 '|'" IDS_NOT_VBARRAY "預期為 VBArray 物件" IDS_JSCRIPT_EXPECTED "預期為 JScript 物件" + IDS_ENUMERATOR_EXPECTED "Enumerator object expected" + IDS_REGEXP_EXPECTED "Regular Expression object expected" IDS_REGEXP_SYNTAX_ERROR "正規表示式語法發生錯誤" + IDS_UNEXPECTED_QUANTIFIER "Unexpected quantifier" + IDS_EXCEPTION_THROWN "Exception thrown and not caught" IDS_URI_INVALID_CODING "要編碼的 URI 內含無效字元" IDS_URI_INVALID_CHAR "要編碼的 URI 內含無效字元" IDS_FRACTION_DIGITS_OUT_OF_RANGE "要編碼的 URI 內含無效字元" @@ -116,7 +142,21 @@ STRINGTABLE IDS_INVALID_LENGTH "陣列長度必須是有限正整數" IDS_ARRAY_EXPECTED "預期為陣列物件" IDS_INVALID_WRITABLE_PROP_DESC "無法在這個物件更改屬性描述符中的 'writable' 屬性為 'true'" + IDS_CYCLIC_PROTO_VALUE "Cyclic __proto__ value" + IDS_CREATE_FOR_NONEXTENSIBLE "Cannot create property for a non-extensible object" + IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "無法重新定義不可設定的屬性 '|'" IDS_NONWRITABLE_MODIFIED "無法修改不可寫入的屬性 '|'" + 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" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" + IDS_WRONG_THIS "'this' is not a | object" + IDS_KEY_NOT_OBJECT "'key' is not an object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "屬性不可同時有存取子和值" + + IDS_COMPILATION_ERROR "Microsoft JScript compilation error" + IDS_RUNTIME_ERROR "Microsoft JScript runtime error" + IDS_UNKNOWN_ERROR "Unknown runtime error" } diff --git a/dll/win32/jscript/lex.c b/dll/win32/jscript/lex.c index 4f0ea45362e..ee29bff1e37 100644 --- a/dll/win32/jscript/lex.c +++ b/dll/win32/jscript/lex.c @@ -41,6 +41,7 @@ static const struct { {L"break", kBREAK, TRUE}, {L"case", kCASE}, {L"catch", kCATCH}, + {L"const", kCONST}, {L"continue", kCONTINUE, TRUE}, {L"default", kDEFAULT}, {L"delete", kDELETE}, @@ -54,6 +55,7 @@ static const struct { {L"if", kIF}, {L"in", kIN}, {L"instanceof", kINSTANCEOF}, + {L"let", kLET, FALSE, SCRIPTLANGUAGEVERSION_ES5}, {L"new", kNEW}, {L"null", kNULL}, {L"return", kRETURN, TRUE}, @@ -115,7 +117,7 @@ static BOOL is_endline(WCHAR c) return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029; } -static int hex_to_int(WCHAR c) +int hex_to_int(WCHAR c) { if('0' <= c && c <= '9') return c-'0'; @@ -159,10 +161,8 @@ static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval) static BOOL skip_html_comment(parser_ctx_t *ctx) { - const WCHAR html_commentW[] = {'<','!','-','-',0}; - if(!ctx->is_html || ctx->ptr+3 >= ctx->end || - memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4)) + memcmp(ctx->ptr, L"