BuiltinExecutables.cpp [plain text]
#include "config.h"
#include "BuiltinExecutables.h"
#include "BuiltinNames.h"
#include "JSCInlines.h"
#include "Parser.h"
#include <wtf/Expected.h>
#include <wtf/NeverDestroyed.h>
namespace JSC {
BuiltinExecutables::BuiltinExecutables(VM& vm)
: m_vm(vm)
#define INITIALIZE_BUILTIN_SOURCE_MEMBERS(name, functionName, overrideName, 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(MAKE_STATIC_STRING_IMPL("(function () { })"));
static NeverDestroyed<const String> derivedConstructorCode(MAKE_STATIC_STRING_IMPL("(function (...args) { super(...args); })"));
switch (constructorKind) {
case ConstructorKind::None:
break;
case ConstructorKind::Base:
return createExecutableOrCrash(m_vm, makeSource(baseConstructorCode, { }), name, constructorKind, ConstructAbility::CanConstruct);
case ConstructorKind::Extends:
return createExecutableOrCrash(m_vm, makeSource(derivedConstructorCode, { }), name, constructorKind, ConstructAbility::CanConstruct);
}
RELEASE_ASSERT_NOT_REACHED();
}
ExpectedUnlinkedFunctionExecutable 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::createExecutableOrCrash(vm, code, name, ConstructorKind::None, constructAbility);
}
UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableOrCrash(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility)
{
auto expected = BuiltinExecutables::createExecutable(vm, source, name, constructorKind, constructAbility);
if (!expected.has_value()) {
dataLogLn("Fatal error compiling builtin function '", name.string(), "'");
CRASH();
}
return expected.value();
}
ExpectedUnlinkedFunctionExecutable 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;
SourceCode parentSourceOverride = isParsingDefaultConstructor ? source : SourceCode();
std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
&vm, source, Identifier(), builtinMode,
JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error,
&positionBeforeLastNewline, constructorKind);
if (!program) {
RELEASE_ASSERT(error.isValid());
return makeUnexpected(WTFMove(error));
}
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());
metadata->setEndPosition(positionBeforeLastNewline);
RELEASE_ASSERT(metadata);
metadata->overrideName(name);
VariableEnvironment dummyTDZVariables;
UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, JSParserScriptMode::Classic, dummyTDZVariables, DerivedContextType::None, WTFMove(parentSourceOverride));
return ExpectedUnlinkedFunctionExecutable(functionExecutable);
}
void BuiltinExecutables::finalize(Handle<Unknown>, void* context)
{
static_cast<Weak<UnlinkedFunctionExecutable>*>(context)->clear();
}
#define DEFINE_BUILTIN_EXECUTABLES(name, functionName, overrideName, length) \
ExpectedUnlinkedFunctionExecutable BuiltinExecutables::name##Executable() \
{\
if (!m_##name##Executable) {\
Identifier executableName = m_vm.propertyNames->builtinNames().functionName##PublicName();\
if (overrideName)\
executableName = Identifier::fromString(&m_vm, overrideName);\
ExpectedUnlinkedFunctionExecutable f = createBuiltinExecutable(m_##name##Source, executableName, s_##name##ConstructAbility);\
if (!f.has_value())\
return f;\
m_##name##Executable = Weak<UnlinkedFunctionExecutable>(f.value(), this, &m_##name##Executable);\
}\
return ExpectedUnlinkedFunctionExecutable(m_##name##Executable.get());\
}
JSC_FOREACH_BUILTIN_CODE(DEFINE_BUILTIN_EXECUTABLES)
#undef EXPOSE_BUILTIN_SOURCES
}