jscript: Use bytecode for '&=' expression implementation.
[wine] / dlls / jscript / jscript.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <assert.h>
20
21 #include "jscript.h"
22 #include "engine.h"
23 #include "objsafe.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28
29 #ifdef _WIN64
30
31 #define CTXARG_T DWORDLONG
32 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
33 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_64Vtbl
34
35 #else
36
37 #define CTXARG_T DWORD
38 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
39 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_32Vtbl
40
41 #endif
42
43 typedef struct {
44     IActiveScript                IActiveScript_iface;
45     IActiveScriptParse           IActiveScriptParse_iface;
46     IActiveScriptParseProcedure2 IActiveScriptParseProcedure2_iface;
47     IActiveScriptProperty        IActiveScriptProperty_iface;
48     IObjectSafety                IObjectSafety_iface;
49
50     LONG ref;
51
52     DWORD safeopt;
53     script_ctx_t *ctx;
54     LONG thread_id;
55     LCID lcid;
56     DWORD version;
57
58     IActiveScriptSite *site;
59
60     parser_ctx_t *queue_head;
61     parser_ctx_t *queue_tail;
62 } JScript;
63
64 void script_release(script_ctx_t *ctx)
65 {
66     if(--ctx->ref)
67         return;
68
69     if(ctx->cc)
70         release_cc(ctx->cc);
71     jsheap_free(&ctx->tmp_heap);
72     SysFreeString(ctx->last_match);
73     heap_free(ctx);
74 }
75
76 static void change_state(JScript *This, SCRIPTSTATE state)
77 {
78     if(This->ctx->state == state)
79         return;
80
81     This->ctx->state = state;
82     if(This->site)
83         IActiveScriptSite_OnStateChange(This->site, state);
84 }
85
86 static inline BOOL is_started(script_ctx_t *ctx)
87 {
88     return ctx->state == SCRIPTSTATE_STARTED
89         || ctx->state == SCRIPTSTATE_CONNECTED
90         || ctx->state == SCRIPTSTATE_DISCONNECTED;
91 }
92
93 static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
94 {
95     exec_ctx_t *exec_ctx;
96     jsexcept_t jsexcept;
97     HRESULT hres;
98
99     hres = create_exec_ctx(This->ctx, NULL, This->ctx->global, NULL, TRUE, &exec_ctx);
100     if(FAILED(hres))
101         return hres;
102
103     IActiveScriptSite_OnEnterScript(This->site);
104
105     memset(&jsexcept, 0, sizeof(jsexcept));
106     hres = exec_source(exec_ctx, parser_ctx, parser_ctx->source, FALSE, &jsexcept, NULL);
107     VariantClear(&jsexcept.var);
108     exec_release(exec_ctx);
109
110     IActiveScriptSite_OnLeaveScript(This->site);
111     return hres;
112 }
113
114 static void clear_script_queue(JScript *This)
115 {
116     parser_ctx_t *iter, *iter2;
117
118     if(!This->queue_head)
119         return;
120
121     iter = This->queue_head;
122     while(iter) {
123         iter2 = iter->next;
124         iter->next = NULL;
125         parser_release(iter);
126         iter = iter2;
127     }
128
129     This->queue_head = This->queue_tail = NULL;
130 }
131
132 static void exec_queued_code(JScript *This)
133 {
134     parser_ctx_t *iter;
135
136     for(iter = This->queue_head; iter; iter = iter->next)
137         exec_global_code(This, iter);
138
139     clear_script_queue(This);
140 }
141
142 static HRESULT set_ctx_site(JScript *This)
143 {
144     HRESULT hres;
145
146     This->ctx->lcid = This->lcid;
147
148     hres = init_global(This->ctx);
149     if(FAILED(hres))
150         return hres;
151
152     IActiveScriptSite_AddRef(This->site);
153     This->ctx->site = This->site;
154
155     change_state(This, SCRIPTSTATE_INITIALIZED);
156     return S_OK;
157 }
158
159 static void decrease_state(JScript *This, SCRIPTSTATE state)
160 {
161     if(This->ctx) {
162         switch(This->ctx->state) {
163         case SCRIPTSTATE_CONNECTED:
164             change_state(This, SCRIPTSTATE_DISCONNECTED);
165             if(state == SCRIPTSTATE_DISCONNECTED)
166                 return;
167             /* FALLTHROUGH */
168         case SCRIPTSTATE_STARTED:
169         case SCRIPTSTATE_DISCONNECTED:
170             clear_script_queue(This);
171
172             if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
173                 change_state(This, SCRIPTSTATE_INITIALIZED);
174             if(state == SCRIPTSTATE_INITIALIZED)
175                 return;
176             /* FALLTHROUGH */
177         case SCRIPTSTATE_INITIALIZED:
178             if(This->ctx->host_global) {
179                 IDispatch_Release(This->ctx->host_global);
180                 This->ctx->host_global = NULL;
181             }
182
183             if(This->ctx->named_items) {
184                 named_item_t *iter, *iter2;
185
186                 iter = This->ctx->named_items;
187                 while(iter) {
188                     iter2 = iter->next;
189
190                     if(iter->disp)
191                         IDispatch_Release(iter->disp);
192                     heap_free(iter->name);
193                     heap_free(iter);
194                     iter = iter2;
195                 }
196
197                 This->ctx->named_items = NULL;
198             }
199
200             if(This->ctx->secmgr) {
201                 IInternetHostSecurityManager_Release(This->ctx->secmgr);
202                 This->ctx->secmgr = NULL;
203             }
204
205             if(This->ctx->site) {
206                 IActiveScriptSite_Release(This->ctx->site);
207                 This->ctx->site = NULL;
208             }
209
210             if(This->ctx->global) {
211                 jsdisp_release(This->ctx->global);
212                 This->ctx->global = NULL;
213             }
214             /* FALLTHROUGH */
215         case SCRIPTSTATE_UNINITIALIZED:
216             change_state(This, state);
217             break;
218         default:
219             assert(0);
220         }
221
222         change_state(This, state);
223     }else if(state == SCRIPTSTATE_UNINITIALIZED) {
224         if(This->site)
225             IActiveScriptSite_OnStateChange(This->site, state);
226     }else {
227         FIXME("NULL ctx\n");
228     }
229
230     if(state == SCRIPTSTATE_UNINITIALIZED)
231         This->thread_id = 0;
232
233     if(This->site) {
234         IActiveScriptSite_Release(This->site);
235         This->site = NULL;
236     }
237 }
238
239 typedef struct {
240     IServiceProvider IServiceProvider_iface;
241
242     LONG ref;
243
244     IServiceProvider *sp;
245 } AXSite;
246
247 static inline AXSite *impl_from_IServiceProvider(IServiceProvider *iface)
248 {
249     return CONTAINING_RECORD(iface, AXSite, IServiceProvider_iface);
250 }
251
252 static HRESULT WINAPI AXSite_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
253 {
254     AXSite *This = impl_from_IServiceProvider(iface);
255
256     if(IsEqualGUID(&IID_IUnknown, riid)) {
257         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
258         *ppv = &This->IServiceProvider_iface;
259     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
260         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
261         *ppv = &This->IServiceProvider_iface;
262     }else {
263         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
264         *ppv = NULL;
265         return E_NOINTERFACE;
266     }
267
268     IUnknown_AddRef((IUnknown*)*ppv);
269     return S_OK;
270 }
271
272 static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface)
273 {
274     AXSite *This = impl_from_IServiceProvider(iface);
275     LONG ref = InterlockedIncrement(&This->ref);
276
277     TRACE("(%p) ref=%d\n", This, ref);
278
279     return ref;
280 }
281
282 static ULONG WINAPI AXSite_Release(IServiceProvider *iface)
283 {
284     AXSite *This = impl_from_IServiceProvider(iface);
285     LONG ref = InterlockedDecrement(&This->ref);
286
287     TRACE("(%p) ref=%d\n", This, ref);
288
289     if(!ref)
290         heap_free(This);
291
292     return ref;
293 }
294
295 static HRESULT WINAPI AXSite_QueryService(IServiceProvider *iface,
296         REFGUID guidService, REFIID riid, void **ppv)
297 {
298     AXSite *This = impl_from_IServiceProvider(iface);
299
300     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
301
302     return IServiceProvider_QueryService(This->sp, guidService, riid, ppv);
303 }
304
305 static IServiceProviderVtbl AXSiteVtbl = {
306     AXSite_QueryInterface,
307     AXSite_AddRef,
308     AXSite_Release,
309     AXSite_QueryService
310 };
311
312 IUnknown *create_ax_site(script_ctx_t *ctx)
313 {
314     IServiceProvider *sp;
315     AXSite *ret;
316     HRESULT hres;
317
318     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp);
319     if(FAILED(hres)) {
320         ERR("Could not get IServiceProvider iface: %08x\n", hres);
321         return NULL;
322     }
323
324     ret = heap_alloc(sizeof(AXSite));
325     if(!ret) {
326         IServiceProvider_Release(sp);
327         return NULL;
328     }
329
330     ret->IServiceProvider_iface.lpVtbl = &AXSiteVtbl;
331     ret->ref = 1;
332     ret->sp = sp;
333
334     return (IUnknown*)&ret->IServiceProvider_iface;
335 }
336
337 static inline JScript *impl_from_IActiveScript(IActiveScript *iface)
338 {
339     return CONTAINING_RECORD(iface, JScript, IActiveScript_iface);
340 }
341
342 static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
343 {
344     JScript *This = impl_from_IActiveScript(iface);
345
346     *ppv = NULL;
347
348     if(IsEqualGUID(riid, &IID_IUnknown)) {
349         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
350         *ppv = &This->IActiveScript_iface;
351     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
352         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
353         *ppv = &This->IActiveScript_iface;
354     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
355         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
356         *ppv = &This->IActiveScriptParse_iface;
357     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure)) {
358         TRACE("(%p)->(IID_IActiveScriptParseProcedure %p)\n", This, ppv);
359         *ppv = &This->IActiveScriptParseProcedure2_iface;
360     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure2)) {
361         TRACE("(%p)->(IID_IActiveScriptParseProcedure2 %p)\n", This, ppv);
362         *ppv = &This->IActiveScriptParseProcedure2_iface;
363     }else if(IsEqualGUID(riid, &IID_IActiveScriptProperty)) {
364         TRACE("(%p)->(IID_IActiveScriptProperty %p)\n", This, ppv);
365         *ppv = &This->IActiveScriptProperty_iface;
366     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
367         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
368         *ppv = &This->IObjectSafety_iface;
369     }
370
371     if(*ppv) {
372         IUnknown_AddRef((IUnknown*)*ppv);
373         return S_OK;
374     }
375
376     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
377     return E_NOINTERFACE;
378 }
379
380 static ULONG WINAPI JScript_AddRef(IActiveScript *iface)
381 {
382     JScript *This = impl_from_IActiveScript(iface);
383     LONG ref = InterlockedIncrement(&This->ref);
384
385     TRACE("(%p) ref=%d\n", This, ref);
386
387     return ref;
388 }
389
390 static ULONG WINAPI JScript_Release(IActiveScript *iface)
391 {
392     JScript *This = impl_from_IActiveScript(iface);
393     LONG ref = InterlockedDecrement(&This->ref);
394
395     TRACE("(%p) ref=%d\n", iface, ref);
396
397     if(!ref) {
398         if(This->ctx && This->ctx->state != SCRIPTSTATE_CLOSED)
399             IActiveScript_Close(&This->IActiveScript_iface);
400         if(This->ctx)
401             script_release(This->ctx);
402         heap_free(This);
403         unlock_module();
404     }
405
406     return ref;
407 }
408
409 static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
410                                             IActiveScriptSite *pass)
411 {
412     JScript *This = impl_from_IActiveScript(iface);
413     LCID lcid;
414     HRESULT hres;
415
416     TRACE("(%p)->(%p)\n", This, pass);
417
418     if(!pass)
419         return E_POINTER;
420
421     if(This->site)
422         return E_UNEXPECTED;
423
424     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
425         return E_UNEXPECTED;
426
427     This->site = pass;
428     IActiveScriptSite_AddRef(This->site);
429
430     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
431     if(hres == S_OK)
432         This->lcid = lcid;
433
434     return This->ctx ? set_ctx_site(This) : S_OK;
435 }
436
437 static HRESULT WINAPI JScript_GetScriptSite(IActiveScript *iface, REFIID riid,
438                                             void **ppvObject)
439 {
440     JScript *This = impl_from_IActiveScript(iface);
441     FIXME("(%p)->()\n", This);
442     return E_NOTIMPL;
443 }
444
445 static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
446 {
447     JScript *This = impl_from_IActiveScript(iface);
448
449     TRACE("(%p)->(%d)\n", This, ss);
450
451     if(This->thread_id && GetCurrentThreadId() != This->thread_id)
452         return E_UNEXPECTED;
453
454     if(ss == SCRIPTSTATE_UNINITIALIZED) {
455         if(This->ctx && This->ctx->state == SCRIPTSTATE_CLOSED)
456             return E_UNEXPECTED;
457
458         decrease_state(This, SCRIPTSTATE_UNINITIALIZED);
459         return S_OK;
460     }
461
462     if(!This->ctx)
463         return E_UNEXPECTED;
464
465     switch(ss) {
466     case SCRIPTSTATE_STARTED:
467     case SCRIPTSTATE_CONNECTED: /* FIXME */
468         if(This->ctx->state == SCRIPTSTATE_CLOSED)
469             return E_UNEXPECTED;
470
471         exec_queued_code(This);
472         break;
473     case SCRIPTSTATE_INITIALIZED:
474         FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n");
475         return S_OK;
476     default:
477         FIXME("unimplemented state %d\n", ss);
478         return E_NOTIMPL;
479     }
480
481     change_state(This, ss);
482     return S_OK;
483 }
484
485 static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
486 {
487     JScript *This = impl_from_IActiveScript(iface);
488
489     TRACE("(%p)->(%p)\n", This, pssState);
490
491     if(!pssState)
492         return E_POINTER;
493
494     if(This->thread_id && This->thread_id != GetCurrentThreadId())
495         return E_UNEXPECTED;
496
497     *pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED;
498     return S_OK;
499 }
500
501 static HRESULT WINAPI JScript_Close(IActiveScript *iface)
502 {
503     JScript *This = impl_from_IActiveScript(iface);
504
505     TRACE("(%p)->()\n", This);
506
507     if(This->thread_id && This->thread_id != GetCurrentThreadId())
508         return E_UNEXPECTED;
509
510     decrease_state(This, SCRIPTSTATE_CLOSED);
511     return S_OK;
512 }
513
514 static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
515                                            LPCOLESTR pstrName, DWORD dwFlags)
516 {
517     JScript *This = impl_from_IActiveScript(iface);
518     named_item_t *item;
519     IDispatch *disp = NULL;
520     HRESULT hres;
521
522     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
523
524     if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED)
525         return E_UNEXPECTED;
526
527     if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) {
528         IUnknown *unk;
529
530         hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL);
531         if(FAILED(hres)) {
532             WARN("GetItemInfo failed: %08x\n", hres);
533             return hres;
534         }
535
536         hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
537         IUnknown_Release(unk);
538         if(FAILED(hres)) {
539             WARN("object does not implement IDispatch\n");
540             return hres;
541         }
542
543         if(This->ctx->host_global)
544             IDispatch_Release(This->ctx->host_global);
545         IDispatch_AddRef(disp);
546         This->ctx->host_global = disp;
547     }
548
549     item = heap_alloc(sizeof(*item));
550     if(!item) {
551         if(disp)
552             IDispatch_Release(disp);
553         return E_OUTOFMEMORY;
554     }
555
556     item->disp = disp;
557     item->flags = dwFlags;
558     item->name = heap_strdupW(pstrName);
559     if(!item->name) {
560         if(disp)
561             IDispatch_Release(disp);
562         heap_free(item);
563         return E_OUTOFMEMORY;
564     }
565
566     item->next = This->ctx->named_items;
567     This->ctx->named_items = item;
568
569     return S_OK;
570 }
571
572 static HRESULT WINAPI JScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
573                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
574 {
575     JScript *This = impl_from_IActiveScript(iface);
576     FIXME("(%p)->()\n", This);
577     return E_NOTIMPL;
578 }
579
580 static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
581                                                 IDispatch **ppdisp)
582 {
583     JScript *This = impl_from_IActiveScript(iface);
584
585     TRACE("(%p)->(%p)\n", This, ppdisp);
586
587     if(!ppdisp)
588         return E_POINTER;
589
590     if(This->thread_id != GetCurrentThreadId() || !This->ctx->global) {
591         *ppdisp = NULL;
592         return E_UNEXPECTED;
593     }
594
595     *ppdisp = to_disp(This->ctx->global);
596     IDispatch_AddRef(*ppdisp);
597     return S_OK;
598 }
599
600 static HRESULT WINAPI JScript_GetCurrentScriptThreadID(IActiveScript *iface,
601                                                        SCRIPTTHREADID *pstridThread)
602 {
603     JScript *This = impl_from_IActiveScript(iface);
604     FIXME("(%p)->()\n", This);
605     return E_NOTIMPL;
606 }
607
608 static HRESULT WINAPI JScript_GetScriptThreadID(IActiveScript *iface,
609                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
610 {
611     JScript *This = impl_from_IActiveScript(iface);
612     FIXME("(%p)->()\n", This);
613     return E_NOTIMPL;
614 }
615
616 static HRESULT WINAPI JScript_GetScriptThreadState(IActiveScript *iface,
617         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
618 {
619     JScript *This = impl_from_IActiveScript(iface);
620     FIXME("(%p)->()\n", This);
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI JScript_InterruptScriptThread(IActiveScript *iface,
625         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
626 {
627     JScript *This = impl_from_IActiveScript(iface);
628     FIXME("(%p)->()\n", This);
629     return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI JScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
633 {
634     JScript *This = impl_from_IActiveScript(iface);
635     FIXME("(%p)->()\n", This);
636     return E_NOTIMPL;
637 }
638
639 static const IActiveScriptVtbl JScriptVtbl = {
640     JScript_QueryInterface,
641     JScript_AddRef,
642     JScript_Release,
643     JScript_SetScriptSite,
644     JScript_GetScriptSite,
645     JScript_SetScriptState,
646     JScript_GetScriptState,
647     JScript_Close,
648     JScript_AddNamedItem,
649     JScript_AddTypeLib,
650     JScript_GetScriptDispatch,
651     JScript_GetCurrentScriptThreadID,
652     JScript_GetScriptThreadID,
653     JScript_GetScriptThreadState,
654     JScript_InterruptScriptThread,
655     JScript_Clone
656 };
657
658 static inline JScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
659 {
660     return CONTAINING_RECORD(iface, JScript, IActiveScriptParse_iface);
661 }
662
663 static HRESULT WINAPI JScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
664 {
665     JScript *This = impl_from_IActiveScriptParse(iface);
666     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
667 }
668
669 static ULONG WINAPI JScriptParse_AddRef(IActiveScriptParse *iface)
670 {
671     JScript *This = impl_from_IActiveScriptParse(iface);
672     return IActiveScript_AddRef(&This->IActiveScript_iface);
673 }
674
675 static ULONG WINAPI JScriptParse_Release(IActiveScriptParse *iface)
676 {
677     JScript *This = impl_from_IActiveScriptParse(iface);
678     return IActiveScript_Release(&This->IActiveScript_iface);
679 }
680
681 static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface)
682 {
683     JScript *This = impl_from_IActiveScriptParse(iface);
684     script_ctx_t *ctx;
685
686     TRACE("(%p)\n", This);
687
688     if(This->ctx)
689         return E_UNEXPECTED;
690
691     ctx = heap_alloc_zero(sizeof(script_ctx_t));
692     if(!ctx)
693         return E_OUTOFMEMORY;
694
695     ctx->ref = 1;
696     ctx->state = SCRIPTSTATE_UNINITIALIZED;
697     ctx->safeopt = This->safeopt;
698     ctx->version = This->version;
699     jsheap_init(&ctx->tmp_heap);
700
701     ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
702     if(ctx) {
703         script_release(ctx);
704         return E_UNEXPECTED;
705     }
706
707     return This->site ? set_ctx_site(This) : S_OK;
708 }
709
710 static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface,
711         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
712         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
713         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
714         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
715 {
716     JScript *This = impl_from_IActiveScriptParse(iface);
717     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
718           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
719           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
720           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
721     return E_NOTIMPL;
722 }
723
724 static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
725         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
726         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
727         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
728 {
729     JScript *This = impl_from_IActiveScriptParse(iface);
730     parser_ctx_t *parser_ctx;
731     HRESULT hres;
732
733     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
734           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
735           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
736
737     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
738         return E_UNEXPECTED;
739
740     hres = script_parse(This->ctx, pstrCode, pstrDelimiter, &parser_ctx);
741     if(FAILED(hres))
742         return hres;
743
744     if(!is_started(This->ctx)) {
745         if(This->queue_tail)
746             This->queue_tail = This->queue_tail->next = parser_ctx;
747         else
748             This->queue_head = This->queue_tail = parser_ctx;
749         return S_OK;
750     }
751
752     hres = exec_global_code(This, parser_ctx);
753     parser_release(parser_ctx);
754
755     return hres;
756 }
757
758 static const IActiveScriptParseVtbl JScriptParseVtbl = {
759     JScriptParse_QueryInterface,
760     JScriptParse_AddRef,
761     JScriptParse_Release,
762     JScriptParse_InitNew,
763     JScriptParse_AddScriptlet,
764     JScriptParse_ParseScriptText
765 };
766
767 static inline JScript *impl_from_IActiveScriptParseProcedure2(IActiveScriptParseProcedure2 *iface)
768 {
769     return CONTAINING_RECORD(iface, JScript, IActiveScriptParseProcedure2_iface);
770 }
771
772 static HRESULT WINAPI JScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
773 {
774     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
775     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
776 }
777
778 static ULONG WINAPI JScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
779 {
780     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
781     return IActiveScript_AddRef(&This->IActiveScript_iface);
782 }
783
784 static ULONG WINAPI JScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
785 {
786     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
787     return IActiveScript_Release(&This->IActiveScript_iface);
788 }
789
790 static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
791         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
792         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
793         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
794 {
795     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
796     parser_ctx_t *parser_ctx;
797     jsdisp_t *dispex;
798     HRESULT hres;
799
800     TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams),
801           debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
802           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp);
803
804     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
805         return E_UNEXPECTED;
806
807     hres = script_parse(This->ctx, pstrCode, pstrDelimiter, &parser_ctx);
808     if(FAILED(hres)) {
809         WARN("Parse failed %08x\n", hres);
810         return hres;
811     }
812
813     hres = create_source_function(parser_ctx, NULL, parser_ctx->source, NULL, NULL, 0, &dispex);
814     parser_release(parser_ctx);
815     if(FAILED(hres))
816         return hres;
817
818     *ppdisp = to_disp(dispex);
819     return S_OK;
820 }
821
822 static const IActiveScriptParseProcedure2Vtbl JScriptParseProcedureVtbl = {
823     JScriptParseProcedure_QueryInterface,
824     JScriptParseProcedure_AddRef,
825     JScriptParseProcedure_Release,
826     JScriptParseProcedure_ParseProcedureText,
827 };
828
829 static inline JScript *impl_from_IActiveScriptProperty(IActiveScriptProperty *iface)
830 {
831     return CONTAINING_RECORD(iface, JScript, IActiveScriptProperty_iface);
832 }
833
834 static HRESULT WINAPI JScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
835 {
836     JScript *This = impl_from_IActiveScriptProperty(iface);
837     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
838 }
839
840 static ULONG WINAPI JScriptProperty_AddRef(IActiveScriptProperty *iface)
841 {
842     JScript *This = impl_from_IActiveScriptProperty(iface);
843     return IActiveScript_AddRef(&This->IActiveScript_iface);
844 }
845
846 static ULONG WINAPI JScriptProperty_Release(IActiveScriptProperty *iface)
847 {
848     JScript *This = impl_from_IActiveScriptProperty(iface);
849     return IActiveScript_Release(&This->IActiveScript_iface);
850 }
851
852 static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
853         VARIANT *pvarIndex, VARIANT *pvarValue)
854 {
855     JScript *This = impl_from_IActiveScriptProperty(iface);
856     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
857     return E_NOTIMPL;
858 }
859
860 static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
861         VARIANT *pvarIndex, VARIANT *pvarValue)
862 {
863     JScript *This = impl_from_IActiveScriptProperty(iface);
864
865     TRACE("(%p)->(%x %s %s)\n", This, dwProperty, debugstr_variant(pvarIndex), debugstr_variant(pvarValue));
866
867     if(pvarIndex)
868         FIXME("unsupported pvarIndex\n");
869
870     switch(dwProperty) {
871     case SCRIPTPROP_INVOKEVERSIONING:
872         if(V_VT(pvarValue) != VT_I4 || V_I4(pvarValue) < 0 || V_I4(pvarValue) > 15) {
873             WARN("invalid value %s\n", debugstr_variant(pvarValue));
874             return E_INVALIDARG;
875         }
876
877         This->version = V_I4(pvarValue);
878         break;
879     default:
880         FIXME("Unimplemented property %x\n", dwProperty);
881         return E_NOTIMPL;
882     }
883
884     return S_OK;
885 }
886
887 static const IActiveScriptPropertyVtbl JScriptPropertyVtbl = {
888     JScriptProperty_QueryInterface,
889     JScriptProperty_AddRef,
890     JScriptProperty_Release,
891     JScriptProperty_GetProperty,
892     JScriptProperty_SetProperty
893 };
894
895 static inline JScript *impl_from_IObjectSafety(IObjectSafety *iface)
896 {
897     return CONTAINING_RECORD(iface, JScript, IObjectSafety_iface);
898 }
899
900 static HRESULT WINAPI JScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
901 {
902     JScript *This = impl_from_IObjectSafety(iface);
903     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
904 }
905
906 static ULONG WINAPI JScriptSafety_AddRef(IObjectSafety *iface)
907 {
908     JScript *This = impl_from_IObjectSafety(iface);
909     return IActiveScript_AddRef(&This->IActiveScript_iface);
910 }
911
912 static ULONG WINAPI JScriptSafety_Release(IObjectSafety *iface)
913 {
914     JScript *This = impl_from_IObjectSafety(iface);
915     return IActiveScript_Release(&This->IActiveScript_iface);
916 }
917
918 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
919
920 static HRESULT WINAPI JScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
921         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
922 {
923     JScript *This = impl_from_IObjectSafety(iface);
924
925     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
926
927     if(!pdwSupportedOptions || !pdwEnabledOptions)
928         return E_POINTER;
929
930     *pdwSupportedOptions = SUPPORTED_OPTIONS;
931     *pdwEnabledOptions = This->safeopt;
932
933     return S_OK;
934 }
935
936 static HRESULT WINAPI JScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
937         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
938 {
939     JScript *This = impl_from_IObjectSafety(iface);
940
941     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
942
943     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
944         return E_FAIL;
945
946     This->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX;
947     return S_OK;
948 }
949
950 static const IObjectSafetyVtbl JScriptSafetyVtbl = {
951     JScriptSafety_QueryInterface,
952     JScriptSafety_AddRef,
953     JScriptSafety_Release,
954     JScriptSafety_GetInterfaceSafetyOptions,
955     JScriptSafety_SetInterfaceSafetyOptions
956 };
957
958 HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
959                                              REFIID riid, void **ppv)
960 {
961     JScript *ret;
962     HRESULT hres;
963
964     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
965
966     if(pUnkOuter) {
967         *ppv = NULL;
968         return CLASS_E_NOAGGREGATION;
969     }
970
971     lock_module();
972
973     ret = heap_alloc_zero(sizeof(*ret));
974     if(!ret)
975         return E_OUTOFMEMORY;
976
977     ret->IActiveScript_iface.lpVtbl = &JScriptVtbl;
978     ret->IActiveScriptParse_iface.lpVtbl = &JScriptParseVtbl;
979     ret->IActiveScriptParseProcedure2_iface.lpVtbl = &JScriptParseProcedureVtbl;
980     ret->IActiveScriptProperty_iface.lpVtbl = &JScriptPropertyVtbl;
981     ret->IObjectSafety_iface.lpVtbl = &JScriptSafetyVtbl;
982     ret->ref = 1;
983     ret->safeopt = INTERFACE_USES_DISPEX;
984
985     hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
986     IActiveScript_Release(&ret->IActiveScript_iface);
987     return hres;
988 }