7e2aa303192861168332e0a22bbdc09d3f96fee0
[WebKit.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-2019 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 "BytecodeCacheError.h"
27 #include "CallFrame.h"
28 #include "CatchScope.h"
29 #include "CodeCache.h"
30 #include "CodeProfiling.h"
31 #include "Exception.h"
32 #include "IdentifierInlines.h"
33 #include "Interpreter.h"
34 #include "JSCInlines.h"
35 #include "JSGlobalObject.h"
36 #include "JSInternalPromise.h"
37 #include "JSInternalPromiseDeferred.h"
38 #include "JSLock.h"
39 #include "JSModuleLoader.h"
40 #include "JSModuleRecord.h"
41 #include "JSWithScope.h"
42 #include "ModuleAnalyzer.h"
43 #include "Parser.h"
44 #include "ProgramExecutable.h"
45 #include "ScriptProfilingScope.h"
46
47 namespace JSC {
48
49 static inline bool checkSyntaxInternal(VM& vm, const SourceCode& source, ParserError& error)
50 {
51     return !!parse<ProgramNode>(
52         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
53         JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
54 }
55
56 bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException)
57 {
58     VM& vm = exec->vm();
59     JSLockHolder lock(vm);
60     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
61
62     ParserError error;
63     if (checkSyntaxInternal(vm, source, error))
64         return true;
65     ASSERT(error.isValid());
66     if (returnedException)
67         *returnedException = error.toErrorObject(exec->lexicalGlobalObject(), source);
68     return false;
69 }
70
71 bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error)
72 {
73     JSLockHolder lock(vm);
74     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
75     return checkSyntaxInternal(vm, source, error);
76 }
77
78 bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& error)
79 {
80     VM& vm = exec->vm();
81     JSLockHolder lock(vm);
82     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
83     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
84         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
85         JSParserStrictMode::Strict, JSParserScriptMode::Module, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
86     if (!moduleProgramNode)
87         return false;
88
89     PrivateName privateName(PrivateName::Description, "EntryPointModule");
90     ModuleAnalyzer moduleAnalyzer(exec, Identifier::fromUid(privateName), source, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
91     moduleAnalyzer.analyze(*moduleProgramNode);
92     return true;
93 }
94
95 RefPtr<CachedBytecode> generateProgramBytecode(VM& vm, const SourceCode& source, int fd, BytecodeCacheError& error)
96 {
97     JSLockHolder lock(vm);
98     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
99
100     VariableEnvironment variablesUnderTDZ;
101     JSParserStrictMode strictMode = JSParserStrictMode::NotStrict;
102     JSParserScriptMode scriptMode = JSParserScriptMode::Classic;
103     EvalContextType evalContextType = EvalContextType::None;
104
105     ParserError parserError;
106     UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, { }, parserError, evalContextType, &variablesUnderTDZ);
107     if (parserError.isValid())
108         error = parserError;
109     if (!unlinkedCodeBlock)
110         return nullptr;
111
112     return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, fd, error, { });
113 }
114
115 RefPtr<CachedBytecode> generateModuleBytecode(VM& vm, const SourceCode& source, int fd, BytecodeCacheError& error)
116 {
117     JSLockHolder lock(vm);
118     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
119
120     VariableEnvironment variablesUnderTDZ;
121     JSParserStrictMode strictMode = JSParserStrictMode::Strict;
122     JSParserScriptMode scriptMode = JSParserScriptMode::Module;
123     EvalContextType evalContextType = EvalContextType::None;
124
125     ParserError parserError;
126     UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, { }, parserError, evalContextType, &variablesUnderTDZ);
127     if (parserError.isValid())
128         error = parserError;
129     if (!unlinkedCodeBlock)
130         return nullptr;
131     return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ModuleType, strictMode, scriptMode, fd, error, { });
132 }
133
134 JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
135 {
136     VM& vm = exec->vm();
137     JSLockHolder lock(vm);
138     auto scope = DECLARE_CATCH_SCOPE(vm);
139     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
140     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
141
142     CodeProfiling profile(source);
143
144     if (!thisValue || thisValue.isUndefinedOrNull())
145         thisValue = vm.vmEntryGlobalObject(exec);
146     JSObject* thisObj = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
147     JSValue result = vm.interpreter->executeProgram(source, exec, thisObj);
148
149     if (scope.exception()) {
150         returnedException = scope.exception();
151         scope.clearException();
152         return jsUndefined();
153     }
154
155     RELEASE_ASSERT(result);
156     return result;
157 }
158
159 JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
160 {
161     VM& vm = exec->vm();
162     ScriptProfilingScope profilingScope(vm.vmEntryGlobalObject(exec), reason);
163     return evaluate(exec, source, thisValue, returnedException);
164 }
165
166 JSValue evaluateWithScopeExtension(ExecState* exec, const SourceCode& source, JSObject* scopeExtensionObject, NakedPtr<Exception>& returnedException)
167 {
168     VM& vm = exec->vm();
169     JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
170
171     if (scopeExtensionObject) {
172         JSScope* ignoredPreviousScope = globalObject->globalScope();
173         globalObject->setGlobalScopeExtension(JSWithScope::create(vm, globalObject, ignoredPreviousScope, scopeExtensionObject));
174     }
175
176     JSValue returnValue = JSC::evaluate(globalObject->globalExec(), source, globalObject, returnedException);
177
178     if (scopeExtensionObject)
179         globalObject->clearGlobalScopeExtension();
180
181     return returnValue;
182 }
183
184 static Symbol* createSymbolForEntryPointModule(VM& vm)
185 {
186     // Generate the unique key for the source-provided module.
187     PrivateName privateName(PrivateName::Description, "EntryPointModule");
188     return Symbol::create(vm, privateName.uid());
189 }
190
191 static JSInternalPromise* rejectPromise(ExecState* exec, JSGlobalObject* globalObject)
192 {
193     VM& vm = exec->vm();
194     auto scope = DECLARE_CATCH_SCOPE(vm);
195     scope.assertNoException();
196     JSValue exception = scope.exception()->value();
197     scope.clearException();
198     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::tryCreate(exec, globalObject);
199     scope.releaseAssertNoException();
200     deferred->reject(exec, exception);
201     scope.releaseAssertNoException();
202     return deferred->promise();
203 }
204
205 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, Symbol* moduleId, JSValue parameters, JSValue scriptFetcher)
206 {
207     VM& vm = exec->vm();
208     JSLockHolder lock(vm);
209     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
210     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
211
212     return vm.vmEntryGlobalObject(exec)->moduleLoader()->loadAndEvaluateModule(exec, moduleId, parameters, scriptFetcher);
213 }
214
215 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const String& moduleName, JSValue parameters, JSValue scriptFetcher)
216 {
217     VM& vm = exec->vm();
218     JSLockHolder lock(vm);
219     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
220     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
221
222     return vm.vmEntryGlobalObject(exec)->moduleLoader()->loadAndEvaluateModule(exec, identifierToJSValue(vm, Identifier::fromString(exec, moduleName)), parameters, scriptFetcher);
223 }
224
225 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const SourceCode& source, JSValue scriptFetcher)
226 {
227     VM& vm = exec->vm();
228     JSLockHolder lock(vm);
229     auto scope = DECLARE_THROW_SCOPE(vm);
230     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
231     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
232
233     Symbol* key = createSymbolForEntryPointModule(vm);
234
235     JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
236
237     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
238     globalObject->moduleLoader()->provideFetch(exec, key, source);
239     RETURN_IF_EXCEPTION(scope, rejectPromise(exec, globalObject));
240
241     return globalObject->moduleLoader()->loadAndEvaluateModule(exec, key, jsUndefined(), scriptFetcher);
242 }
243
244 JSInternalPromise* loadModule(ExecState* exec, const String& moduleName, JSValue parameters, JSValue scriptFetcher)
245 {
246     VM& vm = exec->vm();
247     JSLockHolder lock(vm);
248     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
249     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
250
251     return vm.vmEntryGlobalObject(exec)->moduleLoader()->loadModule(exec, identifierToJSValue(vm, Identifier::fromString(exec, moduleName)), parameters, scriptFetcher);
252 }
253
254 JSInternalPromise* loadModule(ExecState* exec, const SourceCode& source, JSValue scriptFetcher)
255 {
256     VM& vm = exec->vm();
257     JSLockHolder lock(vm);
258     auto scope = DECLARE_THROW_SCOPE(vm);
259     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
260     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
261
262     Symbol* key = createSymbolForEntryPointModule(vm);
263
264     JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
265
266     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
267     // FIXME: Introduce JSSourceCode object to wrap around this source.
268     globalObject->moduleLoader()->provideFetch(exec, key, source);
269     RETURN_IF_EXCEPTION(scope, rejectPromise(exec, globalObject));
270
271     return globalObject->moduleLoader()->loadModule(exec, key, jsUndefined(), scriptFetcher);
272 }
273
274 JSValue linkAndEvaluateModule(ExecState* exec, const Identifier& moduleKey, JSValue scriptFetcher)
275 {
276     VM& vm = exec->vm();
277     JSLockHolder lock(vm);
278     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
279     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
280
281     JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
282     return globalObject->moduleLoader()->linkAndEvaluateModule(exec, identifierToJSValue(vm, moduleKey), scriptFetcher);
283 }
284
285 JSInternalPromise* importModule(ExecState* exec, const Identifier& moduleKey, JSValue parameters, JSValue scriptFetcher)
286 {
287     VM& vm = exec->vm();
288     JSLockHolder lock(vm);
289     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
290     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
291
292     return vm.vmEntryGlobalObject(exec)->moduleLoader()->requestImportModule(exec, moduleKey, parameters, scriptFetcher);
293 }
294
295 } // namespace JSC