From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 194 +++++++++++++++++++++++++++++----------- dlls/jscript/engine.c | 62 +++++++++---- dlls/jscript/function.c | 93 +++++++++++++++---- dlls/jscript/jscript.h | 21 ++++- dlls/jscript/string.c | 76 +++++++++++----- 5 files changed, 334 insertions(+), 112 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 38cac3a28e1..7952d5bbc0d 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -36,7 +36,6 @@ typedef enum { PROP_PROTREF, PROP_ACCESSOR, PROP_DELETED, - PROP_IDX } prop_type_t;
struct _dispex_prop_t { @@ -49,7 +48,6 @@ struct _dispex_prop_t { jsval_t val; const builtin_prop_t *p; DWORD ref; - unsigned idx; struct { jsdisp_t *getter; jsdisp_t *setter; @@ -74,7 +72,12 @@ static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) ref = prop->u.ref;
while((jsdisp = jsdisp->prototype)) { - if(ref >= jsdisp->prop_cnt || jsdisp->props[ref].type == PROP_DELETED) + if(ref >= jsdisp->prop_cnt) { + if(jsdisp->builtin_info->idx_length && indexed_prop_id_to_idx(ref + 1) < jsdisp->builtin_info->idx_length(jsdisp)) + return; + break; + } + if(jsdisp->props[ref].type == PROP_DELETED) break; if(jsdisp->props[ref].type != PROP_PROTREF) return; @@ -94,7 +97,7 @@ static inline BOOL is_dispid_prop(jsdisp_t *This, DISPID id) DWORD idx = prop_id_to_idx(id);
if(idx >= This->prop_cnt) - return FALSE; + return This->builtin_info->idx_length && indexed_prop_id_to_idx(id) < This->builtin_info->idx_length(This); fix_protref_prop(This, &This->props[idx]);
if(This->props[idx].type == PROP_DELETED) @@ -122,6 +125,8 @@ static BOOL is_enumerable(jsdisp_t *This, dispex_prop_t *prop)
if(prop->u.ref < This->prototype->prop_cnt) parent = &This->prototype->props[prop->u.ref]; + else if(This->prototype->builtin_info->idx_length && indexed_prop_id_to_idx(prop->u.ref + 1) < This->prototype->builtin_info->idx_length(This->prototype)) + return TRUE;
if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; @@ -313,15 +318,8 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++) idx = idx*10 + (*ptr-'0'); if(!*ptr && idx < This->builtin_info->idx_length(This)) { - unsigned flags = PROPF_ENUMERABLE; - if(This->builtin_info->idx_put) - flags |= PROPF_WRITABLE; - prop = alloc_prop(This, name, PROP_IDX, flags); - if(!prop) - return E_OUTOFMEMORY; - - prop->u.idx = idx; - goto ret; + *ret = indexed_prop_idx_to_id(idx); + return S_OK; } }
@@ -339,7 +337,7 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n HRESULT hres;
hres = find_prop_name(This, hash, name, case_insens, ret); - if(FAILED(hres)) + if(FAILED(hres) || is_indexed_prop_id(*ret)) return hres;
if(hres == S_OK) { @@ -363,8 +361,8 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n del->u.ref = ref; prop = del; }else { - /* Case insensitive name lookups can differ from the prototype prop's actual name */ - prop = alloc_protref(This, This->prototype->props[ref].name, ref); + /* Case insensitive name lookups can differ from the prototype prop's actual name, but not with indexed props */ + prop = alloc_protref(This, is_indexed_prop_id(*ret) ? name : This->prototype->props[ref].name, ref); if(!prop) return E_OUTOFMEMORY; } @@ -389,7 +387,7 @@ static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_ HRESULT hres;
hres = find_prop_name_prot(This, string_hash(name), name, case_insens, ret); - if(hres != S_FALSE) + if(hres != S_FALSE || is_indexed_prop_id(*ret)) return hres;
if(is_dispex_prop_id(*ret)) { @@ -469,17 +467,14 @@ HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) { dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; - jsdisp_t *prop_obj = jsdisp; HRESULT hres;
- while(prop->type == PROP_PROTREF) { - prop_obj = prop_obj->prototype; - prop = prop_obj->props + prop->u.ref; - } + if(prop->type == PROP_PROTREF) + return jsdisp->prototype->builtin_info->prop_get(jsdisp->prototype, jsthis, prop->u.ref + 1, r);
switch(prop->type) { case PROP_BUILTIN: - hres = prop->u.p->getter(jsdisp->ctx, prop_obj, r); + hres = prop->u.p->getter(jsdisp->ctx, jsdisp, r); break; case PROP_JSVAL: hres = jsval_copy(prop->u.val, r); @@ -493,9 +488,6 @@ HRESULT dispex_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t hres = S_OK; } break; - case PROP_IDX: - hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); - break; default: ERR("type %d\n", prop->type); return E_FAIL; @@ -521,6 +513,9 @@ HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val)
do { prototype_iter = prototype_iter->prototype; + if(!is_dispex_prop_id(prop_iter->u.ref + 1)) + break; + prop_iter = prototype_iter->props + prop_iter->u.ref; } while(prop_iter->type == PROP_PROTREF);
@@ -555,12 +550,6 @@ HRESULT dispex_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) return S_OK; } return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(jsdisp), DISPATCH_METHOD, 1, &val, NULL); - case PROP_IDX: - if(!jsdisp->builtin_info->idx_put) { - TRACE("no put_idx\n"); - return S_OK; - } - return jsdisp->builtin_info->idx_put(jsdisp, prop->u.idx, val); default: ERR("type %d\n", prop->type); return E_FAIL; @@ -599,8 +588,7 @@ HRESULT dispex_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD jsval_disp(jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface), flags, argc, argv, r, caller); } - case PROP_ACCESSOR: - case PROP_IDX: { + case PROP_ACCESSOR: { jsval_t val;
hres = dispex_prop_get(jsdisp, jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface, id, &val); @@ -663,7 +651,6 @@ HRESULT dispex_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, prope switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: - case PROP_IDX: desc->explicit_value = TRUE; if(!flags_only) { hres = dispex_prop_get(jsdisp, to_disp(jsdisp), id, &desc->value); @@ -821,24 +808,107 @@ const WCHAR *dispex_prop_get_static_name(jsdisp_t *jsdisp, DISPID id) return jsdisp->props[prop_id_to_idx(id)].name; }
-static HRESULT fill_props(jsdisp_t *obj) +HRESULT indexed_prop_invoke(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { HRESULT hres; - DISPID id; + jsval_t val;
- if(obj->builtin_info->idx_length) { - unsigned i = 0, len = obj->builtin_info->idx_length(obj); - WCHAR name[12]; + if(is_dispex_prop_id(id)) + return dispex_prop_invoke(jsdisp, jsthis, id, flags, argc, argv, r, caller);
- for(i = 0; i < len; i++) { - swprintf(name, ARRAY_SIZE(name), L"%u", i); - hres = find_prop_name(obj, string_hash(name), name, FALSE, &id); + hres = jsdisp->builtin_info->prop_get(jsdisp, jsthis ? jsthis : to_disp(jsdisp), id, &val); + if(FAILED(hres)) + return hres; + + if(is_object_instance(val)) + hres = disp_call_value_with_caller(jsdisp->ctx, get_object(val), jsval_disp(jsthis ? jsthis : to_disp(jsdisp)), + flags, argc, argv, r, caller); + else { + FIXME("invoke %s\n", debugstr_jsval(val)); + hres = E_NOTIMPL; + } + + jsval_release(val); + return hres; +} + +HRESULT indexed_prop_delete(jsdisp_t *jsdisp, DISPID id, BOOL *ret) +{ + if(is_dispex_prop_id(id)) + return dispex_prop_delete(jsdisp, id, ret); + + /* indexed props are not configurable */ + *ret = FALSE; + return S_OK; +} + +void *indexed_prop_get_name(jsdisp_t *jsdisp, DISPID id, BOOL bstr) +{ + WCHAR buf[11]; + unsigned len; + + if(is_dispex_prop_id(id)) + return dispex_prop_get_name(jsdisp, id, bstr); + + len = swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(id)); + if(bstr) + return SysAllocStringLen(buf, len); + return jsstr_alloc_len(buf, len); +} + +HRESULT indexed_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) +{ + property_desc_t prop_desc; + WCHAR buf[11]; + HRESULT hres; + jsval_t val; + BOOL eq; + + if(is_dispex_prop_id(id)) + return dispex_prop_define(jsdisp, id, desc); + + TRACE("existing prop L"%lu" desc flags %x desc mask %x\n", indexed_prop_id_to_idx(id), desc->flags, desc->mask); + + if((desc->mask & desc->flags & (PROPF_CONFIGURABLE | PROPF_ENUMERABLE)) != (desc->mask & PROPF_ENUMERABLE)) { + hres = JS_E_NONCONFIGURABLE_REDEFINED; + goto throw; + } + + if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { + if(jsdisp->builtin_info->prop_get_desc(jsdisp, id, TRUE, &prop_desc) == S_OK && !(prop_desc.flags & PROPF_WRITABLE)) { + if(desc->mask & desc->flags & PROPF_WRITABLE) { + hres = JS_E_NONWRITABLE_MODIFIED; + goto throw; + } + if(desc->explicit_value) { + hres = jsdisp->builtin_info->prop_get(jsdisp, to_disp(jsdisp), id, &val); + if(FAILED(hres)) + return hres; + hres = jsval_strict_equal(desc->value, val, &eq); + jsval_release(val); + if(FAILED(hres)) + return hres; + if(!eq) { + hres = JS_E_NONWRITABLE_MODIFIED; + goto throw; + } + } + }else if(desc->explicit_value) { + HRESULT hres = jsdisp->builtin_info->prop_put(jsdisp, id, desc->value); if(FAILED(hres)) return hres; } + }else if(desc->explicit_getter || desc->explicit_setter) { + hres = JS_E_NONCONFIGURABLE_REDEFINED; + goto throw; }
return S_OK; + +throw: + swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(id)); + return throw_error(jsdisp->ctx, hres, buf); }
static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref) @@ -849,6 +919,8 @@ static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DW hres = find_prop_name(This, hash, name, FALSE, &id); if(hres != S_FALSE) return hres; + if(is_indexed_prop_id(id)) + return S_OK; if(is_dispex_prop_id(id)) { dispex_prop_t *p = &This->props[prop_id_to_idx(id)]; p->type = PROP_PROTREF; @@ -865,10 +937,6 @@ static HRESULT fill_protrefs(jsdisp_t *This) dispex_prop_t *iter; HRESULT hres;
- hres = fill_props(This); - if(FAILED(hres)) - return hres; - if(!This->prototype) return S_OK;
@@ -876,6 +944,18 @@ static HRESULT fill_protrefs(jsdisp_t *This) if(FAILED(hres)) return hres;
+ if(This->prototype->builtin_info->idx_length) { + DWORD i, len = This->prototype->builtin_info->idx_length(This->prototype); + WCHAR buf[11]; + + for(i = 0; i < len; i++) { + swprintf(buf, ARRAY_SIZE(buf), L"%u", i); + hres = fill_protref(This, string_hash(buf), buf, prop_id_to_idx(indexed_prop_idx_to_id(i))); + if(hres != S_OK) + return hres; + } + } + for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { hres = fill_protref(This, iter->hash, iter->name, iter - This->prototype->props); if(hres != S_OK) @@ -3032,15 +3112,25 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *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; + BOOL fill = FALSE; HRESULT hres; + DWORD idx; + + id = (id == DISPID_STARTENUM) ? indexed_prop_idx_to_id(0) : id + 1; + if(is_indexed_prop_id(id)) { + if(obj->builtin_info->idx_length && indexed_prop_id_to_idx(id) < obj->builtin_info->idx_length(obj)) { + *ret = id; + return S_OK; + } + fill = TRUE; + id = 1; + } + idx = prop_id_to_idx(id);
- if(id == DISPID_STARTENUM || idx >= obj->prop_cnt) { - hres = (enum_type == JSDISP_ENUM_ALL) ? fill_protrefs(obj) : fill_props(obj); + if(fill || idx >= obj->prop_cnt) { + hres = (enum_type == JSDISP_ENUM_ALL) ? fill_protrefs(obj) : S_OK; if(FAILED(hres)) return hres; - if(id == DISPID_STARTENUM) - idx = 0; if(idx >= obj->prop_cnt) return S_FALSE; } diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 2142b70e677..d84bdaa7bcf 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -478,36 +478,60 @@ static void scope_destructor(jsdisp_t *dispex) IDispatch_Release(scope->obj); }
-static unsigned scope_idx_length(jsdisp_t *dispex) +static HRESULT scope_prop_get(jsdisp_t *dispex, IDispatch *jsthis, DISPID id, jsval_t *r) { scope_chain_t *scope = scope_from_dispex(dispex);
- return scope->detached_vars->argc; -} + if(is_dispex_prop_id(id)) + return dispex_prop_get(&scope->dispex, jsthis, id, r);
-static HRESULT scope_idx_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); + return jsval_copy(scope->detached_vars->var[indexed_prop_id_to_idx(id)], r); }
-static HRESULT scope_idx_put(jsdisp_t *dispex, unsigned idx, jsval_t val) +static HRESULT scope_prop_put(jsdisp_t *dispex, DISPID id, jsval_t val) { scope_chain_t *scope = scope_from_dispex(dispex); jsval_t copy, *ref; HRESULT hres;
+ if(is_dispex_prop_id(id)) + return dispex_prop_put(&scope->dispex, id, val); + hres = jsval_copy(val, ©); if(FAILED(hres)) return hres;
- ref = &scope->detached_vars->var[idx]; + ref = &scope->detached_vars->var[indexed_prop_id_to_idx(id)]; jsval_release(*ref); *ref = copy; return S_OK; }
+static HRESULT scope_prop_get_desc(jsdisp_t *dispex, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + if(is_dispex_prop_id(id)) + return dispex_prop_get_desc(&scope->dispex, id, flags_only, desc); + + if(!flags_only) { + HRESULT hres = scope_prop_get(&scope->dispex, to_disp(&scope->dispex), id, &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE | PROPF_WRITABLE; + return S_OK; +} + +static unsigned scope_idx_length(jsdisp_t *dispex) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + return scope->detached_vars->argc; +} + 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); @@ -544,13 +568,17 @@ static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, }
static const builtin_info_t scope_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_NONE, - .destructor = scope_destructor, - .idx_length = scope_idx_length, - .idx_get = scope_idx_get, - .idx_put = scope_idx_put, - .gc_traverse = scope_gc_traverse + .class = JSCLASS_NONE, + .destructor = scope_destructor, + .prop_get = scope_prop_get, + .prop_put = scope_prop_put, + .prop_invoke = indexed_prop_invoke, + .prop_delete = indexed_prop_delete, + .prop_get_desc = scope_prop_get_desc, + .prop_get_name = indexed_prop_get_name, + .prop_define = indexed_prop_define, + .idx_length = scope_idx_length, + .gc_traverse = scope_gc_traverse };
static HRESULT scope_push(script_ctx_t *ctx, scope_chain_t *scope, IDispatch *obj, scope_chain_t **ret) diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 55ec36788c3..45e26e8c294 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -68,6 +68,7 @@ typedef struct { jsval_t *buf; scope_chain_t *scope; unsigned argc; + BYTE readonly_flags[]; } ArgumentsInstance;
static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,jsval_t*,jsdisp_t**r); @@ -117,12 +118,6 @@ static void Arguments_destructor(jsdisp_t *jsdisp) scope_release(arguments->scope); }
-static unsigned Arguments_idx_length(jsdisp_t *jsdisp) -{ - ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - return arguments->argc; -} - static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) { if(arguments->buf) @@ -132,22 +127,33 @@ static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned 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, IDispatch *jsthis, DISPID id, jsval_t *r) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + + if(is_dispex_prop_id(id)) + return dispex_prop_get(&arguments->jsdisp, jsthis, id, r);
- TRACE("%p[%u]\n", arguments, idx); + TRACE("%p[%lu]\n", arguments, idx);
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, DISPID id, jsval_t val) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); jsval_t copy, *ref; HRESULT hres;
- TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); + if(is_dispex_prop_id(id)) + return dispex_prop_put(&arguments->jsdisp, id, val); + + TRACE("%p[%lu] = %s\n", arguments, idx, debugstr_jsval(val)); + + if(arguments->readonly_flags[idx / 8] & (1u << idx % 8)) + return S_OK;
hres = jsval_copy(val, ©); if(FAILED(hres)) @@ -159,6 +165,51 @@ static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) return S_OK; }
+static HRESULT Arguments_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + + if(is_dispex_prop_id(id)) + return dispex_prop_get_desc(&arguments->jsdisp, id, flags_only, desc); + + if(!flags_only) { + HRESULT hres = Arguments_prop_get(&arguments->jsdisp, to_disp(&arguments->jsdisp), id, &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE; + if(!(arguments->readonly_flags[idx / 8] & (1u << idx % 8))) + desc->flags |= PROPF_WRITABLE; + + return S_OK; +} + +static HRESULT Arguments_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + HRESULT hres; + + hres = indexed_prop_define(&arguments->jsdisp, id, desc); + if(FAILED(hres)) + return hres; + + /* Need to keep track of props made read-only */ + if((desc->mask & PROPF_WRITABLE) && !(desc->flags & PROPF_WRITABLE)) + arguments->readonly_flags[idx / 8] |= 1u << idx % 8; + + return hres; +} + +static unsigned Arguments_idx_length(jsdisp_t *jsdisp) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + return arguments->argc; +} + static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *jsdisp) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); @@ -183,14 +234,18 @@ static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op }
static const builtin_info_t Arguments_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_ARGUMENTS, - .call = Arguments_value, - .destructor = Arguments_destructor, - .idx_length = Arguments_idx_length, - .idx_get = Arguments_idx_get, - .idx_put = Arguments_idx_put, - .gc_traverse = Arguments_gc_traverse + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .destructor = Arguments_destructor, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .prop_invoke = indexed_prop_invoke, + .prop_delete = indexed_prop_delete, + .prop_get_desc = Arguments_prop_get_desc, + .prop_get_name = indexed_prop_get_name, + .prop_define = Arguments_prop_define, + .idx_length = Arguments_idx_length, + .gc_traverse = Arguments_gc_traverse };
HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) @@ -198,7 +253,7 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) ArgumentsInstance *args; HRESULT hres;
- args = calloc(1, sizeof(*args)); + args = calloc(1, FIELD_OFFSET(ArgumentsInstance, readonly_flags[(frame->argc + 7) / 8])); if(!args) return E_OUTOFMEMORY;
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 70d71b34337..75a24eddd89 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -138,6 +138,10 @@ HRESULT dispex_prop_get_desc(jsdisp_t*,DISPID,BOOL,property_desc_t*); void *dispex_prop_get_name(jsdisp_t*,DISPID,BOOL); HRESULT dispex_prop_define(jsdisp_t*,DISPID,const property_desc_t*); const WCHAR *dispex_prop_get_static_name(jsdisp_t*,DISPID); +HRESULT indexed_prop_invoke(jsdisp_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); +HRESULT indexed_prop_delete(jsdisp_t*,DISPID,BOOL*); +void *indexed_prop_get_name(jsdisp_t*,DISPID,BOOL); +HRESULT indexed_prop_define(jsdisp_t*,DISPID,const property_desc_t*);
struct thread_data { LONG ref; @@ -200,8 +204,6 @@ typedef struct { void *(*prop_get_name)(jsdisp_t*,DISPID,BOOL); HRESULT (*prop_define)(jsdisp_t*,DISPID,const property_desc_t*); unsigned (*idx_length)(jsdisp_t*); - HRESULT (*idx_get)(jsdisp_t*,unsigned,jsval_t*); - HRESULT (*idx_put)(jsdisp_t*,unsigned,jsval_t); HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*); } builtin_info_t;
@@ -280,6 +282,21 @@ static inline BOOL is_dispex_prop_id(DISPID id) return id > 0; }
+static inline BOOL is_indexed_prop_id(DISPID id) +{ + return id < 0; +} + +static inline DWORD indexed_prop_id_to_idx(DISPID id) +{ + return (DWORD)id - 0x80000000u; +} + +static inline DISPID indexed_prop_idx_to_id(DWORD idx) +{ + return idx + 0x80000000u; +} + enum jsdisp_enum_type { JSDISP_ENUM_ALL, JSDISP_ENUM_OWN, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 63cd24db05a..e62e6313e4a 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1501,6 +1501,48 @@ static void String_destructor(jsdisp_t *dispex) jsstr_release(This->str); }
+static HRESULT String_prop_get(jsdisp_t *jsdisp, IDispatch *jsthis, DISPID id, jsval_t *r) +{ + StringInstance *string = string_from_jsdisp(jsdisp); + DWORD idx = indexed_prop_id_to_idx(id); + jsstr_t *ret; + + if(is_dispex_prop_id(id)) + return dispex_prop_get(&string->dispex, jsthis, id, r); + + ret = jsstr_substr(string->str, idx, 1); + if(!ret) + return E_OUTOFMEMORY; + + TRACE("%p[%lu] = %s\n", string, idx, debugstr_jsstr(ret)); + + *r = jsval_string(ret); + return S_OK; +} + +static HRESULT String_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) +{ + if(is_dispex_prop_id(id)) + return dispex_prop_put(jsdisp, id, val); + return S_OK; +} + +static HRESULT String_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + if(is_dispex_prop_id(id)) + return dispex_prop_get_desc(jsdisp, id, flags_only, desc); + + if(!flags_only) { + HRESULT hres = String_prop_get(jsdisp, to_disp(jsdisp), id, &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE; + return S_OK; +} + static unsigned String_idx_length(jsdisp_t *jsdisp) { StringInstance *string = string_from_jsdisp(jsdisp); @@ -1515,21 +1557,6 @@ static unsigned String_idx_length(jsdisp_t *jsdisp) return string->dispex.ctx->version < 2 ? 0 : jsstr_length(string->str); }
-static HRESULT String_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) -{ - StringInstance *string = string_from_jsdisp(jsdisp); - jsstr_t *ret; - - ret = jsstr_substr(string->str, idx, 1); - if(!ret) - return E_OUTOFMEMORY; - - TRACE("%p[%u] = %s\n", string, idx, debugstr_jsstr(ret)); - - *r = jsval_string(ret); - return S_OK; -} - static const builtin_prop_t String_props[] = { {L"anchor", String_anchor, PROPF_METHOD|1}, {L"big", String_big, PROPF_METHOD}, @@ -1580,13 +1607,18 @@ static const builtin_prop_t StringInst_props[] = { };
static const builtin_info_t StringInst_info = { - DEFAULT_DISPEX_PROP_VTBL_ENTRIES, - .class = JSCLASS_STRING, - .props_cnt = ARRAY_SIZE(StringInst_props), - .props = StringInst_props, - .destructor = String_destructor, - .idx_length = String_idx_length, - .idx_get = String_idx_get, + .class = JSCLASS_STRING, + .props_cnt = ARRAY_SIZE(StringInst_props), + .props = StringInst_props, + .destructor = String_destructor, + .prop_get = String_prop_get, + .prop_put = String_prop_put, + .prop_invoke = indexed_prop_invoke, + .prop_delete = indexed_prop_delete, + .prop_get_desc = String_prop_get_desc, + .prop_get_name = indexed_prop_get_name, + .prop_define = indexed_prop_define, + .idx_length = String_idx_length, };
/* ECMA-262 3rd Edition 15.5.3.2 */