From 0adfd598713b69f8e94008ea97d0a9ca07ffb049 Mon Sep 17 00:00:00 2001 From: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> Date: Sun, 29 Oct 2023 06:23:12 -0700 Subject: [PATCH] Allow moving the metadata part of `JSC::BuiltinExecutables::createExecutable` to compile-time --- Source/JavaScriptCore/CMakeLists.txt | 2 + .../builtins/BuiltinExecutableCreator.cpp | 7 +- .../builtins/BuiltinExecutableCreator.h | 3 + .../builtins/BuiltinExecutables.cpp | 78 ++++++++++++------- .../builtins/BuiltinExecutables.h | 3 +- Source/JavaScriptCore/builtins/BuiltinUtils.h | 3 + .../runtime/BuiltinExecutableMetadata.h | 46 +++++++++++ 7 files changed, 114 insertions(+), 28 deletions(-) create mode 100644 Source/JavaScriptCore/runtime/BuiltinExecutableMetadata.h diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index faecd4a47c597..35f4fb5d318b6 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -1404,6 +1404,8 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS runtime/JSModuleEnvironment.h runtime/JSModuleEnvironmentInlines.h + + runtime/BuiltinExecutableMetadata.h ) if(USE_INSPECTOR_SOCKET_SERVER) diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.cpp index d85ae4727dc8e..66180f2934add 100644 --- a/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.cpp +++ b/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.cpp @@ -34,5 +34,10 @@ UnlinkedFunctionExecutable* createBuiltinExecutable(VM& vm, const SourceCode& so { return BuiltinExecutables::createExecutable(vm, source, ident, implementationVisibility, kind, ability, NeedsClassFieldInitializer::No); } - + +UnlinkedFunctionExecutable* createBuiltinExecutable(VM& vm, const SourceCode& source, const Identifier& ident, ImplementationVisibility implementationVisibility, ConstructorKind kind, ConstructAbility ability, const BuiltinExecutableMetadata& metadata) +{ + return BuiltinExecutables::createExecutable(vm, source, ident, implementationVisibility, kind, ability, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, metadata); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.h b/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.h index d562f79bb3065..66b15410640a9 100644 --- a/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.h +++ b/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.h @@ -30,9 +30,12 @@ #include "ImplementationVisibility.h" #include "ParserModes.h" #include "SourceCode.h" +#include "BuiltinExecutableMetadata.h" namespace JSC { JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* createBuiltinExecutable(VM&, const SourceCode&, const Identifier&, ImplementationVisibility, ConstructorKind, ConstructAbility); +JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* createBuiltinExecutable(VM&, const SourceCode&, const Identifier&, ImplementationVisibility, ConstructorKind, ConstructAbility, const BuiltinExecutableMetadata&); + } // namespace JSC diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp index d2f85a70e784a..5706515bd57cb 100644 --- a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp +++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp @@ -31,6 +31,7 @@ #include "JSCJSValueInlines.h" #include "Parser.h" #include +#include "BuiltinExecutableMetadata.h" namespace JSC { @@ -75,34 +76,39 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(Constru UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const SourceCode& code, const Identifier& name, ImplementationVisibility implementationVisibility, ConstructorKind constructorKind, ConstructAbility constructAbility) { - return createExecutable(m_vm, code, name, implementationVisibility, constructorKind, constructAbility, NeedsClassFieldInitializer::No); + StringView view = code.view(); + RELEASE_ASSERT(!view.isNull()); + RELEASE_ASSERT(view.is8Bit()); + BuiltinExecutableMetadata meta(reinterpret_cast(view.characters8()), view.length()); + return createExecutable(m_vm, code, name, implementationVisibility, constructorKind, constructAbility, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, meta); } UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ImplementationVisibility implementationVisibility, ConstructorKind constructorKind, ConstructAbility constructAbility, NeedsClassFieldInitializer needsClassFieldInitializer, PrivateBrandRequirement privateBrandRequirement) { - // FIXME: Can we just make MetaData computation be constexpr and have the compiler do this for us? - // https://bugs.webkit.org/show_bug.cgi?id=193272 - // Someone should get mad at me for writing this code. But, it prevents us from recursing into - // the parser, and hence, from throwing stack overflow when parsing a builtin. StringView view = source.view(); RELEASE_ASSERT(!view.isNull()); RELEASE_ASSERT(view.is8Bit()); - auto* characters = view.characters8(); + BuiltinExecutableMetadata meta(reinterpret_cast(view.characters8()), view.length()); + return createExecutable(vm, source, name, implementationVisibility, constructorKind, constructAbility, needsClassFieldInitializer, privateBrandRequirement, meta); +} + +BuiltinExecutableMetadata::BuiltinExecutableMetadata(const unsigned char* characters, unsigned length) +{ const char* regularFunctionBegin = "(function ("; const char* asyncFunctionBegin = "(async function ("; - RELEASE_ASSERT(view.length() >= strlen("(function (){})")); - bool isAsyncFunction = view.length() >= strlen("(async function (){})") && !memcmp(characters, asyncFunctionBegin, strlen(asyncFunctionBegin)); + RELEASE_ASSERT(length >= strlen("(function (){})")); + isAsyncFunction = length >= strlen("(async function (){})") && !memcmp(characters, asyncFunctionBegin, strlen(asyncFunctionBegin)); RELEASE_ASSERT(isAsyncFunction || !memcmp(characters, regularFunctionBegin, strlen(regularFunctionBegin))); - unsigned asyncOffset = isAsyncFunction ? strlen("async ") : 0; - unsigned parametersStart = strlen("function (") + asyncOffset; - unsigned startColumn = parametersStart; - int functionKeywordStart = strlen("(") + asyncOffset; - int functionNameStart = parametersStart; - bool isInStrictContext = false; - bool isArrowFunctionBodyExpression = false; + asyncOffset = isAsyncFunction ? strlen("async ") : 0; + parametersStart = strlen("function (") + asyncOffset; + startColumn = parametersStart; + functionKeywordStart = strlen("(") + asyncOffset; + functionNameStart = parametersStart; + isInStrictContext = false; + isArrowFunctionBodyExpression = false; - unsigned parameterCount; + parameterCount = 0; { unsigned i = parametersStart + 1; unsigned commas = 0; @@ -110,7 +116,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S bool sawOneParam = false; bool hasRestParam = false; while (true) { - ASSERT(i < view.length()); + ASSERT(i < length); if (characters[i] == ')') break; @@ -125,7 +131,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S else if (!Lexer::isWhiteSpace(characters[i])) sawOneParam = true; - if (i + 2 < view.length() && characters[i] == '.' && characters[i + 1] == '.' && characters[i + 2] == '.') { + if (i + 2 < length && characters[i] == '.' && characters[i + 1] == '.' && characters[i + 2] == '.') { hasRestParam = true; i += 2; } @@ -146,11 +152,11 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S } } - unsigned lineCount = 0; - unsigned endColumn = 0; - unsigned offsetOfLastNewline = 0; + lineCount = 0; + endColumn = 0; + offsetOfLastNewline = 0; std::optional offsetOfSecondToLastNewline; - for (unsigned i = 0; i < view.length(); ++i) { + for (unsigned i = 0; i < length; ++i) { if (characters[i] == '\n') { if (lineCount) offsetOfSecondToLastNewline = offsetOfLastNewline; @@ -162,7 +168,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S if (!isInStrictContext && (characters[i] == '"' || characters[i] == '\'')) { const unsigned useStrictLength = strlen("use strict"); - if (i + 1 + useStrictLength < view.length()) { + if (i + 1 + useStrictLength < length) { if (!memcmp(characters + i + 1, "use strict", useStrictLength)) { isInStrictContext = true; i += 1 + useStrictLength; @@ -171,14 +177,34 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S } } - unsigned positionBeforeLastNewlineLineStartOffset = offsetOfSecondToLastNewline ? *offsetOfSecondToLastNewline + 1 : 0; + positionBeforeLastNewlineLineStartOffset = offsetOfSecondToLastNewline ? *offsetOfSecondToLastNewline + 1 : 0; - int closeBraceOffsetFromEnd = 1; + closeBraceOffsetFromEnd = 1; while (true) { - if (characters[view.length() - closeBraceOffsetFromEnd] == '}') + if (characters[length - closeBraceOffsetFromEnd] == '}') break; ++closeBraceOffsetFromEnd; } +} + +UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ImplementationVisibility implementationVisibility, ConstructorKind constructorKind, ConstructAbility constructAbility, NeedsClassFieldInitializer needsClassFieldInitializer, PrivateBrandRequirement privateBrandRequirement, const BuiltinExecutableMetadata& meta) +{ + StringView view = source.view(); + unsigned startColumn = meta.startColumn; + unsigned endColumn = meta.endColumn; + int functionKeywordStart = meta.functionKeywordStart; + int functionNameStart = meta.functionNameStart; + unsigned parametersStart = meta.parametersStart; + bool isInStrictContext = meta.isInStrictContext; + bool isArrowFunctionBodyExpression = meta.isArrowFunctionBodyExpression; + bool isAsyncFunction = meta.isAsyncFunction; + + unsigned lineCount = meta.lineCount; + unsigned offsetOfLastNewline = meta.offsetOfLastNewline; + unsigned positionBeforeLastNewlineLineStartOffset = meta.positionBeforeLastNewlineLineStartOffset; + unsigned closeBraceOffsetFromEnd = meta.closeBraceOffsetFromEnd; + unsigned asyncOffset = meta.asyncOffset; + unsigned parameterCount = meta.parameterCount; JSTextPosition positionBeforeLastNewline; positionBeforeLastNewline.line = lineCount; diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.h b/Source/JavaScriptCore/builtins/BuiltinExecutables.h index c9f36aa75f663..50149a1414b19 100644 --- a/Source/JavaScriptCore/builtins/BuiltinExecutables.h +++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.h @@ -37,6 +37,7 @@ namespace JSC { class UnlinkedFunctionExecutable; class Identifier; class VM; +class BuiltinExecutableMetadata; #define BUILTIN_NAME_ONLY(name, functionName, overriddenName, length) name, enum class BuiltinCodeIndex { @@ -61,7 +62,7 @@ SourceCode name##Source(); UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name, NeedsClassFieldInitializer, PrivateBrandRequirement); static UnlinkedFunctionExecutable* createExecutable(VM&, const SourceCode&, const Identifier&, ImplementationVisibility, ConstructorKind, ConstructAbility, NeedsClassFieldInitializer, PrivateBrandRequirement = PrivateBrandRequirement::None); - + static UnlinkedFunctionExecutable* createExecutable(VM&, const SourceCode&, const Identifier&, ImplementationVisibility, ConstructorKind, ConstructAbility, NeedsClassFieldInitializer, PrivateBrandRequirement, const BuiltinExecutableMetadata&); void finalizeUnconditionally(CollectionScope); private: diff --git a/Source/JavaScriptCore/builtins/BuiltinUtils.h b/Source/JavaScriptCore/builtins/BuiltinUtils.h index 6f62ce275b761..9a55aea322121 100644 --- a/Source/JavaScriptCore/builtins/BuiltinUtils.h +++ b/Source/JavaScriptCore/builtins/BuiltinUtils.h @@ -42,7 +42,10 @@ class Identifier; class SourceCode; class UnlinkedFunctionExecutable; class VM; +class BuiltinExecutableMetadata; JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* createBuiltinExecutable(VM&, const SourceCode&, const Identifier&, ImplementationVisibility, ConstructorKind, ConstructAbility); +JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* createBuiltinExecutable(VM&, const SourceCode&, const Identifier&, ImplementationVisibility, ConstructorKind, ConstructAbility, const BuiltinExecutableMetadata&); + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BuiltinExecutableMetadata.h b/Source/JavaScriptCore/runtime/BuiltinExecutableMetadata.h new file mode 100644 index 0000000000000..2107e501e9874 --- /dev/null +++ b/Source/JavaScriptCore/runtime/BuiltinExecutableMetadata.h @@ -0,0 +1,46 @@ +#pragma once + +namespace JSC { + +class BuiltinExecutableMetadata { +public: + BuiltinExecutableMetadata(const unsigned char* data, unsigned length); + BuiltinExecutableMetadata() = default; + BuiltinExecutableMetadata(unsigned startColumn, unsigned endColumn, int functionKeywordStart, int functionNameStart, unsigned parametersStart, bool isInStrictContext, bool isArrowFunctionBodyExpression, bool isAsyncFunction, unsigned asyncOffset, unsigned parameterCount, unsigned lineCount, unsigned offsetOfLastNewline, unsigned positionBeforeLastNewlineLineStartOffset, unsigned closeBraceOffsetFromEnd) + : startColumn(startColumn) + , endColumn(endColumn) + , functionKeywordStart(functionKeywordStart) + , functionNameStart(functionNameStart) + , parametersStart(parametersStart) + , isInStrictContext(isInStrictContext) + , isArrowFunctionBodyExpression(isArrowFunctionBodyExpression) + , isAsyncFunction(isAsyncFunction) + , asyncOffset(asyncOffset) + , parameterCount(parameterCount) + , lineCount(lineCount) + , offsetOfLastNewline(offsetOfLastNewline) + , positionBeforeLastNewlineLineStartOffset(positionBeforeLastNewlineLineStartOffset) + , closeBraceOffsetFromEnd(closeBraceOffsetFromEnd) + { + } + + unsigned startColumn; + unsigned endColumn; + + int functionKeywordStart; + int functionNameStart; + unsigned parametersStart; + bool isInStrictContext; + bool isArrowFunctionBodyExpression; + bool isAsyncFunction; + + unsigned asyncOffset; + unsigned parameterCount; + + unsigned lineCount; + unsigned offsetOfLastNewline; + unsigned positionBeforeLastNewlineLineStartOffset; + unsigned closeBraceOffsetFromEnd; +}; + +} // namespace JSC \ No newline at end of file