Path: blob/master/CodeGen/include/Luau/SharedCodeAllocator.h
2727 views
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details1#pragma once23#include "Luau/CodeAllocationData.h"4#include "Luau/CodeGen.h"5#include "Luau/Common.h"6#include "Luau/NativeProtoExecData.h"78#include <array>9#include <atomic>10#include <memory>11#include <mutex>12#include <optional>13#include <stdint.h>14#include <unordered_map>15#include <vector>1617namespace Luau18{19namespace CodeGen20{2122// SharedCodeAllocator is a native executable code allocator that provides23// shared ownership of the native code. Code is allocated on a per-module24// basis. Each module is uniquely identifiable via an id, which may be a hash25// or other unique value. Each module may contain multiple natively compiled26// functions (protos).27//28// The module is the unit of shared ownership (i.e., it is where the reference29// count is maintained).303132struct CodeAllocator;33class NativeModule;34class NativeModuleRef;35class SharedCodeAllocator;363738// A NativeModule represents a single natively-compiled module (script). It is39// the unit of shared ownership and is thus where the reference count is40// maintained. It owns a set of NativeProtos, with associated native exec data,41// and the allocated native data and code.42class NativeModule43{44public:45NativeModule(46SharedCodeAllocator* allocator,47const std::optional<ModuleId>& moduleId,48const uint8_t* moduleBaseAddress,49std::vector<NativeProtoExecDataPtr> nativeProtos50) noexcept;51NativeModule(52SharedCodeAllocator* allocator,53const std::optional<ModuleId>& moduleId,54CodeAllocationData codeAllocationData,55std::vector<NativeProtoExecDataPtr> nativeProtos56) noexcept;5758NativeModule(const NativeModule&) = delete;59NativeModule(NativeModule&&) = delete;60NativeModule& operator=(const NativeModule&) = delete;61NativeModule& operator=(NativeModule&&) = delete;6263// The NativeModule must not be destroyed if there are any outstanding64// references. It should thus only be destroyed by a call to release()65// that releases the last reference.66~NativeModule() noexcept;6768size_t addRef() const noexcept;69size_t addRefs(size_t count) const noexcept;70size_t release() const noexcept;71[[nodiscard]] size_t getRefcount() const noexcept;7273[[nodiscard]] const std::optional<ModuleId>& getModuleId() const noexcept;7475// Gets the base address of the executable native code for the module.76[[nodiscard]] const uint8_t* getModuleBaseAddress() const noexcept;7778// Gets the information about code allocation for this module.79[[nodiscard]] CodeAllocationData getCodeAllocationData() const noexcept;8081// Attempts to find the NativeProto with the given bytecode id. If no82// NativeProto for that bytecode id exists, a null pointer is returned.83[[nodiscard]] const uint32_t* tryGetNativeProto(uint32_t bytecodeId) const noexcept;8485[[nodiscard]] const std::vector<NativeProtoExecDataPtr>& getNativeProtos() const noexcept;8687private:88mutable std::atomic<size_t> refcount = 0;8990SharedCodeAllocator* allocator = nullptr;91std::optional<ModuleId> moduleId = {};92const uint8_t* moduleBaseAddress_DEPRECATED = nullptr;93CodeAllocationData codeAllocationData;9495std::vector<NativeProtoExecDataPtr> nativeProtos = {};96};9798// A NativeModuleRef is an owning reference to a NativeModule. (Note: We do99// not use shared_ptr, to avoid complex state management in the Luau GC Proto100// object.)101class NativeModuleRef102{103public:104NativeModuleRef() noexcept = default;105NativeModuleRef(const NativeModule* nativeModule) noexcept;106107NativeModuleRef(const NativeModuleRef& other) noexcept;108NativeModuleRef(NativeModuleRef&& other) noexcept;109NativeModuleRef& operator=(NativeModuleRef other) noexcept;110111~NativeModuleRef() noexcept;112113void reset() noexcept;114void swap(NativeModuleRef& other) noexcept;115116[[nodiscard]] bool empty() const noexcept;117explicit operator bool() const noexcept;118119[[nodiscard]] const NativeModule* get() const noexcept;120[[nodiscard]] const NativeModule* operator->() const noexcept;121[[nodiscard]] const NativeModule& operator*() const noexcept;122123private:124const NativeModule* nativeModule = nullptr;125};126127class SharedCodeAllocator128{129public:130SharedCodeAllocator(CodeAllocator* codeAllocator) noexcept;131132SharedCodeAllocator(const SharedCodeAllocator&) = delete;133SharedCodeAllocator(SharedCodeAllocator&&) = delete;134SharedCodeAllocator& operator=(const SharedCodeAllocator&) = delete;135SharedCodeAllocator& operator=(SharedCodeAllocator&&) = delete;136137~SharedCodeAllocator() noexcept;138139// If we have a NativeModule for the given ModuleId, an owning reference to140// it is returned. Otherwise, an empty NativeModuleRef is returned.141[[nodiscard]] NativeModuleRef tryGetNativeModule(const ModuleId& moduleId) const noexcept;142143// If we have a NativeModule for the given ModuleId, an owning reference to144// it is returned. Otherwise, a new NativeModule is created for that ModuleId145// using the provided NativeProtos, data, and code (space is allocated for the146// data and code such that it can be executed). Like std::map::insert, the147// bool result is true if a new module was created; false if an existing148// module is being returned.149std::pair<NativeModuleRef, bool> getOrInsertNativeModule(150const ModuleId& moduleId,151std::vector<NativeProtoExecDataPtr> nativeProtos,152const uint8_t* data,153size_t dataSize,154const uint8_t* code,155size_t codeSize156);157158NativeModuleRef insertAnonymousNativeModule(159std::vector<NativeProtoExecDataPtr> nativeProtos,160const uint8_t* data,161size_t dataSize,162const uint8_t* code,163size_t codeSize164);165166// If a NativeModule exists for the given ModuleId and that NativeModule167// is no longer referenced, the NativeModule is destroyed. This should168// usually only be called by NativeModule::release() when the reference169// count becomes zero170void eraseNativeModuleIfUnreferenced(const NativeModule& nativeModule);171172private:173struct ModuleIdHash174{175[[nodiscard]] size_t operator()(const ModuleId& moduleId) const noexcept;176};177178[[nodiscard]] NativeModuleRef tryGetNativeModuleWithLockHeld(const ModuleId& moduleId) const noexcept;179180mutable std::mutex mutex;181182std::unordered_map<ModuleId, std::unique_ptr<NativeModule>, ModuleIdHash, std::equal_to<>> identifiedModules;183184std::atomic<size_t> anonymousModuleCount = 0;185186CodeAllocator* codeAllocator = nullptr;187};188189} // namespace CodeGen190} // namespace Luau191192193