Skip to content

Commit

Permalink
Put all JIT support framework in place
Browse files Browse the repository at this point in the history
Summary: This makes everything ready for the JIT without the JIT itself.

Reviewed By: neildhar

Differential Revision: D61752810

fbshipit-source-id: 6e7e52699acd19814bf8d9095e51d00f69923309
  • Loading branch information
Tzvetan Mikov authored and facebook-github-bot committed Aug 27, 2024
1 parent 1d3005a commit 419a599
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 36 deletions.
9 changes: 9 additions & 0 deletions include/hermes/ConsoleHost/ConsoleHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,15 @@ struct ExecuteOptions {
/// Execution time limit.
uint32_t timeLimit{0};

/// Force JIT on all functions.
bool forceJIT{false};

/// Dump JIT'ed code.
bool dumpJITCode{false};

/// Fatally crash on any JIT compilation error.
bool jitCrashOnError{false};

/// Perform a full GC just before printing any statistics.
bool forceGCBeforeStats{false};

Expand Down
5 changes: 5 additions & 0 deletions include/hermes/VM/Callable.h
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,11 @@ class JSFunction : public Callable {
runtime.getEmptyCodeBlock());
}

/// A wrapper to convert a SH-style function to CallResult style.
static CallResult<HermesValue> _jittedCall(
JITCompiledFunctionPtr functionPtr,
Runtime &runtime);

