// 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; }
// 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) { SourceCodeKey key = SourceCodeKey( source, name.string(), SourceCodeKey::FunctionType, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict); SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); if (cache) return jsCast<UnlinkedFunctionExecutable*>(cache->cell.get()); JSTextPosition positionBeforeLastNewline; std::unique_ptr<ProgramNode> program = parse<ProgramNode>( &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserCodeType::Program, 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; FunctionBodyNode* body = static_cast<FuncDeclNode*>(funcDecl)->body(); ASSERT(body); if (!body) return nullptr; body->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, body, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables); functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age())); return functionExecutable; }