Skip to content

Commit 984568f

Browse files
committed
v0.8.6+luau622
1 parent aaa17ba commit 984568f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2544
-762
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "luau0-src"
3-
version = "0.8.5+luau617"
3+
version = "0.8.6+luau622"
44
authors = ["Aleksandr Orlenko <[email protected]>"]
55
edition = "2021"
66
repository = "https://github.com/khvzak/luau-src-rs"

luau/CodeGen/include/Luau/CodeGen.h

+52-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#pragma once
33

44
#include <algorithm>
5+
#include <array>
6+
#include <memory>
57
#include <string>
68
#include <vector>
79

@@ -40,6 +42,26 @@ enum class CodeGenCompilationResult
4042
AllocationFailed = 9, // Native codegen failed due to an allocation error
4143
};
4244

45+
struct ProtoCompilationFailure
46+
{
47+
CodeGenCompilationResult result = CodeGenCompilationResult::Success;
48+
49+
std::string debugname;
50+
int line = -1;
51+
};
52+
53+
struct CompilationResult
54+
{
55+
CodeGenCompilationResult result = CodeGenCompilationResult::Success;
56+
57+
std::vector<ProtoCompilationFailure> protoFailures;
58+
59+
[[nodiscard]] bool hasErrors() const
60+
{
61+
return result != CodeGenCompilationResult::Success || !protoFailures.empty();
62+
}
63+
};
64+
4365
struct CompilationStats
4466
{
4567
size_t bytecodeSizeBytes = 0;
@@ -49,23 +71,52 @@ struct CompilationStats
4971

5072
uint32_t functionsTotal = 0;
5173
uint32_t functionsCompiled = 0;
74+
uint32_t functionsBound = 0;
5275
};
5376

5477
using AllocationCallback = void(void* context, void* oldPointer, size_t oldSize, void* newPointer, size_t newSize);
5578

5679
bool isSupported();
5780

81+
class SharedCodeGenContext;
82+
83+
struct SharedCodeGenContextDeleter
84+
{
85+
void operator()(const SharedCodeGenContext* context) const noexcept;
86+
};
87+
88+
using UniqueSharedCodeGenContext = std::unique_ptr<SharedCodeGenContext, SharedCodeGenContextDeleter>;
89+
90+
// Creates a new SharedCodeGenContext that can be used by multiple Luau VMs
91+
// concurrently, using either the default allocator parameters or custom
92+
// allocator parameters.
93+
[[nodiscard]] UniqueSharedCodeGenContext createSharedCodeGenContext();
94+
95+
[[nodiscard]] UniqueSharedCodeGenContext createSharedCodeGenContext(AllocationCallback* allocationCallback, void* allocationCallbackContext);
96+
97+
[[nodiscard]] UniqueSharedCodeGenContext createSharedCodeGenContext(
98+
size_t blockSize, size_t maxTotalSize, AllocationCallback* allocationCallback, void* allocationCallbackContext);
99+
100+
// Destroys the provided SharedCodeGenContext. All Luau VMs using the
101+
// SharedCodeGenContext must be destroyed before this function is called.
102+
void destroySharedCodeGenContext(const SharedCodeGenContext* codeGenContext) noexcept;
103+
58104
void create(lua_State* L, AllocationCallback* allocationCallback, void* allocationCallbackContext);
59105
void create(lua_State* L);
106+
void create(lua_State* L, SharedCodeGenContext* codeGenContext);
60107

61108
// Check if native execution is enabled
62109
[[nodiscard]] bool isNativeExecutionEnabled(lua_State* L);
63110

64111
// Enable or disable native execution according to `enabled` argument
65112
void setNativeExecutionEnabled(lua_State* L, bool enabled);
66113

114+
using ModuleId = std::array<uint8_t, 16>;
115+
67116
// Builds target function and all inner functions
68-
CodeGenCompilationResult compile(lua_State* L, int idx, unsigned int flags = 0, CompilationStats* stats = nullptr);
117+
CodeGenCompilationResult compile_DEPRECATED(lua_State* L, int idx, unsigned int flags = 0, CompilationStats* stats = nullptr);
118+
CompilationResult compile(lua_State* L, int idx, unsigned int flags = 0, CompilationStats* stats = nullptr);
119+
CompilationResult compile(const ModuleId& moduleId, lua_State* L, int idx, unsigned int flags = 0, CompilationStats* stats = nullptr);
69120

70121
using AnnotatorFn = void (*)(void* context, std::string& result, int fid, int instpos);
71122

luau/CodeGen/include/Luau/IrVisitUseDef.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "Luau/Common.h"
55
#include "Luau/IrData.h"
66

7-
LUAU_FASTFLAG(LuauCodegenRemoveDeadStores3)
7+
LUAU_FASTFLAG(LuauCodegenRemoveDeadStores5)
88

