2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
28 static const GUID GUID_JScriptTypeInfo
= {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}};
30 #define FDEX_VERSION_MASK 0xf0000000
31 #define GOLDEN_RATIO 0x9E3779B9U
42 struct _dispex_prop_t
{
50 const builtin_prop_t
*p
;
63 static void fix_protref_prop(jsdisp_t
*jsdisp
, dispex_prop_t
*prop
)
67 if(prop
->type
!= PROP_PROTREF
)
71 while((jsdisp
= jsdisp
->prototype
)) {
72 if(ref
>= jsdisp
->prop_cnt
|| jsdisp
->props
[ref
].type
== PROP_DELETED
)
74 if(jsdisp
->props
[ref
].type
!= PROP_PROTREF
)
76 ref
= jsdisp
->props
[ref
].u
.ref
;
78 prop
->type
= PROP_DELETED
;
81 static inline DISPID
prop_to_id(jsdisp_t
*This
, dispex_prop_t
*prop
)
83 /* don't overlap with DISPID_VALUE */
84 return prop
- This
->props
+ 1;
87 static inline dispex_prop_t
*get_prop(jsdisp_t
*This
, DISPID id
)
91 if(idx
>= This
->prop_cnt
)
93 fix_protref_prop(This
, &This
->props
[idx
]);
95 return This
->props
[idx
].type
== PROP_DELETED
? NULL
: &This
->props
[idx
];
98 static inline BOOL
is_function_prop(dispex_prop_t
*prop
)
102 if (is_object_instance(prop
->u
.val
))
104 jsdisp_t
*jsdisp
= to_jsdisp(get_object(prop
->u
.val
));
106 if (jsdisp
) ret
= is_class(jsdisp
, JSCLASS_FUNCTION
);
111 static DWORD
get_flags(jsdisp_t
*This
, dispex_prop_t
*prop
)
113 if(prop
->type
== PROP_PROTREF
) {
114 dispex_prop_t
*parent
= NULL
;
116 if(prop
->u
.ref
< This
->prototype
->prop_cnt
)
117 parent
= &This
->prototype
->props
[prop
->u
.ref
];
119 if(!parent
|| parent
->type
== PROP_DELETED
) {
120 prop
->type
= PROP_DELETED
;
124 return get_flags(This
->prototype
, parent
);
130 static const builtin_prop_t
*find_builtin_prop(jsdisp_t
*This
, const WCHAR
*name
, BOOL case_insens
)
132 int min
= 0, max
= This
->builtin_info
->props_cnt
-1, i
, r
;
136 for(i
= min
; i
<= max
; i
++)
137 if(!wcsicmp(name
, This
->builtin_info
->props
[i
].name
))
145 r
= wcscmp(name
, This
->builtin_info
->props
[i
].name
);
158 /* Skip prop if it's available only in higher compatibility mode. */
159 version
= (This
->builtin_info
->props
[i
].flags
& PROPF_VERSION_MASK
) >> PROPF_VERSION_SHIFT
;
160 if(version
&& version
> This
->ctx
->version
)
163 /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
164 if((This
->builtin_info
->props
[i
].flags
& PROPF_HTML
) && !This
->ctx
->html_mode
)
167 return This
->builtin_info
->props
+ i
;
170 static inline unsigned string_hash(const WCHAR
*name
)
174 h
= (h
>>(sizeof(unsigned)*8-4)) ^ (h
<<4) ^ towlower(*name
);
178 static inline unsigned get_props_idx(jsdisp_t
*This
, unsigned hash
)
180 return (hash
*GOLDEN_RATIO
) & (This
->buf_size
-1);
183 static inline HRESULT
resize_props(jsdisp_t
*This
)
185 dispex_prop_t
*props
;
188 if(This
->buf_size
!= This
->prop_cnt
)
191 props
= realloc(This
->props
, sizeof(dispex_prop_t
) * This
->buf_size
* 2);
193 return E_OUTOFMEMORY
;
197 for(i
=0; i
<This
->buf_size
; i
++) {
198 This
->props
[i
].bucket_head
= ~0;
199 This
->props
[i
].bucket_next
= ~0;
202 for(i
=0; i
<This
->prop_cnt
; i
++) {
203 props
= This
->props
+i
;
205 bucket
= get_props_idx(This
, props
->hash
);
206 props
->bucket_next
= This
->props
[bucket
].bucket_head
;
207 This
->props
[bucket
].bucket_head
= i
;
213 static inline dispex_prop_t
* alloc_prop(jsdisp_t
*This
, const WCHAR
*name
, prop_type_t type
, DWORD flags
)
218 if(FAILED(resize_props(This
)))
221 prop
= &This
->props
[This
->prop_cnt
];
222 prop
->name
= wcsdup(name
);
227 prop
->hash
= string_hash(name
);
229 bucket
= get_props_idx(This
, prop
->hash
);
230 prop
->bucket_next
= This
->props
[bucket
].bucket_head
;
231 This
->props
[bucket
].bucket_head
= This
->prop_cnt
++;
235 static dispex_prop_t
*alloc_protref(jsdisp_t
*This
, const WCHAR
*name
, DWORD ref
)
239 ret
= alloc_prop(This
, name
, PROP_PROTREF
, 0);
247 static HRESULT
find_prop_name(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, BOOL case_insens
, dispex_prop_t
**ret
)
249 const builtin_prop_t
*builtin
;
250 unsigned bucket
, pos
, prev
= ~0;
254 bucket
= get_props_idx(This
, hash
);
255 pos
= This
->props
[bucket
].bucket_head
;
257 if(case_insens
? !wcsicmp(name
, This
->props
[pos
].name
) : !wcscmp(name
, This
->props
[pos
].name
)) {
259 This
->props
[prev
].bucket_next
= This
->props
[pos
].bucket_next
;
260 This
->props
[pos
].bucket_next
= This
->props
[bucket
].bucket_head
;
261 This
->props
[bucket
].bucket_head
= pos
;
264 *ret
= &This
->props
[pos
];
269 pos
= This
->props
[pos
].bucket_next
;
272 builtin
= find_builtin_prop(This
, name
, case_insens
);
274 unsigned flags
= builtin
->flags
;
275 if(flags
& PROPF_METHOD
) {
278 hres
= create_builtin_function(This
->ctx
, builtin
->invoke
, builtin
->name
, NULL
, flags
, NULL
, &obj
);
282 prop
= alloc_prop(This
, builtin
->name
, PROP_JSVAL
, (flags
& PROPF_ALL
) | PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
285 return E_OUTOFMEMORY
;
288 prop
->type
= PROP_JSVAL
;
289 prop
->u
.val
= jsval_obj(obj
);
292 }else if(builtin
->setter
)
293 flags
|= PROPF_WRITABLE
;
294 flags
&= PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
;
295 prop
= alloc_prop(This
, builtin
->name
, PROP_BUILTIN
, flags
);
297 return E_OUTOFMEMORY
;
304 if(This
->builtin_info
->idx_length
) {
308 for(ptr
= name
; is_digit(*ptr
) && idx
< 0x10000; ptr
++)
309 idx
= idx
*10 + (*ptr
-'0');
310 if(!*ptr
&& idx
< This
->builtin_info
->idx_length(This
)) {
311 unsigned flags
= PROPF_ENUMERABLE
;
312 if(This
->builtin_info
->idx_put
)
313 flags
|= PROPF_WRITABLE
;
314 prop
= alloc_prop(This
, name
, PROP_IDX
, flags
);
316 return E_OUTOFMEMORY
;
328 static HRESULT
find_prop_name_prot(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, BOOL case_insens
, dispex_prop_t
**ret
)
330 dispex_prop_t
*prop
, *del
=NULL
;
333 hres
= find_prop_name(This
, hash
, name
, case_insens
, &prop
);
336 if(prop
&& prop
->type
==PROP_DELETED
) {
339 fix_protref_prop(This
, prop
);
344 if(This
->prototype
) {
345 hres
= find_prop_name_prot(This
->prototype
, hash
, name
, case_insens
, &prop
);
348 if(prop
&& prop
->type
!= PROP_DELETED
) {
350 del
->type
= PROP_PROTREF
;
351 del
->u
.ref
= prop
- This
->prototype
->props
;
354 prop
= alloc_protref(This
, prop
->name
, prop
- This
->prototype
->props
);
356 return E_OUTOFMEMORY
;
368 static HRESULT
ensure_prop_name(jsdisp_t
*This
, const WCHAR
*name
, DWORD create_flags
, BOOL case_insens
, dispex_prop_t
**ret
)
373 hres
= find_prop_name_prot(This
, string_hash(name
), name
, case_insens
, &prop
);
374 if(SUCCEEDED(hres
) && (!prop
|| prop
->type
== PROP_DELETED
)) {
375 TRACE("creating prop %s flags %lx\n", debugstr_w(name
), create_flags
);
378 prop
->type
= PROP_JSVAL
;
379 prop
->flags
= create_flags
;
380 prop
->u
.val
= jsval_undefined();
382 prop
= alloc_prop(This
, name
, PROP_JSVAL
, create_flags
);
384 return E_OUTOFMEMORY
;
387 prop
->u
.val
= jsval_undefined();
394 static IDispatch
*get_this(DISPPARAMS
*dp
)
398 for(i
=0; i
< dp
->cNamedArgs
; i
++) {
399 if(dp
->rgdispidNamedArgs
[i
] == DISPID_THIS
) {
400 if(V_VT(dp
->rgvarg
+i
) == VT_DISPATCH
)
401 return V_DISPATCH(dp
->rgvarg
+i
);
403 WARN("This is not VT_DISPATCH\n");
408 TRACE("no this passed\n");
412 static HRESULT
convert_params(script_ctx_t
*ctx
, const DISPPARAMS
*dp
, jsval_t
*buf
, unsigned *argc
, jsval_t
**ret
)
419 cnt
= dp
->cArgs
- dp
->cNamedArgs
;
422 argv
= malloc(cnt
* sizeof(*argv
));
424 return E_OUTOFMEMORY
;
429 for(i
= 0; i
< cnt
; i
++) {
430 hres
= variant_to_jsval(ctx
, dp
->rgvarg
+dp
->cArgs
-i
-1, argv
+i
);
433 jsval_release(argv
[i
]);
445 static HRESULT
prop_get(jsdisp_t
*This
, IDispatch
*jsthis
, dispex_prop_t
*prop
, jsval_t
*r
)
447 jsdisp_t
*prop_obj
= This
;
450 while(prop
->type
== PROP_PROTREF
) {
451 prop_obj
= prop_obj
->prototype
;
452 prop
= prop_obj
->props
+ prop
->u
.ref
;
457 hres
= prop
->u
.p
->getter(This
->ctx
, prop_obj
, r
);
460 hres
= jsval_copy(prop
->u
.val
, r
);
463 if(prop
->u
.accessor
.getter
) {
464 hres
= jsdisp_call_value(prop
->u
.accessor
.getter
, jsval_disp(jsthis
),
465 DISPATCH_METHOD
, 0, NULL
, r
);
467 *r
= jsval_undefined();
472 hres
= prop_obj
->builtin_info
->idx_get(prop_obj
, prop
->u
.idx
, r
);
475 ERR("type %d\n", prop
->type
);
480 TRACE("fail %08lx\n", hres
);
484 TRACE("%p.%s ret %s\n", This
, debugstr_w(prop
->name
), debugstr_jsval(*r
));
488 static HRESULT
prop_put(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t val
)
492 if(prop
->type
== PROP_PROTREF
) {
493 dispex_prop_t
*prop_iter
= prop
;
494 jsdisp_t
*prototype_iter
= This
;
497 prototype_iter
= prototype_iter
->prototype
;
498 prop_iter
= prototype_iter
->props
+ prop_iter
->u
.ref
;
499 } while(prop_iter
->type
== PROP_PROTREF
);
501 if(prop_iter
->type
== PROP_ACCESSOR
)
507 if(!prop
->u
.p
->setter
) {
508 TRACE("getter with no setter\n");
511 return prop
->u
.p
->setter(This
->ctx
, This
, val
);
514 if(!This
->extensible
)
516 prop
->type
= PROP_JSVAL
;
517 prop
->flags
= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
;
518 prop
->u
.val
= jsval_undefined();
521 if(!(prop
->flags
& PROPF_WRITABLE
))
524 jsval_release(prop
->u
.val
);
527 if(!prop
->u
.accessor
.setter
) {
528 TRACE("no setter\n");
531 return jsdisp_call_value(prop
->u
.accessor
.setter
, jsval_obj(This
), DISPATCH_METHOD
, 1, &val
, NULL
);
533 if(!This
->builtin_info
->idx_put
) {
534 TRACE("no put_idx\n");
537 return This
->builtin_info
->idx_put(This
, prop
->u
.idx
, val
);
539 ERR("type %d\n", prop
->type
);
543 TRACE("%p.%s = %s\n", This
, debugstr_w(prop
->name
), debugstr_jsval(val
));
545 hres
= jsval_copy(val
, &prop
->u
.val
);
549 if(This
->builtin_info
->on_put
)
550 This
->builtin_info
->on_put(This
, prop
->name
);
555 static HRESULT
invoke_prop_func(jsdisp_t
*This
, IDispatch
*jsthis
, dispex_prop_t
*prop
, WORD flags
,
556 unsigned argc
, jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
562 return JS_E_FUNCTION_EXPECTED
;
564 return invoke_prop_func(This
->prototype
, jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
565 This
->prototype
->props
+prop
->u
.ref
, flags
, argc
, argv
, r
, caller
);
567 if(!is_object_instance(prop
->u
.val
)) {
568 FIXME("invoke %s\n", debugstr_jsval(prop
->u
.val
));
572 TRACE("call %s %p\n", debugstr_w(prop
->name
), get_object(prop
->u
.val
));
574 return disp_call_value_with_caller(This
->ctx
, get_object(prop
->u
.val
),
575 jsval_disp(jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
),
576 flags
, argc
, argv
, r
, caller
);
582 hres
= prop_get(This
, jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
, prop
, &val
);
586 if(is_object_instance(val
)) {
587 hres
= disp_call_value_with_caller(This
->ctx
, get_object(val
),
588 jsval_disp(jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
),
589 flags
, argc
, argv
, r
, caller
);
591 FIXME("invoke %s\n", debugstr_jsval(val
));
606 HRESULT
builtin_set_const(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
608 TRACE("%p %s\n", jsthis
, debugstr_jsval(value
));
612 static HRESULT
fill_props(jsdisp_t
*obj
)
617 if(obj
->builtin_info
->idx_length
) {
618 unsigned i
= 0, len
= obj
->builtin_info
->idx_length(obj
);
621 for(i
= 0; i
< len
; i
++) {
622 swprintf(name
, ARRAY_SIZE(name
), L
"%u", i
);
623 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
632 static HRESULT
fill_protrefs(jsdisp_t
*This
)
634 dispex_prop_t
*iter
, *prop
;
637 hres
= fill_props(This
);
644 hres
= fill_protrefs(This
->prototype
);
648 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
649 hres
= find_prop_name(This
, iter
->hash
, iter
->name
, FALSE
, &prop
);
652 if(!prop
|| prop
->type
==PROP_DELETED
) {
654 prop
->type
= PROP_PROTREF
;
656 prop
->u
.ref
= iter
- This
->prototype
->props
;
658 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
660 return E_OUTOFMEMORY
;
668 static void unlink_jsdisp(jsdisp_t
*jsdisp
)
670 dispex_prop_t
*prop
= jsdisp
->props
, *end
;
672 for(end
= prop
+ jsdisp
->prop_cnt
; prop
< end
; prop
++) {
677 jsval_release(prop
->u
.val
);
680 if(prop
->u
.accessor
.getter
)
681 jsdisp_release(prop
->u
.accessor
.getter
);
682 if(prop
->u
.accessor
.setter
)
683 jsdisp_release(prop
->u
.accessor
.setter
);
688 prop
->type
= PROP_DELETED
;
691 if(jsdisp
->prototype
) {
692 jsdisp_release(jsdisp
->prototype
);
693 jsdisp
->prototype
= NULL
;
696 if(jsdisp
->builtin_info
->gc_traverse
)
697 jsdisp
->builtin_info
->gc_traverse(NULL
, GC_TRAVERSE_UNLINK
, jsdisp
);
703 * To deal with circular refcounts, a basic Garbage Collector is used with a variant of the
704 * mark-and-sweep algorithm that doesn't require knowing or traversing any specific "roots".
705 * This works based on the assumption that circular references can only happen when objects
706 * end up pointing to each other, and each other alone, without any external refs.
708 * An "external ref" is a ref to the object that's not from any other object. Example of such
709 * refs can be local variables, the script ctx (which keeps a ref to the global object), etc.
711 * At a high level, there are 3 logical passes done on the entire list of objects:
713 * 1. Speculatively decrease refcounts of each linked-to-object from each object. This ensures
714 * that the only remaining refcount on each object is the number of "external refs" to it.
715 * At the same time, mark all of the objects so that they can be potentially collected.
717 * 2. For each object with a non-zero "external refcount", clear the mark from step 1, and
718 * recursively traverse all linked objects from it, clearing their marks as well (regardless
719 * of their refcount), stopping a given path when the object is unmarked (and then going back
720 * up the GC stack). This basically unmarks all of the objects with "external refcounts"
721 * and those accessible from them, and only the leaked dangling objects will still be marked.
723 * 3. For each object that is marked, unlink all of the objects linked from it, because they
724 * are dangling in a circular refcount and not accessible. This should release them.
726 * During unlinking (GC_TRAVERSE_UNLINK), it is important that we unlink *all* linked objects
727 * from the object, to be certain that releasing the object later will not delete any other
728 * objects. Otherwise calculating the "next" object in the list becomes impossible.
730 * This collection process has to be done periodically, but can be pretty expensive so there
731 * has to be a balance between reclaiming dangling objects and performance.
734 struct gc_stack_chunk
{
735 jsdisp_t
*objects
[1020];
736 struct gc_stack_chunk
*prev
;
740 struct gc_stack_chunk
*chunk
;
741 struct gc_stack_chunk
*next
;
745 static HRESULT
gc_stack_push(struct gc_ctx
*gc_ctx
, jsdisp_t
*obj
)
749 gc_ctx
->chunk
= gc_ctx
->next
;
751 struct gc_stack_chunk
*prev
, *tmp
= malloc(sizeof(*tmp
));
753 return E_OUTOFMEMORY
;
754 prev
= gc_ctx
->chunk
;
756 gc_ctx
->chunk
->prev
= prev
;
758 gc_ctx
->idx
= ARRAY_SIZE(gc_ctx
->chunk
->objects
);
761 gc_ctx
->chunk
->objects
[--gc_ctx
->idx
] = obj
;
765 static jsdisp_t
*gc_stack_pop(struct gc_ctx
*gc_ctx
)
767 jsdisp_t
*obj
= gc_ctx
->chunk
->objects
[gc_ctx
->idx
];
769 if(++gc_ctx
->idx
== ARRAY_SIZE(gc_ctx
->chunk
->objects
)) {
771 gc_ctx
->next
= gc_ctx
->chunk
;
772 gc_ctx
->chunk
= gc_ctx
->chunk
->prev
;
778 HRESULT
gc_run(script_ctx_t
*ctx
)
780 /* Save original refcounts in a linked list of chunks */
786 struct thread_data
*thread_data
= ctx
->thread_data
;
787 jsdisp_t
*obj
, *obj2
, *link
, *link2
;
788 dispex_prop_t
*prop
, *props_end
;
789 struct gc_ctx gc_ctx
= { 0 };
790 unsigned chunk_idx
= 0;
794 /* Prevent recursive calls from side-effects during unlinking (e.g. CollectGarbage from host object's Release) */
795 if(thread_data
->gc_is_unlinking
)
798 if(!(head
= malloc(sizeof(*head
))))
799 return E_OUTOFMEMORY
;
803 /* 1. Save actual refcounts and decrease them speculatively as-if we unlinked the objects */
804 LIST_FOR_EACH_ENTRY(obj
, &thread_data
->objects
, jsdisp_t
, entry
) {
805 if(chunk_idx
== ARRAY_SIZE(chunk
->ref
)) {
806 if(!(chunk
->next
= malloc(sizeof(*chunk
)))) {
812 return E_OUTOFMEMORY
;
814 chunk
= chunk
->next
; chunk_idx
= 0;
817 chunk
->ref
[chunk_idx
++] = obj
->ref
;
819 LIST_FOR_EACH_ENTRY(obj
, &thread_data
->objects
, jsdisp_t
, entry
) {
820 for(prop
= obj
->props
, props_end
= prop
+ obj
->prop_cnt
; prop
< props_end
; prop
++) {
823 if(is_object_instance(prop
->u
.val
) && (link
= to_jsdisp(get_object(prop
->u
.val
))))
827 if(prop
->u
.accessor
.getter
)
828 prop
->u
.accessor
.getter
->ref
--;
829 if(prop
->u
.accessor
.setter
)
830 prop
->u
.accessor
.setter
->ref
--;
838 obj
->prototype
->ref
--;
839 if(obj
->builtin_info
->gc_traverse
)
840 obj
->builtin_info
->gc_traverse(&gc_ctx
, GC_TRAVERSE_SPECULATIVELY
, obj
);
841 obj
->gc_marked
= TRUE
;
844 /* 2. Clear mark on objects with non-zero "external refcount" and all objects accessible from them */
845 LIST_FOR_EACH_ENTRY(obj
, &thread_data
->objects
, jsdisp_t
, entry
) {
846 if(!obj
->ref
|| !obj
->gc_marked
)
849 hres
= gc_stack_push(&gc_ctx
, NULL
);
856 obj2
->gc_marked
= FALSE
;
858 for(prop
= obj2
->props
, props_end
= prop
+ obj2
->prop_cnt
; prop
< props_end
; prop
++) {
861 if(!is_object_instance(prop
->u
.val
))
863 link
= to_jsdisp(get_object(prop
->u
.val
));
867 link
= prop
->u
.accessor
.getter
;
868 link2
= prop
->u
.accessor
.setter
;
873 if(link
&& link
->gc_marked
) {
874 hres
= gc_stack_push(&gc_ctx
, link
);
878 if(link2
&& link2
->gc_marked
) {
879 hres
= gc_stack_push(&gc_ctx
, link2
);
888 if(obj2
->prototype
&& obj2
->prototype
->gc_marked
) {
889 hres
= gc_stack_push(&gc_ctx
, obj2
->prototype
);
894 if(obj2
->builtin_info
->gc_traverse
) {
895 hres
= obj2
->builtin_info
->gc_traverse(&gc_ctx
, GC_TRAVERSE
, obj2
);
900 /* For weak refs, traverse paths accessible from it via the WeakMaps, if the WeakMaps are alive at this point.
901 We need both the key and the WeakMap for the entry to actually be accessible (and thus traversed). */
902 if(obj2
->has_weak_refs
) {
903 struct list
*list
= &RB_ENTRY_VALUE(rb_get(&thread_data
->weak_refs
, obj2
), struct weak_refs_entry
, entry
)->list
;
904 struct weakmap_entry
*entry
;
906 LIST_FOR_EACH_ENTRY(entry
, list
, struct weakmap_entry
, weak_refs_entry
) {
907 if(!entry
->weakmap
->gc_marked
&& is_object_instance(entry
->value
) && (link
= to_jsdisp(get_object(entry
->value
)))) {
908 hres
= gc_stack_push(&gc_ctx
, link
);
918 do obj2
= gc_stack_pop(&gc_ctx
); while(obj2
&& !obj2
->gc_marked
);
922 do obj2
= gc_stack_pop(&gc_ctx
); while(obj2
);
929 chunk
= head
; chunk_idx
= 0;
930 LIST_FOR_EACH_ENTRY(obj
, &thread_data
->objects
, jsdisp_t
, entry
) {
931 obj
->ref
= chunk
->ref
[chunk_idx
++];
932 if(chunk_idx
== ARRAY_SIZE(chunk
->ref
)) {
933 struct chunk
*next
= chunk
->next
;
935 chunk
= next
; chunk_idx
= 0;
943 /* 3. Remove all the links from the marked objects, since they are dangling */
944 thread_data
->gc_is_unlinking
= TRUE
;
946 iter
= list_head(&thread_data
->objects
);
948 obj
= LIST_ENTRY(iter
, jsdisp_t
, entry
);
949 if(!obj
->gc_marked
) {
950 iter
= list_next(&thread_data
->objects
, iter
);
954 /* Grab it since it gets removed when unlinked */
958 /* Releasing unlinked object should not delete any other object,
959 so we can safely obtain the next pointer now */
960 iter
= list_next(&thread_data
->objects
, iter
);
964 thread_data
->gc_is_unlinking
= FALSE
;
965 thread_data
->gc_last_tick
= GetTickCount();
969 HRESULT
gc_process_linked_obj(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, jsdisp_t
*obj
, jsdisp_t
*link
, void **unlink_ref
)
971 if(op
== GC_TRAVERSE_UNLINK
) {
973 jsdisp_release(link
);
977 if(op
== GC_TRAVERSE_SPECULATIVELY
)
979 else if(link
->gc_marked
)
980 return gc_stack_push(gc_ctx
, link
);
984 HRESULT
gc_process_linked_val(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, jsdisp_t
*obj
, jsval_t
*link
)
988 if(op
== GC_TRAVERSE_UNLINK
) {
990 *link
= jsval_undefined();
995 if(!is_object_instance(*link
) || !(jsdisp
= to_jsdisp(get_object(*link
))))
997 if(op
== GC_TRAVERSE_SPECULATIVELY
)
999 else if(jsdisp
->gc_marked
)
1000 return gc_stack_push(gc_ctx
, jsdisp
);
1006 struct typeinfo_func
{
1007 dispex_prop_t
*prop
;
1008 function_code_t
*code
;
1012 ITypeInfo ITypeInfo_iface
;
1013 ITypeComp ITypeComp_iface
;
1018 struct typeinfo_func
*funcs
;
1019 dispex_prop_t
**vars
;
1024 static struct typeinfo_func
*get_func_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
1026 UINT a
= 0, b
= typeinfo
->num_funcs
;
1030 UINT i
= (a
+ b
- 1) / 2;
1031 MEMBERID func_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->funcs
[i
].prop
);
1033 if (memid
== func_memid
)
1034 return &typeinfo
->funcs
[i
];
1035 else if (memid
< func_memid
)
1043 static dispex_prop_t
*get_var_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
1045 UINT a
= 0, b
= typeinfo
->num_vars
;
1049 UINT i
= (a
+ b
- 1) / 2;
1050 MEMBERID var_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->vars
[i
]);
1052 if (memid
== var_memid
)
1053 return typeinfo
->vars
[i
];
1054 else if (memid
< var_memid
)
1062 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeInfo(ITypeInfo
*iface
)
1064 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeInfo_iface
);
1067 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeComp(ITypeComp
*iface
)
1069 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeComp_iface
);
1072 static HRESULT WINAPI
ScriptTypeInfo_QueryInterface(ITypeInfo
*iface
, REFIID riid
, void **ppv
)
1074 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1076 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ITypeInfo
, riid
))
1077 *ppv
= &This
->ITypeInfo_iface
;
1078 else if (IsEqualGUID(&IID_ITypeComp
, riid
))
1079 *ppv
= &This
->ITypeComp_iface
;
1082 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1084 return E_NOINTERFACE
;
1087 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1088 IUnknown_AddRef((IUnknown
*)*ppv
);
1092 static ULONG WINAPI
ScriptTypeInfo_AddRef(ITypeInfo
*iface
)
1094 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1095 LONG ref
= InterlockedIncrement(&This
->ref
);
1097 TRACE("(%p) ref=%ld\n", This
, ref
);
1102 static ULONG WINAPI
ScriptTypeInfo_Release(ITypeInfo
*iface
)
1104 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1105 LONG ref
= InterlockedDecrement(&This
->ref
);
1108 TRACE("(%p) ref=%ld\n", This
, ref
);
1112 for (i
= This
->num_funcs
; i
--;)
1113 release_bytecode(This
->funcs
[i
].code
->bytecode
);
1114 IDispatchEx_Release(&This
->jsdisp
->IDispatchEx_iface
);
1122 static HRESULT WINAPI
ScriptTypeInfo_GetTypeAttr(ITypeInfo
*iface
, TYPEATTR
**ppTypeAttr
)
1124 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1127 TRACE("(%p)->(%p)\n", This
, ppTypeAttr
);
1129 if (!ppTypeAttr
) return E_INVALIDARG
;
1131 attr
= calloc(1, sizeof(*attr
));
1132 if (!attr
) return E_OUTOFMEMORY
;
1134 attr
->guid
= GUID_JScriptTypeInfo
;
1135 attr
->lcid
= LOCALE_USER_DEFAULT
;
1136 attr
->memidConstructor
= MEMBERID_NIL
;
1137 attr
->memidDestructor
= MEMBERID_NIL
;
1138 attr
->cbSizeInstance
= 4;
1139 attr
->typekind
= TKIND_DISPATCH
;
1140 attr
->cFuncs
= This
->num_funcs
;
1141 attr
->cVars
= This
->num_vars
;
1142 attr
->cImplTypes
= 1;
1143 attr
->cbSizeVft
= sizeof(IDispatchVtbl
);
1144 attr
->cbAlignment
= 4;
1145 attr
->wTypeFlags
= TYPEFLAG_FDISPATCHABLE
;
1146 attr
->wMajorVerNum
= JSCRIPT_MAJOR_VERSION
;
1147 attr
->wMinorVerNum
= JSCRIPT_MINOR_VERSION
;
1153 static HRESULT WINAPI
ScriptTypeInfo_GetTypeComp(ITypeInfo
*iface
, ITypeComp
**ppTComp
)
1155 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1157 TRACE("(%p)->(%p)\n", This
, ppTComp
);
1159 if (!ppTComp
) return E_INVALIDARG
;
1161 *ppTComp
= &This
->ITypeComp_iface
;
1162 ITypeInfo_AddRef(iface
);
1166 static HRESULT WINAPI
ScriptTypeInfo_GetFuncDesc(ITypeInfo
*iface
, UINT index
, FUNCDESC
**ppFuncDesc
)
1168 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1169 struct typeinfo_func
*func
;
1173 TRACE("(%p)->(%u %p)\n", This
, index
, ppFuncDesc
);
1175 if (!ppFuncDesc
) return E_INVALIDARG
;
1176 if (index
>= This
->num_funcs
) return TYPE_E_ELEMENTNOTFOUND
;
1177 func
= &This
->funcs
[index
];
1179 /* Store the parameter array after the FUNCDESC structure */
1180 desc
= calloc(1, sizeof(*desc
) + sizeof(ELEMDESC
) * func
->code
->param_cnt
);
1181 if (!desc
) return E_OUTOFMEMORY
;
1183 desc
->memid
= prop_to_id(This
->jsdisp
, func
->prop
);
1184 desc
->funckind
= FUNC_DISPATCH
;
1185 desc
->invkind
= INVOKE_FUNC
;
1186 desc
->callconv
= CC_STDCALL
;
1187 desc
->cParams
= func
->code
->param_cnt
;
1188 desc
->elemdescFunc
.tdesc
.vt
= VT_VARIANT
;
1190 if (func
->code
->param_cnt
) desc
->lprgelemdescParam
= (ELEMDESC
*)(desc
+ 1);
1191 for (i
= 0; i
< func
->code
->param_cnt
; i
++)
1192 desc
->lprgelemdescParam
[i
].tdesc
.vt
= VT_VARIANT
;
1198 static HRESULT WINAPI
ScriptTypeInfo_GetVarDesc(ITypeInfo
*iface
, UINT index
, VARDESC
**ppVarDesc
)
1200 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1203 TRACE("(%p)->(%u %p)\n", This
, index
, ppVarDesc
);
1205 if (!ppVarDesc
) return E_INVALIDARG
;
1206 if (index
>= This
->num_vars
) return TYPE_E_ELEMENTNOTFOUND
;
1208 desc
= calloc(1, sizeof(*desc
));
1209 if (!desc
) return E_OUTOFMEMORY
;
1211 desc
->memid
= prop_to_id(This
->jsdisp
, This
->vars
[index
]);
1212 desc
->varkind
= VAR_DISPATCH
;
1213 desc
->elemdescVar
.tdesc
.vt
= VT_VARIANT
;
1219 static HRESULT WINAPI
ScriptTypeInfo_GetNames(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*rgBstrNames
,
1220 UINT cMaxNames
, UINT
*pcNames
)
1222 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1223 struct typeinfo_func
*func
;
1224 ITypeInfo
*disp_typeinfo
;
1229 TRACE("(%p)->(%ld %p %u %p)\n", This
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
1231 if (!rgBstrNames
|| !pcNames
) return E_INVALIDARG
;
1232 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1234 func
= get_func_from_memid(This
, memid
);
1237 var
= get_var_from_memid(This
, memid
);
1240 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1241 if (FAILED(hr
)) return hr
;
1243 return ITypeInfo_GetNames(disp_typeinfo
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
1248 if (!cMaxNames
) return S_OK
;
1250 rgBstrNames
[0] = SysAllocString(func
? func
->prop
->name
: var
->name
);
1251 if (!rgBstrNames
[0]) return E_OUTOFMEMORY
;
1256 unsigned num
= min(cMaxNames
, func
->code
->param_cnt
+ 1);
1258 for (; i
< num
; i
++)
1260 if (!(rgBstrNames
[i
] = SysAllocString(func
->code
->params
[i
- 1])))
1262 do SysFreeString(rgBstrNames
[--i
]); while (i
);
1263 return E_OUTOFMEMORY
;
1272 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo
*iface
, UINT index
, HREFTYPE
*pRefType
)
1274 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1276 TRACE("(%p)->(%u %p)\n", This
, index
, pRefType
);
1278 /* We only inherit from IDispatch */
1279 if (!pRefType
) return E_INVALIDARG
;
1280 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
1286 static HRESULT WINAPI
ScriptTypeInfo_GetImplTypeFlags(ITypeInfo
*iface
, UINT index
, INT
*pImplTypeFlags
)
1288 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1290 TRACE("(%p)->(%u %p)\n", This
, index
, pImplTypeFlags
);
1292 if (!pImplTypeFlags
) return E_INVALIDARG
;
1293 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
1295 *pImplTypeFlags
= 0;
1299 static HRESULT WINAPI
ScriptTypeInfo_GetIDsOfNames(ITypeInfo
*iface
, LPOLESTR
*rgszNames
, UINT cNames
,
1302 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1303 ITypeInfo
*disp_typeinfo
;
1308 TRACE("(%p)->(%p %u %p)\n", This
, rgszNames
, cNames
, pMemId
);
1310 if (!rgszNames
|| !cNames
|| !pMemId
) return E_INVALIDARG
;
1312 for (i
= 0; i
< cNames
; i
++) pMemId
[i
] = MEMBERID_NIL
;
1313 name
= rgszNames
[0];
1315 for (i
= 0; i
< This
->num_funcs
; i
++)
1317 struct typeinfo_func
*func
= &This
->funcs
[i
];
1319 if (wcsicmp(name
, func
->prop
->name
)) continue;
1320 pMemId
[0] = prop_to_id(This
->jsdisp
, func
->prop
);
1322 for (j
= 1; j
< cNames
; j
++)
1324 name
= rgszNames
[j
];
1325 for (arg
= func
->code
->param_cnt
; --arg
>= 0;)
1326 if (!wcsicmp(name
, func
->code
->params
[arg
]))
1331 hr
= DISP_E_UNKNOWNNAME
;
1336 for (i
= 0; i
< This
->num_vars
; i
++)
1338 dispex_prop_t
*var
= This
->vars
[i
];
1340 if (wcsicmp(name
, var
->name
)) continue;
1341 pMemId
[0] = prop_to_id(This
->jsdisp
, var
);
1345 /* Look into the inherited IDispatch */
1346 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1347 if (FAILED(hr
)) return hr
;
1349 return ITypeInfo_GetIDsOfNames(disp_typeinfo
, rgszNames
, cNames
, pMemId
);
1352 static HRESULT WINAPI
ScriptTypeInfo_Invoke(ITypeInfo
*iface
, PVOID pvInstance
, MEMBERID memid
, WORD wFlags
,
1353 DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1355 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1356 ITypeInfo
*disp_typeinfo
;
1360 TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This
, pvInstance
, memid
, wFlags
,
1361 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1363 if (!pvInstance
) return E_INVALIDARG
;
1364 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1366 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1368 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1369 if (FAILED(hr
)) return hr
;
1371 return ITypeInfo_Invoke(disp_typeinfo
, pvInstance
, memid
, wFlags
, pDispParams
,
1372 pVarResult
, pExcepInfo
, puArgErr
);
1375 hr
= IUnknown_QueryInterface((IUnknown
*)pvInstance
, &IID_IDispatch
, (void**)&disp
);
1376 if (FAILED(hr
)) return hr
;
1378 hr
= IDispatch_Invoke(disp
, memid
, &IID_NULL
, LOCALE_USER_DEFAULT
, wFlags
,
1379 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1380 IDispatch_Release(disp
);
1385 static HRESULT WINAPI
ScriptTypeInfo_GetDocumentation(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrName
,
1386 BSTR
*pBstrDocString
, DWORD
*pdwHelpContext
, BSTR
*pBstrHelpFile
)
1388 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1389 struct typeinfo_func
*func
;
1390 ITypeInfo
*disp_typeinfo
;
1394 TRACE("(%p)->(%ld %p %p %p %p)\n", This
, memid
, pBstrName
, pBstrDocString
, pdwHelpContext
, pBstrHelpFile
);
1396 if (pBstrDocString
) *pBstrDocString
= NULL
;
1397 if (pdwHelpContext
) *pdwHelpContext
= 0;
1398 if (pBstrHelpFile
) *pBstrHelpFile
= NULL
;
1400 if (memid
== MEMBERID_NIL
)
1402 if (pBstrName
&& !(*pBstrName
= SysAllocString(L
"JScriptTypeInfo")))
1403 return E_OUTOFMEMORY
;
1404 if (pBstrDocString
&&
1405 !(*pBstrDocString
= SysAllocString(L
"JScript Type Info")))
1407 if (pBstrName
) SysFreeString(*pBstrName
);
1408 return E_OUTOFMEMORY
;
1412 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1414 func
= get_func_from_memid(This
, memid
);
1417 var
= get_var_from_memid(This
, memid
);
1420 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1421 if (FAILED(hr
)) return hr
;
1423 return ITypeInfo_GetDocumentation(disp_typeinfo
, memid
, pBstrName
, pBstrDocString
,
1424 pdwHelpContext
, pBstrHelpFile
);
1430 *pBstrName
= SysAllocString(func
? func
->prop
->name
: var
->name
);
1433 return E_OUTOFMEMORY
;
1438 static HRESULT WINAPI
ScriptTypeInfo_GetDllEntry(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
,
1439 BSTR
*pBstrDllName
, BSTR
*pBstrName
, WORD
*pwOrdinal
)
1441 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1442 ITypeInfo
*disp_typeinfo
;
1445 TRACE("(%p)->(%ld %d %p %p %p)\n", This
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1447 if (pBstrDllName
) *pBstrDllName
= NULL
;
1448 if (pBstrName
) *pBstrName
= NULL
;
1449 if (pwOrdinal
) *pwOrdinal
= 0;
1451 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1453 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1454 if (FAILED(hr
)) return hr
;
1456 return ITypeInfo_GetDllEntry(disp_typeinfo
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1458 return TYPE_E_BADMODULEKIND
;
1461 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeInfo(ITypeInfo
*iface
, HREFTYPE hRefType
, ITypeInfo
**ppTInfo
)
1463 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1466 TRACE("(%p)->(%lx %p)\n", This
, hRefType
, ppTInfo
);
1468 if (!ppTInfo
|| (INT
)hRefType
< 0) return E_INVALIDARG
;
1470 if (hRefType
& ~3) return E_FAIL
;
1473 hr
= get_dispatch_typeinfo(ppTInfo
);
1474 if (FAILED(hr
)) return hr
;
1479 ITypeInfo_AddRef(*ppTInfo
);
1483 static HRESULT WINAPI
ScriptTypeInfo_AddressOfMember(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
, PVOID
*ppv
)
1485 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1486 ITypeInfo
*disp_typeinfo
;
1489 TRACE("(%p)->(%ld %d %p)\n", This
, memid
, invKind
, ppv
);
1491 if (!ppv
) return E_INVALIDARG
;
1494 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1496 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1497 if (FAILED(hr
)) return hr
;
1499 return ITypeInfo_AddressOfMember(disp_typeinfo
, memid
, invKind
, ppv
);
1501 return TYPE_E_BADMODULEKIND
;
1504 static HRESULT WINAPI
ScriptTypeInfo_CreateInstance(ITypeInfo
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, PVOID
*ppvObj
)
1506 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1508 TRACE("(%p)->(%p %s %p)\n", This
, pUnkOuter
, debugstr_guid(riid
), ppvObj
);
1510 if (!ppvObj
) return E_INVALIDARG
;
1513 return TYPE_E_BADMODULEKIND
;
1516 static HRESULT WINAPI
ScriptTypeInfo_GetMops(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrMops
)
1518 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1519 ITypeInfo
*disp_typeinfo
;
1522 TRACE("(%p)->(%ld %p)\n", This
, memid
, pBstrMops
);
1524 if (!pBstrMops
) return E_INVALIDARG
;
1526 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1528 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1529 if (FAILED(hr
)) return hr
;
1531 return ITypeInfo_GetMops(disp_typeinfo
, memid
, pBstrMops
);
1538 static HRESULT WINAPI
ScriptTypeInfo_GetContainingTypeLib(ITypeInfo
*iface
, ITypeLib
**ppTLib
, UINT
*pIndex
)
1540 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1542 FIXME("(%p)->(%p %p)\n", This
, ppTLib
, pIndex
);
1547 static void WINAPI
ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo
*iface
, TYPEATTR
*pTypeAttr
)
1549 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1551 TRACE("(%p)->(%p)\n", This
, pTypeAttr
);
1556 static void WINAPI
ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo
*iface
, FUNCDESC
*pFuncDesc
)
1558 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1560 TRACE("(%p)->(%p)\n", This
, pFuncDesc
);
1565 static void WINAPI
ScriptTypeInfo_ReleaseVarDesc(ITypeInfo
*iface
, VARDESC
*pVarDesc
)
1567 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1569 TRACE("(%p)->(%p)\n", This
, pVarDesc
);
1574 static const ITypeInfoVtbl ScriptTypeInfoVtbl
= {
1575 ScriptTypeInfo_QueryInterface
,
1576 ScriptTypeInfo_AddRef
,
1577 ScriptTypeInfo_Release
,
1578 ScriptTypeInfo_GetTypeAttr
,
1579 ScriptTypeInfo_GetTypeComp
,
1580 ScriptTypeInfo_GetFuncDesc
,
1581 ScriptTypeInfo_GetVarDesc
,
1582 ScriptTypeInfo_GetNames
,
1583 ScriptTypeInfo_GetRefTypeOfImplType
,
1584 ScriptTypeInfo_GetImplTypeFlags
,
1585 ScriptTypeInfo_GetIDsOfNames
,
1586 ScriptTypeInfo_Invoke
,
1587 ScriptTypeInfo_GetDocumentation
,
1588 ScriptTypeInfo_GetDllEntry
,
1589 ScriptTypeInfo_GetRefTypeInfo
,
1590 ScriptTypeInfo_AddressOfMember
,
1591 ScriptTypeInfo_CreateInstance
,
1592 ScriptTypeInfo_GetMops
,
1593 ScriptTypeInfo_GetContainingTypeLib
,
1594 ScriptTypeInfo_ReleaseTypeAttr
,
1595 ScriptTypeInfo_ReleaseFuncDesc
,
1596 ScriptTypeInfo_ReleaseVarDesc
1599 static HRESULT WINAPI
ScriptTypeComp_QueryInterface(ITypeComp
*iface
, REFIID riid
, void **ppv
)
1601 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1602 return ITypeInfo_QueryInterface(&This
->ITypeInfo_iface
, riid
, ppv
);
1605 static ULONG WINAPI
ScriptTypeComp_AddRef(ITypeComp
*iface
)
1607 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1608 return ITypeInfo_AddRef(&This
->ITypeInfo_iface
);
1611 static ULONG WINAPI
ScriptTypeComp_Release(ITypeComp
*iface
)
1613 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1614 return ITypeInfo_Release(&This
->ITypeInfo_iface
);
1617 static HRESULT WINAPI
ScriptTypeComp_Bind(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
, WORD wFlags
,
1618 ITypeInfo
**ppTInfo
, DESCKIND
*pDescKind
, BINDPTR
*pBindPtr
)
1620 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1621 UINT flags
= wFlags
? wFlags
: ~0;
1622 ITypeInfo
*disp_typeinfo
;
1623 ITypeComp
*disp_typecomp
;
1627 TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This
, debugstr_w(szName
), lHashVal
,
1628 wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1630 if (!szName
|| !ppTInfo
|| !pDescKind
|| !pBindPtr
)
1631 return E_INVALIDARG
;
1633 for (i
= 0; i
< This
->num_funcs
; i
++)
1635 if (wcsicmp(szName
, This
->funcs
[i
].prop
->name
)) continue;
1636 if (!(flags
& INVOKE_FUNC
)) return TYPE_E_TYPEMISMATCH
;
1638 hr
= ITypeInfo_GetFuncDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpfuncdesc
);
1639 if (FAILED(hr
)) return hr
;
1641 *pDescKind
= DESCKIND_FUNCDESC
;
1642 *ppTInfo
= &This
->ITypeInfo_iface
;
1643 ITypeInfo_AddRef(*ppTInfo
);
1647 for (i
= 0; i
< This
->num_vars
; i
++)
1649 if (wcsicmp(szName
, This
->vars
[i
]->name
)) continue;
1650 if (!(flags
& INVOKE_PROPERTYGET
)) return TYPE_E_TYPEMISMATCH
;
1652 hr
= ITypeInfo_GetVarDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpvardesc
);
1653 if (FAILED(hr
)) return hr
;
1655 *pDescKind
= DESCKIND_VARDESC
;
1656 *ppTInfo
= &This
->ITypeInfo_iface
;
1657 ITypeInfo_AddRef(*ppTInfo
);
1661 /* Look into the inherited IDispatch */
1662 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1663 if (FAILED(hr
)) return hr
;
1665 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1666 if (FAILED(hr
)) return hr
;
1668 hr
= ITypeComp_Bind(disp_typecomp
, szName
, lHashVal
, wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1669 ITypeComp_Release(disp_typecomp
);
1673 static HRESULT WINAPI
ScriptTypeComp_BindType(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
,
1674 ITypeInfo
**ppTInfo
, ITypeComp
**ppTComp
)
1676 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1677 ITypeInfo
*disp_typeinfo
;
1678 ITypeComp
*disp_typecomp
;
1681 TRACE("(%p)->(%s %08lx %p %p)\n", This
, debugstr_w(szName
), lHashVal
, ppTInfo
, ppTComp
);
1683 if (!szName
|| !ppTInfo
|| !ppTComp
)
1684 return E_INVALIDARG
;
1686 /* Look into the inherited IDispatch */
1687 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1688 if (FAILED(hr
)) return hr
;
1690 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1691 if (FAILED(hr
)) return hr
;
1693 hr
= ITypeComp_BindType(disp_typecomp
, szName
, lHashVal
, ppTInfo
, ppTComp
);
1694 ITypeComp_Release(disp_typecomp
);
1698 static const ITypeCompVtbl ScriptTypeCompVtbl
= {
1699 ScriptTypeComp_QueryInterface
,
1700 ScriptTypeComp_AddRef
,
1701 ScriptTypeComp_Release
,
1702 ScriptTypeComp_Bind
,
1703 ScriptTypeComp_BindType
1706 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
1708 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
1711 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
1713 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1715 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1716 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1717 *ppv
= &This
->IDispatchEx_iface
;
1718 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
1719 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
1720 *ppv
= &This
->IDispatchEx_iface
;
1721 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
1722 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
1723 *ppv
= &This
->IDispatchEx_iface
;
1725 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1727 return E_NOINTERFACE
;
1730 jsdisp_addref(This
);
1734 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
1736 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1737 jsdisp_addref(This
);
1741 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
1743 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1744 ULONG ref
= --This
->ref
;
1745 TRACE("(%p) ref=%ld\n", This
, ref
);
1751 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
1753 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1755 TRACE("(%p)->(%p)\n", This
, pctinfo
);
1761 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
1762 ITypeInfo
**ppTInfo
)
1764 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1765 dispex_prop_t
*prop
, *cur
, *end
, **typevar
;
1766 UINT num_funcs
= 0, num_vars
= 0;
1767 struct typeinfo_func
*typefunc
;
1768 function_code_t
*func_code
;
1769 ScriptTypeInfo
*typeinfo
;
1772 TRACE("(%p)->(%u %lu %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
1774 if (iTInfo
!= 0) return DISP_E_BADINDEX
;
1776 for (prop
= This
->props
, end
= prop
+ This
->prop_cnt
; prop
!= end
; prop
++)
1778 if (prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1781 /* If two identifiers differ only by case, the TypeInfo fails */
1782 pos
= This
->props
[get_props_idx(This
, prop
->hash
)].bucket_head
;
1785 cur
= This
->props
+ pos
;
1787 if (prop
->hash
== cur
->hash
&& prop
!= cur
&&
1788 cur
->type
== PROP_JSVAL
&& (cur
->flags
& PROPF_ENUMERABLE
) &&
1789 !wcsicmp(prop
->name
, cur
->name
))
1791 return TYPE_E_AMBIGUOUSNAME
;
1793 pos
= cur
->bucket_next
;
1796 if (is_function_prop(prop
))
1798 if (Function_get_code(as_jsdisp(get_object(prop
->u
.val
))))
1804 if (!(typeinfo
= malloc(sizeof(*typeinfo
))))
1805 return E_OUTOFMEMORY
;
1807 typeinfo
->ITypeInfo_iface
.lpVtbl
= &ScriptTypeInfoVtbl
;
1808 typeinfo
->ITypeComp_iface
.lpVtbl
= &ScriptTypeCompVtbl
;
1810 typeinfo
->num_vars
= num_vars
;
1811 typeinfo
->num_funcs
= num_funcs
;
1812 typeinfo
->jsdisp
= This
;
1814 typeinfo
->funcs
= malloc(sizeof(*typeinfo
->funcs
) * num_funcs
);
1815 if (!typeinfo
->funcs
)
1818 return E_OUTOFMEMORY
;
1821 typeinfo
->vars
= malloc(sizeof(*typeinfo
->vars
) * num_vars
);
1822 if (!typeinfo
->vars
)
1824 free(typeinfo
->funcs
);
1826 return E_OUTOFMEMORY
;
1829 typefunc
= typeinfo
->funcs
;
1830 typevar
= typeinfo
->vars
;
1831 for (prop
= This
->props
; prop
!= end
; prop
++)
1833 if (prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1836 if (is_function_prop(prop
))
1838 func_code
= Function_get_code(as_jsdisp(get_object(prop
->u
.val
)));
1839 if (!func_code
) continue;
1841 typefunc
->prop
= prop
;
1842 typefunc
->code
= func_code
;
1845 /* The function may be deleted, so keep a ref */
1846 bytecode_addref(func_code
->bytecode
);
1852 /* Keep a ref to the props and their names */
1853 IDispatchEx_AddRef(&This
->IDispatchEx_iface
);
1855 *ppTInfo
= &typeinfo
->ITypeInfo_iface
;
1859 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
1860 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
1863 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1867 TRACE("(%p)->(%s %p %u %lu %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
1873 hres
= jsdisp_get_id(This
, rgszNames
[0], 0, rgDispId
);
1877 /* DISPIDs for parameters don't seem to be supported */
1879 for(i
= 1; i
< cNames
; i
++)
1880 rgDispId
[i
] = DISPID_UNKNOWN
;
1881 hres
= DISP_E_UNKNOWNNAME
;
1887 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
1888 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1889 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1891 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1893 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
1894 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1896 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
1897 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
1900 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
1902 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1904 TRACE("(%p)->(%s %lx %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
1906 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameCaseInsensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
1907 FIXME("Unsupported grfdex %lx\n", grfdex
);
1911 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
1914 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
1915 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
1917 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1918 IServiceProvider
*prev_caller
;
1919 dispex_prop_t
*prop
;
1923 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
1926 V_VT(pvarRes
) = VT_EMPTY
;
1928 prop
= get_prop(This
, id
);
1929 if(!prop
&& id
!= DISPID_VALUE
) {
1930 TRACE("invalid id\n");
1931 return DISP_E_MEMBERNOTFOUND
;
1934 enter_script(This
->ctx
, &ei
);
1936 prev_caller
= This
->ctx
->jscaller
->caller
;
1937 This
->ctx
->jscaller
->caller
= pspCaller
;
1939 IServiceProvider_AddRef(pspCaller
);
1942 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
1943 wFlags
= DISPATCH_METHOD
;
1945 case DISPATCH_METHOD
:
1946 case DISPATCH_CONSTRUCT
: {
1947 jsval_t
*argv
, buf
[6], r
;
1948 IDispatch
*passed_this
;
1951 hres
= convert_params(This
->ctx
, pdp
, buf
, &argc
, &argv
);
1955 passed_this
= get_this(pdp
);
1957 hres
= invoke_prop_func(This
, passed_this
, prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
1959 hres
= jsdisp_call_value(This
, passed_this
? jsval_disp(passed_this
) : jsval_undefined(), wFlags
, argc
, argv
, pvarRes
? &r
: NULL
);
1962 jsval_release(argv
[argc
]);
1965 if(SUCCEEDED(hres
) && pvarRes
) {
1966 hres
= jsval_to_variant(r
, pvarRes
);
1971 case DISPATCH_PROPERTYGET
: {
1975 hres
= prop_get(This
, to_disp(This
), prop
, &r
);
1977 hres
= to_primitive(This
->ctx
, jsval_obj(This
), &r
, NO_HINT
);
1978 if(hres
== JS_E_TO_PRIMITIVE
)
1979 hres
= DISP_E_MEMBERNOTFOUND
;
1982 if(SUCCEEDED(hres
)) {
1983 hres
= jsval_to_variant(r
, pvarRes
);
1988 case DISPATCH_PROPERTYPUTREF
| DISPATCH_PROPERTYPUT
:
1989 case DISPATCH_PROPERTYPUTREF
:
1990 case DISPATCH_PROPERTYPUT
: {
1995 hres
= DISP_E_MEMBERNOTFOUND
;
1999 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
2000 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
2004 if(i
== pdp
->cNamedArgs
) {
2005 TRACE("no value to set\n");
2006 hres
= DISP_E_PARAMNOTOPTIONAL
;
2010 hres
= variant_to_jsval(This
->ctx
, pdp
->rgvarg
+i
, &val
);
2014 hres
= prop_put(This
, prop
, val
);
2019 FIXME("Unimplemented flags %x\n", wFlags
);
2020 hres
= E_INVALIDARG
;
2024 This
->ctx
->jscaller
->caller
= prev_caller
;
2026 IServiceProvider_Release(pspCaller
);
2027 return leave_script(This
->ctx
, hres
);
2030 static HRESULT
delete_prop(dispex_prop_t
*prop
, BOOL
*ret
)
2032 if(prop
->type
== PROP_PROTREF
) {
2037 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2044 if(prop
->type
== PROP_JSVAL
)
2045 jsval_release(prop
->u
.val
);
2046 if(prop
->type
== PROP_ACCESSOR
) {
2047 if(prop
->u
.accessor
.getter
)
2048 jsdisp_release(prop
->u
.accessor
.getter
);
2049 if(prop
->u
.accessor
.setter
)
2050 jsdisp_release(prop
->u
.accessor
.setter
);
2052 prop
->type
= PROP_DELETED
;
2056 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
2058 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2059 dispex_prop_t
*prop
;
2063 TRACE("(%p)->(%s %lx)\n", This
, debugstr_w(bstrName
), grfdex
);
2065 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameCaseInsensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
2066 FIXME("Unsupported grfdex %lx\n", grfdex
);
2068 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, grfdex
& fdexNameCaseInsensitive
, &prop
);
2072 TRACE("not found\n");
2076 return delete_prop(prop
, &b
);
2079 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
2081 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2082 dispex_prop_t
*prop
;
2085 TRACE("(%p)->(%lx)\n", This
, id
);
2087 prop
= get_prop(This
, id
);
2089 WARN("invalid id\n");
2090 return DISP_E_MEMBERNOTFOUND
;
2093 return delete_prop(prop
, &b
);
2096 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
2098 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2099 FIXME("(%p)->(%lx %lx %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
2103 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
2105 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2106 dispex_prop_t
*prop
;
2108 TRACE("(%p)->(%lx %p)\n", This
, id
, pbstrName
);
2110 prop
= get_prop(This
, id
);
2112 return DISP_E_MEMBERNOTFOUND
;
2114 *pbstrName
= SysAllocString(prop
->name
);
2116 return E_OUTOFMEMORY
;
2121 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
2123 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2124 HRESULT hres
= S_FALSE
;
2126 TRACE("(%p)->(%lx %lx %p)\n", This
, grfdex
, id
, pid
);
2128 if(id
!= DISPID_VALUE
)
2129 hres
= jsdisp_next_prop(This
, id
, JSDISP_ENUM_ALL
, pid
);
2131 *pid
= DISPID_STARTENUM
;
2135 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
2137 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2138 FIXME("(%p)->(%p)\n", This
, ppunk
);
2142 static IDispatchExVtbl DispatchExVtbl
= {
2143 DispatchEx_QueryInterface
,
2146 DispatchEx_GetTypeInfoCount
,
2147 DispatchEx_GetTypeInfo
,
2148 DispatchEx_GetIDsOfNames
,
2150 DispatchEx_GetDispID
,
2151 DispatchEx_InvokeEx
,
2152 DispatchEx_DeleteMemberByName
,
2153 DispatchEx_DeleteMemberByDispID
,
2154 DispatchEx_GetMemberProperties
,
2155 DispatchEx_GetMemberName
,
2156 DispatchEx_GetNextDispID
,
2157 DispatchEx_GetNameSpaceParent
2160 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
2162 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
2163 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
2166 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
2168 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
2171 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
2175 /* FIXME: Use better heuristics to decide when to run the GC */
2176 if(GetTickCount() - ctx
->thread_data
->gc_last_tick
> 30000)
2179 TRACE("%p (%p)\n", dispex
, prototype
);
2181 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
2183 dispex
->builtin_info
= builtin_info
;
2184 dispex
->extensible
= TRUE
;
2185 dispex
->prop_cnt
= 0;
2187 dispex
->props
= calloc(1, sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
2189 return E_OUTOFMEMORY
;
2191 for(i
= 0; i
< dispex
->buf_size
; i
++) {
2192 dispex
->props
[i
].bucket_head
= ~0;
2193 dispex
->props
[i
].bucket_next
= ~0;
2196 dispex
->prototype
= prototype
;
2198 jsdisp_addref(prototype
);
2203 list_add_tail(&ctx
->thread_data
->objects
, &dispex
->entry
);
2207 static const builtin_info_t dispex_info
= {
2215 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
2220 ret
= calloc(1, sizeof(jsdisp_t
));
2222 return E_OUTOFMEMORY
;
2224 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
2234 void jsdisp_free(jsdisp_t
*obj
)
2236 dispex_prop_t
*prop
;
2238 list_remove(&obj
->entry
);
2240 TRACE("(%p)\n", obj
);
2242 if(obj
->has_weak_refs
) {
2243 struct list
*list
= &RB_ENTRY_VALUE(rb_get(&obj
->ctx
->thread_data
->weak_refs
, obj
), struct weak_refs_entry
, entry
)->list
;
2245 remove_weakmap_entry(LIST_ENTRY(list
->next
, struct weakmap_entry
, weak_refs_entry
));
2246 } while(obj
->has_weak_refs
);
2249 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
2250 switch(prop
->type
) {
2252 jsval_release(prop
->u
.val
);
2255 if(prop
->u
.accessor
.getter
)
2256 jsdisp_release(prop
->u
.accessor
.getter
);
2257 if(prop
->u
.accessor
.setter
)
2258 jsdisp_release(prop
->u
.accessor
.setter
);
2266 script_release(obj
->ctx
);
2268 jsdisp_release(obj
->prototype
);
2270 if(obj
->builtin_info
->destructor
)
2271 obj
->builtin_info
->destructor(obj
);
2278 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
2280 ULONG ref
= ++jsdisp
->ref
;
2281 TRACE("(%p) ref=%ld\n", jsdisp
, ref
);
2285 void jsdisp_release(jsdisp_t
*jsdisp
)
2287 ULONG ref
= --jsdisp
->ref
;
2289 TRACE("(%p) ref=%ld\n", jsdisp
, ref
);
2292 jsdisp_free(jsdisp
);
2297 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
2299 jsdisp_t
*prot
= NULL
;
2300 dispex_prop_t
*prop
;
2303 hres
= find_prop_name_prot(constr
, string_hash(L
"prototype"), L
"prototype", FALSE
, &prop
);
2304 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
2307 hres
= prop_get(constr
, to_disp(constr
), prop
, &val
);
2309 ERR("Could not get prototype\n");
2313 if(is_object_instance(val
))
2314 prot
= iface_to_jsdisp(get_object(val
));
2316 prot
= jsdisp_addref(ctx
->object_prototype
);
2321 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
2324 jsdisp_release(prot
);
2328 jsdisp_t
*iface_to_jsdisp(IDispatch
*iface
)
2330 return iface
->lpVtbl
== (const IDispatchVtbl
*)&DispatchExVtbl
2331 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx
*)iface
))
2335 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
2337 dispex_prop_t
*prop
;
2340 if(jsdisp
->extensible
&& (flags
& fdexNameEnsure
))
2341 hres
= ensure_prop_name(jsdisp
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
,
2342 flags
& fdexNameCaseInsensitive
, &prop
);
2344 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, flags
& fdexNameCaseInsensitive
, &prop
);
2348 if(prop
&& prop
->type
!=PROP_DELETED
) {
2349 *id
= prop_to_id(jsdisp
, prop
);
2353 TRACE("not found %s\n", debugstr_w(name
));
2354 *id
= DISPID_UNKNOWN
;
2355 return DISP_E_UNKNOWNNAME
;
2358 HRESULT
jsdisp_get_idx_id(jsdisp_t
*jsdisp
, DWORD idx
, DISPID
*id
)
2362 swprintf(name
, ARRAY_SIZE(name
), L
"%u", idx
);
2363 return jsdisp_get_id(jsdisp
, name
, 0, id
);
2366 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
2370 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2372 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
2373 hres
= Function_invoke(jsfunc
, vthis
, flags
, argc
, argv
, r
);
2375 if(!jsfunc
->builtin_info
->call
) {
2376 WARN("Not a function\n");
2377 return JS_E_FUNCTION_EXPECTED
;
2380 if(jsfunc
->ctx
->state
== SCRIPTSTATE_UNINITIALIZED
|| jsfunc
->ctx
->state
== SCRIPTSTATE_CLOSED
)
2381 return E_UNEXPECTED
;
2383 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2384 hres
= jsfunc
->builtin_info
->call(jsfunc
->ctx
, vthis
, flags
, argc
, argv
, r
);
2389 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
2391 dispex_prop_t
*prop
;
2393 prop
= get_prop(disp
, id
);
2395 return DISP_E_MEMBERNOTFOUND
;
2397 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, &disp
->ctx
->jscaller
->IServiceProvider_iface
);
2400 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
2402 dispex_prop_t
*prop
;
2405 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, FALSE
, &prop
);
2409 if(!prop
|| prop
->type
== PROP_DELETED
)
2410 return JS_E_INVALID_PROPERTY
;
2412 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, &disp
->ctx
->jscaller
->IServiceProvider_iface
);
2415 static HRESULT
disp_invoke(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*params
, VARIANT
*r
,
2416 IServiceProvider
*caller
)
2418 IDispatchEx
*dispex
;
2422 memset(&ei
, 0, sizeof(ei
));
2423 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2424 if(SUCCEEDED(hres
)) {
2425 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, params
, r
, &ei
, caller
);
2426 IDispatchEx_Release(dispex
);
2430 if(flags
== DISPATCH_CONSTRUCT
) {
2431 WARN("IDispatch cannot be constructor\n");
2432 return DISP_E_MEMBERNOTFOUND
;
2435 if(params
->cNamedArgs
== 1 && params
->rgdispidNamedArgs
[0] == DISPID_THIS
) {
2436 params
->cNamedArgs
= 0;
2437 params
->rgdispidNamedArgs
= NULL
;
2442 TRACE("using IDispatch\n");
2443 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, params
, r
, &ei
, &err
);
2446 if(hres
== DISP_E_EXCEPTION
) {
2447 TRACE("DISP_E_EXCEPTION: %08lx %s %s\n", ei
.scode
, debugstr_w(ei
.bstrSource
), debugstr_w(ei
.bstrDescription
));
2449 ctx
->ei
->error
= (SUCCEEDED(ei
.scode
) || ei
.scode
== DISP_E_EXCEPTION
) ? E_FAIL
: ei
.scode
;
2451 ctx
->ei
->source
= jsstr_alloc_len(ei
.bstrSource
, SysStringLen(ei
.bstrSource
));
2452 if(ei
.bstrDescription
)
2453 ctx
->ei
->message
= jsstr_alloc_len(ei
.bstrDescription
, SysStringLen(ei
.bstrDescription
));
2454 SysFreeString(ei
.bstrSource
);
2455 SysFreeString(ei
.bstrDescription
);
2456 SysFreeString(ei
.bstrHelpFile
);
2462 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2464 VARIANT buf
[6], retv
;
2470 jsdisp
= iface_to_jsdisp(disp
);
2471 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2472 if(flags
& DISPATCH_PROPERTYPUT
) {
2473 FIXME("disp_call(propput) on builtin object\n");
2474 jsdisp_release(jsdisp
);
2478 if(ctx
!= jsdisp
->ctx
)
2479 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2480 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
2481 jsdisp_release(jsdisp
);
2485 jsdisp_release(jsdisp
);
2487 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2489 flags
|= DISPATCH_PROPERTYGET
;
2493 if(flags
& DISPATCH_PROPERTYPUT
) {
2494 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
2497 dp
.rgdispidNamedArgs
= &propput_dispid
;
2500 dp
.rgdispidNamedArgs
= NULL
;
2503 if(dp
.cArgs
> ARRAY_SIZE(buf
)) {
2504 dp
.rgvarg
= malloc(argc
* sizeof(VARIANT
));
2506 return E_OUTOFMEMORY
;
2511 for(i
=0; i
<argc
; i
++) {
2512 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
2515 VariantClear(dp
.rgvarg
+argc
-i
-1);
2516 if(dp
.rgvarg
!= buf
)
2522 V_VT(&retv
) = VT_EMPTY
;
2523 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, ret
? &retv
: NULL
, &ctx
->jscaller
->IServiceProvider_iface
);
2525 for(i
=0; i
<argc
; i
++)
2526 VariantClear(dp
.rgvarg
+argc
-i
-1);
2527 if(dp
.rgvarg
!= buf
)
2530 if(SUCCEEDED(hres
) && ret
)
2531 hres
= variant_to_jsval(ctx
, &retv
, ret
);
2532 VariantClear(&retv
);
2536 HRESULT
disp_call_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2538 IDispatchEx
*dispex
;
2544 if((jsdisp
= to_jsdisp(disp
)) && jsdisp
->ctx
== ctx
)
2545 return jsdisp_call_name(jsdisp
, name
, flags
, argc
, argv
, ret
);
2547 if(!(bstr
= SysAllocString(name
)))
2548 return E_OUTOFMEMORY
;
2549 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2550 if(SUCCEEDED(hres
) && dispex
) {
2551 hres
= IDispatchEx_GetDispID(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
), &id
);
2552 IDispatchEx_Release(dispex
);
2554 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2556 SysFreeString(bstr
);
2560 return disp_call(ctx
, disp
, id
, flags
, argc
, argv
, ret
);
2563 HRESULT
disp_call_value_with_caller(script_ctx_t
*ctx
, IDispatch
*disp
, jsval_t vthis
, WORD flags
, unsigned argc
,
2564 jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
2566 VARIANT buf
[6], retv
, *args
= buf
;
2571 HRESULT hres
= S_OK
;
2573 static DISPID this_id
= DISPID_THIS
;
2575 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2577 jsdisp
= iface_to_jsdisp(disp
);
2578 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2579 hres
= jsdisp_call_value(jsdisp
, vthis
, flags
, argc
, argv
, r
);
2580 jsdisp_release(jsdisp
);
2584 jsdisp_release(jsdisp
);
2586 if(is_object_instance(vthis
) && (ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
||
2587 ((jsdisp
= to_jsdisp(get_object(vthis
))) && is_class(jsdisp
, JSCLASS_OBJECT
))))
2588 jsthis
= get_object(vthis
);
2592 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2593 if(r
&& argc
&& flags
== DISPATCH_METHOD
)
2594 flags
|= DISPATCH_PROPERTYGET
;
2597 dp
.cArgs
= argc
+ 1;
2599 dp
.rgdispidNamedArgs
= &this_id
;
2603 dp
.rgdispidNamedArgs
= NULL
;
2606 if(dp
.cArgs
> ARRAY_SIZE(buf
) && !(args
= malloc(dp
.cArgs
* sizeof(VARIANT
))))
2607 return E_OUTOFMEMORY
;
2611 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
2612 V_DISPATCH(dp
.rgvarg
) = jsthis
;
2615 for(i
=0; SUCCEEDED(hres
) && i
< argc
; i
++)
2616 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
2618 if(SUCCEEDED(hres
)) {
2619 V_VT(&retv
) = VT_EMPTY
;
2620 hres
= disp_invoke(ctx
, disp
, DISPID_VALUE
, flags
, &dp
, r
? &retv
: NULL
, caller
);
2623 for(i
= 0; i
< argc
; i
++)
2624 VariantClear(dp
.rgvarg
+ dp
.cArgs
- i
- 1);
2633 hres
= variant_to_jsval(ctx
, &retv
, r
);
2634 VariantClear(&retv
);
2638 HRESULT
jsdisp_propput(jsdisp_t
*obj
, const WCHAR
*name
, DWORD flags
, BOOL
throw, jsval_t val
)
2640 dispex_prop_t
*prop
;
2644 hres
= ensure_prop_name(obj
, name
, flags
, FALSE
, &prop
);
2646 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
2649 if(!prop
|| (prop
->type
== PROP_DELETED
&& !obj
->extensible
))
2650 return throw ? JS_E_INVALID_ACTION
: S_OK
;
2652 return prop_put(obj
, prop
, val
);
2655 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
2657 return jsdisp_propput(obj
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, FALSE
, val
);
2660 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
2664 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2665 return jsdisp_propput(obj
, buf
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, TRUE
, val
);
2668 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
2673 jsdisp
= iface_to_jsdisp(disp
);
2674 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2675 dispex_prop_t
*prop
;
2677 prop
= get_prop(jsdisp
, id
);
2679 hres
= prop_put(jsdisp
, prop
, val
);
2681 hres
= DISP_E_MEMBERNOTFOUND
;
2683 jsdisp_release(jsdisp
);
2685 DISPID dispid
= DISPID_PROPERTYPUT
;
2686 DWORD flags
= DISPATCH_PROPERTYPUT
;
2688 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
2691 jsdisp_release(jsdisp
);
2692 hres
= jsval_to_variant(val
, &var
);
2696 if(V_VT(&var
) == VT_DISPATCH
)
2697 flags
|= DISPATCH_PROPERTYPUTREF
;
2699 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, NULL
, &ctx
->jscaller
->IServiceProvider_iface
);
2706 HRESULT
disp_propput_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, jsval_t val
)
2711 jsdisp
= iface_to_jsdisp(disp
);
2712 if(!jsdisp
|| jsdisp
->ctx
!= ctx
) {
2713 IDispatchEx
*dispex
;
2718 jsdisp_release(jsdisp
);
2719 if(!(str
= SysAllocString(name
)))
2720 return E_OUTOFMEMORY
;
2722 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2723 if(SUCCEEDED(hres
)) {
2724 hres
= IDispatchEx_GetDispID(dispex
, str
, make_grfdex(ctx
, fdexNameEnsure
|fdexNameCaseSensitive
), &id
);
2725 IDispatchEx_Release(dispex
);
2727 TRACE("using IDispatch\n");
2728 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &str
, 1, 0, &id
);
2734 return disp_propput(ctx
, disp
, id
, val
);
2737 hres
= jsdisp_propput_name(jsdisp
, name
, val
);
2738 jsdisp_release(jsdisp
);
2742 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
2744 dispex_prop_t
*prop
;
2747 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, FALSE
, &prop
);
2751 if(!prop
|| prop
->type
==PROP_DELETED
) {
2752 *val
= jsval_undefined();
2756 return prop_get(obj
, to_disp(obj
), prop
, val
);
2759 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
2762 dispex_prop_t
*prop
;
2765 swprintf(name
, ARRAY_SIZE(name
), L
"%d", idx
);
2767 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, FALSE
, &prop
);
2771 if(!prop
|| prop
->type
==PROP_DELETED
) {
2772 *r
= jsval_undefined();
2773 return DISP_E_UNKNOWNNAME
;
2776 return prop_get(obj
, to_disp(obj
), prop
, r
);
2779 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
2781 dispex_prop_t
*prop
;
2783 prop
= get_prop(jsdisp
, id
);
2785 return DISP_E_MEMBERNOTFOUND
;
2787 return prop_get(jsdisp
, to_disp(jsdisp
), prop
, val
);
2790 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
2792 DISPPARAMS dp
= {NULL
,NULL
,0,0};
2797 jsdisp
= iface_to_jsdisp(disp
);
2798 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2799 hres
= jsdisp_propget(jsdisp
, id
, val
);
2800 jsdisp_release(jsdisp
);
2804 jsdisp_release(jsdisp
);
2806 V_VT(&var
) = VT_EMPTY
;
2807 hres
= disp_invoke(ctx
, disp
, id
, INVOKE_PROPERTYGET
, &dp
, &var
, &ctx
->jscaller
->IServiceProvider_iface
);
2808 if(SUCCEEDED(hres
)) {
2809 hres
= variant_to_jsval(ctx
, &var
, val
);
2815 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
2818 dispex_prop_t
*prop
;
2822 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2824 hres
= find_prop_name(obj
, string_hash(buf
), buf
, FALSE
, &prop
);
2825 if(FAILED(hres
) || !prop
)
2828 hres
= delete_prop(prop
, &b
);
2831 return b
? S_OK
: JS_E_INVALID_ACTION
;
2834 HRESULT
disp_delete(IDispatch
*disp
, DISPID id
, BOOL
*ret
)
2836 IDispatchEx
*dispex
;
2840 jsdisp
= iface_to_jsdisp(disp
);
2842 dispex_prop_t
*prop
;
2844 prop
= get_prop(jsdisp
, id
);
2846 hres
= delete_prop(prop
, ret
);
2848 hres
= DISP_E_MEMBERNOTFOUND
;
2850 jsdisp_release(jsdisp
);
2854 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2860 hres
= IDispatchEx_DeleteMemberByDispID(dispex
, id
);
2861 IDispatchEx_Release(dispex
);
2865 *ret
= hres
== S_OK
;
2869 HRESULT
jsdisp_next_prop(jsdisp_t
*obj
, DISPID id
, enum jsdisp_enum_type enum_type
, DISPID
*ret
)
2871 dispex_prop_t
*iter
;
2875 if(id
== DISPID_STARTENUM
|| idx
>= obj
->prop_cnt
) {
2876 hres
= (enum_type
== JSDISP_ENUM_ALL
) ? fill_protrefs(obj
) : fill_props(obj
);
2879 if(id
== DISPID_STARTENUM
)
2881 if(idx
>= obj
->prop_cnt
)
2885 for(iter
= &obj
->props
[idx
]; iter
< obj
->props
+ obj
->prop_cnt
; iter
++) {
2886 if(iter
->type
== PROP_DELETED
)
2888 if(enum_type
!= JSDISP_ENUM_ALL
&& iter
->type
== PROP_PROTREF
)
2890 if(enum_type
!= JSDISP_ENUM_OWN
&& !(get_flags(obj
, iter
) & PROPF_ENUMERABLE
))
2892 *ret
= prop_to_id(obj
, iter
);
2896 if(obj
->ctx
->html_mode
)
2897 return jsdisp_next_prop(obj
, prop_to_id(obj
, iter
- 1), enum_type
, ret
);
2902 HRESULT
disp_delete_name(script_ctx_t
*ctx
, IDispatch
*disp
, jsstr_t
*name
, BOOL
*ret
)
2904 IDispatchEx
*dispex
;
2909 jsdisp
= iface_to_jsdisp(disp
);
2911 dispex_prop_t
*prop
;
2914 ptr
= jsstr_flatten(name
);
2916 jsdisp_release(jsdisp
);
2917 return E_OUTOFMEMORY
;
2920 hres
= find_prop_name(jsdisp
, string_hash(ptr
), ptr
, FALSE
, &prop
);
2922 hres
= delete_prop(prop
, ret
);
2928 jsdisp_release(jsdisp
);
2932 bstr
= SysAllocStringLen(NULL
, jsstr_length(name
));
2934 return E_OUTOFMEMORY
;
2935 jsstr_flush(name
, bstr
);
2937 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2938 if(SUCCEEDED(hres
)) {
2939 hres
= IDispatchEx_DeleteMemberByName(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
));
2941 *ret
= hres
== S_OK
;
2942 IDispatchEx_Release(dispex
);
2946 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2947 if(SUCCEEDED(hres
)) {
2948 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2950 }else if(hres
== DISP_E_UNKNOWNNAME
) {
2951 /* Property doesn't exist, so nothing to delete */
2957 SysFreeString(bstr
);
2961 HRESULT
jsdisp_get_own_property(jsdisp_t
*obj
, const WCHAR
*name
, BOOL flags_only
,
2962 property_desc_t
*desc
)
2964 dispex_prop_t
*prop
;
2967 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
2972 return DISP_E_UNKNOWNNAME
;
2974 memset(desc
, 0, sizeof(*desc
));
2976 switch(prop
->type
) {
2980 desc
->mask
|= PROPF_WRITABLE
;
2981 desc
->explicit_value
= TRUE
;
2983 hres
= prop_get(obj
, to_disp(obj
), prop
, &desc
->value
);
2989 desc
->explicit_getter
= desc
->explicit_setter
= TRUE
;
2991 desc
->getter
= prop
->u
.accessor
.getter
2992 ? jsdisp_addref(prop
->u
.accessor
.getter
) : NULL
;
2993 desc
->setter
= prop
->u
.accessor
.setter
2994 ? jsdisp_addref(prop
->u
.accessor
.setter
) : NULL
;
2998 return DISP_E_UNKNOWNNAME
;
3001 desc
->flags
= prop
->flags
& (PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
3002 desc
->mask
|= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
;
3006 HRESULT
jsdisp_define_property(jsdisp_t
*obj
, const WCHAR
*name
, property_desc_t
*desc
)
3008 dispex_prop_t
*prop
;
3011 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
3015 if((!prop
|| prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) && !obj
->extensible
)
3016 return throw_error(obj
->ctx
, JS_E_OBJECT_NONEXTENSIBLE
, name
);
3018 if(!prop
&& !(prop
= alloc_prop(obj
, name
, PROP_DELETED
, 0)))
3019 return E_OUTOFMEMORY
;
3021 if(prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) {
3022 prop
->flags
= desc
->flags
;
3023 if(desc
->explicit_getter
|| desc
->explicit_setter
) {
3024 prop
->type
= PROP_ACCESSOR
;
3025 prop
->u
.accessor
.getter
= desc
->getter
? jsdisp_addref(desc
->getter
) : NULL
;
3026 prop
->u
.accessor
.setter
= desc
->setter
? jsdisp_addref(desc
->setter
) : NULL
;
3027 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name
),
3028 prop
->u
.accessor
.getter
, prop
->u
.accessor
.setter
);
3030 prop
->type
= PROP_JSVAL
;
3031 if(desc
->explicit_value
) {
3032 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
3036 prop
->u
.val
= jsval_undefined();
3038 TRACE("%s = %s\n", debugstr_w(name
), debugstr_jsval(prop
->u
.val
));
3043 TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(name
),
3044 prop
->flags
, desc
->flags
, desc
->mask
);
3046 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
3047 if(((desc
->mask
& PROPF_CONFIGURABLE
) && (desc
->flags
& PROPF_CONFIGURABLE
))
3048 || ((desc
->mask
& PROPF_ENUMERABLE
)
3049 && ((desc
->flags
& PROPF_ENUMERABLE
) != (prop
->flags
& PROPF_ENUMERABLE
))))
3050 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3053 if(desc
->explicit_value
|| (desc
->mask
& PROPF_WRITABLE
)) {
3054 if(prop
->type
== PROP_ACCESSOR
) {
3055 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
3056 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3057 if(prop
->u
.accessor
.getter
)
3058 jsdisp_release(prop
->u
.accessor
.getter
);
3059 if(prop
->u
.accessor
.setter
)
3060 jsdisp_release(prop
->u
.accessor
.setter
);
3062 prop
->type
= PROP_JSVAL
;
3063 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
3065 prop
->u
.val
= jsval_undefined();
3069 if(!(prop
->flags
& PROPF_CONFIGURABLE
) && !(prop
->flags
& PROPF_WRITABLE
)) {
3070 if((desc
->mask
& PROPF_WRITABLE
) && (desc
->flags
& PROPF_WRITABLE
))
3071 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
3072 if(desc
->explicit_value
) {
3073 if(prop
->type
== PROP_JSVAL
) {
3075 hres
= jsval_strict_equal(desc
->value
, prop
->u
.val
, &eq
);
3079 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
3081 FIXME("redefinition of property type %d\n", prop
->type
);
3085 if(desc
->explicit_value
) {
3086 if(prop
->type
== PROP_JSVAL
)
3087 jsval_release(prop
->u
.val
);
3089 prop
->type
= PROP_JSVAL
;
3090 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
3092 prop
->u
.val
= jsval_undefined();
3097 }else if(desc
->explicit_getter
|| desc
->explicit_setter
) {
3098 if(prop
->type
!= PROP_ACCESSOR
) {
3099 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
3100 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3101 if(prop
->type
== PROP_JSVAL
)
3102 jsval_release(prop
->u
.val
);
3103 prop
->type
= PROP_ACCESSOR
;
3104 prop
->u
.accessor
.getter
= prop
->u
.accessor
.setter
= NULL
;
3105 }else if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
3106 if((desc
->explicit_getter
&& desc
->getter
!= prop
->u
.accessor
.getter
)
3107 || (desc
->explicit_setter
&& desc
->setter
!= prop
->u
.accessor
.setter
))
3108 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3111 if(desc
->explicit_getter
) {
3112 if(prop
->u
.accessor
.getter
) {
3113 jsdisp_release(prop
->u
.accessor
.getter
);
3114 prop
->u
.accessor
.getter
= NULL
;
3117 prop
->u
.accessor
.getter
= jsdisp_addref(desc
->getter
);
3119 if(desc
->explicit_setter
) {
3120 if(prop
->u
.accessor
.setter
) {
3121 jsdisp_release(prop
->u
.accessor
.setter
);
3122 prop
->u
.accessor
.setter
= NULL
;
3125 prop
->u
.accessor
.setter
= jsdisp_addref(desc
->setter
);
3129 prop
->flags
= (prop
->flags
& ~desc
->mask
) | (desc
->flags
& desc
->mask
);
3133 HRESULT
jsdisp_define_data_property(jsdisp_t
*obj
, const WCHAR
*name
, unsigned flags
, jsval_t value
)
3135 property_desc_t prop_desc
= { flags
, flags
, TRUE
};
3136 prop_desc
.value
= value
;
3137 return jsdisp_define_property(obj
, name
, &prop_desc
);
3140 HRESULT
jsdisp_change_prototype(jsdisp_t
*obj
, jsdisp_t
*proto
)
3145 if(obj
->prototype
== proto
)
3147 if(!obj
->extensible
)
3148 return JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE
;
3150 for(iter
= proto
; iter
; iter
= iter
->prototype
)
3152 return JS_E_CYCLIC_PROTO_VALUE
;
3154 if(obj
->prototype
) {
3155 for(i
= 0; i
< obj
->prop_cnt
; i
++)
3156 if(obj
->props
[i
].type
== PROP_PROTREF
)
3157 obj
->props
[i
].type
= PROP_DELETED
;
3158 jsdisp_release(obj
->prototype
);
3161 obj
->prototype
= proto
;
3163 jsdisp_addref(proto
);
3167 void jsdisp_freeze(jsdisp_t
*obj
, BOOL seal
)
3171 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
3172 if(!seal
&& obj
->props
[i
].type
== PROP_JSVAL
)
3173 obj
->props
[i
].flags
&= ~PROPF_WRITABLE
;
3174 obj
->props
[i
].flags
&= ~PROPF_CONFIGURABLE
;
3177 obj
->extensible
= FALSE
;
3180 BOOL
jsdisp_is_frozen(jsdisp_t
*obj
, BOOL sealed
)
3187 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
3188 if(obj
->props
[i
].type
== PROP_JSVAL
) {
3189 if(!sealed
&& (obj
->props
[i
].flags
& PROPF_WRITABLE
))
3191 }else if(obj
->props
[i
].type
!= PROP_ACCESSOR
)
3193 if(obj
->props
[i
].flags
& PROPF_CONFIGURABLE
)
3200 HRESULT
jsdisp_get_prop_name(jsdisp_t
*obj
, DISPID id
, jsstr_t
**r
)
3202 dispex_prop_t
*prop
= get_prop(obj
, id
);
3205 return DISP_E_MEMBERNOTFOUND
;
3207 *r
= jsstr_alloc(prop
->name
);
3208 return *r
? S_OK
: E_OUTOFMEMORY
;