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