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