bd177984b1962f517a0361ecc4a25367fcd7eaab
[WebKit-https.git] / Source / JavaScriptCore / runtime / Completion.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003-2017 Apple Inc.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "Completion.h"
25
26 #include "CallFrame.h"
27 #include "CodeProfiling.h"
28 #include "Exception.h"
29 #include "IdentifierInlines.h"
30 #include "Interpreter.h"
31 #include "JSCInlines.h"
32 #include "JSGlobalObject.h"
33 #include "JSInternalPromise.h"
34 #include "JSInternalPromiseDeferred.h"
35 #include "JSLock.h"
36 #include "JSModuleLoader.h"
37 #include "JSModuleRecord.h"
38 #include "JSWithScope.h"
39 #include "ModuleAnalyzer.h"
40 #include "Parser.h"
41 #include "ProgramExecutable.h"
42 #include "ScriptProfilingScope.h"
43 #include <wtf/WTFThreadData.h>
44
45 namespace JSC {
46
47 bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException)
48 {
49     JSLockHolder lock(exec);
50     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
51
52     ProgramExecutable* program = ProgramExecutable::create(exec, source);
53     JSObject* error = program->checkSyntax(exec);
54     if (error) {
55         if (returnedException)
56             *returnedException = error;
57         return false;
58     }
59
60     return true;
61 }
62     
63 bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error)
64 {
65     JSLockHolder lock(vm);
66     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
67     return !!parse<ProgramNode>(
68         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
69         JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
70 }
71
72 bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& error)
73 {
74     VM& vm = exec->vm();
75     JSLockHolder lock(vm);
76     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
77     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
78         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
79         JSParserStrictMode::Strict, JSParserScriptMode::Module, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
80     if (!moduleProgramNode)
81         return false;
82
83     PrivateName privateName(PrivateName::Description, "EntryPointModule");
84     ModuleAnalyzer moduleAnalyzer(exec, Identifier::fromUid(privateName), source, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
85     moduleAnalyzer.analyze(*moduleProgramNode);
86     return true;
87 }
88
89 JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
90 {
91     VM& vm = exec->vm();
92     JSLockHolder lock(vm);
93     auto scope = DECLARE_CATCH_SCOPE(vm);
94     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
95     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
96
97     CodeProfiling profile(source);
98
99     if (!thisValue || thisValue.isUndefinedOrNull())
100         thisValue = exec->vmEntryGlobalObject();
101     JSObject* thisObj = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
102     JSValue result = exec->interpreter()->executeProgram(source, exec, thisObj);
103
104     if (scope.exception()) {
105         returnedException = scope.exception();
106         scope.clearException();
107         return jsUndefined();
108     }
109
110     RELEASE_ASSERT(result);
111     return result;
112 }
113
114 JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
115 {
116     ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
117     return evaluate(exec, source, thisValue, returnedException);
118 }
119
120 JSValue evaluateWithScopeExtension(ExecState* exec, const SourceCode& source, JSObject* scopeExtensionObject, NakedPtr<Exception>& returnedException)
121 {
122     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
123
124     if (scopeExtensionObject) {
125         JSScope* ignoredPreviousScope = globalObject->globalScope();
126         globalObject->setGlobalScopeExtension(JSWithScope::create(exec->vm(), globalObject, scopeExtensionObject, ignoredPreviousScope));
127     }
128
129     JSValue returnValue = JSC::evaluate(globalObject->globalExec(), source, globalObject, returnedException);
130
131     if (scopeExtensionObject)
132         globalObject->clearGlobalScopeExtension();
133
134     return returnValue;
135 }
136
137 static Symbol* createSymbolForEntryPointModule(VM& vm)
138 {
139     // Generate the unique key for the source-provided module.
140     PrivateName privateName(PrivateName::Description, "EntryPointModule");
141     return Symbol::create(vm, privateName.uid());
142 }
143
144 static JSInternalPromise* rejectPromise(ExecState* exec, JSGlobalObject* globalObject)
145 {
146     VM& vm = exec->vm();
147     auto scope = DECLARE_CATCH_SCOPE(vm);
148     scope.assertNoException();
149     JSValue exception = scope.exception()->value();
150     scope.clearException();
151     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
152     deferred->reject(exec, exception);
153     return deferred->promise();
154 }
155
156 static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer, JSValue scriptFetcher)
157 {
158     return globalObject->moduleLoader()->loadAndEvaluateModule(exec, moduleName, referrer, scriptFetcher);
159 }
160
161 static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName, JSValue scriptFetcher)
162 {
163     return loadAndEvaluateModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined(), scriptFetcher);
164 }
165
166 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const String& moduleName, JSValue scriptFetcher)
167 {
168     JSLockHolder lock(exec);
169     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
170     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
171
172     return loadAndEvaluateModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName), scriptFetcher);
173 }
174
175 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const SourceCode& source, JSValue scriptFetcher)
176 {
177     VM& vm = exec->vm();
178     JSLockHolder lock(vm);
179     auto scope = DECLARE_THROW_SCOPE(vm);
180     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
181     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
182
183     Symbol* key = createSymbolForEntryPointModule(vm);
184
185     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
186
187     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
188     globalObject->moduleLoader()->provide(exec, key, JSModuleLoader::Status::Fetch, source);
189     RETURN_IF_EXCEPTION(scope, rejectPromise(exec, globalObject));
190
191     return loadAndEvaluateModule(lock, exec, globalObject, key, jsUndefined(), scriptFetcher);
192 }
193
194 static JSInternalPromise* loadModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer, JSValue scriptFetcher)
195 {
196     return globalObject->moduleLoader()->loadModule(exec, moduleName, referrer, scriptFetcher);
197 }
198
199 static JSInternalPromise* loadModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName, JSValue scriptFetcher)
200 {
201     return loadModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined(), scriptFetcher);
202 }
203
204 JSInternalPromise* loadModule(ExecState* exec, const String& moduleName, JSValue scriptFetcher)
205 {
206     JSLockHolder lock(exec);
207     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
208     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
209
210     return loadModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName), scriptFetcher);
211 }
212
213 JSInternalPromise* loadModule(ExecState* exec, const SourceCode& source, JSValue scriptFetcher)
214 {
215     VM& vm = exec->vm();
216     JSLockHolder lock(vm);
217     auto scope = DECLARE_THROW_SCOPE(vm);
218     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
219     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
220
221     Symbol* key = createSymbolForEntryPointModule(vm);
222
223     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
224
225     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
226     // FIXME: Introduce JSSourceCode object to wrap around this source.
227     globalObject->moduleLoader()->provide(exec, key, JSModuleLoader::Status::Fetch, source);
228     RETURN_IF_EXCEPTION(scope, rejectPromise(exec, globalObject));
229
230     return loadModule(lock, exec, globalObject, key, jsUndefined(), scriptFetcher);
231 }
232
233 JSValue linkAndEvaluateModule(ExecState* exec, const Identifier& moduleKey, JSValue scriptFetcher)
234 {
235     JSLockHolder lock(exec);
236     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
237     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
238
239     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
240     return globalObject->moduleLoader()->linkAndEvaluateModule(exec, identifierToJSValue(exec->vm(), moduleKey), scriptFetcher);
241 }
242
243 JSInternalPromise* importModule(ExecState* exec, const Identifier& moduleKey, JSValue scriptFetcher)
244 {
245     JSLockHolder lock(exec);
246     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
247     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
248
249     return exec->vmEntryGlobalObject()->moduleLoader()->requestImportModule(exec, moduleKey, scriptFetcher);
250 }
251
252 } // namespace JSC