Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Compiler/include/Luau/BytecodeBuilder.h
2727 views
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/Bytecode.h"
5
#include "Luau/DenseHash.h"
6
#include "Luau/StringUtils.h"
7
8
#include <string>
9
10
namespace Luau
11
{
12
13
class BytecodeEncoder
14
{
15
public:
16
virtual ~BytecodeEncoder() {}
17
18
virtual void encode(uint32_t* data, size_t count) = 0;
19
};
20
21
class BytecodeBuilder
22
{
23
public:
24
// BytecodeBuilder does *not* copy the data passed via StringRef; instead, it keeps the ref around until finalize()
25
// Please be careful with the lifetime of the data that's being passed because of this.
26
// The safe and correct pattern is to only build StringRefs out of pieces of AST (AstName or AstArray<>) that are backed by AstAllocator.
27
// Note that you must finalize() the builder before the Allocator backing the Ast is destroyed.
28
struct StringRef
29
{
30
// To construct a StringRef, use sref() from Compiler.cpp.
31
const char* data = nullptr;
32
size_t length = 0;
33
34
bool operator==(const StringRef& other) const;
35
};
36
37
struct TableShape
38
{
39
static const unsigned int kMaxLength = 32;
40
41
int32_t keys[kMaxLength];
42
// constants are indices that correspond to the proto constant table
43
// if a key does not have an associated constant to fill in, it has a sentinel value of -1
44
int32_t constants[kMaxLength];
45
unsigned int length = 0;
46
bool hasConstants = false;
47
48
bool operator==(const TableShape& other) const;
49
};
50
51
BytecodeBuilder(BytecodeEncoder* encoder = 0);
52
53
uint32_t beginFunction(uint8_t numparams, bool isvararg = false);
54
void endFunction(uint8_t maxstacksize, uint8_t numupvalues, uint8_t flags = 0);
55
56
void setMainFunction(uint32_t fid);
57
58
int32_t addConstantNil();
59
int32_t addConstantBoolean(bool value);
60
int32_t addConstantNumber(double value);
61
int32_t addConstantInteger(int64_t value);
62
int32_t addConstantVector(float x, float y, float z, float w);
63
int32_t addConstantString(StringRef value);
64
int32_t addImport(uint32_t iid);
65
int32_t addConstantTable(const TableShape& shape);
66
int32_t addConstantClosure(uint32_t fid);
67
68
int16_t addChildFunction(uint32_t fid);
69
70
void emitABC(LuauOpcode op, uint8_t a, uint8_t b, uint8_t c);
71
void emitAD(LuauOpcode op, uint8_t a, int16_t d);
72
void emitE(LuauOpcode op, int32_t e);
73
void emitAux(uint32_t aux);
74
75
void undoEmit(LuauOpcode op);
76
77
size_t emitLabel();
78
79
[[nodiscard]] bool patchJumpD(size_t jumpLabel, size_t targetLabel);
80
[[nodiscard]] bool patchSkipC(size_t jumpLabel, size_t targetLabel);
81
82
void foldJumps();
83
void expandJumps();
84
85
void setFunctionTypeInfo(std::string value);
86
void pushLocalTypeInfo(LuauBytecodeType type, uint8_t reg, uint32_t startpc, uint32_t endpc);
87
void pushUpvalTypeInfo(LuauBytecodeType type);
88
89
uint32_t addUserdataType(const char* name);
90
void useUserdataType(uint32_t index);
91
92
void setDebugFunctionName(StringRef name);
93
void setDebugFunctionLineDefined(int line);
94
void setDebugLine(int line);
95
void pushDebugLocal(StringRef name, uint8_t reg, uint32_t startpc, uint32_t endpc);
96
void pushDebugUpval(StringRef name);
97
98
size_t getInstructionCount() const;
99
size_t getTotalInstructionCount() const;
100
uint32_t getDebugPC() const;
101
102
void addDebugRemark(const char* format, ...) LUAU_PRINTF_ATTR(2, 3);
103
104
void finalize();
105
106
enum DumpFlags
107
{
108
Dump_Code = 1 << 0,
109
Dump_Lines = 1 << 1,
110
Dump_Source = 1 << 2,
111
Dump_Locals = 1 << 3,
112
Dump_Remarks = 1 << 4,
113
Dump_Types = 1 << 5,
114
Dump_Constants = 1 << 6,
115
};
116
117
void setDumpFlags(uint32_t flags)
118
{
119
dumpFlags = flags;
120
dumpFunctionPtr = &BytecodeBuilder::dumpCurrentFunction;
121
}
122
123
void setDumpSource(const std::string& source);
124
125
bool needsDebugRemarks() const
126
{
127
return (dumpFlags & Dump_Remarks) != 0;
128
}
129
130
const std::string& getBytecode() const
131
{
132
LUAU_ASSERT(!bytecode.empty()); // did you forget to call finalize?
133
return bytecode;
134
}
135
136
std::string dumpFunction(uint32_t id) const;
137
std::string dumpEverything() const;
138
std::string dumpSourceRemarks() const;
139
std::string dumpTypeInfo() const;
140
141
void annotateInstruction(std::string& result, uint32_t fid, uint32_t instpos) const;
142
143
static uint32_t getImportId(int32_t id0);
144
static uint32_t getImportId(int32_t id0, int32_t id1);
145
static uint32_t getImportId(int32_t id0, int32_t id1, int32_t id2);
146
147
static int decomposeImportId(uint32_t ids, int32_t& id0, int32_t& id1, int32_t& id2);
148
149
static uint32_t getStringHash(StringRef key);
150
151
static std::string getError(const std::string& message);
152
153
static uint8_t getVersion();
154
static uint8_t getTypeEncodingVersion();
155
156
private:
157
struct Constant
158
{
159
enum Type
160
{
161
Type_Nil,
162
Type_Boolean,
163
Type_Number,
164
Type_Integer,
165
Type_Vector,
166
Type_String,
167
Type_Import,
168
Type_Table,
169
Type_Closure,
170
};
171
172
Type type;
173
union
174
{
175
bool valueBoolean;
176
double valueNumber;
177
int64_t valueInteger64;
178
float valueVector[4];
179
unsigned int valueString; // index into string table
180
uint32_t valueImport; // 10-10-10-2 encoded import id
181
uint32_t valueTable; // index into tableShapes[]
182
uint32_t valueClosure; // index of function in global list
183
};
184
};
185
186
struct ConstantKey
187
{
188
Constant::Type type;
189
// Note: this stores value* from Constant; when type is Type_Number, this stores the same bits as double does but in uint64_t.
190
// For Type_Vector, x and y are stored in 'value' and z and w are stored in 'extra'.
191
uint64_t value;
192
uint64_t extra = 0;
193
194
bool operator==(const ConstantKey& key) const
195
{
196
return type == key.type && value == key.value && extra == key.extra;
197
}
198
};
199
200
struct Function
201
{
202
std::string data;
203
204
uint8_t maxstacksize = 0;
205
uint8_t numparams = 0;
206
uint8_t numupvalues = 0;
207
bool isvararg = false;
208
209
unsigned int debugname = 0;
210
int debuglinedefined = 0;
211
212
std::string dump;
213
std::string dumpname;
214
std::vector<int> dumpinstoffs;
215
std::string typeinfo;
216
};
217
218
struct DebugLocal
219
{
220
unsigned int name;
221
222
uint8_t reg;
223
uint32_t startpc;
224
uint32_t endpc;
225
};
226
227
struct DebugUpval
228
{
229
unsigned int name;
230
};
231
232
struct TypedLocal
233
{
234
LuauBytecodeType type;
235
uint8_t reg;
236
uint32_t startpc;
237
uint32_t endpc;
238
};
239
240
struct TypedUpval
241
{
242
LuauBytecodeType type;
243
};
244
245
struct UserdataType
246
{
247
std::string name;
248
uint32_t nameRef = 0;
249
bool used = false;
250
};
251
252
struct Jump
253
{
254
uint32_t source;
255
uint32_t target;
256
};
257
258
struct StringRefHash
259
{
260
size_t operator()(const StringRef& v) const;
261
};
262
263
struct ConstantKeyHash
264
{
265
size_t operator()(const ConstantKey& key) const;
266
};
267
268
struct TableShapeHash
269
{
270
size_t operator()(const TableShape& v) const;
271
};
272
273
std::vector<Function> functions;
274
uint32_t currentFunction = ~0u;
275
uint32_t mainFunction = ~0u;
276
277
size_t totalInstructionCount = 0;
278
std::vector<uint32_t> insns;
279
std::vector<int> lines;
280
std::vector<Constant> constants;
281
std::vector<uint32_t> protos;
282
std::vector<Jump> jumps;
283
284
std::vector<TableShape> tableShapes;
285
286
bool hasLongJumps = false;
287
288
DenseHashMap<ConstantKey, int32_t, ConstantKeyHash> constantMap;
289
DenseHashMap<TableShape, int32_t, TableShapeHash> tableShapeMap;
290
DenseHashMap<uint32_t, int16_t> protoMap;
291
292
int debugLine = 0;
293
294
std::vector<DebugLocal> debugLocals;
295
std::vector<DebugUpval> debugUpvals;
296
297
std::vector<TypedLocal> typedLocals;
298
std::vector<TypedUpval> typedUpvals;
299
300
std::vector<UserdataType> userdataTypes;
301
302
DenseHashMap<StringRef, unsigned int, StringRefHash> stringTable;
303
std::vector<StringRef> debugStrings;
304
305
std::vector<std::pair<uint32_t, uint32_t>> debugRemarks;
306
std::string debugRemarkBuffer;
307
308
BytecodeEncoder* encoder = nullptr;
309
std::string bytecode;
310
311
uint32_t dumpFlags = 0;
312
std::vector<std::string> dumpSource;
313
std::vector<std::pair<int, std::string>> dumpRemarks;
314
315
std::string tempTypeInfo;
316
317
std::string (BytecodeBuilder::*dumpFunctionPtr)(std::vector<int>&) const = nullptr;
318
319
void validate() const;
320
void validateInstructions() const;
321
void validateVariadic() const;
322
323
std::string dumpCurrentFunction(std::vector<int>& dumpinstoffs) const;
324
void dumpConstant(std::string& result, int k) const;
325
void dumpInstruction(const uint32_t* opcode, std::string& output, int targetLabel) const;
326
327
void writeFunction(std::string& ss, uint32_t id, uint8_t flags);
328
void writeLineInfo(std::string& ss) const;
329
void writeStringTable(std::string& ss) const;
330
331
int32_t addConstant(const ConstantKey& key, const Constant& value);
332
unsigned int addStringTableEntry(StringRef value);
333
334
const char* tryGetUserdataTypeName(LuauBytecodeType type) const;
335
};
336
337
} // namespace Luau
338
339