Jit/codegen/gen_asm.h (157 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) #pragma once #include "Python.h" #include "opcode.h" #include "Jit/bitvector.h" #include "Jit/codegen/environ.h" #include "Jit/codegen/x86_64.h" #include "Jit/hir/hir.h" #include "Jit/jit_rt.h" #include "Jit/lir/lir.h" #include "Jit/pyjit.h" #include "Jit/util.h" #include <asmjit/asmjit.h> #include <algorithm> #include <list> #include <string> #include <unordered_map> #include <unordered_set> #include <vector> namespace jit { namespace codegen { // Generate the final stage trampoline that is responsible for finishing // execution in the interpreter and then returning the result to the caller. void* generateDeoptTrampoline(bool generator_mode); void* generateJitTrampoline(); class NativeGenerator { public: NativeGenerator(const hir::Function* func) : func_(func), deopt_trampoline_(generateDeoptTrampoline(false)), deopt_trampoline_generators_(generateDeoptTrampoline(true)), jit_trampoline_(generateJitTrampoline()), frame_header_size_(calcFrameHeaderSize(func)), max_inline_depth_(calcMaxInlineDepth(func)) { env_.has_inlined_functions = max_inline_depth_ > 0; } NativeGenerator( const hir::Function* func, void* deopt_trampoline, void* deopt_trampoline_generators, void* jit_trampoline) : func_(func), deopt_trampoline_(deopt_trampoline), deopt_trampoline_generators_(deopt_trampoline_generators), jit_trampoline_(jit_trampoline), frame_header_size_(calcFrameHeaderSize(func)), max_inline_depth_(calcMaxInlineDepth(func)) { env_.has_inlined_functions = max_inline_depth_ > 0; } void SetJSONOutput(nlohmann::json* json) { JIT_CHECK(json != nullptr, "expected non-null stream"); this->json = json; } ~NativeGenerator() { if (as_ != nullptr) { delete as_; } } std::string GetFunctionName() const; void* GetEntryPoint(); int GetCompiledFunctionSize() const; int GetCompiledFunctionStackSize() const; int GetCompiledFunctionSpillStackSize() const; const hir::Function* GetFunction() const { return func_; } CodeRuntime* codeRuntime() const { return env_.code_rt; } bool isGen() const { return func_->code->co_flags & kCoFlagsAnyGenerator; } #ifdef __ASM_DEBUG const char* GetPyFunctionName() const; #endif private: const hir::Function* func_; void* entry_{nullptr}; asmjit::x86::Builder* as_{nullptr}; void* deopt_trampoline_{nullptr}; void* deopt_trampoline_generators_{nullptr}; void* jit_trampoline_{nullptr}; int compiled_size_{-1}; int spill_stack_size_{-1}; int frame_header_size_; int max_inline_depth_; int calcFrameHeaderSize(const hir::Function* func); int calcMaxInlineDepth(const hir::Function* func); size_t numGpRegsForArgs() const; bool forEachArgumentRegInfo( std::function<void(std::optional<asmjit::x86::Reg>, size_t)> cb) const; void generateCode(asmjit::CodeHolder& code); void generateFunctionEntry(); void linkOnStackShadowFrame( asmjit::x86::Gp tstate_reg, asmjit::x86::Gp scratch_reg); void initializeFrameHeader( asmjit::x86::Gp tstate_reg, asmjit::x86::Gp scratch_reg); int setupFrameAndSaveCallerRegisters(asmjit::x86::Gp tstate_reg); void generatePrologue( asmjit::Label correct_arg_count, asmjit::Label native_entry_point); void loadOrGenerateLinkFrame( asmjit::x86::Gp tstate_reg, const std::vector< std::pair<const asmjit::x86::Reg, const asmjit::x86::Reg>>& save_regs); void generateEpilogue(asmjit::BaseNode* epilogue_cursor); void generateEpilogueUnlinkFrame(asmjit::x86::Gp tstate_reg, bool is_gen); void generateDeoptExits(); void linkDeoptPatchers(const asmjit::CodeHolder& code); void linkIPtoBCMappings(const asmjit::CodeHolder& code); void generateResumeEntry(); void generateStaticMethodTypeChecks(asmjit::Label setup_frame); void generateStaticEntryPoint( asmjit::Label native_entry_point, asmjit::Label static_jmp_location); void generateTypedArgumentInfo(); void loadTState(asmjit::x86::Gp dst_reg); void CollectOptimizableLoadMethods(); FRIEND_TEST(LinearScanAllocatorTest, RegAllocation); friend class BackendTest; void generateAssemblyBody(); std::unique_ptr<lir::Function> lir_func_; Environ env_; nlohmann::json* json{nullptr}; }; class NativeGeneratorFactory { public: NativeGeneratorFactory() { deopt_trampoline_ = generateDeoptTrampoline(false); deopt_trampoline_generators_ = generateDeoptTrampoline(true); jit_trampoline_ = generateJitTrampoline(); } static Runtime* runtime() { if (s_jit_asm_code_rt_ == nullptr) { s_jit_asm_code_rt_ = new Runtime; } return s_jit_asm_code_rt_; } std::unique_ptr<NativeGenerator> operator()(const hir::Function* func) const { return std::make_unique<NativeGenerator>( func, deopt_trampoline_, deopt_trampoline_generators_, jit_trampoline_); } static void shutdown() { _PyJIT_ClearDictCaches(); delete s_jit_asm_code_rt_; s_jit_asm_code_rt_ = nullptr; } DISALLOW_COPY_AND_ASSIGN(NativeGeneratorFactory); private: static Runtime* s_jit_asm_code_rt_; void* deopt_trampoline_; void* deopt_trampoline_generators_; void* jit_trampoline_; }; // Returns whether or not we can load/store reg from/to addr with a single // instruction. bool canLoadStoreAddr(asmjit::x86::Gp reg, int64_t addr); } // namespace codegen } // namespace jit