// FIXME: There's no need to add the function's name to the key here. It's already in the source code. UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) { bool isArrowFunctionContext = false; SourceCodeKey key( source, name.string(), SourceCodeType::FunctionType, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserCommentMode::Classic, DerivedContextType::None, EvalContextType::None, isArrowFunctionContext); SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); if (cache) { UnlinkedFunctionExecutable* executable = jsCast<UnlinkedFunctionExecutable*>(cache->cell.get()); source.provider()->setSourceURLDirective(executable->sourceURLDirective()); source.provider()->setSourceMappingURLDirective(executable->sourceMappingURLDirective()); return executable; } JSTextPosition positionBeforeLastNewline; std::unique_ptr<ProgramNode> program = parse<ProgramNode>( &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserCommentMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error, &positionBeforeLastNewline); if (!program) { RELEASE_ASSERT(error.isValid()); return nullptr; } // This function assumes an input string that would result in a single function declaration. StatementNode* statement = program->singleStatement(); ASSERT(statement); ASSERT(statement->isBlock()); if (!statement || !statement->isBlock()) return nullptr; StatementNode* funcDecl = static_cast<BlockNode*>(statement)->singleStatement(); ASSERT(funcDecl); ASSERT(funcDecl->isFuncDeclNode()); if (!funcDecl || !funcDecl->isFuncDeclNode()) return nullptr; FunctionMetadataNode* metadata = static_cast<FuncDeclNode*>(funcDecl)->metadata(); ASSERT(metadata); if (!metadata) return nullptr; metadata->overrideName(name); metadata->setEndPosition(positionBeforeLastNewline); // The Function constructor only has access to global variables, so no variables will be under TDZ. VariableEnvironment emptyTDZVariables; UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, JSParserCommentMode::Classic, emptyTDZVariables, DerivedContextType::None); functionExecutable->setSourceURLDirective(source.provider()->sourceURL()); functionExecutable->setSourceMappingURLDirective(source.provider()->sourceMappingURL()); m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age())); return functionExecutable; }
BuiltinExecutables::BuiltinExecutables(VM& vm) : m_vm(vm) #define INITIALIZE_BUILTIN_SOURCE_MEMBERS(name, functionName, length) , m_##name##Source(makeSource(StringImpl::createFromLiteral(s_##name, length))) JSC_FOREACH_BUILTIN_CODE(INITIALIZE_BUILTIN_SOURCE_MEMBERS) #undef EXPOSE_BUILTIN_STRINGS { } UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name) { static NeverDestroyed<const String> baseConstructorCode(ASCIILiteral("(function () { })")); static NeverDestroyed<const String> derivedConstructorCode(ASCIILiteral("(function () { super(...arguments); })")); switch (constructorKind) { case ConstructorKind::None: break; case ConstructorKind::Base: return createExecutable(m_vm, makeSource(baseConstructorCode), name, constructorKind, ConstructAbility::CanConstruct); case ConstructorKind::Extends: return createExecutable(m_vm, makeSource(derivedConstructorCode), name, constructorKind, ConstructAbility::CanConstruct); } ASSERT_NOT_REACHED(); return nullptr; } UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const SourceCode& code, const Identifier& name, ConstructAbility constructAbility) { return createExecutable(m_vm, code, name, ConstructorKind::None, constructAbility); } UnlinkedFunctionExecutable* createBuiltinExecutable(VM& vm, const SourceCode& code, const Identifier& name, ConstructAbility constructAbility) { return BuiltinExecutables::createExecutable(vm, code, name, ConstructorKind::None, constructAbility); } UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility) { JSTextPosition positionBeforeLastNewline; ParserError error; bool isParsingDefaultConstructor = constructorKind != ConstructorKind::None; JSParserBuiltinMode builtinMode = isParsingDefaultConstructor ? JSParserBuiltinMode::NotBuiltin : JSParserBuiltinMode::Builtin; UnlinkedFunctionKind kind = isParsingDefaultConstructor ? UnlinkedNormalFunction : UnlinkedBuiltinFunction; RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr; std::unique_ptr<ProgramNode> program = parse<ProgramNode>( &vm, source, Identifier(), builtinMode, JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error, &positionBeforeLastNewline, constructorKind); if (!program) { dataLog("Fatal error compiling builtin function '", name.string(), "': ", error.message()); CRASH(); } StatementNode* exprStatement = program->singleStatement(); RELEASE_ASSERT(exprStatement); RELEASE_ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); RELEASE_ASSERT(funcExpr); RELEASE_ASSERT(funcExpr->isFuncExprNode()); FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(funcExpr)->metadata(); RELEASE_ASSERT(!program->hasCapturedVariables()); metadata->setEndPosition(positionBeforeLastNewline); RELEASE_ASSERT(metadata); RELEASE_ASSERT(metadata->ident().isNull()); // This function assumes an input string that would result in a single anonymous function expression. metadata->setEndPosition(positionBeforeLastNewline); RELEASE_ASSERT(metadata); metadata->overrideName(name); VariableEnvironment dummyTDZVariables; UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, dummyTDZVariables, DerivedContextType::None, WTFMove(sourceOverride)); return functionExecutable; }