UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, 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()); RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); if (!program) { 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(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); RELEASE_ASSERT(funcExpr->isFuncExprNode()); FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); ASSERT(body->ident().isNull()); UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body); functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); addResult.iterator->value = SourceCodeValue(globalData, functionExecutable, m_sourceCode.age()); return functionExecutable; }
UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error) { GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string()); const Strong<UnlinkedFunctionExecutable>* result = m_cachedGlobalFunctions.find(key); if (result) return result->get(); RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); if (!program) { ASSERT(error.m_type != ParserError::ErrorNone); return 0; } // This function assumes an input string that would result in a single anonymous function expression. StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); ASSERT(body->ident().isNull()); UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body); functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); m_cachedGlobalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable)); return functionExecutable; }
PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) { RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), debugger, exec, source, errLine, errMsg); if (!program) return 0; StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); if (!exprStatement || !exprStatement->isExprStatement()) return 0; ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); if (!funcExpr || !funcExpr->isFuncExprNode()) return 0; FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); }
FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception); if (!program) { ASSERT(*exception); return 0; } // Uses of this function that would not result in a single function expression are invalid. StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); return FunctionExecutable::create(exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); }
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; }