Line data Source code
1 : /* Copyright (C) 2021 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. 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
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #ifndef INCLUDED_SCRIPTREQUEST
19 : #define INCLUDED_SCRIPTREQUEST
20 :
21 : #include "scriptinterface/ScriptForward.h"
22 :
23 : // Ignore warnings in SM headers.
24 : #if GCC_VERSION || CLANG_VERSION
25 : # pragma GCC diagnostic push
26 : # pragma GCC diagnostic ignored "-Wunused-parameter"
27 : # pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
28 : #elif MSC_VERSION
29 : # pragma warning(push, 1)
30 : #endif
31 :
32 : #include "js/RootingAPI.h"
33 :
34 : #if GCC_VERSION || CLANG_VERSION
35 : # pragma GCC diagnostic pop
36 : #elif MSC_VERSION
37 : # pragma warning(pop)
38 : #endif
39 :
40 : #include <memory>
41 :
42 : class ScriptInterface;
43 :
44 : /**
45 : * Spidermonkey maintains some 'local' state via the JSContext* object.
46 : * This object is an argument to most JSAPI functions.
47 : * Furthermore, this state is Realm (~ global) dependent. For many reasons, including GC safety,
48 : * The JSContext* Realm must be set up correctly when accessing it.
49 : * 'Entering' and 'Leaving' realms must be done in a LIFO manner.
50 : * SM recommends using JSAutoRealm, which provides an RAII option.
51 : *
52 : * ScriptRequest combines both of the above in a single convenient package,
53 : * providing safe access to the JSContext*, the global object, and ensuring that the proper realm has been entered.
54 : * Most scriptinterface/ functions will take a ScriptRequest, to ensure proper rooting. You may sometimes
55 : * have to create one from a ScriptInterface.
56 : *
57 : * Be particularly careful when manipulating several script interfaces.
58 : */
59 : class ScriptRequest
60 : {
61 : ScriptRequest() = delete;
62 : ScriptRequest(const ScriptRequest& rq) = delete;
63 : ScriptRequest& operator=(const ScriptRequest& rq) = delete;
64 : public:
65 : /**
66 : * NB: the definitions are in scriptinterface.cpp, because these access members of the PImpled
67 : * implementation of ScriptInterface, and that seemed more convenient.
68 : */
69 : ScriptRequest(const ScriptInterface& scriptInterface);
70 30504 : ScriptRequest(const ScriptInterface* scriptInterface) : ScriptRequest(*scriptInterface) {}
71 27 : ScriptRequest(std::shared_ptr<ScriptInterface> scriptInterface) : ScriptRequest(*scriptInterface) {}
72 : ~ScriptRequest();
73 :
74 : /**
75 : * Create a script request from a JSContext.
76 : * This can be used to get the script interface in a JSNative function.
77 : * In general, you shouldn't have to rely on this otherwise.
78 : */
79 : ScriptRequest(JSContext* cx);
80 :
81 : /**
82 : * Return the scriptInterface active when creating this ScriptRequest.
83 : * Note that this is multi-request safe: even if another ScriptRequest is created,
84 : * it will point to the original scriptInterface, and thus can be used to re-enter the realm.
85 : */
86 : const ScriptInterface& GetScriptInterface() const;
87 :
88 : JS::Value globalValue() const;
89 :
90 : // Note that JSContext actually changes behind the scenes when creating another ScriptRequest for another realm,
91 : // so be _very_ careful when juggling between different realms.
92 : JSContext* cx;
93 : JS::HandleObject glob;
94 : JS::HandleObject nativeScope;
95 : private:
96 : const ScriptInterface& m_ScriptInterface;
97 : JS::Realm* m_FormerRealm;
98 : };
99 :
100 :
101 : #endif // INCLUDED_SCRIPTREQUEST
|