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 typedef struct _function_vtbl_t function_vtbl_t
;
32 const function_vtbl_t
*vtbl
;
37 struct _function_vtbl_t
{
38 HRESULT (*call
)(script_ctx_t
*,FunctionInstance
*,jsval_t
,unsigned,unsigned,jsval_t
*,jsval_t
*);
39 HRESULT (*toString
)(FunctionInstance
*,jsstr_t
**);
40 function_code_t
* (*get_code
)(FunctionInstance
*);
41 void (*destructor
)(FunctionInstance
*);
42 HRESULT (*gc_traverse
)(struct gc_ctx
*,enum gc_traverse_op
,FunctionInstance
*);
46 FunctionInstance function
;
47 scope_chain_t
*scope_chain
;
49 function_code_t
*func_code
;
50 } InterpretedFunction
;
53 FunctionInstance function
;
54 builtin_invoke_t proc
;
59 FunctionInstance function
;
60 FunctionInstance
*target
;
68 InterpretedFunction
*function
;
74 static HRESULT
create_bind_function(script_ctx_t
*,FunctionInstance
*,jsval_t
,unsigned,jsval_t
*,jsdisp_t
**r
);
76 static HRESULT
no_gc_traverse(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, FunctionInstance
*function
)
81 static inline FunctionInstance
*function_from_jsdisp(jsdisp_t
*jsdisp
)
83 return CONTAINING_RECORD(jsdisp
, FunctionInstance
, dispex
);
86 static inline FunctionInstance
*function_this(jsval_t vthis
)
88 jsdisp_t
*jsdisp
= is_object_instance(vthis
) ? to_jsdisp(get_object(vthis
)) : NULL
;
89 return (jsdisp
&& is_class(jsdisp
, JSCLASS_FUNCTION
)) ? function_from_jsdisp(jsdisp
) : NULL
;
92 static inline ArgumentsInstance
*arguments_from_jsdisp(jsdisp_t
*jsdisp
)
94 return CONTAINING_RECORD(jsdisp
, ArgumentsInstance
, jsdisp
);
97 static HRESULT
Arguments_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
104 static void Arguments_destructor(jsdisp_t
*jsdisp
)
106 ArgumentsInstance
*arguments
= arguments_from_jsdisp(jsdisp
);
108 TRACE("(%p)\n", arguments
);
112 for(i
= 0; i
< arguments
->argc
; i
++)
113 jsval_release(arguments
->buf
[i
]);
114 free(arguments
->buf
);
117 if(arguments
->function
)
118 jsdisp_release(&arguments
->function
->function
.dispex
);
122 static unsigned Arguments_idx_length(jsdisp_t
*jsdisp
)
124 ArgumentsInstance
*arguments
= arguments_from_jsdisp(jsdisp
);
125 return arguments
->argc
;
128 static jsval_t
*get_argument_ref(ArgumentsInstance
*arguments
, unsigned idx
)
131 return arguments
->buf
+ idx
;
132 if(arguments
->frame
->base_scope
->frame
|| idx
>= arguments
->frame
->function
->param_cnt
)
133 return arguments
->jsdisp
.ctx
->stack
+ arguments
->frame
->arguments_off
+ idx
;
137 static HRESULT
Arguments_idx_get(jsdisp_t
*jsdisp
, unsigned idx
, jsval_t
*r
)
139 ArgumentsInstance
*arguments
= arguments_from_jsdisp(jsdisp
);
142 TRACE("%p[%u]\n", arguments
, idx
);
144 if((ref
= get_argument_ref(arguments
, idx
)))
145 return jsval_copy(*ref
, r
);
147 /* FIXME: Accessing by name won't work for duplicated argument names */
148 return jsdisp_propget_name(arguments
->frame
->base_scope
->jsobj
,
149 arguments
->function
->func_code
->params
[idx
], r
);
152 static HRESULT
Arguments_idx_put(jsdisp_t
*jsdisp
, unsigned idx
, jsval_t val
)
154 ArgumentsInstance
*arguments
= arguments_from_jsdisp(jsdisp
);
158 TRACE("%p[%u] = %s\n", arguments
, idx
, debugstr_jsval(val
));
160 if((ref
= get_argument_ref(arguments
, idx
))) {
162 hres
= jsval_copy(val
, ©
);
171 /* FIXME: Accessing by name won't work for duplicated argument names */
172 return jsdisp_propput_name(arguments
->frame
->base_scope
->jsobj
,
173 arguments
->function
->func_code
->params
[idx
], val
);
176 static HRESULT
Arguments_gc_traverse(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, jsdisp_t
*jsdisp
)
178 ArgumentsInstance
*arguments
= arguments_from_jsdisp(jsdisp
);
183 for(i
= 0; i
< arguments
->argc
; i
++) {
184 hres
= gc_process_linked_val(gc_ctx
, op
, jsdisp
, &arguments
->buf
[i
]);
190 return gc_process_linked_obj(gc_ctx
, op
, jsdisp
, &arguments
->function
->function
.dispex
, (void**)&arguments
->function
);
193 static const builtin_info_t Arguments_info
= {
197 Arguments_destructor
,
199 Arguments_idx_length
,
202 Arguments_gc_traverse
205 HRESULT
setup_arguments_object(script_ctx_t
*ctx
, call_frame_t
*frame
)
207 ArgumentsInstance
*args
;
210 args
= calloc(1, sizeof(*args
));
212 return E_OUTOFMEMORY
;
214 hres
= init_dispex_from_constr(&args
->jsdisp
, ctx
, &Arguments_info
, ctx
->object_constr
);
220 args
->function
= (InterpretedFunction
*)function_from_jsdisp(jsdisp_addref(frame
->function_instance
));
221 args
->argc
= frame
->argc
;
224 hres
= jsdisp_define_data_property(&args
->jsdisp
, L
"length", PROPF_WRITABLE
| PROPF_CONFIGURABLE
,
225 jsval_number(args
->argc
));
227 hres
= jsdisp_define_data_property(&args
->jsdisp
, L
"callee", PROPF_WRITABLE
| PROPF_CONFIGURABLE
,
228 jsval_obj(&args
->function
->function
.dispex
));
230 hres
= jsdisp_propput(frame
->base_scope
->jsobj
, L
"arguments", PROPF_WRITABLE
, TRUE
, jsval_obj(&args
->jsdisp
));
232 jsdisp_release(&args
->jsdisp
);
236 frame
->arguments_obj
= &args
->jsdisp
;
240 void detach_arguments_object(jsdisp_t
*args_disp
)
242 ArgumentsInstance
*arguments
= arguments_from_jsdisp(args_disp
);
243 call_frame_t
*frame
= arguments
->frame
;
244 const BOOL on_stack
= frame
->base_scope
->frame
== frame
;
247 /* Reset arguments value to cut the reference cycle. Note that since all activation contexts have
248 * their own arguments property, it's impossible to use prototype's one during name lookup */
249 jsdisp_propput_name(frame
->base_scope
->jsobj
, L
"arguments", jsval_undefined());
250 arguments
->frame
= NULL
;
252 /* Don't bother coppying arguments if call frame holds the last reference. */
253 if(arguments
->jsdisp
.ref
> 1) {
254 arguments
->buf
= malloc(arguments
->argc
* sizeof(*arguments
->buf
));
258 for(i
= 0; i
< arguments
->argc
; i
++) {
259 if(on_stack
|| i
>= frame
->function
->param_cnt
)
260 hres
= jsval_copy(arguments
->jsdisp
.ctx
->stack
[frame
->arguments_off
+ i
], arguments
->buf
+i
);
262 hres
= jsdisp_propget_name(frame
->base_scope
->jsobj
, frame
->function
->params
[i
], arguments
->buf
+i
);
264 arguments
->buf
[i
] = jsval_undefined();
267 ERR("out of memory\n");
272 jsdisp_release(frame
->arguments_obj
);
275 HRESULT
Function_invoke(jsdisp_t
*func_this
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
277 FunctionInstance
*function
;
279 TRACE("func %p this %s\n", func_this
, debugstr_jsval(vthis
));
281 assert(is_class(func_this
, JSCLASS_FUNCTION
));
282 function
= function_from_jsdisp(func_this
);
284 if(function
->dispex
.ctx
->state
== SCRIPTSTATE_UNINITIALIZED
|| function
->dispex
.ctx
->state
== SCRIPTSTATE_CLOSED
) {
285 WARN("Script engine state does not allow running code.\n");
289 return function
->vtbl
->call(function
->dispex
.ctx
, function
, vthis
, flags
, argc
, argv
, r
);
292 static HRESULT
Function_get_length(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t
*r
)
294 TRACE("%p\n", jsthis
);
296 *r
= jsval_number(function_from_jsdisp(jsthis
)->length
);
300 static HRESULT
Function_toString(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
303 FunctionInstance
*function
;
309 if(!(function
= function_this(vthis
)))
310 return JS_E_FUNCTION_EXPECTED
;
312 hres
= function
->vtbl
->toString(function
, &str
);
317 *r
= jsval_string(str
);
323 static HRESULT
array_to_args(script_ctx_t
*ctx
, jsdisp_t
*arg_array
, unsigned *argc
, jsval_t
**ret
)
329 hres
= jsdisp_propget_name(arg_array
, L
"length", &val
);
333 hres
= to_uint32(ctx
, val
, &length
);
338 argv
= malloc(length
* sizeof(*argv
));
340 return E_OUTOFMEMORY
;
342 for(i
=0; i
<length
; i
++) {
343 hres
= jsdisp_get_idx(arg_array
, i
, argv
+i
);
344 if(hres
== DISP_E_UNKNOWNNAME
) {
345 argv
[i
] = jsval_undefined();
346 }else if(FAILED(hres
)) {
348 jsval_release(argv
[i
]);
359 static HRESULT
Function_apply(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
361 jsval_t this_val
= jsval_undefined();
362 FunctionInstance
*function
;
363 jsval_t
*args
= NULL
;
369 if(is_null_disp(vthis
))
370 return JS_E_OBJECT_REQUIRED
;
371 if(!is_object_instance(vthis
) || (!(function
= function_this(vthis
)) && to_jsdisp(get_object(vthis
))))
372 return JS_E_FUNCTION_EXPECTED
;
375 if(ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
&& !is_undefined(argv
[0]) && !is_null(argv
[0])) {
377 hres
= to_object(ctx
, argv
[0], &this_obj
);
380 this_val
= jsval_disp(this_obj
);
382 hres
= jsval_copy(argv
[0], &this_val
);
389 jsdisp_t
*arg_array
= NULL
;
391 if(is_object_instance(argv
[1])) {
392 arg_array
= iface_to_jsdisp(get_object(argv
[1]));
394 (!is_class(arg_array
, JSCLASS_ARRAY
) && !is_class(arg_array
, JSCLASS_ARGUMENTS
) )) {
395 jsdisp_release(arg_array
);
401 hres
= array_to_args(ctx
, arg_array
, &cnt
, &args
);
402 jsdisp_release(arg_array
);
404 FIXME("throw TypeError\n");
409 if(SUCCEEDED(hres
)) {
411 hres
= function
->vtbl
->call(ctx
, function
, this_val
, flags
, cnt
, args
, r
);
414 hres
= disp_call_value(ctx
, get_object(vthis
), this_val
, DISPATCH_METHOD
, cnt
, args
, &res
);
415 if(SUCCEEDED(hres
)) {
424 jsval_release(this_val
);
425 for(i
=0; i
< cnt
; i
++)
426 jsval_release(args
[i
]);
431 static HRESULT
Function_call(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
434 jsval_t this_val
= jsval_undefined();
435 FunctionInstance
*function
;
441 if(is_null_disp(vthis
))
442 return JS_E_OBJECT_REQUIRED
;
443 if(!(function
= function_this(vthis
)))
444 return JS_E_FUNCTION_EXPECTED
;
447 if(ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
&& !is_undefined(argv
[0]) && !is_null(argv
[0])) {
449 hres
= to_object(ctx
, argv
[0], &this_obj
);
452 this_val
= jsval_disp(this_obj
);
454 hres
= jsval_copy(argv
[0], &this_val
);
461 hres
= function
->vtbl
->call(ctx
, function
, this_val
, flags
, cnt
, argv
+ 1, r
);
463 jsval_release(this_val
);
467 static HRESULT
Function_bind(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
470 jsval_t bound_this
= jsval_undefined();
471 FunctionInstance
*function
;
472 jsdisp_t
*new_function
;
477 if(!(function
= function_this(vthis
)))
478 return JS_E_FUNCTION_EXPECTED
;
482 }else if(is_null(argv
[0])) {
483 bound_this
= argv
[0];
484 }else if(!is_undefined(argv
[0])) {
486 hres
= to_object(ctx
, argv
[0], &obj
);
489 bound_this
= jsval_disp(obj
);
492 hres
= create_bind_function(ctx
, function
, bound_this
, argc
- 1, argv
+ 1, &new_function
);
493 jsval_release(bound_this
);
498 *r
= jsval_obj(new_function
);
500 jsdisp_release(new_function
);
504 HRESULT
Function_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
507 FunctionInstance
*function
;
511 if(!(function
= function_this(vthis
))) {
512 ERR("dispex is not a function\n");
516 return function
->vtbl
->call(ctx
, function
, vthis
, flags
, argc
, argv
, r
);
519 HRESULT
Function_get_value(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t
*r
)
521 FunctionInstance
*function
= function_from_jsdisp(jsthis
);
527 hres
= function
->vtbl
->toString(function
, &str
);
531 *r
= jsval_string(str
);
535 static HRESULT
Function_get_arguments(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t
*r
)
537 FunctionInstance
*function
= function_from_jsdisp(jsthis
);
543 for(frame
= ctx
->call_ctx
; frame
; frame
= frame
->prev_frame
) {
544 if(frame
->function_instance
== &function
->dispex
) {
545 if(!frame
->arguments_obj
) {
546 hres
= setup_arguments_object(ctx
, frame
);
550 *r
= jsval_obj(jsdisp_addref(frame
->arguments_obj
));
559 function_code_t
*Function_get_code(jsdisp_t
*jsthis
)
561 FunctionInstance
*function
;
563 assert(is_class(jsthis
, JSCLASS_FUNCTION
));
564 function
= function_from_jsdisp(jsthis
);
566 return function
->vtbl
->get_code(function
);
569 static void Function_destructor(jsdisp_t
*dispex
)
571 FunctionInstance
*function
= function_from_jsdisp(dispex
);
572 function
->vtbl
->destructor(function
);
576 static HRESULT
Function_gc_traverse(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, jsdisp_t
*dispex
)
578 FunctionInstance
*function
= function_from_jsdisp(dispex
);
579 return function
->vtbl
->gc_traverse(gc_ctx
, op
, function
);
582 static const builtin_prop_t Function_props
[] = {
583 {L
"apply", Function_apply
, PROPF_METHOD
|2},
584 {L
"arguments", NULL
, 0, Function_get_arguments
},
585 {L
"bind", Function_bind
, PROPF_METHOD
|PROPF_ES5
|1},
586 {L
"call", Function_call
, PROPF_METHOD
|1},
587 {L
"length", NULL
, 0, Function_get_length
},
588 {L
"toString", Function_toString
, PROPF_METHOD
}
591 static const builtin_info_t Function_info
= {
594 ARRAY_SIZE(Function_props
),
604 static const builtin_prop_t FunctionInst_props
[] = {
605 {L
"arguments", NULL
, 0, Function_get_arguments
},
606 {L
"length", NULL
, 0, Function_get_length
}
609 static const builtin_info_t FunctionInst_info
= {
612 ARRAY_SIZE(FunctionInst_props
),
622 static HRESULT
create_function(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, const function_vtbl_t
*vtbl
, size_t size
,
623 DWORD flags
, BOOL funcprot
, jsdisp_t
*prototype
, void **ret
)
625 FunctionInstance
*function
;
628 function
= calloc(1, size
);
630 return E_OUTOFMEMORY
;
633 hres
= init_dispex(&function
->dispex
, ctx
, builtin_info
, prototype
);
634 else if(builtin_info
)
635 hres
= init_dispex_from_constr(&function
->dispex
, ctx
, builtin_info
, ctx
->function_constr
);
637 hres
= init_dispex_from_constr(&function
->dispex
, ctx
, &FunctionInst_info
, ctx
->function_constr
);
643 function
->vtbl
= vtbl
;
644 function
->flags
= flags
;
645 function
->length
= flags
& PROPF_ARGMASK
;
651 static HRESULT
NativeFunction_call(script_ctx_t
*ctx
, FunctionInstance
*func
, jsval_t vthis
, unsigned flags
,
652 unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
654 NativeFunction
*function
= (NativeFunction
*)func
;
656 if((flags
& DISPATCH_CONSTRUCT
) && !(function
->function
.flags
& PROPF_CONSTR
))
657 return JS_E_INVALID_ACTION
;
658 return function
->proc(ctx
, vthis
, flags
& ~DISPATCH_JSCRIPT_INTERNAL_MASK
, argc
, argv
, r
);
661 static HRESULT
NativeFunction_toString(FunctionInstance
*func
, jsstr_t
**ret
)
663 NativeFunction
*function
= (NativeFunction
*)func
;
668 static const WCHAR native_prefixW
[] = L
"\nfunction ";
669 static const WCHAR native_suffixW
[] = L
"() {\n [native code]\n}\n";
671 name_len
= function
->name
? lstrlenW(function
->name
) : 0;
672 str
= jsstr_alloc_buf(ARRAY_SIZE(native_prefixW
) + ARRAY_SIZE(native_suffixW
) + name_len
- 2, &ptr
);
674 return E_OUTOFMEMORY
;
676 memcpy(ptr
, native_prefixW
, sizeof(native_prefixW
));
677 ptr
+= ARRAY_SIZE(native_prefixW
) - 1;
678 memcpy(ptr
, function
->name
, name_len
*sizeof(WCHAR
));
680 memcpy(ptr
, native_suffixW
, sizeof(native_suffixW
));
686 static function_code_t
*NativeFunction_get_code(FunctionInstance
*function
)
691 static void NativeFunction_destructor(FunctionInstance
*function
)
695 static const function_vtbl_t NativeFunctionVtbl
= {
697 NativeFunction_toString
,
698 NativeFunction_get_code
,
699 NativeFunction_destructor
,
703 HRESULT
create_builtin_function(script_ctx_t
*ctx
, builtin_invoke_t value_proc
, const WCHAR
*name
,
704 const builtin_info_t
*builtin_info
, DWORD flags
, jsdisp_t
*prototype
, jsdisp_t
**ret
)
706 NativeFunction
*function
;
709 if(!ctx
->function_constr
)
712 hres
= create_function(ctx
, builtin_info
, &NativeFunctionVtbl
, sizeof(NativeFunction
), flags
, FALSE
, NULL
, (void**)&function
);
717 hres
= jsdisp_define_data_property(&function
->function
.dispex
, L
"length", 0,
718 jsval_number(function
->function
.length
));
720 hres
= jsdisp_define_data_property(&function
->function
.dispex
, L
"prototype", 0, prototype
? jsval_obj(prototype
) : jsval_null());
722 jsdisp_release(&function
->function
.dispex
);
726 function
->proc
= value_proc
;
727 function
->name
= name
;
729 *ret
= &function
->function
.dispex
;
733 static HRESULT
set_constructor_prop(script_ctx_t
*ctx
, jsdisp_t
*constr
, jsdisp_t
*prot
)
735 return jsdisp_define_data_property(prot
, L
"constructor", PROPF_WRITABLE
| PROPF_CONFIGURABLE
,
739 HRESULT
create_builtin_constructor(script_ctx_t
*ctx
, builtin_invoke_t value_proc
, const WCHAR
*name
,
740 const builtin_info_t
*builtin_info
, DWORD flags
, jsdisp_t
*prototype
, jsdisp_t
**ret
)
745 hres
= create_builtin_function(ctx
, value_proc
, name
, builtin_info
, flags
, prototype
, &constr
);
749 hres
= set_constructor_prop(ctx
, constr
, prototype
);
751 jsdisp_release(constr
);
760 * Create the actual prototype on demand, since it is a circular ref, which prevents the vast
761 * majority of functions from being released quickly, leading to unnecessary scope detach.
763 static HRESULT
InterpretedFunction_get_prototype(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t
*r
)
768 hres
= create_object(ctx
, NULL
, &prototype
);
772 hres
= jsdisp_define_data_property(jsthis
, L
"prototype", PROPF_WRITABLE
, jsval_obj(prototype
));
774 hres
= set_constructor_prop(ctx
, jsthis
, prototype
);
776 jsdisp_release(prototype
);
780 *r
= jsval_obj(prototype
);
784 static HRESULT
InterpretedFunction_set_prototype(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
786 return jsdisp_define_data_property(jsthis
, L
"prototype", PROPF_WRITABLE
, value
);
789 static const builtin_prop_t InterpretedFunction_props
[] = {
790 {L
"arguments", NULL
, 0, Function_get_arguments
},
791 {L
"length", NULL
, 0, Function_get_length
},
792 {L
"prototype", NULL
, 0, InterpretedFunction_get_prototype
, InterpretedFunction_set_prototype
}
795 static const builtin_info_t InterpretedFunction_info
= {
798 ARRAY_SIZE(InterpretedFunction_props
),
799 InterpretedFunction_props
,
808 static HRESULT
InterpretedFunction_call(script_ctx_t
*ctx
, FunctionInstance
*func
, jsval_t vthis
, unsigned flags
,
809 unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
811 InterpretedFunction
*function
= (InterpretedFunction
*)func
;
812 IDispatch
*this_obj
= NULL
;
813 DWORD exec_flags
= 0;
817 TRACE("%p\n", function
);
819 if(flags
& DISPATCH_CONSTRUCT
) {
820 hres
= create_object(ctx
, &function
->function
.dispex
, &new_obj
);
823 this_obj
= to_disp(new_obj
);
824 }else if(is_object_instance(vthis
)) {
825 this_obj
= get_object(vthis
);
826 IDispatch_AddRef(this_obj
);
827 }else if(ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
&& !is_undefined(vthis
) && !is_null(vthis
)) {
828 hres
= to_object(ctx
, vthis
, &this_obj
);
833 if(flags
& DISPATCH_JSCRIPT_CALLEREXECSSOURCE
)
834 exec_flags
|= EXEC_RETURN_TO_INTERP
;
835 if(flags
& DISPATCH_CONSTRUCT
)
836 exec_flags
|= EXEC_CONSTRUCTOR
;
837 hres
= exec_source(ctx
, exec_flags
, function
->code
, function
->func_code
, function
->scope_chain
, this_obj
,
838 &function
->function
.dispex
, argc
, argv
, r
);
840 IDispatch_Release(this_obj
);
844 static HRESULT
InterpretedFunction_toString(FunctionInstance
*func
, jsstr_t
**ret
)
846 InterpretedFunction
*function
= (InterpretedFunction
*)func
;
848 *ret
= jsstr_alloc_len(function
->func_code
->source
, function
->func_code
->source_len
);
849 return *ret
? S_OK
: E_OUTOFMEMORY
;
852 static function_code_t
*InterpretedFunction_get_code(FunctionInstance
*func
)
854 InterpretedFunction
*function
= (InterpretedFunction
*)func
;
856 return function
->func_code
;
859 static void InterpretedFunction_destructor(FunctionInstance
*func
)
861 InterpretedFunction
*function
= (InterpretedFunction
*)func
;
863 release_bytecode(function
->code
);
864 if(function
->scope_chain
)
865 scope_release(function
->scope_chain
);
868 static HRESULT
InterpretedFunction_gc_traverse(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, FunctionInstance
*func
)
870 InterpretedFunction
*function
= (InterpretedFunction
*)func
;
872 if(!function
->scope_chain
)
874 return gc_process_linked_obj(gc_ctx
, op
, &function
->function
.dispex
, &function
->scope_chain
->dispex
,
875 (void**)&function
->scope_chain
);
878 static const function_vtbl_t InterpretedFunctionVtbl
= {
879 InterpretedFunction_call
,
880 InterpretedFunction_toString
,
881 InterpretedFunction_get_code
,
882 InterpretedFunction_destructor
,
883 InterpretedFunction_gc_traverse
886 HRESULT
create_source_function(script_ctx_t
*ctx
, bytecode_t
*code
, function_code_t
*func_code
,
887 scope_chain_t
*scope_chain
, jsdisp_t
**ret
)
889 InterpretedFunction
*function
;
892 hres
= create_function(ctx
, &InterpretedFunction_info
, &InterpretedFunctionVtbl
, sizeof(InterpretedFunction
),
893 PROPF_CONSTR
, FALSE
, NULL
, (void**)&function
);
898 scope_addref(scope_chain
);
899 function
->scope_chain
= scope_chain
;
902 bytecode_addref(code
);
903 function
->code
= code
;
904 function
->func_code
= func_code
;
905 function
->function
.length
= function
->func_code
->param_cnt
;
907 *ret
= &function
->function
.dispex
;
911 static HRESULT
BindFunction_call(script_ctx_t
*ctx
, FunctionInstance
*func
, jsval_t vthis
, unsigned flags
,
912 unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
914 BindFunction
*function
= (BindFunction
*)func
;
915 jsval_t
*call_args
= NULL
;
919 TRACE("%p\n", function
);
921 call_argc
= function
->argc
+ argc
;
923 call_args
= malloc(call_argc
* sizeof(*call_args
));
925 return E_OUTOFMEMORY
;
928 memcpy(call_args
, function
->args
, function
->argc
* sizeof(*call_args
));
930 memcpy(call_args
+ function
->argc
, argv
, argc
* sizeof(*call_args
));
933 hres
= function
->target
->vtbl
->call(ctx
, function
->target
, function
->this, flags
, call_argc
, call_args
, r
);
939 static HRESULT
BindFunction_toString(FunctionInstance
*function
, jsstr_t
**ret
)
941 *ret
= jsstr_alloc(L
"\nfunction() {\n [native code]\n}\n");
942 return *ret
? S_OK
: E_OUTOFMEMORY
;
945 static function_code_t
*BindFunction_get_code(FunctionInstance
*function
)
950 static void BindFunction_destructor(FunctionInstance
*func
)
952 BindFunction
*function
= (BindFunction
*)func
;
955 TRACE("%p\n", function
);
957 for(i
= 0; i
< function
->argc
; i
++)
958 jsval_release(function
->args
[i
]);
960 jsdisp_release(&function
->target
->dispex
);
961 jsval_release(function
->this);
964 static HRESULT
BindFunction_gc_traverse(struct gc_ctx
*gc_ctx
, enum gc_traverse_op op
, FunctionInstance
*func
)
966 BindFunction
*function
= (BindFunction
*)func
;
970 for(i
= 0; i
< function
->argc
; i
++) {
971 hres
= gc_process_linked_val(gc_ctx
, op
, &function
->function
.dispex
, &function
->args
[i
]);
976 hres
= gc_process_linked_obj(gc_ctx
, op
, &function
->function
.dispex
, &function
->target
->dispex
, (void**)&function
->target
);
980 return gc_process_linked_val(gc_ctx
, op
, &function
->function
.dispex
, &function
->this);
983 static const function_vtbl_t BindFunctionVtbl
= {
985 BindFunction_toString
,
986 BindFunction_get_code
,
987 BindFunction_destructor
,
988 BindFunction_gc_traverse
991 static HRESULT
create_bind_function(script_ctx_t
*ctx
, FunctionInstance
*target
, jsval_t bound_this
, unsigned argc
,
992 jsval_t
*argv
, jsdisp_t
**ret
)
994 BindFunction
*function
;
997 hres
= create_function(ctx
, NULL
, &BindFunctionVtbl
, FIELD_OFFSET(BindFunction
, args
[argc
]), PROPF_METHOD
,
998 FALSE
, NULL
, (void**)&function
);
1002 jsdisp_addref(&target
->dispex
);
1003 function
->target
= target
;
1005 hres
= jsval_copy(bound_this
, &function
->this);
1007 jsdisp_release(&function
->function
.dispex
);
1011 for(function
->argc
= 0; function
->argc
< argc
; function
->argc
++) {
1012 hres
= jsval_copy(argv
[function
->argc
], function
->args
+ function
->argc
);
1014 jsdisp_release(&function
->function
.dispex
);
1019 function
->function
.length
= target
->length
> argc
? target
->length
- argc
: 0;
1021 *ret
= &function
->function
.dispex
;
1025 static HRESULT
construct_function(script_ctx_t
*ctx
, unsigned argc
, jsval_t
*argv
, IDispatch
**ret
)
1027 WCHAR
*str
= NULL
, *ptr
;
1028 unsigned len
= 0, i
= 0;
1031 jsstr_t
**params
= NULL
;
1033 HRESULT hres
= S_OK
;
1035 static const WCHAR function_anonymousW
[] = L
"function anonymous(";
1036 static const WCHAR function_beginW
[] = L
") {\n";
1037 static const WCHAR function_endW
[] = L
"\n}";
1040 params
= malloc(argc
*sizeof(*params
));
1042 return E_OUTOFMEMORY
;
1045 len
= (argc
-2)*2; /* separating commas */
1046 for(i
=0; i
< argc
; i
++) {
1047 hres
= to_string(ctx
, argv
[i
], params
+i
);
1050 len
+= jsstr_length(params
[i
]);
1054 if(SUCCEEDED(hres
)) {
1055 len
+= ARRAY_SIZE(function_anonymousW
) + ARRAY_SIZE(function_beginW
) + ARRAY_SIZE(function_endW
) - 2;
1056 str
= malloc(len
*sizeof(WCHAR
));
1058 memcpy(str
, function_anonymousW
, sizeof(function_anonymousW
));
1059 ptr
= str
+ ARRAY_SIZE(function_anonymousW
) - 1;
1062 ptr
+= jsstr_flush(params
[j
], ptr
);
1069 memcpy(ptr
, function_beginW
, sizeof(function_beginW
));
1070 ptr
+= ARRAY_SIZE(function_beginW
) - 1;
1072 ptr
+= jsstr_flush(params
[argc
-1], ptr
);
1073 memcpy(ptr
, function_endW
, sizeof(function_endW
));
1075 TRACE("%s\n", debugstr_w(str
));
1077 hres
= E_OUTOFMEMORY
;
1082 jsstr_release(params
[--i
]);
1087 hres
= compile_script(ctx
, str
, 0, 0, NULL
, NULL
, FALSE
, FALSE
,
1088 ctx
->call_ctx
? ctx
->call_ctx
->bytecode
->named_item
: NULL
, &code
);
1093 if(code
->global_code
.func_cnt
!= 1 || code
->global_code
.var_cnt
!= 1) {
1094 ERR("Invalid parser result!\n");
1095 release_bytecode(code
);
1096 return E_UNEXPECTED
;
1099 hres
= create_source_function(ctx
, code
, code
->global_code
.funcs
, NULL
, &function
);
1100 release_bytecode(code
);
1104 *ret
= to_disp(function
);
1108 static HRESULT
FunctionConstr_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1116 case DISPATCH_METHOD
:
1117 case DISPATCH_CONSTRUCT
: {
1120 hres
= construct_function(ctx
, argc
, argv
, &ret
);
1124 if(r
) *r
= jsval_disp(ret
);
1125 else IDispatch_Release(ret
);
1129 FIXME("unimplemented flags %x\n", flags
);
1136 static HRESULT
FunctionProt_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1143 HRESULT
init_function_constr(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
)
1145 NativeFunction
*prot
, *constr
;
1148 hres
= create_function(ctx
, &Function_info
, &NativeFunctionVtbl
, sizeof(NativeFunction
), PROPF_CONSTR
,
1149 TRUE
, object_prototype
, (void**)&prot
);
1153 prot
->proc
= FunctionProt_value
;
1154 prot
->name
= L
"prototype";
1156 hres
= create_function(ctx
, &FunctionInst_info
, &NativeFunctionVtbl
, sizeof(NativeFunction
), PROPF_CONSTR
|1,
1157 TRUE
, &prot
->function
.dispex
, (void**)&constr
);
1158 if(SUCCEEDED(hres
)) {
1159 constr
->proc
= FunctionConstr_value
;
1160 constr
->name
= L
"Function";
1161 hres
= jsdisp_define_data_property(&constr
->function
.dispex
, L
"prototype", 0, jsval_obj(&prot
->function
.dispex
));
1163 hres
= set_constructor_prop(ctx
, &constr
->function
.dispex
, &prot
->function
.dispex
);
1165 jsdisp_release(&constr
->function
.dispex
);
1167 jsdisp_release(&prot
->function
.dispex
);
1171 ctx
->function_constr
= &constr
->function
.dispex
;