1 | /* |
2 | * Copyright (C) 2010 Google Inc. All rights reserved. |
3 | * Copyright (C) 2016-2017 Apple Inc. All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
16 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
18 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
24 | * THE POSSIBILITY OF SUCH DAMAGE. |
25 | */ |
26 | |
27 | #pragma once |
28 | |
29 | #include "CustomElementReactionQueue.h" |
30 | #include "JSDOMBinding.h" |
31 | #include "ThreadGlobalData.h" |
32 | #include <JavaScriptCore/CatchScope.h> |
33 | #include <JavaScriptCore/Completion.h> |
34 | #include <JavaScriptCore/Microtask.h> |
35 | #include <wtf/ForbidHeapAllocation.h> |
36 | #include <wtf/MainThread.h> |
37 | |
38 | namespace WebCore { |
39 | |
40 | class InspectorInstrumentationCookie; |
41 | class ScriptExecutionContext; |
42 | |
43 | class JSExecState { |
44 | WTF_MAKE_NONCOPYABLE(JSExecState); |
45 | WTF_FORBID_HEAP_ALLOCATION; |
46 | friend class JSMainThreadNullState; |
47 | public: |
48 | static JSC::ExecState* currentState() |
49 | { |
50 | return threadGlobalData().currentState(); |
51 | }; |
52 | |
53 | static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException) |
54 | { |
55 | JSExecState currentState(exec); |
56 | return JSC::call(exec, functionObject, callType, callData, thisValue, args, returnedException); |
57 | }; |
58 | |
59 | static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException) |
60 | { |
61 | JSExecState currentState(exec); |
62 | return JSC::evaluate(exec, source, thisValue, returnedException); |
63 | }; |
64 | |
65 | static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue()) |
66 | { |
67 | NakedPtr<JSC::Exception> unused; |
68 | return evaluate(exec, source, thisValue, unused); |
69 | }; |
70 | |
71 | static JSC::JSValue profiledCall(JSC::ExecState* exec, JSC::ProfilingReason reason, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException) |
72 | { |
73 | JSExecState currentState(exec); |
74 | return JSC::profiledCall(exec, reason, functionObject, callType, callData, thisValue, args, returnedException); |
75 | } |
76 | |
77 | static JSC::JSValue profiledEvaluate(JSC::ExecState* exec, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException) |
78 | { |
79 | JSExecState currentState(exec); |
80 | return JSC::profiledEvaluate(exec, reason, source, thisValue, returnedException); |
81 | } |
82 | |
83 | static JSC::JSValue profiledEvaluate(JSC::ExecState* exec, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue()) |
84 | { |
85 | NakedPtr<JSC::Exception> unused; |
86 | return profiledEvaluate(exec, reason, source, thisValue, unused); |
87 | } |
88 | |
89 | static void runTask(JSC::ExecState* exec, JSC::Microtask& task) |
90 | { |
91 | JSExecState currentState(exec); |
92 | task.run(exec); |
93 | } |
94 | |
95 | static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const String& moduleName, JSC::JSValue parameters, JSC::JSValue scriptFetcher) |
96 | { |
97 | JSExecState currentState(&state); |
98 | return *JSC::loadModule(&state, moduleName, parameters, scriptFetcher); |
99 | } |
100 | |
101 | static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const JSC::SourceCode& sourceCode, JSC::JSValue scriptFetcher) |
102 | { |
103 | JSExecState currentState(&state); |
104 | return *JSC::loadModule(&state, sourceCode, scriptFetcher); |
105 | } |
106 | |
107 | static JSC::JSValue linkAndEvaluateModule(JSC::ExecState& state, const JSC::Identifier& moduleKey, JSC::JSValue scriptFetcher, NakedPtr<JSC::Exception>& returnedException) |
108 | { |
109 | JSC::VM& vm = state.vm(); |
110 | auto scope = DECLARE_CATCH_SCOPE(vm); |
111 | |
112 | JSExecState currentState(&state); |
113 | auto returnValue = JSC::linkAndEvaluateModule(&state, moduleKey, scriptFetcher); |
114 | if (UNLIKELY(scope.exception())) { |
115 | returnedException = scope.exception(); |
116 | scope.clearException(); |
117 | return JSC::jsUndefined(); |
118 | } |
119 | return returnValue; |
120 | } |
121 | |
122 | static InspectorInstrumentationCookie instrumentFunctionCall(ScriptExecutionContext*, JSC::CallType, const JSC::CallData&); |
123 | static InspectorInstrumentationCookie instrumentFunctionConstruct(ScriptExecutionContext*, JSC::ConstructType, const JSC::ConstructData&); |
124 | |
125 | private: |
126 | explicit JSExecState(JSC::ExecState* exec) |
127 | : m_previousState(currentState()) |
128 | , m_lock(exec) |
129 | { |
130 | setCurrentState(exec); |
131 | }; |
132 | |
133 | ~JSExecState() |
134 | { |
135 | JSC::VM& vm = currentState()->vm(); |
136 | auto scope = DECLARE_CATCH_SCOPE(vm); |
137 | scope.assertNoException(); |
138 | |
139 | JSC::ExecState* state = currentState(); |
140 | bool didExitJavaScript = state && !m_previousState; |
141 | |
142 | setCurrentState(m_previousState); |
143 | |
144 | if (didExitJavaScript) |
145 | didLeaveScriptContext(state); |
146 | } |
147 | |
148 | static void setCurrentState(JSC::ExecState* state) |
149 | { |
150 | threadGlobalData().setCurrentState(state); |
151 | } |
152 | |
153 | template<typename Type, Type jsType, typename DataType> static InspectorInstrumentationCookie instrumentFunctionInternal(ScriptExecutionContext*, Type, const DataType&); |
154 | |
155 | JSC::ExecState* m_previousState; |
156 | JSC::JSLockHolder m_lock; |
157 | |
158 | static void didLeaveScriptContext(JSC::ExecState*); |
159 | }; |
160 | |
161 | // Null state prevents origin security checks. |
162 | // Used by non-JavaScript bindings (ObjC, GObject). |
163 | class JSMainThreadNullState { |
164 | WTF_MAKE_NONCOPYABLE(JSMainThreadNullState); |
165 | WTF_FORBID_HEAP_ALLOCATION; |
166 | public: |
167 | explicit JSMainThreadNullState() |
168 | : m_previousState(JSExecState::currentState()) |
169 | , m_customElementReactionStack(m_previousState) |
170 | { |
171 | ASSERT(isMainThread()); |
172 | JSExecState::setCurrentState(nullptr); |
173 | } |
174 | |
175 | ~JSMainThreadNullState() |
176 | { |
177 | ASSERT(isMainThread()); |
178 | JSExecState::setCurrentState(m_previousState); |
179 | } |
180 | |
181 | private: |
182 | JSC::ExecState* m_previousState; |
183 | CustomElementReactionStack m_customElementReactionStack; |
184 | }; |
185 | |
186 | JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException); |
187 | JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException); |
188 | |
189 | } // namespace WebCore |
190 | |