/// Create a Function with no environment and a CodeBlock simply returning
/// undefined, with the prototype property auto-initialized to new Object().
static PseudoHandle<JSFunction> create(
Expand Down
87 changes: 87 additions & 0 deletions include/hermes/VM/CodeBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifndef HERMES_VM_CODEBLOCK_H
#define HERMES_VM_CODEBLOCK_H

#include "JIT/Config.h"
#include "hermes/BCGen/HBC/BCProvider.h"
#include "hermes/BCGen/HBC/BytecodeFileFormat.h"
#include "hermes/Inst/Inst.h"
Expand All @@ -29,6 +30,9 @@ namespace vm {
class RuntimeModule;
class CodeBlock;

/// A pointer to JIT-compiled function.
typedef HermesValue (*JITCompiledFunctionPtr)(Runtime *runtime);

/// A sequence of instructions representing the body of a function.
class CodeBlock final
: private llvh::TrailingObjects<CodeBlock, PropertyCacheEntry> {
Expand All @@ -46,6 +50,23 @@ class CodeBlock final
/// ID of this function in the module's function list.
uint32_t functionID_;

#ifndef HERMESVM_JIT
#error "JIT config not included"
#endif
#if HERMESVM_JIT
/// Set to true if for some reason we don't want to JIT this block, for
/// example because it contains constructs that the JIT can't handle.
bool dontJIT_ = false;

/// If this CodeBlock was compiled, a pointer to the body.
JITCompiledFunctionPtr JITCompiled_ = nullptr;

/// Function execution count.
/// Ideally, a function's hotness should also include if it has a loop and how
/// hot that loop is.
uint32_t executionCount_ = 0;
#endif

/// Total size of the property cache.
const uint32_t propertyCacheSize_;

Expand Down Expand Up @@ -217,6 +238,72 @@ class CodeBlock final
}
#endif

#if HERMESVM_JIT
/// \return true if JIT is disabled for this function.
bool getDontJIT() const {
return dontJIT_;
}

/// Enable or disable JIT compilation of this function.
void setDontJIT(bool dontJIT) {
dontJIT_ = dontJIT;
}

/// \return the native code for this function, or null if it hasn't been
/// compiled to native.
JITCompiledFunctionPtr getJITCompiled() const {
return JITCompiled_;
}

/// Set the native code for this function.
void setJITCompiled(JITCompiledFunctionPtr JITCompiled) {
JITCompiled_ = JITCompiled;
}

/// Increment the function execution count.
void incrementExecutionCount() {
executionCount_++;
}

/// \return the function execution count
uint32_t getExecutionCount() const {
return executionCount_;
}

/// Reset the function execution count to 0
void clearExecutionCount() {
executionCount_ = 0;
}
#else
/// \return true if JIT is disabled for this function.
bool getDontJIT() const {
return true;
}

/// Enable or disable JIT compilation of this function.
void setDontJIT(bool dontJIT) {}

/// \return the native code for this function, or null if it hasn't been
/// compiled to native.
JITCompiledFunctionPtr getJITCompiled() const {
return nullptr;
}

/// Set the native code for this function.
void setJITCompiled(JITCompiledFunctionPtr JITCompiled) {}

/// Increment the function executionCount_ count
void incrementExecutionCount() {}

/// \return the function executionCount_ count as 0 if the JIT is not enabled
uint32_t getExecutionCount() const {
return 0;
}

/// Reset the function executionCount_ count to 0
void clearExecutionCount() {}
#endif

inline PropertyCacheEntry *getReadCacheEntry(uint8_t idx) {
assert(idx < writePropCacheOffset_ && "idx out of ReadCache bound");
return &propertyCache()[idx];
Expand Down
70 changes: 70 additions & 0 deletions include/hermes/VM/JIT/JIT.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#ifndef HERMES_VM_JIT_JIT_H
#define HERMES_VM_JIT_JIT_H

#include "hermes/VM/JIT/Config.h"

#include "hermes/VM/CodeBlock.h"

namespace hermes {
namespace vm {

/// All state related to JIT compilation.
class JITContext {
public:
/// Construct a JIT context. No executable memory is allocated before it is
/// needed.
/// \param enable whether JIT is enabled.
JITContext(bool enable) {}
~JITContext() = default;

JITContext(const JITContext &) = delete;
void operator=(const JITContext &) = delete;

/// Compile a function to native code and return the native pointer. If the
/// function was previously compiled, return the existing body. If it cannot
/// be compiled, return nullptr.
inline JITCompiledFunctionPtr compile(
Runtime &runtime,
CodeBlock *codeBlock) {
return codeBlock->getJITCompiled();
}

/// \return true if JIT compilation is enabled.
bool isEnabled() const {
return false;
}

/// Enable or disable JIT compilation.
void setEnabled(bool enabled) {}

/// Enable or disable dumping JIT'ed Code.
void setDumpJITCode(bool dump) {}

/// \return true if dumping JIT'ed Code is enabled.
bool getDumpJITCode() {
return false;
}

/// Set the flag to fatally crash on JIT compilation errors.
void setCrashOnError(bool crash) {}

/// \return true if we should fatally crash on JIT compilation errors.
bool getCrashOnError() {
return false;
}

/// Whether to force jitting of all functions right away.
void setForceJIT(bool force) {}
};

} // namespace vm
} // namespace hermes

#endif // HERMES_VM_JIT_JIT_H
9 changes: 9 additions & 0 deletions include/hermes/VM/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "hermes/VM/IdentifierTable.h"
#include "hermes/VM/InternalProperty.h"
#include "hermes/VM/InterpreterState.h"
#include "hermes/VM/JIT/JIT.h"
#include "hermes/VM/Predefined.h"
#include "hermes/VM/Profiler.h"
#include "hermes/VM/Profiler/SamplingProfilerDefs.h"
Expand Down Expand Up @@ -578,6 +579,10 @@ class Runtime : public RuntimeBase, public HandleRootOwner {
/// Return the global object.
Handle<JSObject> getGlobal();

/// Return the JIT context.
JITContext &getJITContext() {
return jitContext_;
}
/// Returns trailing data for all runtime modules.
std::vector<llvh::ArrayRef<uint8_t>> getEpilogues();

Expand Down Expand Up @@ -1121,6 +1126,9 @@ class Runtime : public RuntimeBase, public HandleRootOwner {
std::vector<std::function<void(HeapSnapshot &)>> customSnapshotNodeFuncs_;
std::vector<std::function<void(HeapSnapshot &)>> customSnapshotEdgeFuncs_;

/// All state related to JIT compilation.
JITContext jitContext_;

/// Set to true if we should enable ES6 Promise.
const bool hasES6Promise_;

Expand Down Expand Up @@ -1166,6 +1174,7 @@ class Runtime : public RuntimeBase, public HandleRootOwner {
friend class RuntimeModule;
friend class MarkRootsPhaseTimer;
friend struct RuntimeOffsets;
friend class JITContext;
friend class ScopedNativeDepthReducer;
friend class ScopedNativeDepthTracker;
friend class ScopedNativeCallFrame;
Expand Down
28 changes: 28 additions & 0 deletions include/hermes/VM/RuntimeFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,34 @@ struct VMOnlyRuntimeFlags {
"TTI notification"),
llvh::cl::cat(GCCategory),
llvh::cl::init(false)};

llvh::cl::opt<bool> EnableJIT{
"Xjit",
llvh::cl::Hidden,
llvh::cl::cat(RuntimeCategory),
llvh::cl::desc("enable JIT compilation"),
llvh::cl::init(false)};

llvh::cl::opt<bool> ForceJIT{
"Xforce-jit",
llvh::cl::Hidden,
llvh::cl::cat(RuntimeCategory),
llvh::cl::desc("force JIT compilation of every function"),
llvh::cl::init(false)};

llvh::cl::opt<bool> DumpJITCode{
"Xdump-jitcode",
llvh::cl::Hidden,
llvh::cl::cat(RuntimeCategory),
llvh::cl::desc("dump JIT'ed code"),
llvh::cl::init(false)};

llvh::cl::opt<bool> JITCrashOnError{
"Xjit-crash-on-error",
llvh::cl::Hidden,
llvh::cl::cat(RuntimeCategory),
llvh::cl::desc("crash on any JIT compilation error"),
llvh::cl::init(false)};
};

/// All command line runtime options relevant to the VM, including options
Expand Down
5 changes: 5 additions & 0 deletions lib/ConsoleHost/ConsoleHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ bool executeHBCBytecodeImpl(
std::unique_ptr<vm::StatSamplingThread> statSampler;
auto runtime = vm::Runtime::create(options.runtimeConfig);

// TODO: surely this should use RuntimeConfig?
runtime->getJITContext().setForceJIT(options.forceJIT);
runtime->getJITContext().setDumpJITCode(options.dumpJITCode);
runtime->getJITContext().setCrashOnError(options.jitCrashOnError);

if (options.timeLimit > 0) {
runtime->timeLimitMonitor = vm::TimeLimitMonitor::getOrCreate();
runtime->timeLimitMonitor->watchRuntime(
Expand Down
Loading

0 comments on commit 419a599

Please sign in to comment.