UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) { SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal); CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); if (!addResult.isNewEntry) return jsCast<UnlinkedFunctionExecutable*>(addResult.iterator->value.cell.get()); JSTextPosition positionBeforeLastNewline; RefPtr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline); if (!program) { RELEASE_ASSERT(error.m_type != ParserError::ErrorNone); m_sourceCode.remove(addResult.iterator); return 0; } // This function assumes an input string that would result in a single anonymous function expression. 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()); FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); RELEASE_ASSERT(!program->hasCapturedVariables()); body->setEndPosition(positionBeforeLastNewline); RELEASE_ASSERT(body); RELEASE_ASSERT(body->ident().isNull()); UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, UnlinkedNormalFunction); functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); addResult.iterator->value = 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; }