99
namespace Luau
1010
{
@@ -188,7 +188,7 @@ static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrInst& i
188188
visitor.def(inst.b);
189189
break;
190190
case IrCmd::FALLBACK_FORGPREP:
191-
if (FFlag::LuauCodegenRemoveDeadStores3)
191+
if (FFlag::LuauCodegenRemoveDeadStores5)
192192
{
193193
// This instruction doesn't always redefine Rn, Rn+1, Rn+2, so we have to mark it as implicit use
194194
visitor.useRange(vmRegOp(inst.b), 3);
@@ -216,7 +216,8 @@ static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrInst& i
216216

217217
// After optimizations with DebugLuauAbortingChecks enabled, CHECK_TAG Rn, tag, block instructions are generated
218218
case IrCmd::CHECK_TAG:
219-
visitor.maybeUse(inst.a);
219+
if (!FFlag::LuauCodegenRemoveDeadStores5)
220+
visitor.maybeUse(inst.a);
220221
break;
221222

222223
default:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2+
#pragma once
3+
4+
#include <memory>
5+
#include <stdint.h>
6+
7+
namespace Luau
8+
{
9+
namespace CodeGen
10+
{
11+
12+
// The NativeProtoExecData is constant metadata associated with a NativeProto.
13+
// We generally refer to the NativeProtoExecData via a pointer to the instruction
14+
// offsets array because this makes the logic in the entry gate simpler.
15+
16+
class NativeModule;
17+
18+
struct NativeProtoExecDataHeader
19+
{
20+
// The NativeModule that owns this NativeProto. This is initialized
21+
// when the NativeProto is bound to the NativeModule via assignToModule().
22+
NativeModule* nativeModule = nullptr;
23+
24+
// We store the native code offset until the code is allocated in executable
25+
// pages, after which point we store the actual address.
26+
const uint8_t* entryOffsetOrAddress = nullptr;
27+
28+
// The bytecode id of the proto
29+
uint32_t bytecodeId = 0;
30+
31+
// The number of bytecode instructions in the proto. This is the number of
32+
// elements in the instruction offsets array following this header.
33+
uint32_t bytecodeInstructionCount = 0;
34+
35+
// The size of the native code for this NativeProto, in bytes.
36+
size_t nativeCodeSize = 0;
37+
};
38+
39+
// Make sure that the instruction offsets array following the header will be
40+
// correctly aligned:
41+
static_assert(sizeof(NativeProtoExecDataHeader) % sizeof(uint32_t) == 0);
42+
43+
struct NativeProtoExecDataDeleter
44+
{
45+
void operator()(const uint32_t* instructionOffsets) const noexcept;
46+
};
47+
48+
using NativeProtoExecDataPtr = std::unique_ptr<uint32_t[], NativeProtoExecDataDeleter>;
49+
50+
[[nodiscard]] NativeProtoExecDataPtr createNativeProtoExecData(uint32_t bytecodeInstructionCount);
51+
void destroyNativeProtoExecData(const uint32_t* instructionOffsets) noexcept;
52+
53+
[[nodiscard]] NativeProtoExecDataHeader& getNativeProtoExecDataHeader(uint32_t* instructionOffsets) noexcept;
54+
[[nodiscard]] const NativeProtoExecDataHeader& getNativeProtoExecDataHeader(const uint32_t* instructionOffsets) noexcept;
55+
56+
} // namespace CodeGen
57+
} // namespace Luau
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2+
#pragma once
3+
4+
#include "Luau/CodeGen.h"
5+
#include "Luau/Common.h"
6+
#include "Luau/NativeProtoExecData.h"
7+
8+
#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>
16+
17+
namespace Luau
18+
{
19+
namespace CodeGen
20+
{
21+
22+
// SharedCodeAllocator is a native executable code allocator that provides
23+
// shared ownership of the native code. Code is allocated on a per-module
24+
// basis. Each module is uniquely identifiable via an id, which may be a hash
25+
// or other unique value. Each module may contain multiple natively compiled
26+
// functions (protos).
27+
//
28+
// The module is the unit of shared ownership (i.e., it is where the reference
29+
// count is maintained).
30+
31+
32+
struct CodeAllocator;
33+
class NativeModule;
34+
class NativeModuleRef;
35+
class SharedCodeAllocator;
36+
37+
38+
// A NativeModule represents a single natively-compiled module (script). It is
39+
// the unit of shared ownership and is thus where the reference count is
40+
// maintained. It owns a set of NativeProtos, with associated native exec data,
41+
// and the allocated native data and code.
42+
class NativeModule
43+
{
44+
public:
45+
NativeModule(SharedCodeAllocator* allocator, const std::optional<ModuleId>& moduleId, const uint8_t* moduleBaseAddress,
46+
std::vector<NativeProtoExecDataPtr> nativeProtos) noexcept;
47+
48+
NativeModule(const NativeModule&) = delete;
49+
NativeModule(NativeModule&&) = delete;
50+
NativeModule& operator=(const NativeModule&) = delete;
51+
NativeModule& operator=(NativeModule&&) = delete;
52+
53+
// The NativeModule must not be destroyed if there are any outstanding
54+
// references. It should thus only be destroyed by a call to release()
55+
// that releases the last reference.
56+
~NativeModule() noexcept;
57+
58+
size_t addRef() const noexcept;
59+
size_t addRefs(size_t count) const noexcept;
60+
size_t release() const noexcept;
61+
[[nodiscard]] size_t getRefcount() const noexcept;
62+
63+
[[nodiscard]] const std::optional<ModuleId>& getModuleId() const noexcept;
64+
65+
// Gets the base address of the executable native code for the module.
66+
[[nodiscard]] const uint8_t* getModuleBaseAddress() const noexcept;
67+
68+
// Attempts to find the NativeProto with the given bytecode id. If no
69+
// NativeProto for that bytecode id exists, a null pointer is returned.
70+
[[nodiscard]] const uint32_t* tryGetNativeProto(uint32_t bytecodeId) const noexcept;
71+
72+
[[nodiscard]] const std::vector<NativeProtoExecDataPtr>& getNativeProtos() const noexcept;
73+
74+
private:
75+
mutable std::atomic<size_t> refcount = 0;
76+
77+
SharedCodeAllocator* allocator = nullptr;
78+
std::optional<ModuleId> moduleId = {};
79+
const uint8_t* moduleBaseAddress = nullptr;
80+
81+
std::vector<NativeProtoExecDataPtr> nativeProtos = {};
82+
};
83+
84+
// A NativeModuleRef is an owning reference to a NativeModule. (Note: We do
85+
// not use shared_ptr, to avoid complex state management in the Luau GC Proto
86+
// object.)
87+
class NativeModuleRef
88+
{
89+
public:
90+
NativeModuleRef() noexcept = default;
91+
NativeModuleRef(const NativeModule* nativeModule) noexcept;
92+
93+
NativeModuleRef(const NativeModuleRef& other) noexcept;
94+
NativeModuleRef(NativeModuleRef&& other) noexcept;
95+
NativeModuleRef& operator=(NativeModuleRef other) noexcept;
96+
97+
~NativeModuleRef() noexcept;
98+
99+
void reset() noexcept;
100+
void swap(NativeModuleRef& other) noexcept;
101+
102+
[[nodiscard]] bool empty() const noexcept;
103+
explicit operator bool() const noexcept;
104+
105+
[[nodiscard]] const NativeModule* get() const noexcept;
106+
[[nodiscard]] const NativeModule* operator->() const noexcept;
107+
[[nodiscard]] const NativeModule& operator*() const noexcept;
108+
109+
private:
110+
const NativeModule* nativeModule = nullptr;
111+
};
112+
113+
class SharedCodeAllocator
114+
{
115+
public:
116+
SharedCodeAllocator(CodeAllocator* codeAllocator) noexcept;
117+
118+
SharedCodeAllocator(const SharedCodeAllocator&) = delete;
119+
SharedCodeAllocator(SharedCodeAllocator&&) = delete;
120+
SharedCodeAllocator& operator=(const SharedCodeAllocator&) = delete;
121+
SharedCodeAllocator& operator=(SharedCodeAllocator&&) = delete;
122+
123+
~SharedCodeAllocator() noexcept;
124+
125+
// If we have a NativeModule for the given ModuleId, an owning reference to
126+
// it is returned. Otherwise, an empty NativeModuleRef is returned.
127+
[[nodiscard]] NativeModuleRef tryGetNativeModule(const ModuleId& moduleId) const noexcept;
128+
129+
// If we have a NativeModule for the given ModuleId, an owning reference to
130+
// it is returned. Otherwise, a new NativeModule is created for that ModuleId
131+
// using the provided NativeProtos, data, and code (space is allocated for the
132+
// data and code such that it can be executed). Like std::map::insert, the
133+
// bool result is true if a new module was created; false if an existing
134+
// module is being returned.
135+
std::pair<NativeModuleRef, bool> getOrInsertNativeModule(const ModuleId& moduleId, std::vector<NativeProtoExecDataPtr> nativeProtos,
136+
const uint8_t* data, size_t dataSize, const uint8_t* code, size_t codeSize);
137+
138+
NativeModuleRef insertAnonymousNativeModule(
139+
std::vector<NativeProtoExecDataPtr> nativeProtos, const uint8_t* data, size_t dataSize, const uint8_t* code, size_t codeSize);
140+
141+
// If a NativeModule exists for the given ModuleId and that NativeModule
142+
// is no longer referenced, the NativeModule is destroyed. This should
143+
// usually only be called by NativeModule::release() when the reference
144+
// count becomes zero
145+
void eraseNativeModuleIfUnreferenced(const NativeModule& nativeModule);
146+
147+
private:
148+
struct ModuleIdHash
149+
{
150+
[[nodiscard]] size_t operator()(const ModuleId& moduleId) const noexcept;
151+
};
152+
153+
[[nodiscard]] NativeModuleRef tryGetNativeModuleWithLockHeld(const ModuleId& moduleId) const noexcept;
154+
155+
mutable std::mutex mutex;
156+
157+
std::unordered_map<ModuleId, std::unique_ptr<NativeModule>, ModuleIdHash, std::equal_to<>> identifiedModules;
158+
159+
std::atomic<size_t> anonymousModuleCount = 0;
160+
161+
CodeAllocator* codeAllocator = nullptr;
162+
};
163+
164+
} // namespace CodeGen
165+
} // namespace Luau

0 commit comments

Comments
 (0)