From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/arraybuf.c | 4 - dlls/jscript/dispex.c | 218 ++++++++++++++++++++++++++++---------- dlls/jscript/engine.c | 53 ++++++--- dlls/jscript/enumerator.c | 2 - dlls/jscript/function.c | 87 ++++++++++----- dlls/jscript/jscript.h | 24 ++++- dlls/jscript/jsregexp.c | 4 - dlls/jscript/set.c | 6 -- dlls/jscript/string.c | 68 ++++++++---- 9 files changed, 332 insertions(+), 134 deletions(-)
diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 62dfe614d65..fe20558fe50 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -617,8 +617,6 @@ static const builtin_info_t DataView_info = { DataView_destructor, NULL, NULL, - NULL, - NULL, DataView_gc_traverse };
@@ -630,8 +628,6 @@ static const builtin_info_t DataViewInst_info = { DataView_destructor, NULL, NULL, - NULL, - NULL, DataView_gc_traverse };
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index d17e0c04228..ddd78a8fad6 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; @@ -67,6 +65,15 @@ static inline DWORD prop_id_to_idx(DISPID id) return id - 1; }
+static inline const struct prop_desc_vtbl *get_prop_vtbl(jsdisp_t *jsdisp, DISPID id) +{ + if(prop_id_to_idx(id) < jsdisp->prop_cnt) + return &dispex_prop_vtbl; + if(is_dispex_prop_id(id) || !jsdisp->builtin_info->get_prop_vtbl) + return NULL; + return jsdisp->builtin_info->get_prop_vtbl(jsdisp, id); +} + static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) { DWORD ref; @@ -76,7 +83,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(get_prop_vtbl(jsdisp, ref + 1)) + return; + break; + } + if(jsdisp->props[ref].type == PROP_DELETED) break; if(jsdisp->props[ref].type != PROP_PROTREF) return; @@ -93,16 +105,17 @@ static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop)
static inline BOOL get_prop(jsdisp_t *This, DISPID id, struct prop_desc *ret) { - DWORD idx = prop_id_to_idx(id); - - if(idx >= This->prop_cnt) - return FALSE; - fix_protref_prop(This, &This->props[idx]); + const struct prop_desc_vtbl *vtbl = get_prop_vtbl(This, id);
- if(This->props[idx].type == PROP_DELETED) + if(!vtbl) return FALSE; + if(is_dispex_prop_id(id)) { + fix_protref_prop(This, &This->props[prop_id_to_idx(id)]);
- ret->vtbl = &dispex_prop_vtbl; + if(This->props[prop_id_to_idx(id)].type == PROP_DELETED) + return FALSE; + } + ret->vtbl = vtbl; ret->jsdisp = This; ret->id = id; return TRUE; @@ -112,7 +125,7 @@ static inline struct prop_desc get_prop_from_protref(jsdisp_t *prot, DWORD ref) { struct prop_desc prop;
- prop.vtbl = &dispex_prop_vtbl; + prop.vtbl = is_dispex_prop_id(ref + 1) ? &dispex_prop_vtbl : prot->builtin_info->get_prop_vtbl(prot, ref + 1); prop.jsdisp = prot; prop.id = ref + 1; return prop; @@ -138,6 +151,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(get_prop_vtbl(This->prototype, prop->u.ref + 1)) + return TRUE;
if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; @@ -322,22 +337,18 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, goto ret_prop; }
- if(This->builtin_info->idx_length) { + if(This->builtin_info->get_prop_vtbl) { + const struct prop_desc_vtbl *vtbl; const WCHAR *ptr; unsigned idx = 0;
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_prop; + if(!*ptr && (vtbl = This->builtin_info->get_prop_vtbl(This, indexed_prop_idx_to_id(idx)))) { + ret->vtbl = vtbl; + ret->jsdisp = This; + ret->id = indexed_prop_idx_to_id(idx); + return S_OK; } }
@@ -357,7 +368,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->id)) return hres;
if(hres == S_OK) { @@ -406,7 +417,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->id)) return hres;
if(is_dispex_prop_id(ret->id)) { @@ -483,10 +494,17 @@ static HRESULT dispex_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_ { dispex_prop_t *p = &prop->jsdisp->props[prop_id_to_idx(prop->id)]; jsdisp_t *prop_obj = prop->jsdisp; + const WCHAR *name = p->name; + struct prop_desc prot_prop; HRESULT hres;
while(p->type == PROP_PROTREF) { prop_obj = prop_obj->prototype; + prot_prop = get_prop_from_protref(prop_obj, p->u.ref); + if(!is_dispex_prop_id(prot_prop.id)) { + hres = prot_prop.vtbl->get(&prot_prop, jsthis, r); + goto ret; + } p = prop_obj->props + p->u.ref; }
@@ -506,9 +524,6 @@ static HRESULT dispex_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_ hres = S_OK; } break; - case PROP_IDX: - hres = prop_obj->builtin_info->idx_get(prop_obj, p->u.idx, r); - break; default: ERR("type %d\n", p->type); return E_FAIL; @@ -519,7 +534,8 @@ static HRESULT dispex_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_ return hres; }
- TRACE("%p.%s ret %s\n", prop->jsdisp, debugstr_w(p->name), debugstr_jsval(*r)); +ret: + TRACE("%p.%s ret %s\n", prop->jsdisp, debugstr_w(name), debugstr_jsval(*r)); return hres; }
@@ -527,6 +543,7 @@ static HRESULT dispex_prop_put(struct prop_desc *prop, jsval_t val) { dispex_prop_t *p = &prop->jsdisp->props[prop_id_to_idx(prop->id)]; jsdisp_t *jsdisp = prop->jsdisp; + struct prop_desc prot_prop; HRESULT hres;
if(p->type == PROP_PROTREF) { @@ -535,6 +552,10 @@ static HRESULT dispex_prop_put(struct prop_desc *prop, jsval_t val)
do { prototype_iter = prototype_iter->prototype; + prot_prop = get_prop_from_protref(prototype_iter, prop_iter->u.ref); + if(!is_dispex_prop_id(prot_prop.id)) + return prot_prop.vtbl->put(&prot_prop, val); + prop_iter = prototype_iter->props + prop_iter->u.ref; } while(prop_iter->type == PROP_PROTREF);
@@ -569,12 +590,6 @@ static HRESULT dispex_prop_put(struct prop_desc *prop, jsval_t val) return S_OK; } return jsdisp_call_value(p->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, p->u.idx, val); default: ERR("type %d\n", p->type); return E_FAIL; @@ -619,8 +634,7 @@ static HRESULT dispex_prop_invoke(struct prop_desc *prop, IDispatch *jsthis, WOR 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(prop, jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface, &val); @@ -683,7 +697,6 @@ static HRESULT dispex_prop_get_desc(struct prop_desc *prop, BOOL flags_only, pro switch(p->type) { case PROP_BUILTIN: case PROP_JSVAL: - case PROP_IDX: desc->explicit_value = TRUE; if(!flags_only) { hres = dispex_prop_get(prop, to_disp(prop->jsdisp), &desc->value); @@ -846,30 +859,103 @@ static const struct prop_desc_vtbl dispex_prop_vtbl = { dispex_prop_define };
-HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) +HRESULT indexed_prop_invoke(struct prop_desc *prop, IDispatch *jsthis, WORD flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { - TRACE("%p %s\n", jsthis, debugstr_jsval(value)); + jsdisp_t *jsdisp = prop->jsdisp; + HRESULT hres; + jsval_t val; + + hres = prop->vtbl->get(prop, jsthis ? jsthis : (IDispatch*)&jsdisp->IDispatchEx_iface, &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 : (IDispatch*)&jsdisp->IDispatchEx_iface), + 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(struct prop_desc *prop, BOOL *ret) +{ + /* indexed props are not configurable */ + *ret = FALSE; return S_OK; }
-static HRESULT fill_props(jsdisp_t *obj) +void *indexed_prop_get_name(struct prop_desc *prop, BOOL bstr) { - struct prop_desc prop; + WCHAR buf[11]; + unsigned len; + + len = swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(prop->id)); + if(bstr) + return SysAllocStringLen(buf, len); + return jsstr_alloc_len(buf, len); +} + +HRESULT indexed_prop_define(struct prop_desc *prop, property_desc_t *desc) +{ + property_desc_t prop_desc; + WCHAR buf[11]; HRESULT hres; + jsval_t val; + BOOL eq; + + TRACE("existing prop L"%lu" desc flags %x desc mask %x\n", indexed_prop_id_to_idx(prop->id), desc->flags, desc->mask);
- if(obj->builtin_info->idx_length) { - unsigned i = 0, len = obj->builtin_info->idx_length(obj); - WCHAR name[12]; + if((desc->mask & desc->flags & (PROPF_CONFIGURABLE | PROPF_ENUMERABLE)) != (desc->mask & PROPF_ENUMERABLE)) { + hres = JS_E_NONCONFIGURABLE_REDEFINED; + goto throw; + }
- for(i = 0; i < len; i++) { - swprintf(name, ARRAY_SIZE(name), L"%u", i); - hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); + if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { + if(prop->vtbl->get_desc(prop, 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 = prop->vtbl->get(prop, to_disp(prop->jsdisp), &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 = prop->vtbl->put(prop, 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(prop->id)); + return throw_error(prop->jsdisp->ctx, hres, buf); +} + +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_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref) @@ -880,6 +966,8 @@ static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DW hres = find_prop_name(This, hash, name, FALSE, &prop); if(hres != S_FALSE) return hres; + if(is_indexed_prop_id(prop.id)) + return S_OK; if(is_dispex_prop_id(prop.id)) { dispex_prop_t *p = &This->props[prop_id_to_idx(prop.id)]; p->type = PROP_PROTREF; @@ -896,10 +984,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;
@@ -907,6 +991,18 @@ static HRESULT fill_protrefs(jsdisp_t *This) if(FAILED(hres)) return hres;
+ if(This->prototype->builtin_info->get_prop_vtbl) { + WCHAR buf[11]; + DWORD i; + + for(i = 0; This->prototype->builtin_info->get_prop_vtbl(This->prototype, indexed_prop_idx_to_id(i)); 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) @@ -3084,15 +3180,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->get_prop_vtbl && obj->builtin_info->get_prop_vtbl(obj, id)) { + *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 76e6a271bdf..b75d8faa1b0 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -479,23 +479,16 @@ static void scope_destructor(jsdisp_t *dispex) free(scope); }
-static unsigned scope_idx_length(jsdisp_t *dispex) +static HRESULT scope_indexed_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_t *r) { - scope_chain_t *scope = scope_from_dispex(dispex); - - return scope->detached_vars->argc; -} - -static HRESULT scope_idx_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) -{ - scope_chain_t *scope = scope_from_dispex(dispex); + scope_chain_t *scope = scope_from_dispex(prop->jsdisp);
- return jsval_copy(scope->detached_vars->var[idx], r); + return jsval_copy(scope->detached_vars->var[indexed_prop_id_to_idx(prop->id)], r); }
-static HRESULT scope_idx_put(jsdisp_t *dispex, unsigned idx, jsval_t val) +static HRESULT scope_indexed_prop_put(struct prop_desc *prop, jsval_t val) { - scope_chain_t *scope = scope_from_dispex(dispex); + scope_chain_t *scope = scope_from_dispex(prop->jsdisp); jsval_t copy, *ref; HRESULT hres;
@@ -503,12 +496,42 @@ static HRESULT scope_idx_put(jsdisp_t *dispex, unsigned idx, jsval_t val) if(FAILED(hres)) return hres;
- ref = &scope->detached_vars->var[idx]; + ref = &scope->detached_vars->var[indexed_prop_id_to_idx(prop->id)]; jsval_release(*ref); *ref = copy; return S_OK; }
+static HRESULT scope_indexed_prop_get_desc(struct prop_desc *prop, BOOL flags_only, property_desc_t *desc) +{ + if(!flags_only) { + HRESULT hres = scope_indexed_prop_get(prop, to_disp(prop->jsdisp), &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE | PROPF_WRITABLE; + return S_OK; +} + +static const struct prop_desc_vtbl scope_indexed_prop_vtbl = { + scope_indexed_prop_get, + scope_indexed_prop_put, + indexed_prop_invoke, + indexed_prop_delete, + scope_indexed_prop_get_desc, + indexed_prop_get_name, + indexed_prop_define +}; + +static const struct prop_desc_vtbl *scope_get_prop_vtbl(jsdisp_t *dispex, DISPID id) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + + return indexed_prop_id_to_idx(id) < scope->detached_vars->argc ? &scope_indexed_prop_vtbl : NULL; +} + 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); @@ -551,9 +574,7 @@ static const builtin_info_t scope_info = { NULL, scope_destructor, NULL, - scope_idx_length, - scope_idx_get, - scope_idx_put, + scope_get_prop_vtbl, scope_gc_traverse };
diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index d962c65d229..ee80341696e 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -198,8 +198,6 @@ static const builtin_info_t EnumeratorInst_info = { Enumerator_destructor, NULL, NULL, - NULL, - NULL, Enumerator_gc_traverse };
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 68f841b38a1..a0ae48e4b1a 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); @@ -119,12 +120,6 @@ static void Arguments_destructor(jsdisp_t *jsdisp) free(arguments); }
-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) @@ -134,22 +129,24 @@ 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_indexed_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_t *r) { - ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + ArgumentsInstance *arguments = arguments_from_jsdisp(prop->jsdisp); + DWORD idx = indexed_prop_id_to_idx(prop->id);
- 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_indexed_prop_put(struct prop_desc *prop, jsval_t val) { - ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + ArgumentsInstance *arguments = arguments_from_jsdisp(prop->jsdisp); + DWORD idx = indexed_prop_id_to_idx(prop->id); jsval_t copy, *ref; HRESULT hres;
- TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); + TRACE("%p[%lu] = %s\n", arguments, idx, debugstr_jsval(val));
hres = jsval_copy(val, ©); if(FAILED(hres)) @@ -161,6 +158,58 @@ static HRESULT Arguments_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) return S_OK; }
+static HRESULT Arguments_indexed_prop_get_desc(struct prop_desc *prop, BOOL flags_only, property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(prop->jsdisp); + DWORD idx = indexed_prop_id_to_idx(prop->id); + + if(!flags_only) { + HRESULT hres = Arguments_indexed_prop_get(prop, to_disp(prop->jsdisp), &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_indexed_prop_define(struct prop_desc *prop, property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(prop->jsdisp); + DWORD idx = indexed_prop_id_to_idx(prop->id); + HRESULT hres; + + hres = indexed_prop_define(prop, 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 const struct prop_desc_vtbl Arguments_indexed_prop_vtbl = { + Arguments_indexed_prop_get, + Arguments_indexed_prop_put, + indexed_prop_invoke, + indexed_prop_delete, + Arguments_indexed_prop_get_desc, + indexed_prop_get_name, + Arguments_indexed_prop_define +}; + +static const struct prop_desc_vtbl *Arguments_get_prop_vtbl(jsdisp_t *jsdisp, DISPID id) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + return indexed_prop_id_to_idx(id) < arguments->argc ? &Arguments_indexed_prop_vtbl : NULL; +} + static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *jsdisp) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); @@ -190,9 +239,7 @@ static const builtin_info_t Arguments_info = { 0, NULL, Arguments_destructor, NULL, - Arguments_idx_length, - Arguments_idx_get, - Arguments_idx_put, + Arguments_get_prop_vtbl, Arguments_gc_traverse };
@@ -201,7 +248,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;
@@ -609,8 +656,6 @@ static const builtin_info_t Function_info = { Function_destructor, NULL, NULL, - NULL, - NULL, Function_gc_traverse };
@@ -628,8 +673,6 @@ static const builtin_info_t FunctionInst_info = { Function_destructor, NULL, NULL, - NULL, - NULL, Function_gc_traverse };
@@ -815,8 +858,6 @@ static const builtin_info_t InterpretedFunction_info = { Function_destructor, NULL, NULL, - NULL, - NULL, Function_gc_traverse };
@@ -947,8 +988,6 @@ static const builtin_info_t BindFunction_info = { Function_destructor, NULL, NULL, - NULL, - NULL, Function_gc_traverse };
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 66de77856ad..a525d33d1f5 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -186,9 +186,7 @@ typedef struct { const builtin_prop_t *props; void (*destructor)(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); + const struct prop_desc_vtbl *(*get_prop_vtbl)(jsdisp_t*,DISPID); HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*); } builtin_info_t;
@@ -269,6 +267,26 @@ 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; +} + +HRESULT indexed_prop_invoke(struct prop_desc*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*); +HRESULT indexed_prop_delete(struct prop_desc*,BOOL*); +void *indexed_prop_get_name(struct prop_desc*,BOOL); +HRESULT indexed_prop_define(struct prop_desc*,property_desc_t*); + enum jsdisp_enum_type { JSDISP_ENUM_ALL, JSDISP_ENUM_OWN, diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index 70673ec190e..31654176ab6 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -577,8 +577,6 @@ static const builtin_info_t RegExp_info = { RegExp_destructor, NULL, NULL, - NULL, - NULL, RegExp_gc_traverse };
@@ -598,8 +596,6 @@ static const builtin_info_t RegExpInst_info = { RegExp_destructor, NULL, NULL, - NULL, - NULL, RegExp_gc_traverse };
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 7e49e31a5d5..990461ea1cf 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -417,8 +417,6 @@ static const builtin_info_t Map_info = { Map_destructor, NULL, NULL, - NULL, - NULL, Map_gc_traverse };
@@ -576,8 +574,6 @@ static const builtin_info_t Set_info = { Map_destructor, NULL, NULL, - NULL, - NULL, Map_gc_traverse };
@@ -873,8 +869,6 @@ static const builtin_info_t WeakMap_info = { WeakMap_destructor, NULL, NULL, - NULL, - NULL, WeakMap_gc_traverse };
diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 4033f0a2b56..f089f0634e7 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1502,35 +1502,66 @@ static void String_destructor(jsdisp_t *dispex) free(This); }
-static unsigned String_idx_length(jsdisp_t *jsdisp) +static HRESULT String_indexed_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_t *r) { - StringInstance *string = string_from_jsdisp(jsdisp); - - /* - * NOTE: For invoke version < 2, indexed array is not implemented at all. - * Newer jscript.dll versions implement it on string type, not class, - * which is not how it should work according to spec. IE9 implements it - * properly, but it uses its own JavaScript engine inside MSHTML. We - * implement it here, but in the way IE9 and spec work. - */ - 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); + StringInstance *string = string_from_jsdisp(prop->jsdisp); + DWORD idx = indexed_prop_id_to_idx(prop->id); 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)); + TRACE("%p[%lu] = %s\n", string, idx, debugstr_jsstr(ret));
*r = jsval_string(ret); return S_OK; }
+static HRESULT String_indexed_prop_put(struct prop_desc *prop, jsval_t val) +{ + return S_OK; +} + +static HRESULT String_indexed_prop_get_desc(struct prop_desc *prop, BOOL flags_only, property_desc_t *desc) +{ + if(!flags_only) { + HRESULT hres = String_indexed_prop_get(prop, to_disp(prop->jsdisp), &desc->value); + if(FAILED(hres)) + return hres; + } + + desc->explicit_value = TRUE; + desc->flags = PROPF_ENUMERABLE; + return S_OK; +} + +static const struct prop_desc_vtbl String_indexed_prop_vtbl = { + String_indexed_prop_get, + String_indexed_prop_put, + indexed_prop_invoke, + indexed_prop_delete, + String_indexed_prop_get_desc, + indexed_prop_get_name, + indexed_prop_define +}; + +static const struct prop_desc_vtbl *String_get_prop_vtbl(jsdisp_t *jsdisp, DISPID id) +{ + StringInstance *string = string_from_jsdisp(jsdisp); + + /* + * NOTE: For invoke version < 2, indexed array is not implemented at all. + * Newer jscript.dll versions implement it on string type, not class, + * which is not how it should work according to spec. IE9 implements it + * properly, but it uses its own JavaScript engine inside MSHTML. We + * implement it here, but in the way IE9 and spec work. + */ + if(string->dispex.ctx->version < 2 || indexed_prop_id_to_idx(id) >= jsstr_length(string->str)) + return NULL; + return &String_indexed_prop_vtbl; +} + static const builtin_prop_t String_props[] = { {L"anchor", String_anchor, PROPF_METHOD|1}, {L"big", String_big, PROPF_METHOD}, @@ -1588,8 +1619,7 @@ static const builtin_info_t StringInst_info = { StringInst_props, String_destructor, NULL, - String_idx_length, - String_idx_get + String_get_prop_vtbl };
/* ECMA-262 3rd Edition 15.5.3.2 */