b2f595c2769a2adc68e0f941c883a08802373ce4
[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, 2007, 2013, 2016 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     ProgramExecutable* program = ProgramExecutable::create(exec, source);
100     ASSERT(scope.exception() || program);
101     if (!program) {
102         returnedException = scope.exception();
103         scope.clearException();
104         return jsUndefined();
105     }
106
107     if (!thisValue || thisValue.isUndefinedOrNull())
108         thisValue = exec->vmEntryGlobalObject();
109     JSObject* thisObj = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
110     JSValue result = exec->interpreter()->execute(program, exec, thisObj);
111
112     if (scope.exception()) {
113         returnedException = scope.exception();
114         scope.clearException();
115         return jsUndefined();
116     }
117
118     RELEASE_ASSERT(result);
119     return result;
120 }
121
122 JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
123 {
124     ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
125     return evaluate(exec, source, thisValue, returnedException);
126 }
127
128 JSValue evaluateWithScopeExtension(ExecState* exec, const SourceCode& source, JSObject* scopeExtensionObject, NakedPtr<Exception>& returnedException)
129 {
130     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
131
132     if (scopeExtensionObject) {
133         JSScope* ignoredPreviousScope = globalObject->globalScope();
134         globalObject->setGlobalScopeExtension(JSWithScope::create(exec->vm(), globalObject, scopeExtensionObject, ignoredPreviousScope));
135     }
136
137     JSValue returnValue = JSC::evaluate(globalObject->globalExec(), source, globalObject, returnedException);
138
139     if (scopeExtensionObject)
140         globalObject->clearGlobalScopeExtension();
141
142     return returnValue;
143 }
144
145 static Symbol* createSymbolForEntryPointModule(VM& vm)
146 {
147     // Generate the unique key for the source-provided module.
148     PrivateName privateName(PrivateName::Description, "EntryPointModule");
149     return Symbol::create(vm, privateName.uid());
150 }
151
152 static JSInternalPromise* rejectPromise(ExecState* exec, JSGlobalObject* globalObject)
153 {
154     VM& vm = exec->vm();
155     auto scope = DECLARE_CATCH_SCOPE(vm);
156     ASSERT(scope.exception());
157     JSValue exception = scope.exception()->value();
158     scope.clearException();
159     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
160     deferred->reject(exec, exception);
161     return deferred->promise();
162 }
163
164 static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer, JSValue initiator)
165 {
166     return globalObject->moduleLoader()->loadAndEvaluateModule(exec, moduleName, referrer, initiator);
167 }
168
169 static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName, JSValue initiator)
170 {
171     return loadAndEvaluateModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined(), initiator);
172 }
173
174 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const String& moduleName, JSValue initiator)
175 {
176     JSLockHolder lock(exec);
177     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
178     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
179
180     return loadAndEvaluateModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName), initiator);
181 }
182
183 JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const SourceCode& source, JSValue initiator)
184 {
185     VM& vm = exec->vm();
186     JSLockHolder lock(vm);
187     auto scope = DECLARE_THROW_SCOPE(vm);
188     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
189     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
190
191     Symbol* key = createSymbolForEntryPointModule(vm);
192
193     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
194
195     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
196     globalObject->moduleLoader()->provide(exec, key, JSModuleLoader::Status::Fetch, source);
197     RETURN_IF_EXCEPTION(scope, rejectPromise(exec, globalObject));
198
199     return loadAndEvaluateModule(lock, exec, globalObject, key, jsUndefined(), initiator);
200 }
201
202 static JSInternalPromise* loadModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer, JSValue initiator)
203 {
204     return globalObject->moduleLoader()->loadModule(exec, moduleName, referrer, initiator);
205 }
206
207 static JSInternalPromise* loadModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName, JSValue initiator)
208 {
209     return loadModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined(), initiator);
210 }
211
212 JSInternalPromise* loadModule(ExecState* exec, const String& moduleName, JSValue initiator)
213 {
214     JSLockHolder lock(exec);
215     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
216     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
217
218     return loadModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName), initiator);
219 }
220
221 JSInternalPromise* loadModule(ExecState* exec, const SourceCode& source, JSValue initiator)
222 {
223     VM& vm = exec->vm();
224     JSLockHolder lock(vm);
225     auto scope = DECLARE_THROW_SCOPE(vm);
226     RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
227     RELEASE_ASSERT(!vm.isCollectorBusyOnCurrentThread());
228
229     Symbol* key = createSymbolForEntryPointModule(vm);
230
231     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
232
233     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
234     // FIXME: Introduce JSSourceCode object to wrap around this source.
235     globalObject->moduleLoader()->provide(exec, key, JSModuleLoader::Status::Fetch, source);
236     RETURN_IF_EXCEPTION(scope, rejectPromise(exec, globalObject));
237
238     return loadModule(lock, exec, globalObject, key, jsUndefined(), initiator);
239 }
240
241 JSValue linkAndEvaluateModule(ExecState* exec, const Identifier& moduleKey, JSValue initiator)
242 {
243     JSLockHolder lock(exec);
244     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
245     RELEASE_ASSERT(!exec->vm().isCollectorBusyOnCurrentThread());
246
247     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
248     return globalObject->moduleLoader()->linkAndEvaluateModule(exec, identifierToJSValue(exec->vm(), moduleKey), initiator);
249 }
250
251 } // namespace JSC