WebKit Bugzilla
Attachment 359045 Details for
Bug 193401
: Add API to generate and consume cached bytecode
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193401-20190114184537.patch (text/plain), 14.40 KB, created by
Tadeu Zagallo
on 2019-01-14 09:45:45 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Tadeu Zagallo
Created:
2019-01-14 09:45:45 PST
Size:
14.40 KB
patch
obsolete
>Subversion Revision: 239675 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index eeff51c904bfc794991a5e5d6ac51c987ab44741..009ecb1a051816f0cfb19f0b66a2535b5277bd06 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,34 @@ >+2019-01-14 Tadeu Zagallo <tzagallo@apple.com> >+ >+ Add entry point to eagerly generate bytecode for a given SourceCode >+ https://bugs.webkit.org/show_bug.cgi?id=193401 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a new `generateBytecode` function that eagerly generates bytecode >+ for a given source file and all its functions. Currently, this function >+ relies on Options::diskCachePath() to write the bytecode to disk. >+ >+ This function is not being used for running the bytecode-cache tests yet, >+ because we can't guarantee that all the necessary code has been cached >+ since some tests `load` and `import` other files. >+ >+ * jsc.cpp: >+ (runWithOptions): >+ (printUsageStatement): >+ (CommandLine::parseArguments): >+ * runtime/CodeCache.cpp: >+ (JSC::CodeCacheMap::pruneSlowCase): >+ (JSC::CodeCache::write): >+ (JSC::generateUnlinkedCodeBlockForFunctions): >+ (JSC::writeCodeBlock): >+ (JSC::writeGlobalCodeBlockToDisk): >+ * runtime/CodeCache.h: >+ (JSC::recursivelyGenerateUnlinkedCodeBlock): >+ * runtime/Completion.cpp: >+ (JSC::generateBytecode): >+ * runtime/Completion.h: >+ > 2019-01-08 Tadeu Zagallo <tzagallo@apple.com> > > Cache bytecode to disk >diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp >index be95751f7597552fc24584b6eb789acdb7cff2fc..1c50cc7f27bd14220ec0374945fa1eb22a68a343 100644 >--- a/Source/JavaScriptCore/jsc.cpp >+++ b/Source/JavaScriptCore/jsc.cpp >@@ -422,6 +422,7 @@ public: > bool m_treatWatchdogExceptionAsSuccess { false }; > bool m_alwaysDumpUncaughtException { false }; > bool m_dumpSamplingProfilerData { false }; >+ bool m_generateBytecode { false }; > bool m_enableRemoteDebugging { false }; > > void parseArguments(int, char**); >@@ -2468,12 +2469,17 @@ static void runWithOptions(GlobalObject* globalObject, CommandLine& options, boo > scope.releaseAssertNoException(); > vm.drainMicrotasks(); > } else { >- NakedPtr<Exception> evaluationException; >- JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException); >- scope.assertNoException(); >- if (evaluationException) >- returnValue = evaluationException->value(); >- checkException(globalObject->globalExec(), globalObject, isLastFile, evaluationException, returnValue, options, success); >+ if (options.m_generateBytecode) { >+ ParserError error; >+ generateBytecode(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), error); >+ } else { >+ NakedPtr<Exception> evaluationException; >+ JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException); >+ scope.assertNoException(); >+ if (evaluationException) >+ returnValue = evaluationException->value(); >+ checkException(globalObject->globalExec(), globalObject, isLastFile, evaluationException, returnValue, options, success); >+ } > } > > scriptBuffer.clear(); >@@ -2570,6 +2576,7 @@ static NO_RETURN void printUsageStatement(bool help = false) > fprintf(stderr, " -x Output exit code before terminating\n"); > fprintf(stderr, "\n"); > fprintf(stderr, " --sample Collects and outputs sampling profiler data\n"); >+ fprintf(stderr, " --generate-bytecode Populate bytecode cache and exit\n"); > fprintf(stderr, " --test262-async Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n"); > fprintf(stderr, " --strict-file=<file> Parse the given file as if it were in strict mode (this option may be passed more than once)\n"); > fprintf(stderr, " --module-file=<file> Parse and evaluate the given file as module (this option may be passed more than once)\n"); >@@ -2687,6 +2694,10 @@ void CommandLine::parseArguments(int argc, char** argv) > m_dumpSamplingProfilerData = true; > continue; > } >+ if (!strcmp(arg, "--generate-bytecode")) { >+ m_generateBytecode = true; >+ continue; >+ } > > static const char* timeoutMultiplierOptStr = "--timeoutMultiplier="; > static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr); >diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp >index c32d204b6cd8968181cb0d1df0eab83ec11819d4..1b0e2b848f7127658161f5606e8407bb5a2844d0 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.cpp >+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp >@@ -44,7 +44,10 @@ void CodeCacheMap::pruneSlowCase() > while (m_size > m_capacity || !canPruneQuickly()) { > MapType::iterator it = m_map.begin(); > >- writeCodeBlock(*it->value.cell->vm(), it->key, it->value); >+ VM& vm = *it->value.cell->vm(); >+ UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, it->value.cell.get()); >+ if (codeBlock) >+ writeCodeBlock(vm, it->key, codeBlock); > > m_size -= it->key.length(); > m_map.remove(it); >@@ -158,8 +161,74 @@ UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& v > > void CodeCache::write(VM& vm) > { >- for (const auto& it : m_sourceCode) >- writeCodeBlock(vm, it.key, it.value); >+ for (const auto& it : m_sourceCode) { >+ UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, it.value.cell.get()); >+ if (!codeBlock) >+ continue; >+ writeCodeBlock(vm, it.key, codeBlock); >+ } >+} >+ >+void generateUnlinkedCodeBlockForFunctions(VM& vm, UnlinkedCodeBlock* unlinkedCodeBlock, const SourceCode& parentSource, DebuggerMode debuggerMode, ParserError& error) >+{ >+ auto generate = [&](UnlinkedFunctionExecutable* unlinkedExecutable, CodeSpecializationKind constructorKind) { >+ if (constructorKind == CodeForConstruct && SourceParseModeSet(SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::AsyncMethodMode, SourceParseMode::AsyncFunctionMode).contains(unlinkedExecutable->parseMode())) >+ return; >+ >+ FunctionExecutable* executable = unlinkedExecutable->link(vm, parentSource); >+ const SourceCode& source = executable->source(); >+ UnlinkedFunctionCodeBlock* unlinkedFunctionCodeBlock = unlinkedExecutable->unlinkedCodeBlockFor(vm, source, constructorKind, debuggerMode, error, unlinkedExecutable->parseMode()); >+ if (unlinkedFunctionCodeBlock) >+ generateUnlinkedCodeBlockForFunctions(vm, unlinkedFunctionCodeBlock, source, debuggerMode, error); >+ }; >+ >+ for (unsigned i = 0; i < unlinkedCodeBlock->numberOfFunctionDecls(); i++) { >+ generate(unlinkedCodeBlock->functionDecl(i), CodeForCall); >+ generate(unlinkedCodeBlock->functionDecl(i), CodeForConstruct); >+ } >+ for (unsigned i = 0; i < unlinkedCodeBlock->numberOfFunctionExprs(); i++) { >+ generate(unlinkedCodeBlock->functionExpr(i), CodeForCall); >+ generate(unlinkedCodeBlock->functionExpr(i), CodeForConstruct); >+ } >+} >+ >+void writeCodeBlock(VM& vm, const SourceCodeKey& key, UnlinkedCodeBlock* codeBlock) >+{ >+#if OS(DARWIN) >+ const char* cachePath = Options::diskCachePath(); >+ if (LIKELY(!cachePath)) >+ return; >+ >+ unsigned hash = key.hash(); >+ char filename[512]; >+ int count = snprintf(filename, 512, "%s/%u.cache", cachePath, hash); >+ if (count < 0 || count > 512) >+ return; >+ >+ std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock); >+ >+ int fd = open(filename, O_CREAT | O_WRONLY, 0666); >+ int rc = flock(fd, LOCK_EX | LOCK_NB); >+ if (!rc) >+ ::write(fd, result.first.get(), result.second); >+ close(fd); >+#else >+ UNUSED_PARAM(vm); >+ UNUSED_PARAM(key); >+ UNUSED_PARAM(value); >+#endif >+} >+ >+ >+void writeGlobalCodeBlockToDisk(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode) >+{ >+ SourceCodeKey key( >+ source, String(), codeType, strictMode, scriptMode, >+ DerivedContextType::None, EvalContextType::None, false, debuggerMode, >+ vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, >+ vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No, >+ WTF::nullopt); >+ writeCodeBlock(vm, key, codeBlock); > } > > } >diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h >index 99395f2cd2841139a035c8b1589bb939c69c5702..8c88a855cea230c980477aa167a38c6b488575bb 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.h >+++ b/Source/JavaScriptCore/runtime/CodeCache.h >@@ -36,6 +36,7 @@ > #include "StrongInlines.h" > #include "UnlinkedCodeBlock.h" > #include "UnlinkedEvalCodeBlock.h" >+#include "UnlinkedFunctionCodeBlock.h" > #include "UnlinkedModuleProgramCodeBlock.h" > #include "UnlinkedProgramCodeBlock.h" > #include <sys/stat.h> >@@ -322,36 +323,20 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa > return unlinkedCodeBlock; > } > >-ALWAYS_INLINE static void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& value) >+void generateUnlinkedCodeBlockForFunctions(VM&, UnlinkedCodeBlock*, const SourceCode&, DebuggerMode, ParserError&); >+ >+template <class UnlinkedCodeBlockType, class ExecutableType> >+UnlinkedCodeBlockType* recursivelyGenerateUnlinkedCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ) > { >-#if OS(DARWIN) >- const char* cachePath = Options::diskCachePath(); >- if (LIKELY(!cachePath)) >- return; >- >- UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, value.cell.get()); >- if (!codeBlock) >- return; >- >- unsigned hash = key.hash(); >- char filename[512]; >- int count = snprintf(filename, 512, "%s/%u.cache", cachePath, hash); >- if (count < 0 || count > 512) >- return; >- >- std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock); >- >- int fd = open(filename, O_CREAT | O_WRONLY, 0666); >- int rc = flock(fd, LOCK_EX | LOCK_NB); >- if (!rc) >- ::write(fd, result.first.get(), result.second); >- close(fd); >-#else >- UNUSED_PARAM(vm); >- UNUSED_PARAM(key); >- UNUSED_PARAM(value); >-#endif >+ UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, variablesUnderTDZ); >+ if (!unlinkedCodeBlock) >+ return nullptr; >+ >+ generateUnlinkedCodeBlockForFunctions(vm, unlinkedCodeBlock, source, debuggerMode, error); >+ return unlinkedCodeBlock; > } > >+void writeCodeBlock(VM&, const SourceCodeKey&, UnlinkedCodeBlock*); >+void writeGlobalCodeBlockToDisk(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, DebuggerMode); > > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp >index 1102f66c3226d745cae8cfba20f6af43379abed9..7e9ec35a7979a40dc5bc276f8b4b9bd009f64318 100644 >--- a/Source/JavaScriptCore/runtime/Completion.cpp >+++ b/Source/JavaScriptCore/runtime/Completion.cpp >@@ -25,6 +25,7 @@ > > #include "CallFrame.h" > #include "CatchScope.h" >+#include "CodeCache.h" > #include "CodeProfiling.h" > #include "Exception.h" > #include "IdentifierInlines.h" >@@ -90,6 +91,30 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e > return true; > } > >+bool generateBytecode(ExecState* exec, const SourceCode& source, ParserError& error) >+{ >+ if (!Options::diskCachePath()) >+ return false; >+ >+ VM& vm = exec->vm(); >+ JSLockHolder lock(vm); >+ RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable()); >+ >+ ProgramExecutable* executable = ProgramExecutable::create(exec, source); >+ JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec); >+ >+ VariableEnvironment variablesUnderTDZ; >+ JSParserStrictMode strictMode = JSParserStrictMode::NotStrict; >+ JSParserScriptMode scriptMode = JSParserScriptMode::Classic; >+ DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff; >+ EvalContextType evalContextType = EvalContextType::None; >+ >+ UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); >+ writeGlobalCodeBlockToDisk(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode); >+ >+ return true; >+} >+ > JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException) > { > VM& vm = exec->vm(); >diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h >index de448a408471c742e6f2288f1aa724e33f897497..88026653a58d07b4db9b18cea88e5f5c9d88da8a 100644 >--- a/Source/JavaScriptCore/runtime/Completion.h >+++ b/Source/JavaScriptCore/runtime/Completion.h >@@ -39,6 +39,7 @@ class JSInternalPromise; > JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&); > JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0); > JS_EXPORT_PRIVATE bool checkModuleSyntax(ExecState*, const SourceCode&, ParserError&); >+JS_EXPORT_PRIVATE bool generateBytecode(ExecState*, const SourceCode&, ParserError&); > > JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException); > inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue())
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193401
:
359045
|
359899
|
359954
|
360008
|
360040
|
360114
|
360158