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
, 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
, This
, 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_obj(This
),
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
, 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_props(jsdisp_t
*jsdisp
)
670 dispex_prop_t
*prop
= jsdisp
->props
, *end
;
672 for(end
= prop
+ jsdisp
->prop_cnt
; prop
< end
; prop
++) {
678 jsval_release(prop
->u
.val
);
681 if(prop
->u
.accessor
.getter
)
682 jsdisp_release(prop
->u
.accessor
.getter
);
683 if(prop
->u
.accessor
.setter
)
684 jsdisp_release(prop
->u
.accessor
.setter
);
689 prop
->type
= PROP_DELETED
;
696 * To deal with circular refcounts, a basic Garbage Collector is used with a variant of the
697 * mark-and-sweep algorithm that doesn't require knowing or traversing any specific "roots".
698 * This works based on the assumption that circular references can only happen when objects
699 * end up pointing to each other, and each other alone, without any external refs.
701 * An "external ref" is a ref to the object that's not from any other object. Example of such
702 * refs can be local variables, the script ctx (which keeps a ref to the global object), etc.
704 * At a high level, there are 3 logical passes done on the entire list of objects:
706 * 1. Speculatively decrease refcounts of each linked-to-object from each object. This ensures
707 * that the only remaining refcount on each object is the number of "external refs" to it.
708 * At the same time, mark all of the objects so that they can be potentially collected.
710 * 2. For each object with a non-zero "external refcount", clear the mark from step 1, and
711 * recursively traverse all linked objects from it, clearing their marks as well (regardless
712 * of their refcount), stopping a given path when the object is unmarked (and then going back
713 * up the GC stack). This basically unmarks all of the objects with "external refcounts"
714 * and those accessible from them, and only the leaked dangling objects will still be marked.
716 * 3. For each object that is marked, unlink all of the objects linked from it, because they
717 * are dangling in a circular refcount and not accessible. This should release them.
719 * During unlinking (GC_TRAVERSE_UNLINK), it is important that we unlink *all* linked objects
720 * from the object, to be certain that releasing the object later will not delete any other
721 * objects. Otherwise calculating the "next" object in the list becomes impossible.
723 * This collection process has to be done periodically, but can be pretty expensive so there
724 * has to be a balance between reclaiming dangling objects and performance.
727 struct gc_stack_chunk
{
728 jsdisp_t
*objects
[1020];
729 struct gc_stack_chunk
*prev
;
733 struct gc_stack_chunk
*chunk
;
734 struct gc_stack_chunk
*next
;
738 static HRESULT
gc_stack_push(struct gc_ctx
*gc_ctx
, jsdisp_t
*obj
)
742 gc_ctx
->chunk
= gc_ctx
->next
;
744 struct gc_stack_chunk
*prev
, *tmp
= malloc(sizeof(*tmp
));
746 return E_OUTOFMEMORY
;
747 prev
= gc_ctx
->chunk
;
749 gc_ctx
->chunk
->prev
= prev
;
751 gc_ctx
->idx
= ARRAY_SIZE(gc_ctx
->chunk
->objects
);
754 gc_ctx
->chunk
->objects
[--gc_ctx
->idx
] = obj
;
758 static jsdisp_t
*gc_stack_pop(struct gc_ctx
*gc_ctx
)
760 jsdisp_t
*obj
= gc_ctx
->chunk
->objects
[gc_ctx
->idx
];
762 if(++gc_ctx
->idx
== ARRAY_SIZE(gc_ctx
->chunk
->objects
)) {
764 gc_ctx
->next
= gc_ctx
->chunk
;
765 gc_ctx
->chunk
= gc_ctx
->chunk
->prev
;
771 HRESULT
gc_run(script_ctx_t
*ctx
)
773 /* Save original refcounts in a linked list of chunks */
779 jsdisp_t
*obj
, *obj2
, *link
, *link2
;
780 dispex_prop_t
*prop
, *props_end
;
781 struct gc_ctx gc_ctx
= { 0 };
782 unsigned chunk_idx
= 0;
786 /* Prevent recursive calls from side-effects during unlinking (e.g. CollectGarbage from host object's Release) */
787 if(ctx
->gc_is_unlinking
)
790 if(!(head
= malloc(sizeof(*head
))))
791 return E_OUTOFMEMORY
;
795 /* 1. Save actual refcounts and decrease them speculatively as-if we unlinked the objects */
796 LIST_FOR_EACH_ENTRY(obj
, &ctx
->objects
, jsdisp_t
, entry
) {
797 if(chunk_idx
== ARRAY_SIZE(chunk
->ref
)) {
798 if(!(chunk
->next
= malloc(sizeof(*chunk
)))) {
804 return E_OUTOFMEMORY
;
806 chunk
= chunk
->next
; chunk_idx
= 0;
809 chunk
->ref
[chunk_idx
++] = obj
->ref
;
811 LIST_FOR_EACH_ENTRY(obj
, &ctx
->objects
, jsdisp_t
, entry
) {
812 for(prop
= obj
->props
, props_end
= prop
+ obj
->prop_cnt
; prop
< props_end
; prop
++) {
815 if(is_object_instance(prop
->u
.val
) && (link
= to_jsdisp(get_object(prop
->u
.val
))) && link
->ctx
== ctx
)
819 if(prop
->u
.accessor
.getter
&& prop
->u
.accessor
.getter
->ctx
== ctx
)
820 prop
->u
.accessor
.getter
->ref
--;
821 if(prop
->u
.accessor
.setter
&& prop
->u
.accessor
.setter
->ctx
== ctx
)
822 prop
->u
.accessor
.setter
->ref
--;
829 if(obj
->prototype
&& obj
->prototype
->ctx
== ctx
)
830 obj
->prototype
->ref
--;
831 if(obj
->builtin_info
->gc_traverse
)
832 obj
->builtin_info
->gc_traverse(&gc_ctx
, GC_TRAVERSE_SPECULATIVELY
, obj
);
833 obj
->gc_marked
= TRUE
;
836 /* 2. Clear mark on objects with non-zero "external refcount" and all objects accessible from them */
837 LIST_FOR_EACH_ENTRY(obj
, &ctx
->objects
, jsdisp_t
, entry
) {
838 if(!obj
->ref
|| !obj
->gc_marked
)
841 hres
= gc_stack_push(&gc_ctx
, NULL
);
848 obj2
->gc_marked
= FALSE
;
850 for(prop
= obj2
->props
, props_end
= prop
+ obj2
->prop_cnt
; prop
< props_end
; prop
++) {
853 if(!is_object_instance(prop
->u
.val
))
855 link
= to_jsdisp(get_object(prop
->u
.val
));
859 link
= prop
->u
.accessor
.getter
;
860 link2
= prop
->u
.accessor
.setter
;
865 if(link
&& link
->gc_marked
&& link
->ctx
== ctx
) {
866 hres
= gc_stack_push(&gc_ctx
, link
);
870 if(link2
&& link2
->gc_marked
&& link2
->ctx
== ctx
) {
871 hres
= gc_stack_push(&gc_ctx
, link2
);
880 if(obj2
->prototype
&& obj2
->prototype
->gc_marked
&& obj2
->prototype
->ctx
== ctx
) {
881 hres
= gc_stack_push(&gc_ctx
, obj2
->prototype
);
886 if(obj2
->builtin_info
->gc_traverse
) {
887 hres
= obj2
->builtin_info
->gc_traverse(&gc_ctx
, GC_TRAVERSE
, obj2
);
892 do obj2
= gc_stack_pop(&gc_ctx
); while(obj2
&& !obj2
->gc_marked
);
896 do obj2
= gc_stack_pop(&gc_ctx
); while(obj2
);
903 chunk
= head
; chunk_idx
= 0;
904 LIST_FOR_EACH_ENTRY(obj
, &ctx
->objects
, jsdisp_t
, entry
) {
905 obj
->ref
= chunk
->ref
[chunk_idx
++];
906 if(chunk_idx
== ARRAY_SIZE(chunk
->ref
)) {
907 struct chunk
*next
= chunk
->next
;
909 chunk
= next
; chunk_idx
= 0;
917 /* 3. Remove all the links from the marked objects, since they are dangling */
918 ctx
->gc_is_unlinking
= TRUE
;
920 iter
= list_head(&ctx
->objects
);
922 obj
= LIST_ENTRY(iter
, jsdisp_t
, entry
);
923 if(!obj
->gc_marked
) {
924 iter
= list_next(&ctx
->objects
, iter
);
928 /* Grab it since it gets removed when unlinked */
933 jsdisp_release(obj
->prototype
);
934 obj
->prototype
= NULL
;
937 if(obj
->builtin_info
->gc_traverse
)
938 obj
->builtin_info
->gc_traverse(&gc_ctx
, GC_TRAVERSE_UNLINK
, obj
);
940 /* Releasing unlinked object should not delete any other object,
941 so we can safely obtain the next pointer now */
942 iter
= list_next(&ctx
->objects
, iter
);
946 ctx
->gc_is_unlinking
= FALSE
;
947 ctx
->gc_last_tick
= GetTickCount();
951 HRESULT
gc_process_linked_obj(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, jsdisp_t
*obj
, jsdisp_t
*link
, void **unlink_ref
)
953 if(op
== GC_TRAVERSE_UNLINK
) {
955 jsdisp_release(link
);
959 if(link
->ctx
!= obj
->ctx
)
961 if(op
== GC_TRAVERSE_SPECULATIVELY
)
963 else if(link
->gc_marked
)
964 return gc_stack_push(gc_ctx
, link
);
968 HRESULT
gc_process_linked_val(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, jsdisp_t
*obj
, jsval_t
*link
)
972 if(op
== GC_TRAVERSE_UNLINK
) {
974 *link
= jsval_undefined();
979 if(!is_object_instance(*link
) || !(jsdisp
= to_jsdisp(get_object(*link
))) || jsdisp
->ctx
!= obj
->ctx
)
981 if(op
== GC_TRAVERSE_SPECULATIVELY
)
983 else if(jsdisp
->gc_marked
)
984 return gc_stack_push(gc_ctx
, jsdisp
);
990 struct typeinfo_func
{
992 function_code_t
*code
;
996 ITypeInfo ITypeInfo_iface
;
997 ITypeComp ITypeComp_iface
;
1002 struct typeinfo_func
*funcs
;
1003 dispex_prop_t
**vars
;
1008 static struct typeinfo_func
*get_func_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
1010 UINT a
= 0, b
= typeinfo
->num_funcs
;
1014 UINT i
= (a
+ b
- 1) / 2;
1015 MEMBERID func_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->funcs
[i
].prop
);
1017 if (memid
== func_memid
)
1018 return &typeinfo
->funcs
[i
];
1019 else if (memid
< func_memid
)
1027 static dispex_prop_t
*get_var_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
1029 UINT a
= 0, b
= typeinfo
->num_vars
;
1033 UINT i
= (a
+ b
- 1) / 2;
1034 MEMBERID var_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->vars
[i
]);
1036 if (memid
== var_memid
)
1037 return typeinfo
->vars
[i
];
1038 else if (memid
< var_memid
)
1046 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeInfo(ITypeInfo
*iface
)
1048 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeInfo_iface
);
1051 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeComp(ITypeComp
*iface
)
1053 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeComp_iface
);
1056 static HRESULT WINAPI
ScriptTypeInfo_QueryInterface(ITypeInfo
*iface
, REFIID riid
, void **ppv
)
1058 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1060 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ITypeInfo
, riid
))
1061 *ppv
= &This
->ITypeInfo_iface
;
1062 else if (IsEqualGUID(&IID_ITypeComp
, riid
))
1063 *ppv
= &This
->ITypeComp_iface
;
1066 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1068 return E_NOINTERFACE
;
1071 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1072 IUnknown_AddRef((IUnknown
*)*ppv
);
1076 static ULONG WINAPI
ScriptTypeInfo_AddRef(ITypeInfo
*iface
)
1078 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1079 LONG ref
= InterlockedIncrement(&This
->ref
);
1081 TRACE("(%p) ref=%ld\n", This
, ref
);
1086 static ULONG WINAPI
ScriptTypeInfo_Release(ITypeInfo
*iface
)
1088 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1089 LONG ref
= InterlockedDecrement(&This
->ref
);
1092 TRACE("(%p) ref=%ld\n", This
, ref
);
1096 for (i
= This
->num_funcs
; i
--;)
1097 release_bytecode(This
->funcs
[i
].code
->bytecode
);
1098 IDispatchEx_Release(&This
->jsdisp
->IDispatchEx_iface
);
1106 static HRESULT WINAPI
ScriptTypeInfo_GetTypeAttr(ITypeInfo
*iface
, TYPEATTR
**ppTypeAttr
)
1108 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1111 TRACE("(%p)->(%p)\n", This
, ppTypeAttr
);
1113 if (!ppTypeAttr
) return E_INVALIDARG
;
1115 attr
= calloc(1, sizeof(*attr
));
1116 if (!attr
) return E_OUTOFMEMORY
;
1118 attr
->guid
= GUID_JScriptTypeInfo
;
1119 attr
->lcid
= LOCALE_USER_DEFAULT
;
1120 attr
->memidConstructor
= MEMBERID_NIL
;
1121 attr
->memidDestructor
= MEMBERID_NIL
;
1122 attr
->cbSizeInstance
= 4;
1123 attr
->typekind
= TKIND_DISPATCH
;
1124 attr
->cFuncs
= This
->num_funcs
;
1125 attr
->cVars
= This
->num_vars
;
1126 attr
->cImplTypes
= 1;
1127 attr
->cbSizeVft
= sizeof(IDispatchVtbl
);
1128 attr
->cbAlignment
= 4;
1129 attr
->wTypeFlags
= TYPEFLAG_FDISPATCHABLE
;
1130 attr
->wMajorVerNum
= JSCRIPT_MAJOR_VERSION
;
1131 attr
->wMinorVerNum
= JSCRIPT_MINOR_VERSION
;
1137 static HRESULT WINAPI
ScriptTypeInfo_GetTypeComp(ITypeInfo
*iface
, ITypeComp
**ppTComp
)
1139 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1141 TRACE("(%p)->(%p)\n", This
, ppTComp
);
1143 if (!ppTComp
) return E_INVALIDARG
;
1145 *ppTComp
= &This
->ITypeComp_iface
;
1146 ITypeInfo_AddRef(iface
);
1150 static HRESULT WINAPI
ScriptTypeInfo_GetFuncDesc(ITypeInfo
*iface
, UINT index
, FUNCDESC
**ppFuncDesc
)
1152 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1153 struct typeinfo_func
*func
;
1157 TRACE("(%p)->(%u %p)\n", This
, index
, ppFuncDesc
);
1159 if (!ppFuncDesc
) return E_INVALIDARG
;
1160 if (index
>= This
->num_funcs
) return TYPE_E_ELEMENTNOTFOUND
;
1161 func
= &This
->funcs
[index
];
1163 /* Store the parameter array after the FUNCDESC structure */
1164 desc
= calloc(1, sizeof(*desc
) + sizeof(ELEMDESC
) * func
->code
->param_cnt
);
1165 if (!desc
) return E_OUTOFMEMORY
;
1167 desc
->memid
= prop_to_id(This
->jsdisp
, func
->prop
);
1168 desc
->funckind
= FUNC_DISPATCH
;
1169 desc
->invkind
= INVOKE_FUNC
;
1170 desc
->callconv
= CC_STDCALL
;
1171 desc
->cParams
= func
->code
->param_cnt
;
1172 desc
->elemdescFunc
.tdesc
.vt
= VT_VARIANT
;
1174 if (func
->code
->param_cnt
) desc
->lprgelemdescParam
= (ELEMDESC
*)(desc
+ 1);
1175 for (i
= 0; i
< func
->code
->param_cnt
; i
++)
1176 desc
->lprgelemdescParam
[i
].tdesc
.vt
= VT_VARIANT
;
1182 static HRESULT WINAPI
ScriptTypeInfo_GetVarDesc(ITypeInfo
*iface
, UINT index
, VARDESC
**ppVarDesc
)
1184 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1187 TRACE("(%p)->(%u %p)\n", This
, index
, ppVarDesc
);
1189 if (!ppVarDesc
) return E_INVALIDARG
;
1190 if (index
>= This
->num_vars
) return TYPE_E_ELEMENTNOTFOUND
;
1192 desc
= calloc(1, sizeof(*desc
));
1193 if (!desc
) return E_OUTOFMEMORY
;
1195 desc
->memid
= prop_to_id(This
->jsdisp
, This
->vars
[index
]);
1196 desc
->varkind
= VAR_DISPATCH
;
1197 desc
->elemdescVar
.tdesc
.vt
= VT_VARIANT
;
1203 static HRESULT WINAPI
ScriptTypeInfo_GetNames(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*rgBstrNames
,
1204 UINT cMaxNames
, UINT
*pcNames
)
1206 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1207 struct typeinfo_func
*func
;
1208 ITypeInfo
*disp_typeinfo
;
1213 TRACE("(%p)->(%ld %p %u %p)\n", This
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
1215 if (!rgBstrNames
|| !pcNames
) return E_INVALIDARG
;
1216 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1218 func
= get_func_from_memid(This
, memid
);
1221 var
= get_var_from_memid(This
, memid
);
1224 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1225 if (FAILED(hr
)) return hr
;
1227 return ITypeInfo_GetNames(disp_typeinfo
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
1232 if (!cMaxNames
) return S_OK
;
1234 rgBstrNames
[0] = SysAllocString(func
? func
->prop
->name
: var
->name
);
1235 if (!rgBstrNames
[0]) return E_OUTOFMEMORY
;
1240 unsigned num
= min(cMaxNames
, func
->code
->param_cnt
+ 1);
1242 for (; i
< num
; i
++)
1244 if (!(rgBstrNames
[i
] = SysAllocString(func
->code
->params
[i
- 1])))
1246 do SysFreeString(rgBstrNames
[--i
]); while (i
);
1247 return E_OUTOFMEMORY
;
1256 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo
*iface
, UINT index
, HREFTYPE
*pRefType
)
1258 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1260 TRACE("(%p)->(%u %p)\n", This
, index
, pRefType
);
1262 /* We only inherit from IDispatch */
1263 if (!pRefType
) return E_INVALIDARG
;
1264 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
1270 static HRESULT WINAPI
ScriptTypeInfo_GetImplTypeFlags(ITypeInfo
*iface
, UINT index
, INT
*pImplTypeFlags
)
1272 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1274 TRACE("(%p)->(%u %p)\n", This
, index
, pImplTypeFlags
);
1276 if (!pImplTypeFlags
) return E_INVALIDARG
;
1277 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
1279 *pImplTypeFlags
= 0;
1283 static HRESULT WINAPI
ScriptTypeInfo_GetIDsOfNames(ITypeInfo
*iface
, LPOLESTR
*rgszNames
, UINT cNames
,
1286 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1287 ITypeInfo
*disp_typeinfo
;
1292 TRACE("(%p)->(%p %u %p)\n", This
, rgszNames
, cNames
, pMemId
);
1294 if (!rgszNames
|| !cNames
|| !pMemId
) return E_INVALIDARG
;
1296 for (i
= 0; i
< cNames
; i
++) pMemId
[i
] = MEMBERID_NIL
;
1297 name
= rgszNames
[0];
1299 for (i
= 0; i
< This
->num_funcs
; i
++)
1301 struct typeinfo_func
*func
= &This
->funcs
[i
];
1303 if (wcsicmp(name
, func
->prop
->name
)) continue;
1304 pMemId
[0] = prop_to_id(This
->jsdisp
, func
->prop
);
1306 for (j
= 1; j
< cNames
; j
++)
1308 name
= rgszNames
[j
];
1309 for (arg
= func
->code
->param_cnt
; --arg
>= 0;)
1310 if (!wcsicmp(name
, func
->code
->params
[arg
]))
1315 hr
= DISP_E_UNKNOWNNAME
;
1320 for (i
= 0; i
< This
->num_vars
; i
++)
1322 dispex_prop_t
*var
= This
->vars
[i
];
1324 if (wcsicmp(name
, var
->name
)) continue;
1325 pMemId
[0] = prop_to_id(This
->jsdisp
, var
);
1329 /* Look into the inherited IDispatch */
1330 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1331 if (FAILED(hr
)) return hr
;
1333 return ITypeInfo_GetIDsOfNames(disp_typeinfo
, rgszNames
, cNames
, pMemId
);
1336 static HRESULT WINAPI
ScriptTypeInfo_Invoke(ITypeInfo
*iface
, PVOID pvInstance
, MEMBERID memid
, WORD wFlags
,
1337 DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1339 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1340 ITypeInfo
*disp_typeinfo
;
1344 TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This
, pvInstance
, memid
, wFlags
,
1345 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1347 if (!pvInstance
) return E_INVALIDARG
;
1348 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1350 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1352 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1353 if (FAILED(hr
)) return hr
;
1355 return ITypeInfo_Invoke(disp_typeinfo
, pvInstance
, memid
, wFlags
, pDispParams
,
1356 pVarResult
, pExcepInfo
, puArgErr
);
1359 hr
= IUnknown_QueryInterface((IUnknown
*)pvInstance
, &IID_IDispatch
, (void**)&disp
);
1360 if (FAILED(hr
)) return hr
;
1362 hr
= IDispatch_Invoke(disp
, memid
, &IID_NULL
, LOCALE_USER_DEFAULT
, wFlags
,
1363 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1364 IDispatch_Release(disp
);
1369 static HRESULT WINAPI
ScriptTypeInfo_GetDocumentation(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrName
,
1370 BSTR
*pBstrDocString
, DWORD
*pdwHelpContext
, BSTR
*pBstrHelpFile
)
1372 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1373 struct typeinfo_func
*func
;
1374 ITypeInfo
*disp_typeinfo
;
1378 TRACE("(%p)->(%ld %p %p %p %p)\n", This
, memid
, pBstrName
, pBstrDocString
, pdwHelpContext
, pBstrHelpFile
);
1380 if (pBstrDocString
) *pBstrDocString
= NULL
;
1381 if (pdwHelpContext
) *pdwHelpContext
= 0;
1382 if (pBstrHelpFile
) *pBstrHelpFile
= NULL
;
1384 if (memid
== MEMBERID_NIL
)
1386 if (pBstrName
&& !(*pBstrName
= SysAllocString(L
"JScriptTypeInfo")))
1387 return E_OUTOFMEMORY
;
1388 if (pBstrDocString
&&
1389 !(*pBstrDocString
= SysAllocString(L
"JScript Type Info")))
1391 if (pBstrName
) SysFreeString(*pBstrName
);
1392 return E_OUTOFMEMORY
;
1396 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1398 func
= get_func_from_memid(This
, memid
);
1401 var
= get_var_from_memid(This
, memid
);
1404 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1405 if (FAILED(hr
)) return hr
;
1407 return ITypeInfo_GetDocumentation(disp_typeinfo
, memid
, pBstrName
, pBstrDocString
,
1408 pdwHelpContext
, pBstrHelpFile
);
1414 *pBstrName
= SysAllocString(func
? func
->prop
->name
: var
->name
);
1417 return E_OUTOFMEMORY
;
1422 static HRESULT WINAPI
ScriptTypeInfo_GetDllEntry(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
,
1423 BSTR
*pBstrDllName
, BSTR
*pBstrName
, WORD
*pwOrdinal
)
1425 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1426 ITypeInfo
*disp_typeinfo
;
1429 TRACE("(%p)->(%ld %d %p %p %p)\n", This
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1431 if (pBstrDllName
) *pBstrDllName
= NULL
;
1432 if (pBstrName
) *pBstrName
= NULL
;
1433 if (pwOrdinal
) *pwOrdinal
= 0;
1435 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1437 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1438 if (FAILED(hr
)) return hr
;
1440 return ITypeInfo_GetDllEntry(disp_typeinfo
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1442 return TYPE_E_BADMODULEKIND
;
1445 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeInfo(ITypeInfo
*iface
, HREFTYPE hRefType
, ITypeInfo
**ppTInfo
)
1447 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1450 TRACE("(%p)->(%lx %p)\n", This
, hRefType
, ppTInfo
);
1452 if (!ppTInfo
|| (INT
)hRefType
< 0) return E_INVALIDARG
;
1454 if (hRefType
& ~3) return E_FAIL
;
1457 hr
= get_dispatch_typeinfo(ppTInfo
);
1458 if (FAILED(hr
)) return hr
;
1463 ITypeInfo_AddRef(*ppTInfo
);
1467 static HRESULT WINAPI
ScriptTypeInfo_AddressOfMember(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
, PVOID
*ppv
)
1469 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1470 ITypeInfo
*disp_typeinfo
;
1473 TRACE("(%p)->(%ld %d %p)\n", This
, memid
, invKind
, ppv
);
1475 if (!ppv
) return E_INVALIDARG
;
1478 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1480 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1481 if (FAILED(hr
)) return hr
;
1483 return ITypeInfo_AddressOfMember(disp_typeinfo
, memid
, invKind
, ppv
);
1485 return TYPE_E_BADMODULEKIND
;
1488 static HRESULT WINAPI
ScriptTypeInfo_CreateInstance(ITypeInfo
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, PVOID
*ppvObj
)
1490 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1492 TRACE("(%p)->(%p %s %p)\n", This
, pUnkOuter
, debugstr_guid(riid
), ppvObj
);
1494 if (!ppvObj
) return E_INVALIDARG
;
1497 return TYPE_E_BADMODULEKIND
;
1500 static HRESULT WINAPI
ScriptTypeInfo_GetMops(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrMops
)
1502 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1503 ITypeInfo
*disp_typeinfo
;
1506 TRACE("(%p)->(%ld %p)\n", This
, memid
, pBstrMops
);
1508 if (!pBstrMops
) return E_INVALIDARG
;
1510 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1512 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1513 if (FAILED(hr
)) return hr
;
1515 return ITypeInfo_GetMops(disp_typeinfo
, memid
, pBstrMops
);
1522 static HRESULT WINAPI
ScriptTypeInfo_GetContainingTypeLib(ITypeInfo
*iface
, ITypeLib
**ppTLib
, UINT
*pIndex
)
1524 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1526 FIXME("(%p)->(%p %p)\n", This
, ppTLib
, pIndex
);
1531 static void WINAPI
ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo
*iface
, TYPEATTR
*pTypeAttr
)
1533 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1535 TRACE("(%p)->(%p)\n", This
, pTypeAttr
);
1540 static void WINAPI
ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo
*iface
, FUNCDESC
*pFuncDesc
)
1542 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1544 TRACE("(%p)->(%p)\n", This
, pFuncDesc
);
1549 static void WINAPI
ScriptTypeInfo_ReleaseVarDesc(ITypeInfo
*iface
, VARDESC
*pVarDesc
)
1551 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1553 TRACE("(%p)->(%p)\n", This
, pVarDesc
);
1558 static const ITypeInfoVtbl ScriptTypeInfoVtbl
= {
1559 ScriptTypeInfo_QueryInterface
,
1560 ScriptTypeInfo_AddRef
,
1561 ScriptTypeInfo_Release
,
1562 ScriptTypeInfo_GetTypeAttr
,
1563 ScriptTypeInfo_GetTypeComp
,
1564 ScriptTypeInfo_GetFuncDesc
,
1565 ScriptTypeInfo_GetVarDesc
,
1566 ScriptTypeInfo_GetNames
,
1567 ScriptTypeInfo_GetRefTypeOfImplType
,
1568 ScriptTypeInfo_GetImplTypeFlags
,
1569 ScriptTypeInfo_GetIDsOfNames
,
1570 ScriptTypeInfo_Invoke
,
1571 ScriptTypeInfo_GetDocumentation
,
1572 ScriptTypeInfo_GetDllEntry
,
1573 ScriptTypeInfo_GetRefTypeInfo
,
1574 ScriptTypeInfo_AddressOfMember
,
1575 ScriptTypeInfo_CreateInstance
,
1576 ScriptTypeInfo_GetMops
,
1577 ScriptTypeInfo_GetContainingTypeLib
,
1578 ScriptTypeInfo_ReleaseTypeAttr
,
1579 ScriptTypeInfo_ReleaseFuncDesc
,
1580 ScriptTypeInfo_ReleaseVarDesc
1583 static HRESULT WINAPI
ScriptTypeComp_QueryInterface(ITypeComp
*iface
, REFIID riid
, void **ppv
)
1585 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1586 return ITypeInfo_QueryInterface(&This
->ITypeInfo_iface
, riid
, ppv
);
1589 static ULONG WINAPI
ScriptTypeComp_AddRef(ITypeComp
*iface
)
1591 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1592 return ITypeInfo_AddRef(&This
->ITypeInfo_iface
);
1595 static ULONG WINAPI
ScriptTypeComp_Release(ITypeComp
*iface
)
1597 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1598 return ITypeInfo_Release(&This
->ITypeInfo_iface
);
1601 static HRESULT WINAPI
ScriptTypeComp_Bind(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
, WORD wFlags
,
1602 ITypeInfo
**ppTInfo
, DESCKIND
*pDescKind
, BINDPTR
*pBindPtr
)
1604 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1605 UINT flags
= wFlags
? wFlags
: ~0;
1606 ITypeInfo
*disp_typeinfo
;
1607 ITypeComp
*disp_typecomp
;
1611 TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This
, debugstr_w(szName
), lHashVal
,
1612 wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1614 if (!szName
|| !ppTInfo
|| !pDescKind
|| !pBindPtr
)
1615 return E_INVALIDARG
;
1617 for (i
= 0; i
< This
->num_funcs
; i
++)
1619 if (wcsicmp(szName
, This
->funcs
[i
].prop
->name
)) continue;
1620 if (!(flags
& INVOKE_FUNC
)) return TYPE_E_TYPEMISMATCH
;
1622 hr
= ITypeInfo_GetFuncDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpfuncdesc
);
1623 if (FAILED(hr
)) return hr
;
1625 *pDescKind
= DESCKIND_FUNCDESC
;
1626 *ppTInfo
= &This
->ITypeInfo_iface
;
1627 ITypeInfo_AddRef(*ppTInfo
);
1631 for (i
= 0; i
< This
->num_vars
; i
++)
1633 if (wcsicmp(szName
, This
->vars
[i
]->name
)) continue;
1634 if (!(flags
& INVOKE_PROPERTYGET
)) return TYPE_E_TYPEMISMATCH
;
1636 hr
= ITypeInfo_GetVarDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpvardesc
);
1637 if (FAILED(hr
)) return hr
;
1639 *pDescKind
= DESCKIND_VARDESC
;
1640 *ppTInfo
= &This
->ITypeInfo_iface
;
1641 ITypeInfo_AddRef(*ppTInfo
);
1645 /* Look into the inherited IDispatch */
1646 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1647 if (FAILED(hr
)) return hr
;
1649 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1650 if (FAILED(hr
)) return hr
;
1652 hr
= ITypeComp_Bind(disp_typecomp
, szName
, lHashVal
, wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1653 ITypeComp_Release(disp_typecomp
);
1657 static HRESULT WINAPI
ScriptTypeComp_BindType(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
,
1658 ITypeInfo
**ppTInfo
, ITypeComp
**ppTComp
)
1660 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1661 ITypeInfo
*disp_typeinfo
;
1662 ITypeComp
*disp_typecomp
;
1665 TRACE("(%p)->(%s %08lx %p %p)\n", This
, debugstr_w(szName
), lHashVal
, ppTInfo
, ppTComp
);
1667 if (!szName
|| !ppTInfo
|| !ppTComp
)
1668 return E_INVALIDARG
;
1670 /* Look into the inherited IDispatch */
1671 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1672 if (FAILED(hr
)) return hr
;
1674 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1675 if (FAILED(hr
)) return hr
;
1677 hr
= ITypeComp_BindType(disp_typecomp
, szName
, lHashVal
, ppTInfo
, ppTComp
);
1678 ITypeComp_Release(disp_typecomp
);
1682 static const ITypeCompVtbl ScriptTypeCompVtbl
= {
1683 ScriptTypeComp_QueryInterface
,
1684 ScriptTypeComp_AddRef
,
1685 ScriptTypeComp_Release
,
1686 ScriptTypeComp_Bind
,
1687 ScriptTypeComp_BindType
1690 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
1692 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
1695 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
1697 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1699 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1700 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1701 *ppv
= &This
->IDispatchEx_iface
;
1702 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
1703 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
1704 *ppv
= &This
->IDispatchEx_iface
;
1705 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
1706 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
1707 *ppv
= &This
->IDispatchEx_iface
;
1709 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1711 return E_NOINTERFACE
;
1714 jsdisp_addref(This
);
1718 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
1720 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1721 jsdisp_addref(This
);
1725 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
1727 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1728 ULONG ref
= --This
->ref
;
1729 TRACE("(%p) ref=%ld\n", This
, ref
);
1735 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
1737 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1739 TRACE("(%p)->(%p)\n", This
, pctinfo
);
1745 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
1746 ITypeInfo
**ppTInfo
)
1748 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1749 dispex_prop_t
*prop
, *cur
, *end
, **typevar
;
1750 UINT num_funcs
= 0, num_vars
= 0;
1751 struct typeinfo_func
*typefunc
;
1752 function_code_t
*func_code
;
1753 ScriptTypeInfo
*typeinfo
;
1756 TRACE("(%p)->(%u %lu %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
1758 if (iTInfo
!= 0) return DISP_E_BADINDEX
;
1760 for (prop
= This
->props
, end
= prop
+ This
->prop_cnt
; prop
!= end
; prop
++)
1762 if (prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1765 /* If two identifiers differ only by case, the TypeInfo fails */
1766 pos
= This
->props
[get_props_idx(This
, prop
->hash
)].bucket_head
;
1769 cur
= This
->props
+ pos
;
1771 if (prop
->hash
== cur
->hash
&& prop
!= cur
&&
1772 cur
->type
== PROP_JSVAL
&& (cur
->flags
& PROPF_ENUMERABLE
) &&
1773 !wcsicmp(prop
->name
, cur
->name
))
1775 return TYPE_E_AMBIGUOUSNAME
;
1777 pos
= cur
->bucket_next
;
1780 if (is_function_prop(prop
))
1782 if (Function_get_code(as_jsdisp(get_object(prop
->u
.val
))))
1788 if (!(typeinfo
= malloc(sizeof(*typeinfo
))))
1789 return E_OUTOFMEMORY
;
1791 typeinfo
->ITypeInfo_iface
.lpVtbl
= &ScriptTypeInfoVtbl
;
1792 typeinfo
->ITypeComp_iface
.lpVtbl
= &ScriptTypeCompVtbl
;
1794 typeinfo
->num_vars
= num_vars
;
1795 typeinfo
->num_funcs
= num_funcs
;
1796 typeinfo
->jsdisp
= This
;
1798 typeinfo
->funcs
= malloc(sizeof(*typeinfo
->funcs
) * num_funcs
);
1799 if (!typeinfo
->funcs
)
1802 return E_OUTOFMEMORY
;
1805 typeinfo
->vars
= malloc(sizeof(*typeinfo
->vars
) * num_vars
);
1806 if (!typeinfo
->vars
)
1808 free(typeinfo
->funcs
);
1810 return E_OUTOFMEMORY
;
1813 typefunc
= typeinfo
->funcs
;
1814 typevar
= typeinfo
->vars
;
1815 for (prop
= This
->props
; prop
!= end
; prop
++)
1817 if (prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1820 if (is_function_prop(prop
))
1822 func_code
= Function_get_code(as_jsdisp(get_object(prop
->u
.val
)));
1823 if (!func_code
) continue;
1825 typefunc
->prop
= prop
;
1826 typefunc
->code
= func_code
;
1829 /* The function may be deleted, so keep a ref */
1830 bytecode_addref(func_code
->bytecode
);
1836 /* Keep a ref to the props and their names */
1837 IDispatchEx_AddRef(&This
->IDispatchEx_iface
);
1839 *ppTInfo
= &typeinfo
->ITypeInfo_iface
;
1843 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
1844 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
1847 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1851 TRACE("(%p)->(%s %p %u %lu %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
1857 hres
= jsdisp_get_id(This
, rgszNames
[0], 0, rgDispId
);
1861 /* DISPIDs for parameters don't seem to be supported */
1863 for(i
= 1; i
< cNames
; i
++)
1864 rgDispId
[i
] = DISPID_UNKNOWN
;
1865 hres
= DISP_E_UNKNOWNNAME
;
1871 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
1872 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1873 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1875 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1877 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
1878 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1880 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
1881 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
1884 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
1886 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1888 TRACE("(%p)->(%s %lx %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
1890 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameCaseInsensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
1891 FIXME("Unsupported grfdex %lx\n", grfdex
);
1895 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
1898 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
1899 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
1901 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1902 IServiceProvider
*prev_caller
;
1903 dispex_prop_t
*prop
;
1907 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
1910 V_VT(pvarRes
) = VT_EMPTY
;
1912 prop
= get_prop(This
, id
);
1913 if(!prop
&& id
!= DISPID_VALUE
) {
1914 TRACE("invalid id\n");
1915 return DISP_E_MEMBERNOTFOUND
;
1918 enter_script(This
->ctx
, &ei
);
1920 prev_caller
= This
->ctx
->jscaller
->caller
;
1921 This
->ctx
->jscaller
->caller
= pspCaller
;
1923 IServiceProvider_AddRef(pspCaller
);
1926 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
1927 wFlags
= DISPATCH_METHOD
;
1929 case DISPATCH_METHOD
:
1930 case DISPATCH_CONSTRUCT
: {
1931 jsval_t
*argv
, buf
[6], r
;
1932 IDispatch
*passed_this
;
1935 hres
= convert_params(This
->ctx
, pdp
, buf
, &argc
, &argv
);
1939 passed_this
= get_this(pdp
);
1941 hres
= invoke_prop_func(This
, passed_this
, prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
1943 hres
= jsdisp_call_value(This
, passed_this
? jsval_disp(passed_this
) : jsval_undefined(), wFlags
, argc
, argv
, pvarRes
? &r
: NULL
);
1946 jsval_release(argv
[argc
]);
1949 if(SUCCEEDED(hres
) && pvarRes
) {
1950 hres
= jsval_to_variant(r
, pvarRes
);
1955 case DISPATCH_PROPERTYGET
: {
1959 hres
= prop_get(This
, prop
, &r
);
1961 hres
= to_primitive(This
->ctx
, jsval_obj(This
), &r
, NO_HINT
);
1962 if(hres
== JS_E_TO_PRIMITIVE
)
1963 hres
= DISP_E_MEMBERNOTFOUND
;
1966 if(SUCCEEDED(hres
)) {
1967 hres
= jsval_to_variant(r
, pvarRes
);
1972 case DISPATCH_PROPERTYPUTREF
| DISPATCH_PROPERTYPUT
:
1973 case DISPATCH_PROPERTYPUTREF
:
1974 case DISPATCH_PROPERTYPUT
: {
1979 hres
= DISP_E_MEMBERNOTFOUND
;
1983 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
1984 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
1988 if(i
== pdp
->cNamedArgs
) {
1989 TRACE("no value to set\n");
1990 hres
= DISP_E_PARAMNOTOPTIONAL
;
1994 hres
= variant_to_jsval(This
->ctx
, pdp
->rgvarg
+i
, &val
);
1998 hres
= prop_put(This
, prop
, val
);
2003 FIXME("Unimplemented flags %x\n", wFlags
);
2004 hres
= E_INVALIDARG
;
2008 This
->ctx
->jscaller
->caller
= prev_caller
;
2010 IServiceProvider_Release(pspCaller
);
2011 return leave_script(This
->ctx
, hres
);
2014 static HRESULT
delete_prop(dispex_prop_t
*prop
, BOOL
*ret
)
2016 if(prop
->type
== PROP_PROTREF
) {
2021 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2028 if(prop
->type
== PROP_JSVAL
)
2029 jsval_release(prop
->u
.val
);
2030 if(prop
->type
== PROP_ACCESSOR
) {
2031 if(prop
->u
.accessor
.getter
)
2032 jsdisp_release(prop
->u
.accessor
.getter
);
2033 if(prop
->u
.accessor
.setter
)
2034 jsdisp_release(prop
->u
.accessor
.setter
);
2036 prop
->type
= PROP_DELETED
;
2040 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
2042 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2043 dispex_prop_t
*prop
;
2047 TRACE("(%p)->(%s %lx)\n", This
, debugstr_w(bstrName
), grfdex
);
2049 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameCaseInsensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
2050 FIXME("Unsupported grfdex %lx\n", grfdex
);
2052 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, grfdex
& fdexNameCaseInsensitive
, &prop
);
2056 TRACE("not found\n");
2060 return delete_prop(prop
, &b
);
2063 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
2065 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2066 dispex_prop_t
*prop
;
2069 TRACE("(%p)->(%lx)\n", This
, id
);
2071 prop
= get_prop(This
, id
);
2073 WARN("invalid id\n");
2074 return DISP_E_MEMBERNOTFOUND
;
2077 return delete_prop(prop
, &b
);
2080 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
2082 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2083 FIXME("(%p)->(%lx %lx %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
2087 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
2089 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2090 dispex_prop_t
*prop
;
2092 TRACE("(%p)->(%lx %p)\n", This
, id
, pbstrName
);
2094 prop
= get_prop(This
, id
);
2096 return DISP_E_MEMBERNOTFOUND
;
2098 *pbstrName
= SysAllocString(prop
->name
);
2100 return E_OUTOFMEMORY
;
2105 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
2107 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2108 HRESULT hres
= S_FALSE
;
2110 TRACE("(%p)->(%lx %lx %p)\n", This
, grfdex
, id
, pid
);
2112 if(id
!= DISPID_VALUE
)
2113 hres
= jsdisp_next_prop(This
, id
, JSDISP_ENUM_ALL
, pid
);
2115 *pid
= DISPID_STARTENUM
;
2119 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
2121 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
2122 FIXME("(%p)->(%p)\n", This
, ppunk
);
2126 static IDispatchExVtbl DispatchExVtbl
= {
2127 DispatchEx_QueryInterface
,
2130 DispatchEx_GetTypeInfoCount
,
2131 DispatchEx_GetTypeInfo
,
2132 DispatchEx_GetIDsOfNames
,
2134 DispatchEx_GetDispID
,
2135 DispatchEx_InvokeEx
,
2136 DispatchEx_DeleteMemberByName
,
2137 DispatchEx_DeleteMemberByDispID
,
2138 DispatchEx_GetMemberProperties
,
2139 DispatchEx_GetMemberName
,
2140 DispatchEx_GetNextDispID
,
2141 DispatchEx_GetNameSpaceParent
2144 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
2146 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
2147 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
2150 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
2152 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
2155 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
2159 /* FIXME: Use better heuristics to decide when to run the GC */
2160 if(GetTickCount() - ctx
->gc_last_tick
> 30000)
2163 TRACE("%p (%p)\n", dispex
, prototype
);
2165 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
2167 dispex
->builtin_info
= builtin_info
;
2168 dispex
->extensible
= TRUE
;
2169 dispex
->prop_cnt
= 0;
2171 dispex
->props
= calloc(1, sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
2173 return E_OUTOFMEMORY
;
2175 for(i
= 0; i
< dispex
->buf_size
; i
++) {
2176 dispex
->props
[i
].bucket_head
= ~0;
2177 dispex
->props
[i
].bucket_next
= ~0;
2180 dispex
->prototype
= prototype
;
2182 jsdisp_addref(prototype
);
2187 list_add_tail(&ctx
->objects
, &dispex
->entry
);
2191 static const builtin_info_t dispex_info
= {
2199 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
2204 ret
= calloc(1, sizeof(jsdisp_t
));
2206 return E_OUTOFMEMORY
;
2208 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
2218 void jsdisp_free(jsdisp_t
*obj
)
2220 dispex_prop_t
*prop
;
2222 list_remove(&obj
->entry
);
2224 TRACE("(%p)\n", obj
);
2226 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
2227 switch(prop
->type
) {
2229 jsval_release(prop
->u
.val
);
2232 if(prop
->u
.accessor
.getter
)
2233 jsdisp_release(prop
->u
.accessor
.getter
);
2234 if(prop
->u
.accessor
.setter
)
2235 jsdisp_release(prop
->u
.accessor
.setter
);
2243 script_release(obj
->ctx
);
2245 jsdisp_release(obj
->prototype
);
2247 if(obj
->builtin_info
->destructor
)
2248 obj
->builtin_info
->destructor(obj
);
2255 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
2257 ULONG ref
= ++jsdisp
->ref
;
2258 TRACE("(%p) ref=%ld\n", jsdisp
, ref
);
2262 void jsdisp_release(jsdisp_t
*jsdisp
)
2264 ULONG ref
= --jsdisp
->ref
;
2266 TRACE("(%p) ref=%ld\n", jsdisp
, ref
);
2269 jsdisp_free(jsdisp
);
2274 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
2276 jsdisp_t
*prot
= NULL
;
2277 dispex_prop_t
*prop
;
2280 hres
= find_prop_name_prot(constr
, string_hash(L
"prototype"), L
"prototype", FALSE
, &prop
);
2281 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
2284 hres
= prop_get(constr
, prop
, &val
);
2286 ERR("Could not get prototype\n");
2290 if(is_object_instance(val
))
2291 prot
= iface_to_jsdisp(get_object(val
));
2293 prot
= jsdisp_addref(ctx
->object_prototype
);
2298 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
2301 jsdisp_release(prot
);
2305 jsdisp_t
*iface_to_jsdisp(IDispatch
*iface
)
2307 return iface
->lpVtbl
== (const IDispatchVtbl
*)&DispatchExVtbl
2308 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx
*)iface
))
2312 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
2314 dispex_prop_t
*prop
;
2317 if(jsdisp
->extensible
&& (flags
& fdexNameEnsure
))
2318 hres
= ensure_prop_name(jsdisp
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
,
2319 flags
& fdexNameCaseInsensitive
, &prop
);
2321 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, flags
& fdexNameCaseInsensitive
, &prop
);
2325 if(prop
&& prop
->type
!=PROP_DELETED
) {
2326 *id
= prop_to_id(jsdisp
, prop
);
2330 TRACE("not found %s\n", debugstr_w(name
));
2331 *id
= DISPID_UNKNOWN
;
2332 return DISP_E_UNKNOWNNAME
;
2335 HRESULT
jsdisp_get_idx_id(jsdisp_t
*jsdisp
, DWORD idx
, DISPID
*id
)
2339 swprintf(name
, ARRAY_SIZE(name
), L
"%u", idx
);
2340 return jsdisp_get_id(jsdisp
, name
, 0, id
);
2343 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
2347 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2349 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
2350 hres
= Function_invoke(jsfunc
, vthis
, flags
, argc
, argv
, r
);
2352 if(!jsfunc
->builtin_info
->call
) {
2353 WARN("Not a function\n");
2354 return JS_E_FUNCTION_EXPECTED
;
2357 if(jsfunc
->ctx
->state
== SCRIPTSTATE_UNINITIALIZED
|| jsfunc
->ctx
->state
== SCRIPTSTATE_CLOSED
)
2358 return E_UNEXPECTED
;
2360 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2361 hres
= jsfunc
->builtin_info
->call(jsfunc
->ctx
, vthis
, flags
, argc
, argv
, r
);
2366 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
2368 dispex_prop_t
*prop
;
2370 prop
= get_prop(disp
, id
);
2372 return DISP_E_MEMBERNOTFOUND
;
2374 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, &disp
->ctx
->jscaller
->IServiceProvider_iface
);
2377 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
2379 dispex_prop_t
*prop
;
2382 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, FALSE
, &prop
);
2386 if(!prop
|| prop
->type
== PROP_DELETED
)
2387 return JS_E_INVALID_PROPERTY
;
2389 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, &disp
->ctx
->jscaller
->IServiceProvider_iface
);
2392 static HRESULT
disp_invoke(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*params
, VARIANT
*r
,
2393 IServiceProvider
*caller
)
2395 IDispatchEx
*dispex
;
2399 memset(&ei
, 0, sizeof(ei
));
2400 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2401 if(SUCCEEDED(hres
)) {
2402 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, params
, r
, &ei
, caller
);
2403 IDispatchEx_Release(dispex
);
2407 if(flags
== DISPATCH_CONSTRUCT
) {
2408 WARN("IDispatch cannot be constructor\n");
2409 return DISP_E_MEMBERNOTFOUND
;
2412 if(params
->cNamedArgs
== 1 && params
->rgdispidNamedArgs
[0] == DISPID_THIS
) {
2413 params
->cNamedArgs
= 0;
2414 params
->rgdispidNamedArgs
= NULL
;
2419 TRACE("using IDispatch\n");
2420 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, params
, r
, &ei
, &err
);
2423 if(hres
== DISP_E_EXCEPTION
) {
2424 TRACE("DISP_E_EXCEPTION: %08lx %s %s\n", ei
.scode
, debugstr_w(ei
.bstrSource
), debugstr_w(ei
.bstrDescription
));
2426 ctx
->ei
->error
= (SUCCEEDED(ei
.scode
) || ei
.scode
== DISP_E_EXCEPTION
) ? E_FAIL
: ei
.scode
;
2428 ctx
->ei
->source
= jsstr_alloc_len(ei
.bstrSource
, SysStringLen(ei
.bstrSource
));
2429 if(ei
.bstrDescription
)
2430 ctx
->ei
->message
= jsstr_alloc_len(ei
.bstrDescription
, SysStringLen(ei
.bstrDescription
));
2431 SysFreeString(ei
.bstrSource
);
2432 SysFreeString(ei
.bstrDescription
);
2433 SysFreeString(ei
.bstrHelpFile
);
2439 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2441 VARIANT buf
[6], retv
;
2447 jsdisp
= iface_to_jsdisp(disp
);
2448 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2449 if(flags
& DISPATCH_PROPERTYPUT
) {
2450 FIXME("disp_call(propput) on builtin object\n");
2451 jsdisp_release(jsdisp
);
2455 if(ctx
!= jsdisp
->ctx
)
2456 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2457 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
2458 jsdisp_release(jsdisp
);
2462 jsdisp_release(jsdisp
);
2464 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2466 flags
|= DISPATCH_PROPERTYGET
;
2470 if(flags
& DISPATCH_PROPERTYPUT
) {
2471 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
2474 dp
.rgdispidNamedArgs
= &propput_dispid
;
2477 dp
.rgdispidNamedArgs
= NULL
;
2480 if(dp
.cArgs
> ARRAY_SIZE(buf
)) {
2481 dp
.rgvarg
= malloc(argc
* sizeof(VARIANT
));
2483 return E_OUTOFMEMORY
;
2488 for(i
=0; i
<argc
; i
++) {
2489 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
2492 VariantClear(dp
.rgvarg
+argc
-i
-1);
2493 if(dp
.rgvarg
!= buf
)
2499 V_VT(&retv
) = VT_EMPTY
;
2500 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, ret
? &retv
: NULL
, &ctx
->jscaller
->IServiceProvider_iface
);
2502 for(i
=0; i
<argc
; i
++)
2503 VariantClear(dp
.rgvarg
+argc
-i
-1);
2504 if(dp
.rgvarg
!= buf
)
2507 if(SUCCEEDED(hres
) && ret
)
2508 hres
= variant_to_jsval(ctx
, &retv
, ret
);
2509 VariantClear(&retv
);
2513 HRESULT
disp_call_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2515 IDispatchEx
*dispex
;
2521 if((jsdisp
= to_jsdisp(disp
)) && jsdisp
->ctx
== ctx
)
2522 return jsdisp_call_name(jsdisp
, name
, flags
, argc
, argv
, ret
);
2524 if(!(bstr
= SysAllocString(name
)))
2525 return E_OUTOFMEMORY
;
2526 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2527 if(SUCCEEDED(hres
) && dispex
) {
2528 hres
= IDispatchEx_GetDispID(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
), &id
);
2529 IDispatchEx_Release(dispex
);
2531 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2533 SysFreeString(bstr
);
2537 return disp_call(ctx
, disp
, id
, flags
, argc
, argv
, ret
);
2540 HRESULT
disp_call_value_with_caller(script_ctx_t
*ctx
, IDispatch
*disp
, jsval_t vthis
, WORD flags
, unsigned argc
,
2541 jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
2543 VARIANT buf
[6], retv
, *args
= buf
;
2548 HRESULT hres
= S_OK
;
2550 static DISPID this_id
= DISPID_THIS
;
2552 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2554 jsdisp
= iface_to_jsdisp(disp
);
2555 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2556 hres
= jsdisp_call_value(jsdisp
, vthis
, flags
, argc
, argv
, r
);
2557 jsdisp_release(jsdisp
);
2561 jsdisp_release(jsdisp
);
2563 if(is_object_instance(vthis
) && (ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
||
2564 ((jsdisp
= to_jsdisp(get_object(vthis
))) && is_class(jsdisp
, JSCLASS_OBJECT
))))
2565 jsthis
= get_object(vthis
);
2569 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2570 if(r
&& argc
&& flags
== DISPATCH_METHOD
)
2571 flags
|= DISPATCH_PROPERTYGET
;
2574 dp
.cArgs
= argc
+ 1;
2576 dp
.rgdispidNamedArgs
= &this_id
;
2580 dp
.rgdispidNamedArgs
= NULL
;
2583 if(dp
.cArgs
> ARRAY_SIZE(buf
) && !(args
= malloc(dp
.cArgs
* sizeof(VARIANT
))))
2584 return E_OUTOFMEMORY
;
2588 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
2589 V_DISPATCH(dp
.rgvarg
) = jsthis
;
2592 for(i
=0; SUCCEEDED(hres
) && i
< argc
; i
++)
2593 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
2595 if(SUCCEEDED(hres
)) {
2596 V_VT(&retv
) = VT_EMPTY
;
2597 hres
= disp_invoke(ctx
, disp
, DISPID_VALUE
, flags
, &dp
, r
? &retv
: NULL
, caller
);
2600 for(i
= 0; i
< argc
; i
++)
2601 VariantClear(dp
.rgvarg
+ dp
.cArgs
- i
- 1);
2610 hres
= variant_to_jsval(ctx
, &retv
, r
);
2611 VariantClear(&retv
);
2615 HRESULT
jsdisp_propput(jsdisp_t
*obj
, const WCHAR
*name
, DWORD flags
, BOOL
throw, jsval_t val
)
2617 dispex_prop_t
*prop
;
2621 hres
= ensure_prop_name(obj
, name
, flags
, FALSE
, &prop
);
2623 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
2626 if(!prop
|| (prop
->type
== PROP_DELETED
&& !obj
->extensible
))
2627 return throw ? JS_E_INVALID_ACTION
: S_OK
;
2629 return prop_put(obj
, prop
, val
);
2632 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
2634 return jsdisp_propput(obj
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, FALSE
, val
);
2637 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
2641 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2642 return jsdisp_propput(obj
, buf
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, TRUE
, val
);
2645 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
2650 jsdisp
= iface_to_jsdisp(disp
);
2651 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2652 dispex_prop_t
*prop
;
2654 prop
= get_prop(jsdisp
, id
);
2656 hres
= prop_put(jsdisp
, prop
, val
);
2658 hres
= DISP_E_MEMBERNOTFOUND
;
2660 jsdisp_release(jsdisp
);
2662 DISPID dispid
= DISPID_PROPERTYPUT
;
2663 DWORD flags
= DISPATCH_PROPERTYPUT
;
2665 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
2668 jsdisp_release(jsdisp
);
2669 hres
= jsval_to_variant(val
, &var
);
2673 if(V_VT(&var
) == VT_DISPATCH
)
2674 flags
|= DISPATCH_PROPERTYPUTREF
;
2676 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, NULL
, &ctx
->jscaller
->IServiceProvider_iface
);
2683 HRESULT
disp_propput_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, jsval_t val
)
2688 jsdisp
= iface_to_jsdisp(disp
);
2689 if(!jsdisp
|| jsdisp
->ctx
!= ctx
) {
2690 IDispatchEx
*dispex
;
2695 jsdisp_release(jsdisp
);
2696 if(!(str
= SysAllocString(name
)))
2697 return E_OUTOFMEMORY
;
2699 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2700 if(SUCCEEDED(hres
)) {
2701 hres
= IDispatchEx_GetDispID(dispex
, str
, make_grfdex(ctx
, fdexNameEnsure
|fdexNameCaseSensitive
), &id
);
2702 IDispatchEx_Release(dispex
);
2704 TRACE("using IDispatch\n");
2705 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &str
, 1, 0, &id
);
2711 return disp_propput(ctx
, disp
, id
, val
);
2714 hres
= jsdisp_propput_name(jsdisp
, name
, val
);
2715 jsdisp_release(jsdisp
);
2719 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
2721 dispex_prop_t
*prop
;
2724 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, FALSE
, &prop
);
2728 if(!prop
|| prop
->type
==PROP_DELETED
) {
2729 *val
= jsval_undefined();
2733 return prop_get(obj
, prop
, val
);
2736 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
2739 dispex_prop_t
*prop
;
2742 swprintf(name
, ARRAY_SIZE(name
), L
"%d", idx
);
2744 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, FALSE
, &prop
);
2748 if(!prop
|| prop
->type
==PROP_DELETED
) {
2749 *r
= jsval_undefined();
2750 return DISP_E_UNKNOWNNAME
;
2753 return prop_get(obj
, prop
, r
);
2756 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
2758 dispex_prop_t
*prop
;
2760 prop
= get_prop(jsdisp
, id
);
2762 return DISP_E_MEMBERNOTFOUND
;
2764 return prop_get(jsdisp
, prop
, val
);
2767 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
2769 DISPPARAMS dp
= {NULL
,NULL
,0,0};
2774 jsdisp
= iface_to_jsdisp(disp
);
2775 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2776 hres
= jsdisp_propget(jsdisp
, id
, val
);
2777 jsdisp_release(jsdisp
);
2781 jsdisp_release(jsdisp
);
2783 V_VT(&var
) = VT_EMPTY
;
2784 hres
= disp_invoke(ctx
, disp
, id
, INVOKE_PROPERTYGET
, &dp
, &var
, &ctx
->jscaller
->IServiceProvider_iface
);
2785 if(SUCCEEDED(hres
)) {
2786 hres
= variant_to_jsval(ctx
, &var
, val
);
2792 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
2795 dispex_prop_t
*prop
;
2799 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2801 hres
= find_prop_name(obj
, string_hash(buf
), buf
, FALSE
, &prop
);
2802 if(FAILED(hres
) || !prop
)
2805 hres
= delete_prop(prop
, &b
);
2808 return b
? S_OK
: JS_E_INVALID_ACTION
;
2811 HRESULT
disp_delete(IDispatch
*disp
, DISPID id
, BOOL
*ret
)
2813 IDispatchEx
*dispex
;
2817 jsdisp
= iface_to_jsdisp(disp
);
2819 dispex_prop_t
*prop
;
2821 prop
= get_prop(jsdisp
, id
);
2823 hres
= delete_prop(prop
, ret
);
2825 hres
= DISP_E_MEMBERNOTFOUND
;
2827 jsdisp_release(jsdisp
);
2831 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2837 hres
= IDispatchEx_DeleteMemberByDispID(dispex
, id
);
2838 IDispatchEx_Release(dispex
);
2842 *ret
= hres
== S_OK
;
2846 HRESULT
jsdisp_next_prop(jsdisp_t
*obj
, DISPID id
, enum jsdisp_enum_type enum_type
, DISPID
*ret
)
2848 dispex_prop_t
*iter
;
2852 if(id
== DISPID_STARTENUM
|| idx
>= obj
->prop_cnt
) {
2853 hres
= (enum_type
== JSDISP_ENUM_ALL
) ? fill_protrefs(obj
) : fill_props(obj
);
2856 if(id
== DISPID_STARTENUM
)
2858 if(idx
>= obj
->prop_cnt
)
2862 for(iter
= &obj
->props
[idx
]; iter
< obj
->props
+ obj
->prop_cnt
; iter
++) {
2863 if(iter
->type
== PROP_DELETED
)
2865 if(enum_type
!= JSDISP_ENUM_ALL
&& iter
->type
== PROP_PROTREF
)
2867 if(enum_type
!= JSDISP_ENUM_OWN
&& !(get_flags(obj
, iter
) & PROPF_ENUMERABLE
))
2869 *ret
= prop_to_id(obj
, iter
);
2873 if(obj
->ctx
->html_mode
)
2874 return jsdisp_next_prop(obj
, prop_to_id(obj
, iter
- 1), enum_type
, ret
);
2879 HRESULT
disp_delete_name(script_ctx_t
*ctx
, IDispatch
*disp
, jsstr_t
*name
, BOOL
*ret
)
2881 IDispatchEx
*dispex
;
2886 jsdisp
= iface_to_jsdisp(disp
);
2888 dispex_prop_t
*prop
;
2891 ptr
= jsstr_flatten(name
);
2893 jsdisp_release(jsdisp
);
2894 return E_OUTOFMEMORY
;
2897 hres
= find_prop_name(jsdisp
, string_hash(ptr
), ptr
, FALSE
, &prop
);
2899 hres
= delete_prop(prop
, ret
);
2905 jsdisp_release(jsdisp
);
2909 bstr
= SysAllocStringLen(NULL
, jsstr_length(name
));
2911 return E_OUTOFMEMORY
;
2912 jsstr_flush(name
, bstr
);
2914 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2915 if(SUCCEEDED(hres
)) {
2916 hres
= IDispatchEx_DeleteMemberByName(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
));
2918 *ret
= hres
== S_OK
;
2919 IDispatchEx_Release(dispex
);
2923 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2924 if(SUCCEEDED(hres
)) {
2925 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2927 }else if(hres
== DISP_E_UNKNOWNNAME
) {
2928 /* Property doesn't exist, so nothing to delete */
2934 SysFreeString(bstr
);
2938 HRESULT
jsdisp_get_own_property(jsdisp_t
*obj
, const WCHAR
*name
, BOOL flags_only
,
2939 property_desc_t
*desc
)
2941 dispex_prop_t
*prop
;
2944 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
2949 return DISP_E_UNKNOWNNAME
;
2951 memset(desc
, 0, sizeof(*desc
));
2953 switch(prop
->type
) {
2957 desc
->mask
|= PROPF_WRITABLE
;
2958 desc
->explicit_value
= TRUE
;
2960 hres
= prop_get(obj
, prop
, &desc
->value
);
2966 desc
->explicit_getter
= desc
->explicit_setter
= TRUE
;
2968 desc
->getter
= prop
->u
.accessor
.getter
2969 ? jsdisp_addref(prop
->u
.accessor
.getter
) : NULL
;
2970 desc
->setter
= prop
->u
.accessor
.setter
2971 ? jsdisp_addref(prop
->u
.accessor
.setter
) : NULL
;
2975 return DISP_E_UNKNOWNNAME
;
2978 desc
->flags
= prop
->flags
& (PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
2979 desc
->mask
|= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
;
2983 HRESULT
jsdisp_define_property(jsdisp_t
*obj
, const WCHAR
*name
, property_desc_t
*desc
)
2985 dispex_prop_t
*prop
;
2988 hres
= find_prop_name(obj
, string_hash(name
), name
, FALSE
, &prop
);
2992 if((!prop
|| prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) && !obj
->extensible
)
2993 return throw_error(obj
->ctx
, JS_E_OBJECT_NONEXTENSIBLE
, name
);
2995 if(!prop
&& !(prop
= alloc_prop(obj
, name
, PROP_DELETED
, 0)))
2996 return E_OUTOFMEMORY
;
2998 if(prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) {
2999 prop
->flags
= desc
->flags
;
3000 if(desc
->explicit_getter
|| desc
->explicit_setter
) {
3001 prop
->type
= PROP_ACCESSOR
;
3002 prop
->u
.accessor
.getter
= desc
->getter
? jsdisp_addref(desc
->getter
) : NULL
;
3003 prop
->u
.accessor
.setter
= desc
->setter
? jsdisp_addref(desc
->setter
) : NULL
;
3004 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name
),
3005 prop
->u
.accessor
.getter
, prop
->u
.accessor
.setter
);
3007 prop
->type
= PROP_JSVAL
;
3008 if(desc
->explicit_value
) {
3009 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
3013 prop
->u
.val
= jsval_undefined();
3015 TRACE("%s = %s\n", debugstr_w(name
), debugstr_jsval(prop
->u
.val
));
3020 TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(name
),
3021 prop
->flags
, desc
->flags
, desc
->mask
);
3023 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
3024 if(((desc
->mask
& PROPF_CONFIGURABLE
) && (desc
->flags
& PROPF_CONFIGURABLE
))
3025 || ((desc
->mask
& PROPF_ENUMERABLE
)
3026 && ((desc
->flags
& PROPF_ENUMERABLE
) != (prop
->flags
& PROPF_ENUMERABLE
))))
3027 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3030 if(desc
->explicit_value
|| (desc
->mask
& PROPF_WRITABLE
)) {
3031 if(prop
->type
== PROP_ACCESSOR
) {
3032 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
3033 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3034 if(prop
->u
.accessor
.getter
)
3035 jsdisp_release(prop
->u
.accessor
.getter
);
3036 if(prop
->u
.accessor
.setter
)
3037 jsdisp_release(prop
->u
.accessor
.setter
);
3039 prop
->type
= PROP_JSVAL
;
3040 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
3042 prop
->u
.val
= jsval_undefined();
3046 if(!(prop
->flags
& PROPF_CONFIGURABLE
) && !(prop
->flags
& PROPF_WRITABLE
)) {
3047 if((desc
->mask
& PROPF_WRITABLE
) && (desc
->flags
& PROPF_WRITABLE
))
3048 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
3049 if(desc
->explicit_value
) {
3050 if(prop
->type
== PROP_JSVAL
) {
3052 hres
= jsval_strict_equal(desc
->value
, prop
->u
.val
, &eq
);
3056 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
3058 FIXME("redefinition of property type %d\n", prop
->type
);
3062 if(desc
->explicit_value
) {
3063 if(prop
->type
== PROP_JSVAL
)
3064 jsval_release(prop
->u
.val
);
3066 prop
->type
= PROP_JSVAL
;
3067 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
3069 prop
->u
.val
= jsval_undefined();
3074 }else if(desc
->explicit_getter
|| desc
->explicit_setter
) {
3075 if(prop
->type
!= PROP_ACCESSOR
) {
3076 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
3077 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3078 if(prop
->type
== PROP_JSVAL
)
3079 jsval_release(prop
->u
.val
);
3080 prop
->type
= PROP_ACCESSOR
;
3081 prop
->u
.accessor
.getter
= prop
->u
.accessor
.setter
= NULL
;
3082 }else if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
3083 if((desc
->explicit_getter
&& desc
->getter
!= prop
->u
.accessor
.getter
)
3084 || (desc
->explicit_setter
&& desc
->setter
!= prop
->u
.accessor
.setter
))
3085 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
3088 if(desc
->explicit_getter
) {
3089 if(prop
->u
.accessor
.getter
) {
3090 jsdisp_release(prop
->u
.accessor
.getter
);
3091 prop
->u
.accessor
.getter
= NULL
;
3094 prop
->u
.accessor
.getter
= jsdisp_addref(desc
->getter
);
3096 if(desc
->explicit_setter
) {
3097 if(prop
->u
.accessor
.setter
) {
3098 jsdisp_release(prop
->u
.accessor
.setter
);
3099 prop
->u
.accessor
.setter
= NULL
;
3102 prop
->u
.accessor
.setter
= jsdisp_addref(desc
->setter
);
3106 prop
->flags
= (prop
->flags
& ~desc
->mask
) | (desc
->flags
& desc
->mask
);
3110 HRESULT
jsdisp_define_data_property(jsdisp_t
*obj
, const WCHAR
*name
, unsigned flags
, jsval_t value
)
3112 property_desc_t prop_desc
= { flags
, flags
, TRUE
};
3113 prop_desc
.value
= value
;
3114 return jsdisp_define_property(obj
, name
, &prop_desc
);
3117 HRESULT
jsdisp_change_prototype(jsdisp_t
*obj
, jsdisp_t
*proto
)
3122 if(obj
->prototype
== proto
)
3124 if(!obj
->extensible
)
3125 return JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE
;
3127 for(iter
= proto
; iter
; iter
= iter
->prototype
)
3129 return JS_E_CYCLIC_PROTO_VALUE
;
3131 if(obj
->prototype
) {
3132 for(i
= 0; i
< obj
->prop_cnt
; i
++)
3133 if(obj
->props
[i
].type
== PROP_PROTREF
)
3134 obj
->props
[i
].type
= PROP_DELETED
;
3135 jsdisp_release(obj
->prototype
);
3138 obj
->prototype
= proto
;
3140 jsdisp_addref(proto
);
3144 void jsdisp_freeze(jsdisp_t
*obj
, BOOL seal
)
3148 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
3149 if(!seal
&& obj
->props
[i
].type
== PROP_JSVAL
)
3150 obj
->props
[i
].flags
&= ~PROPF_WRITABLE
;
3151 obj
->props
[i
].flags
&= ~PROPF_CONFIGURABLE
;
3154 obj
->extensible
= FALSE
;
3157 BOOL
jsdisp_is_frozen(jsdisp_t
*obj
, BOOL sealed
)
3164 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
3165 if(obj
->props
[i
].type
== PROP_JSVAL
) {
3166 if(!sealed
&& (obj
->props
[i
].flags
& PROPF_WRITABLE
))
3168 }else if(obj
->props
[i
].type
!= PROP_ACCESSOR
)
3170 if(obj
->props
[i
].flags
& PROPF_CONFIGURABLE
)
3177 HRESULT
jsdisp_get_prop_name(jsdisp_t
*obj
, DISPID id
, jsstr_t
**r
)
3179 dispex_prop_t
*prop
= get_prop(obj
, id
);
3182 return DISP_E_MEMBERNOTFOUND
;
3184 *r
= jsstr_alloc(prop
->name
);
3185 return *r
? S_OK
: E_OUTOFMEMORY
;