Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/CodeGen/src/BytecodeAnalysis.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/BytecodeAnalysis.h"
3
4
#include "Luau/CodeGenOptions.h"
5
#include "Luau/IrData.h"
6
#include "Luau/IrUtils.h"
7
8
#include "lobject.h"
9
#include "lstate.h"
10
11
#include <algorithm>
12
13
LUAU_FASTFLAG(LuauCodegenSetBlockEntryState3)
14
15
namespace Luau
16
{
17
namespace CodeGen
18
{
19
20
template<typename T>
21
static T read(uint8_t* data, size_t& offset)
22
{
23
T result;
24
memcpy(&result, data + offset, sizeof(T));
25
offset += sizeof(T);
26
27
return result;
28
}
29
30
static uint32_t readVarInt(uint8_t* data, size_t& offset)
31
{
32
uint32_t result = 0;
33
uint32_t shift = 0;
34
35
uint8_t byte;
36
37
do
38
{
39
byte = read<uint8_t>(data, offset);
40
result |= (byte & 127) << shift;
41
shift += 7;
42
} while (byte & 128);
43
44
return result;
45
}
46
47
void loadBytecodeTypeInfo(IrFunction& function)
48
{
49
Proto* proto = function.proto;
50
51
if (!proto)
52
return;
53
54
BytecodeTypeInfo& typeInfo = function.bcTypeInfo;
55
56
// If there is no typeinfo, we generate default values for arguments and upvalues
57
if (!proto->typeinfo)
58
{
59
typeInfo.argumentTypes.resize(proto->numparams, LBC_TYPE_ANY);
60
typeInfo.upvalueTypes.resize(proto->nups, LBC_TYPE_ANY);
61
return;
62
}
63
64
uint8_t* data = proto->typeinfo;
65
size_t offset = 0;
66
67
uint32_t typeSize = readVarInt(data, offset);
68
uint32_t upvalCount = readVarInt(data, offset);
69
uint32_t localCount = readVarInt(data, offset);
70
71
if (typeSize != 0)
72
{
73
uint8_t* types = (uint8_t*)data + offset;
74
75
CODEGEN_ASSERT(typeSize == uint32_t(2 + proto->numparams));
76
CODEGEN_ASSERT(types[0] == LBC_TYPE_FUNCTION);
77
CODEGEN_ASSERT(types[1] == proto->numparams);
78
79
typeInfo.argumentTypes.resize(proto->numparams);
80
81
// Skip two bytes of function type introduction
82
memcpy(typeInfo.argumentTypes.data(), types + 2, proto->numparams);
83
offset += typeSize;
84
}
85
86
if (upvalCount != 0)
87
{
88
CODEGEN_ASSERT(upvalCount == unsigned(proto->nups));
89
90
typeInfo.upvalueTypes.resize(upvalCount);
91
92
uint8_t* types = (uint8_t*)data + offset;
93
memcpy(typeInfo.upvalueTypes.data(), types, upvalCount);
94
offset += upvalCount;
95
}
96
97
if (localCount != 0)
98
{
99
typeInfo.regTypes.resize(localCount);
100
101
for (uint32_t i = 0; i < localCount; i++)
102
{
103
BytecodeRegTypeInfo& info = typeInfo.regTypes[i];
104
105
info.type = read<uint8_t>(data, offset);
106
info.reg = read<uint8_t>(data, offset);
107
info.startpc = readVarInt(data, offset);
108
info.endpc = info.startpc + readVarInt(data, offset);
109
}
110
}
111
112
// Preserve original information
113
if (FFlag::LuauCodegenSetBlockEntryState3)
114
function.bcOriginalTypeInfo = function.bcTypeInfo;
115
116
CODEGEN_ASSERT(offset == size_t(proto->sizetypeinfo));
117
}
118
119
static void prepareRegTypeInfoLookups(BytecodeTypeInfo& typeInfo)
120
{
121
// Sort by register first, then by end PC
122
std::sort(
123
typeInfo.regTypes.begin(),
124
typeInfo.regTypes.end(),
125
[](const BytecodeRegTypeInfo& a, const BytecodeRegTypeInfo& b)
126
{
127
if (a.reg != b.reg)
128
return a.reg < b.reg;
129
130
return a.endpc < b.endpc;
131
}
132
);
133
134
// Prepare data for all registers as 'regTypes' might be missing temporaries
135
typeInfo.regTypeOffsets.resize(256 + 1);
136
137
for (size_t i = 0; i < typeInfo.regTypes.size(); i++)
138
{
139
const BytecodeRegTypeInfo& el = typeInfo.regTypes[i];
140
141
// Data is sorted by register order, so when we visit register Rn last time
142
// If means that register Rn+1 starts one after the slot where Rn ends
143
typeInfo.regTypeOffsets[el.reg + 1] = uint32_t(i + 1);
144
}
145
146
// Fill in holes with the offset of the previous register
147
for (size_t i = 1; i < typeInfo.regTypeOffsets.size(); i++)
148
{
149
uint32_t& el = typeInfo.regTypeOffsets[i];
150
151
if (el == 0)
152
el = typeInfo.regTypeOffsets[i - 1];
153
}
154
}
155
156
static BytecodeRegTypeInfo* findRegType(BytecodeTypeInfo& info, uint8_t reg, int pc)
157
{
158
auto b = info.regTypes.begin() + info.regTypeOffsets[reg];
159
auto e = info.regTypes.begin() + info.regTypeOffsets[reg + 1];
160
161
// Doesn't have info
162
if (b == e)
163
return nullptr;
164
165
// No info after the last live range
166
if (pc >= (e - 1)->endpc)
167
return nullptr;
168
169
for (auto it = b; it != e; ++it)
170
{
171
CODEGEN_ASSERT(it->reg == reg);
172
173
if (pc >= it->startpc && pc < it->endpc)
174
return &*it;
175
}
176
177
return nullptr;
178
}
179
180
static void refineRegType(BytecodeTypeInfo& info, uint8_t reg, int pc, uint8_t ty)
181
{
182
if (ty != LBC_TYPE_ANY)
183
{
184
if (BytecodeRegTypeInfo* regType = findRegType(info, reg, pc))
185
{
186
// Right now, we only refine register types that were unknown
187
if (regType->type == LBC_TYPE_ANY)
188
regType->type = ty;
189
}
190
else if (reg < info.argumentTypes.size())
191
{
192
if (info.argumentTypes[reg] == LBC_TYPE_ANY)
193
info.argumentTypes[reg] = ty;
194
}
195
}
196
}
197
198
static void refineUpvalueType(BytecodeTypeInfo& info, int up, uint8_t ty)
199
{
200
if (ty != LBC_TYPE_ANY)
201
{
202
if (size_t(up) < info.upvalueTypes.size())
203
{
204
if (info.upvalueTypes[up] == LBC_TYPE_ANY)
205
info.upvalueTypes[up] = ty;
206
}
207
}
208
}
209
210
static uint8_t getBytecodeConstantTag(Proto* proto, unsigned ki)
211
{
212
TValue protok = proto->k[ki];
213
214
switch (protok.tt)
215
{
216
case LUA_TNIL:
217
return LBC_TYPE_NIL;
218
case LUA_TBOOLEAN:
219
return LBC_TYPE_BOOLEAN;
220
case LUA_TLIGHTUSERDATA:
221
return LBC_TYPE_USERDATA;
222
case LUA_TNUMBER:
223
return LBC_TYPE_NUMBER;
224
case LUA_TINTEGER:
225
return LBC_TYPE_INTEGER;
226
case LUA_TVECTOR:
227
return LBC_TYPE_VECTOR;
228
case LUA_TSTRING:
229
return LBC_TYPE_STRING;
230
case LUA_TTABLE:
231
return LBC_TYPE_TABLE;
232
case LUA_TFUNCTION:
233
return LBC_TYPE_FUNCTION;
234
case LUA_TUSERDATA:
235
return LBC_TYPE_USERDATA;
236
case LUA_TTHREAD:
237
return LBC_TYPE_THREAD;
238
case LUA_TBUFFER:
239
return LBC_TYPE_BUFFER;
240
}
241
242
return LBC_TYPE_ANY;
243
}
244
245
static void applyBuiltinCall(LuauBuiltinFunction bfid, BytecodeTypes& types)
246
{
247
switch (bfid)
248
{
249
case LBF_NONE:
250
case LBF_ASSERT:
251
types.result = LBC_TYPE_ANY;
252
break;
253
case LBF_MATH_ABS:
254
case LBF_MATH_ACOS:
255
case LBF_MATH_ASIN:
256
types.result = LBC_TYPE_NUMBER;
257
types.a = LBC_TYPE_NUMBER;
258
break;
259
case LBF_MATH_ATAN2:
260
types.result = LBC_TYPE_NUMBER;
261
types.a = LBC_TYPE_NUMBER;
262
types.b = LBC_TYPE_NUMBER;
263
break;
264
case LBF_MATH_ATAN:
265
case LBF_MATH_CEIL:
266
case LBF_MATH_COSH:
267
case LBF_MATH_COS:
268
case LBF_MATH_DEG:
269
case LBF_MATH_EXP:
270
case LBF_MATH_FLOOR:
271
types.result = LBC_TYPE_NUMBER;
272
types.a = LBC_TYPE_NUMBER;
273
break;
274
case LBF_MATH_FMOD:
275
types.result = LBC_TYPE_NUMBER;
276
types.a = LBC_TYPE_NUMBER;
277
types.b = LBC_TYPE_NUMBER;
278
break;
279
case LBF_MATH_FREXP:
280
types.result = LBC_TYPE_NUMBER;
281
types.a = LBC_TYPE_NUMBER;
282
break;
283
case LBF_MATH_LDEXP:
284
types.result = LBC_TYPE_NUMBER;
285
types.a = LBC_TYPE_NUMBER;
286
types.b = LBC_TYPE_NUMBER;
287
break;
288
case LBF_MATH_LOG10:
289
types.result = LBC_TYPE_NUMBER;
290
types.a = LBC_TYPE_NUMBER;
291
break;
292
case LBF_MATH_LOG:
293
types.result = LBC_TYPE_NUMBER;
294
types.a = LBC_TYPE_NUMBER;
295
types.b = LBC_TYPE_NUMBER; // We can mark optional arguments
296
break;
297
case LBF_MATH_MAX:
298
case LBF_MATH_MIN:
299
types.result = LBC_TYPE_NUMBER;
300
types.a = LBC_TYPE_NUMBER;
301
types.b = LBC_TYPE_NUMBER;
302
types.c = LBC_TYPE_NUMBER; // We can mark optional arguments
303
break;
304
case LBF_MATH_MODF:
305
types.result = LBC_TYPE_NUMBER;
306
types.a = LBC_TYPE_NUMBER;
307
break;
308
case LBF_MATH_POW:
309
types.result = LBC_TYPE_NUMBER;
310
types.a = LBC_TYPE_NUMBER;
311
types.b = LBC_TYPE_NUMBER;
312
break;
313
case LBF_MATH_RAD:
314
case LBF_MATH_SINH:
315
case LBF_MATH_SIN:
316
case LBF_MATH_SQRT:
317
case LBF_MATH_TANH:
318
case LBF_MATH_TAN:
319
types.result = LBC_TYPE_NUMBER;
320
types.a = LBC_TYPE_NUMBER;
321
break;
322
case LBF_BIT32_ARSHIFT:
323
types.result = LBC_TYPE_NUMBER;
324
types.a = LBC_TYPE_NUMBER;
325
types.b = LBC_TYPE_NUMBER;
326
break;
327
case LBF_BIT32_BAND:
328
types.result = LBC_TYPE_NUMBER;
329
types.a = LBC_TYPE_NUMBER;
330
types.b = LBC_TYPE_NUMBER;
331
types.c = LBC_TYPE_NUMBER; // We can mark optional arguments
332
break;
333
case LBF_BIT32_BNOT:
334
types.result = LBC_TYPE_NUMBER;
335
types.a = LBC_TYPE_NUMBER;
336
break;
337
case LBF_BIT32_BOR:
338
case LBF_BIT32_BXOR:
339
case LBF_BIT32_BTEST:
340
case LBF_BIT32_EXTRACT:
341
types.result = LBC_TYPE_NUMBER;
342
types.a = LBC_TYPE_NUMBER;
343
types.b = LBC_TYPE_NUMBER;
344
types.c = LBC_TYPE_NUMBER; // We can mark optional arguments
345
break;
346
case LBF_BIT32_LROTATE:
347
case LBF_BIT32_LSHIFT:
348
types.result = LBC_TYPE_NUMBER;
349
types.a = LBC_TYPE_NUMBER;
350
types.b = LBC_TYPE_NUMBER;
351
break;
352
case LBF_BIT32_REPLACE:
353
types.result = LBC_TYPE_NUMBER;
354
types.a = LBC_TYPE_NUMBER;
355
types.b = LBC_TYPE_NUMBER;
356
types.c = LBC_TYPE_NUMBER; // We can mark optional arguments
357
break;
358
case LBF_BIT32_RROTATE:
359
case LBF_BIT32_RSHIFT:
360
types.result = LBC_TYPE_NUMBER;
361
types.a = LBC_TYPE_NUMBER;
362
types.b = LBC_TYPE_NUMBER;
363
break;
364
case LBF_TYPE:
365
types.result = LBC_TYPE_STRING;
366
break;
367
case LBF_STRING_BYTE:
368
types.result = LBC_TYPE_NUMBER;
369
types.a = LBC_TYPE_STRING;
370
types.b = LBC_TYPE_NUMBER;
371
break;
372
case LBF_STRING_CHAR:
373
types.result = LBC_TYPE_STRING;
374
375
// We can mark optional arguments
376
types.a = LBC_TYPE_NUMBER;
377
types.b = LBC_TYPE_NUMBER;
378
types.c = LBC_TYPE_NUMBER;
379
break;
380
case LBF_STRING_LEN:
381
types.result = LBC_TYPE_NUMBER;
382
types.a = LBC_TYPE_STRING;
383
break;
384
case LBF_TYPEOF:
385
types.result = LBC_TYPE_STRING;
386
break;
387
case LBF_STRING_SUB:
388
types.result = LBC_TYPE_STRING;
389
types.a = LBC_TYPE_STRING;
390
types.b = LBC_TYPE_NUMBER;
391
types.c = LBC_TYPE_NUMBER;
392
break;
393
case LBF_MATH_CLAMP:
394
types.result = LBC_TYPE_NUMBER;
395
types.a = LBC_TYPE_NUMBER;
396
types.b = LBC_TYPE_NUMBER;
397
types.c = LBC_TYPE_NUMBER;
398
break;
399
case LBF_MATH_SIGN:
400
types.result = LBC_TYPE_NUMBER;
401
types.a = LBC_TYPE_NUMBER;
402
break;
403
case LBF_MATH_ROUND:
404
types.result = LBC_TYPE_NUMBER;
405
types.a = LBC_TYPE_NUMBER;
406
break;
407
case LBF_RAWGET:
408
types.result = LBC_TYPE_ANY;
409
types.a = LBC_TYPE_TABLE;
410
break;
411
case LBF_RAWEQUAL:
412
types.result = LBC_TYPE_BOOLEAN;
413
break;
414
case LBF_TABLE_UNPACK:
415
types.result = LBC_TYPE_ANY;
416
types.a = LBC_TYPE_TABLE;
417
types.b = LBC_TYPE_NUMBER; // We can mark optional arguments
418
break;
419
case LBF_VECTOR:
420
types.result = LBC_TYPE_VECTOR;
421
types.a = LBC_TYPE_NUMBER;
422
types.b = LBC_TYPE_NUMBER;
423
types.c = LBC_TYPE_NUMBER;
424
break;
425
case LBF_BIT32_COUNTLZ:
426
case LBF_BIT32_COUNTRZ:
427
types.result = LBC_TYPE_NUMBER;
428
types.a = LBC_TYPE_NUMBER;
429
break;
430
case LBF_SELECT_VARARG:
431
types.result = LBC_TYPE_ANY;
432
break;
433
case LBF_RAWLEN:
434
types.result = LBC_TYPE_NUMBER;
435
break;
436
case LBF_BIT32_EXTRACTK:
437
types.result = LBC_TYPE_NUMBER;
438
types.a = LBC_TYPE_NUMBER;
439
types.b = LBC_TYPE_NUMBER;
440
break;
441
case LBF_GETMETATABLE:
442
types.result = LBC_TYPE_TABLE;
443
break;
444
case LBF_TONUMBER:
445
types.result = LBC_TYPE_NUMBER;
446
break;
447
case LBF_TOSTRING:
448
types.result = LBC_TYPE_STRING;
449
break;
450
case LBF_BIT32_BYTESWAP:
451
types.result = LBC_TYPE_NUMBER;
452
types.a = LBC_TYPE_NUMBER;
453
break;
454
case LBF_BUFFER_READI8:
455
case LBF_BUFFER_READU8:
456
types.result = LBC_TYPE_NUMBER;
457
types.a = LBC_TYPE_BUFFER;
458
types.b = LBC_TYPE_NUMBER;
459
break;
460
case LBF_BUFFER_WRITEU8:
461
types.result = LBC_TYPE_NIL;
462
types.a = LBC_TYPE_BUFFER;
463
types.b = LBC_TYPE_NUMBER;
464
types.c = LBC_TYPE_NUMBER;
465
break;
466
case LBF_BUFFER_READI16:
467
case LBF_BUFFER_READU16:
468
types.result = LBC_TYPE_NUMBER;
469
types.a = LBC_TYPE_BUFFER;
470
types.b = LBC_TYPE_NUMBER;
471
break;
472
case LBF_BUFFER_WRITEU16:
473
types.result = LBC_TYPE_NIL;
474
types.a = LBC_TYPE_BUFFER;
475
types.b = LBC_TYPE_NUMBER;
476
types.c = LBC_TYPE_NUMBER;
477
break;
478
case LBF_BUFFER_READI32:
479
case LBF_BUFFER_READU32:
480
types.result = LBC_TYPE_NUMBER;
481
types.a = LBC_TYPE_BUFFER;
482
types.b = LBC_TYPE_NUMBER;
483
break;
484
case LBF_BUFFER_WRITEU32:
485
types.result = LBC_TYPE_NIL;
486
types.a = LBC_TYPE_BUFFER;
487
types.b = LBC_TYPE_NUMBER;
488
types.c = LBC_TYPE_NUMBER;
489
break;
490
case LBF_BUFFER_READF32:
491
types.result = LBC_TYPE_NUMBER;
492
types.a = LBC_TYPE_BUFFER;
493
types.b = LBC_TYPE_NUMBER;
494
break;
495
case LBF_BUFFER_WRITEF32:
496
types.result = LBC_TYPE_NIL;
497
types.a = LBC_TYPE_BUFFER;
498
types.b = LBC_TYPE_NUMBER;
499
types.c = LBC_TYPE_NUMBER;
500
break;
501
case LBF_BUFFER_READF64:
502
types.result = LBC_TYPE_NUMBER;
503
types.a = LBC_TYPE_BUFFER;
504
types.b = LBC_TYPE_NUMBER;
505
break;
506
case LBF_BUFFER_WRITEF64:
507
types.result = LBC_TYPE_NIL;
508
types.a = LBC_TYPE_BUFFER;
509
types.b = LBC_TYPE_NUMBER;
510
types.c = LBC_TYPE_NUMBER;
511
break;
512
case LBF_TABLE_INSERT:
513
types.result = LBC_TYPE_NIL;
514
types.a = LBC_TYPE_TABLE;
515
break;
516
case LBF_RAWSET:
517
types.result = LBC_TYPE_ANY;
518
types.a = LBC_TYPE_TABLE;
519
break;
520
case LBF_SETMETATABLE:
521
types.result = LBC_TYPE_TABLE;
522
types.a = LBC_TYPE_TABLE;
523
types.b = LBC_TYPE_TABLE;
524
break;
525
case LBF_VECTOR_MAGNITUDE:
526
types.result = LBC_TYPE_NUMBER;
527
types.a = LBC_TYPE_VECTOR;
528
break;
529
case LBF_VECTOR_NORMALIZE:
530
types.result = LBC_TYPE_VECTOR;
531
types.a = LBC_TYPE_VECTOR;
532
break;
533
case LBF_VECTOR_CROSS:
534
types.result = LBC_TYPE_VECTOR;
535
types.a = LBC_TYPE_VECTOR;
536
types.b = LBC_TYPE_VECTOR;
537
break;
538
case LBF_VECTOR_DOT:
539
types.result = LBC_TYPE_NUMBER;
540
types.a = LBC_TYPE_VECTOR;
541
types.b = LBC_TYPE_VECTOR;
542
break;
543
case LBF_VECTOR_FLOOR:
544
case LBF_VECTOR_CEIL:
545
case LBF_VECTOR_ABS:
546
case LBF_VECTOR_SIGN:
547
case LBF_VECTOR_CLAMP:
548
types.result = LBC_TYPE_VECTOR;
549
types.a = LBC_TYPE_VECTOR;
550
types.b = LBC_TYPE_VECTOR;
551
break;
552
case LBF_VECTOR_MIN:
553
case LBF_VECTOR_MAX:
554
types.result = LBC_TYPE_VECTOR;
555
types.a = LBC_TYPE_VECTOR;
556
types.b = LBC_TYPE_VECTOR;
557
types.c = LBC_TYPE_VECTOR; // We can mark optional arguments
558
break;
559
case LBF_VECTOR_LERP:
560
types.result = LBC_TYPE_VECTOR;
561
types.a = LBC_TYPE_VECTOR;
562
types.b = LBC_TYPE_VECTOR;
563
types.c = LBC_TYPE_NUMBER;
564
break;
565
case LBF_MATH_LERP:
566
types.result = LBC_TYPE_NUMBER;
567
types.a = LBC_TYPE_NUMBER;
568
types.b = LBC_TYPE_NUMBER;
569
types.c = LBC_TYPE_NUMBER;
570
break;
571
case LBF_MATH_ISNAN:
572
types.result = LBC_TYPE_BOOLEAN;
573
types.a = LBC_TYPE_NUMBER;
574
break;
575
case LBF_MATH_ISINF:
576
types.result = LBC_TYPE_BOOLEAN;
577
types.a = LBC_TYPE_NUMBER;
578
break;
579
case LBF_MATH_ISFINITE:
580
types.result = LBC_TYPE_BOOLEAN;
581
types.a = LBC_TYPE_NUMBER;
582
break;
583
case LBF_INTEGER_NEG:
584
case LBF_INTEGER_BSWAP:
585
case LBF_INTEGER_BNOT:
586
case LBF_INTEGER_COUNTLZ:
587
case LBF_INTEGER_COUNTRZ:
588
types.result = LBC_TYPE_INTEGER;
589
types.a = LBC_TYPE_INTEGER;
590
break;
591
592
case LBF_INTEGER_MIN:
593
case LBF_INTEGER_MAX:
594
case LBF_INTEGER_BAND:
595
case LBF_INTEGER_BOR:
596
case LBF_INTEGER_BXOR:
597
types.a = LBC_TYPE_INTEGER;
598
types.b = LBC_TYPE_INTEGER;
599
types.c = LBC_TYPE_INTEGER; // We can mark optional arguments
600
types.result = LBC_TYPE_INTEGER;
601
break;
602
603
case LBF_INTEGER_ADD:
604
case LBF_INTEGER_SUB:
605
case LBF_INTEGER_MUL:
606
case LBF_INTEGER_DIV:
607
case LBF_INTEGER_IDIV:
608
case LBF_INTEGER_REM:
609
case LBF_INTEGER_UDIV:
610
case LBF_INTEGER_UREM:
611
case LBF_INTEGER_MOD:
612
case LBF_INTEGER_LSHIFT:
613
case LBF_INTEGER_LROTATE:
614
case LBF_INTEGER_RROTATE:
615
case LBF_INTEGER_RSHIFT:
616
case LBF_INTEGER_ARSHIFT:
617
types.a = LBC_TYPE_INTEGER;
618
types.b = LBC_TYPE_INTEGER;
619
types.result = LBC_TYPE_INTEGER;
620
break;
621
case LBF_INTEGER_CLAMP:
622
case LBF_INTEGER_EXTRACT:
623
types.a = LBC_TYPE_INTEGER;
624
types.b = LBC_TYPE_INTEGER;
625
types.c = LBC_TYPE_INTEGER;
626
types.result = LBC_TYPE_INTEGER;
627
break;
628
case LBF_INTEGER_BTEST:
629
types.a = LBC_TYPE_INTEGER;
630
types.b = LBC_TYPE_INTEGER;
631
types.c = LBC_TYPE_INTEGER; // We can mark optional arguments
632
types.result = LBC_TYPE_BOOLEAN;
633
break;
634
case LBF_INTEGER_LT:
635
case LBF_INTEGER_LE:
636
case LBF_INTEGER_GT:
637
case LBF_INTEGER_GE:
638
case LBF_INTEGER_ULT:
639
case LBF_INTEGER_ULE:
640
case LBF_INTEGER_UGT:
641
case LBF_INTEGER_UGE:
642
types.a = LBC_TYPE_INTEGER;
643
types.b = LBC_TYPE_INTEGER;
644
types.result = LBC_TYPE_BOOLEAN;
645
break;
646
case LBF_INTEGER_TONUMBER:
647
types.a = LBC_TYPE_INTEGER;
648
types.result = LBC_TYPE_NUMBER;
649
break;
650
case LBF_INTEGER_CREATE:
651
types.a = LBC_TYPE_NUMBER;
652
types.result = LBC_TYPE_INTEGER;
653
break;
654
}
655
}
656
657
static HostMetamethod opcodeToHostMetamethod(LuauOpcode op)
658
{
659
switch (int(op))
660
{
661
case LOP_ADD:
662
return HostMetamethod::Add;
663
case LOP_SUB:
664
return HostMetamethod::Sub;
665
case LOP_MUL:
666
return HostMetamethod::Mul;
667
case LOP_DIV:
668
return HostMetamethod::Div;
669
case LOP_IDIV:
670
return HostMetamethod::Idiv;
671
case LOP_MOD:
672
return HostMetamethod::Mod;
673
case LOP_POW:
674
return HostMetamethod::Pow;
675
case LOP_ADDK:
676
return HostMetamethod::Add;
677
case LOP_SUBK:
678
return HostMetamethod::Sub;
679
case LOP_MULK:
680
return HostMetamethod::Mul;
681
case LOP_DIVK:
682
return HostMetamethod::Div;
683
case LOP_IDIVK:
684
return HostMetamethod::Idiv;
685
case LOP_MODK:
686
return HostMetamethod::Mod;
687
case LOP_POWK:
688
return HostMetamethod::Pow;
689
case LOP_SUBRK:
690
return HostMetamethod::Sub;
691
case LOP_DIVRK:
692
return HostMetamethod::Div;
693
default:
694
CODEGEN_ASSERT(!"opcode is not assigned to a host metamethod");
695
}
696
697
return HostMetamethod::Add;
698
}
699
700
void buildBytecodeBlocks(IrFunction& function, const std::vector<uint8_t>& jumpTargets)
701
{
702
Proto* proto = function.proto;
703
CODEGEN_ASSERT(proto);
704
705
std::vector<BytecodeBlock>& bcBlocks = function.bcBlocks;
706
707
// Using the same jump targets, create VM bytecode basic blocks
708
bcBlocks.push_back(BytecodeBlock{0, -1});
709
710
int previ = 0;
711
712
for (int i = 0; i < proto->sizecode;)
713
{
714
const Instruction* pc = &proto->code[i];
715
LuauOpcode op = LuauOpcode(LUAU_INSN_OP(*pc));
716
717
int nexti = i + getOpLength(op);
718
719
// If instruction is a jump target, begin new block starting from it
720
if (i != 0 && jumpTargets[i])
721
{
722
bcBlocks.back().finishpc = previ;
723
bcBlocks.push_back(BytecodeBlock{i, -1});
724
}
725
726
int target = getJumpTarget(*pc, uint32_t(i));
727
728
// Implicit fallthrough terminate the block and might start a new one
729
if (target >= 0 && !isFastCall(op))
730
{
731
bcBlocks.back().finishpc = i;
732
733
// Start a new block if there was no explicit jump for the fallthrough
734
if (!jumpTargets[nexti])
735
bcBlocks.push_back(BytecodeBlock{nexti, -1});
736
}
737
// Returns just terminate the block
738
else if (int(op) == LOP_RETURN)
739
{
740
bcBlocks.back().finishpc = i;
741
}
742
743
previ = i;
744
i = nexti;
745
CODEGEN_ASSERT(i <= proto->sizecode);
746
}
747
}
748
749
void analyzeBytecodeTypes(IrFunction& function, const HostIrHooks& hostHooks)
750
{
751
Proto* proto = function.proto;
752
CODEGEN_ASSERT(proto);
753
754
BytecodeTypeInfo& bcTypeInfo = function.bcTypeInfo;
755
756
prepareRegTypeInfoLookups(bcTypeInfo);
757
758
// Setup our current knowledge of type tags based on arguments
759
uint8_t regTags[256];
760
memset(regTags, LBC_TYPE_ANY, 256);
761
762
function.bcTypes.resize(proto->sizecode);
763
764
// Now that we have VM basic blocks, we can attempt to track register type tags locally
765
for (const BytecodeBlock& block : function.bcBlocks)
766
{
767
CODEGEN_ASSERT(block.startpc != -1);
768
CODEGEN_ASSERT(block.finishpc != -1);
769
770
// At the block start, reset or knowledge to the starting state
771
// In the future we might be able to propagate some info between the blocks as well
772
for (size_t i = 0; i < bcTypeInfo.argumentTypes.size(); i++)
773
{
774
uint8_t et = bcTypeInfo.argumentTypes[i];
775
776
// TODO: if argument is optional, this might force a VM exit unnecessarily
777
regTags[i] = et & ~LBC_TYPE_OPTIONAL_BIT;
778
}
779
780
for (int i = proto->numparams; i < proto->maxstacksize; ++i)
781
regTags[i] = LBC_TYPE_ANY;
782
783
// Namecall instruction has a hook which specifies the result of the next call instruction
784
LuauBytecodeType knownNextCallResult = LBC_TYPE_ANY;
785
786
for (int i = block.startpc; i <= block.finishpc;)
787
{
788
const Instruction* pc = &proto->code[i];
789
LuauOpcode op = LuauOpcode(LUAU_INSN_OP(*pc));
790
791
// Assign known register types from local type information
792
// TODO: this is an expensive walk for each instruction
793
// TODO: it's best to lookup when register is actually used in the instruction
794
for (BytecodeRegTypeInfo& el : bcTypeInfo.regTypes)
795
{
796
if (el.type != LBC_TYPE_ANY && i >= el.startpc && i < el.endpc)
797
regTags[el.reg] = el.type;
798
}
799
800
BytecodeTypes& bcType = function.bcTypes[i];
801
802
switch (int(op))
803
{
804
case LOP_NOP:
805
break;
806
case LOP_LOADNIL:
807
{
808
int ra = LUAU_INSN_A(*pc);
809
regTags[ra] = LBC_TYPE_NIL;
810
bcType.result = regTags[ra];
811
break;
812
}
813
case LOP_LOADB:
814
{
815
int ra = LUAU_INSN_A(*pc);
816
regTags[ra] = LBC_TYPE_BOOLEAN;
817
bcType.result = regTags[ra];
818
819
refineRegType(bcTypeInfo, ra, i, bcType.result);
820
break;
821
}
822
case LOP_LOADN:
823
{
824
int ra = LUAU_INSN_A(*pc);
825
regTags[ra] = LBC_TYPE_NUMBER;
826
bcType.result = regTags[ra];
827
828
refineRegType(bcTypeInfo, ra, i, bcType.result);
829
break;
830
}
831
case LOP_LOADK:
832
{
833
int ra = LUAU_INSN_A(*pc);
834
int kb = LUAU_INSN_D(*pc);
835
bcType.a = getBytecodeConstantTag(proto, kb);
836
regTags[ra] = bcType.a;
837
bcType.result = regTags[ra];
838
839
refineRegType(bcTypeInfo, ra, i, bcType.result);
840
break;
841
}
842
case LOP_LOADKX:
843
{
844
int ra = LUAU_INSN_A(*pc);
845
int kb = int(pc[1]);
846
bcType.a = getBytecodeConstantTag(proto, kb);
847
regTags[ra] = bcType.a;
848
bcType.result = regTags[ra];
849
850
refineRegType(bcTypeInfo, ra, i, bcType.result);
851
break;
852
}
853
case LOP_MOVE:
854
{
855
int ra = LUAU_INSN_A(*pc);
856
int rb = LUAU_INSN_B(*pc);
857
bcType.a = regTags[rb];
858
regTags[ra] = regTags[rb];
859
bcType.result = regTags[ra];
860
861
refineRegType(bcTypeInfo, ra, i, bcType.result);
862
break;
863
}
864
case LOP_GETTABLE:
865
{
866
int ra = LUAU_INSN_A(*pc);
867
int rb = LUAU_INSN_B(*pc);
868
int rc = LUAU_INSN_C(*pc);
869
870
regTags[ra] = LBC_TYPE_ANY;
871
872
bcType.a = regTags[rb];
873
bcType.b = regTags[rc];
874
875
bcType.result = regTags[ra];
876
break;
877
}
878
case LOP_SETTABLE:
879
{
880
int rb = LUAU_INSN_B(*pc);
881
int rc = LUAU_INSN_C(*pc);
882
bcType.a = regTags[rb];
883
bcType.b = regTags[rc];
884
break;
885
}
886
case LOP_GETTABLEKS:
887
{
888
int ra = LUAU_INSN_A(*pc);
889
int rb = LUAU_INSN_B(*pc);
890
uint32_t kc = pc[1];
891
892
bcType.a = regTags[rb];
893
bcType.b = getBytecodeConstantTag(proto, kc);
894
895
regTags[ra] = LBC_TYPE_ANY;
896
897
TString* str = gco2ts(function.proto->k[kc].value.gc);
898
const char* field = getstr(str);
899
900
if (bcType.a == LBC_TYPE_VECTOR)
901
{
902
if (str->len == 1)
903
{
904
// Same handling as LOP_GETTABLEKS block in lvmexecute.cpp - case-insensitive comparison with "X" / "Y" / "Z"
905
char ch = field[0] | ' ';
906
907
if (ch == 'x' || ch == 'y' || ch == 'z')
908
regTags[ra] = LBC_TYPE_NUMBER;
909
}
910
911
if (regTags[ra] == LBC_TYPE_ANY && hostHooks.vectorAccessBytecodeType)
912
regTags[ra] = hostHooks.vectorAccessBytecodeType(field, str->len);
913
}
914
else if (isCustomUserdataBytecodeType(bcType.a))
915
{
916
if (regTags[ra] == LBC_TYPE_ANY && hostHooks.userdataAccessBytecodeType)
917
regTags[ra] = hostHooks.userdataAccessBytecodeType(bcType.a, field, str->len);
918
}
919
920
bcType.result = regTags[ra];
921
break;
922
}
923
case LOP_SETTABLEKS:
924
{
925
int rb = LUAU_INSN_B(*pc);
926
927
bcType.a = regTags[rb];
928
bcType.b = LBC_TYPE_STRING;
929
break;
930
}
931
case LOP_GETTABLEN:
932
{
933
int ra = LUAU_INSN_A(*pc);
934
int rb = LUAU_INSN_B(*pc);
935
936
regTags[ra] = LBC_TYPE_ANY;
937
938
bcType.a = regTags[rb];
939
bcType.b = LBC_TYPE_NUMBER;
940
941
bcType.result = regTags[ra];
942
break;
943
}
944
case LOP_SETTABLEN:
945
{
946
int rb = LUAU_INSN_B(*pc);
947
948
bcType.a = regTags[rb];
949
bcType.b = LBC_TYPE_NUMBER;
950
break;
951
}
952
case LOP_ADD:
953
case LOP_SUB:
954
{
955
int ra = LUAU_INSN_A(*pc);
956
int rb = LUAU_INSN_B(*pc);
957
int rc = LUAU_INSN_C(*pc);
958
959
bcType.a = regTags[rb];
960
bcType.b = regTags[rc];
961
962
regTags[ra] = LBC_TYPE_ANY;
963
964
if (bcType.a == LBC_TYPE_NUMBER && bcType.b == LBC_TYPE_NUMBER)
965
regTags[ra] = LBC_TYPE_NUMBER;
966
else if (bcType.a == LBC_TYPE_VECTOR && bcType.b == LBC_TYPE_VECTOR)
967
regTags[ra] = LBC_TYPE_VECTOR;
968
else if (hostHooks.userdataMetamethodBytecodeType &&
969
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
970
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
971
972
bcType.result = regTags[ra];
973
break;
974
}
975
case LOP_MUL:
976
case LOP_DIV:
977
case LOP_IDIV:
978
{
979
int ra = LUAU_INSN_A(*pc);
980
int rb = LUAU_INSN_B(*pc);
981
int rc = LUAU_INSN_C(*pc);
982
983
bcType.a = regTags[rb];
984
bcType.b = regTags[rc];
985
986
regTags[ra] = LBC_TYPE_ANY;
987
988
if (bcType.a == LBC_TYPE_NUMBER)
989
{
990
if (bcType.b == LBC_TYPE_NUMBER)
991
regTags[ra] = LBC_TYPE_NUMBER;
992
else if (bcType.b == LBC_TYPE_VECTOR)
993
regTags[ra] = LBC_TYPE_VECTOR;
994
}
995
else if (bcType.a == LBC_TYPE_VECTOR)
996
{
997
if (bcType.b == LBC_TYPE_NUMBER || bcType.b == LBC_TYPE_VECTOR)
998
regTags[ra] = LBC_TYPE_VECTOR;
999
}
1000
else if (hostHooks.userdataMetamethodBytecodeType &&
1001
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1002
{
1003
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1004
}
1005
1006
bcType.result = regTags[ra];
1007
break;
1008
}
1009
case LOP_MOD:
1010
case LOP_POW:
1011
{
1012
int ra = LUAU_INSN_A(*pc);
1013
int rb = LUAU_INSN_B(*pc);
1014
int rc = LUAU_INSN_C(*pc);
1015
1016
bcType.a = regTags[rb];
1017
bcType.b = regTags[rc];
1018
1019
regTags[ra] = LBC_TYPE_ANY;
1020
1021
if (bcType.a == LBC_TYPE_NUMBER && bcType.b == LBC_TYPE_NUMBER)
1022
regTags[ra] = LBC_TYPE_NUMBER;
1023
else if (hostHooks.userdataMetamethodBytecodeType &&
1024
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1025
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1026
1027
bcType.result = regTags[ra];
1028
break;
1029
}
1030
case LOP_ADDK:
1031
case LOP_SUBK:
1032
{
1033
int ra = LUAU_INSN_A(*pc);
1034
int rb = LUAU_INSN_B(*pc);
1035
int kc = LUAU_INSN_C(*pc);
1036
1037
bcType.a = regTags[rb];
1038
bcType.b = getBytecodeConstantTag(proto, kc);
1039
1040
regTags[ra] = LBC_TYPE_ANY;
1041
1042
if (bcType.a == LBC_TYPE_NUMBER && bcType.b == LBC_TYPE_NUMBER)
1043
regTags[ra] = LBC_TYPE_NUMBER;
1044
else if (bcType.a == LBC_TYPE_VECTOR && bcType.b == LBC_TYPE_VECTOR)
1045
regTags[ra] = LBC_TYPE_VECTOR;
1046
else if (hostHooks.userdataMetamethodBytecodeType &&
1047
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1048
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1049
1050
bcType.result = regTags[ra];
1051
break;
1052
}
1053
case LOP_MULK:
1054
case LOP_DIVK:
1055
case LOP_IDIVK:
1056
{
1057
int ra = LUAU_INSN_A(*pc);
1058
int rb = LUAU_INSN_B(*pc);
1059
int kc = LUAU_INSN_C(*pc);
1060
1061
bcType.a = regTags[rb];
1062
bcType.b = getBytecodeConstantTag(proto, kc);
1063
1064
regTags[ra] = LBC_TYPE_ANY;
1065
1066
if (bcType.a == LBC_TYPE_NUMBER)
1067
{
1068
if (bcType.b == LBC_TYPE_NUMBER)
1069
regTags[ra] = LBC_TYPE_NUMBER;
1070
else if (bcType.b == LBC_TYPE_VECTOR)
1071
regTags[ra] = LBC_TYPE_VECTOR;
1072
}
1073
else if (bcType.a == LBC_TYPE_VECTOR)
1074
{
1075
if (bcType.b == LBC_TYPE_NUMBER || bcType.b == LBC_TYPE_VECTOR)
1076
regTags[ra] = LBC_TYPE_VECTOR;
1077
}
1078
else if (hostHooks.userdataMetamethodBytecodeType &&
1079
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1080
{
1081
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1082
}
1083
1084
bcType.result = regTags[ra];
1085
break;
1086
}
1087
case LOP_MODK:
1088
case LOP_POWK:
1089
{
1090
int ra = LUAU_INSN_A(*pc);
1091
int rb = LUAU_INSN_B(*pc);
1092
int kc = LUAU_INSN_C(*pc);
1093
1094
bcType.a = regTags[rb];
1095
bcType.b = getBytecodeConstantTag(proto, kc);
1096
1097
regTags[ra] = LBC_TYPE_ANY;
1098
1099
if (bcType.a == LBC_TYPE_NUMBER && bcType.b == LBC_TYPE_NUMBER)
1100
regTags[ra] = LBC_TYPE_NUMBER;
1101
else if (hostHooks.userdataMetamethodBytecodeType &&
1102
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1103
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1104
1105
bcType.result = regTags[ra];
1106
break;
1107
}
1108
case LOP_SUBRK:
1109
{
1110
int ra = LUAU_INSN_A(*pc);
1111
int kb = LUAU_INSN_B(*pc);
1112
int rc = LUAU_INSN_C(*pc);
1113
1114
bcType.a = getBytecodeConstantTag(proto, kb);
1115
bcType.b = regTags[rc];
1116
1117
regTags[ra] = LBC_TYPE_ANY;
1118
1119
if (bcType.a == LBC_TYPE_NUMBER && bcType.b == LBC_TYPE_NUMBER)
1120
regTags[ra] = LBC_TYPE_NUMBER;
1121
else if (bcType.a == LBC_TYPE_VECTOR && bcType.b == LBC_TYPE_VECTOR)
1122
regTags[ra] = LBC_TYPE_VECTOR;
1123
else if (hostHooks.userdataMetamethodBytecodeType &&
1124
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1125
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1126
1127
bcType.result = regTags[ra];
1128
break;
1129
}
1130
case LOP_DIVRK:
1131
{
1132
int ra = LUAU_INSN_A(*pc);
1133
int kb = LUAU_INSN_B(*pc);
1134
int rc = LUAU_INSN_C(*pc);
1135
1136
bcType.a = getBytecodeConstantTag(proto, kb);
1137
bcType.b = regTags[rc];
1138
1139
regTags[ra] = LBC_TYPE_ANY;
1140
1141
if (bcType.a == LBC_TYPE_NUMBER)
1142
{
1143
if (bcType.b == LBC_TYPE_NUMBER)
1144
regTags[ra] = LBC_TYPE_NUMBER;
1145
else if (bcType.b == LBC_TYPE_VECTOR)
1146
regTags[ra] = LBC_TYPE_VECTOR;
1147
}
1148
else if (bcType.a == LBC_TYPE_VECTOR)
1149
{
1150
if (bcType.b == LBC_TYPE_NUMBER || bcType.b == LBC_TYPE_VECTOR)
1151
regTags[ra] = LBC_TYPE_VECTOR;
1152
}
1153
else if (hostHooks.userdataMetamethodBytecodeType &&
1154
(isCustomUserdataBytecodeType(bcType.a) || isCustomUserdataBytecodeType(bcType.b)))
1155
{
1156
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, bcType.b, opcodeToHostMetamethod(op));
1157
}
1158
1159
bcType.result = regTags[ra];
1160
break;
1161
}
1162
case LOP_NOT:
1163
{
1164
int ra = LUAU_INSN_A(*pc);
1165
int rb = LUAU_INSN_B(*pc);
1166
1167
bcType.a = regTags[rb];
1168
1169
regTags[ra] = LBC_TYPE_BOOLEAN;
1170
bcType.result = regTags[ra];
1171
break;
1172
}
1173
case LOP_MINUS:
1174
{
1175
int ra = LUAU_INSN_A(*pc);
1176
int rb = LUAU_INSN_B(*pc);
1177
1178
bcType.a = regTags[rb];
1179
1180
regTags[ra] = LBC_TYPE_ANY;
1181
1182
if (bcType.a == LBC_TYPE_NUMBER)
1183
regTags[ra] = LBC_TYPE_NUMBER;
1184
else if (bcType.a == LBC_TYPE_VECTOR)
1185
regTags[ra] = LBC_TYPE_VECTOR;
1186
else if (hostHooks.userdataMetamethodBytecodeType && isCustomUserdataBytecodeType(bcType.a))
1187
regTags[ra] = hostHooks.userdataMetamethodBytecodeType(bcType.a, LBC_TYPE_ANY, HostMetamethod::Minus);
1188
1189
bcType.result = regTags[ra];
1190
break;
1191
}
1192
case LOP_LENGTH:
1193
{
1194
int ra = LUAU_INSN_A(*pc);
1195
int rb = LUAU_INSN_B(*pc);
1196
1197
bcType.a = regTags[rb];
1198
1199
regTags[ra] = LBC_TYPE_NUMBER; // Even if it's a custom __len, it's ok to assume a sane result
1200
bcType.result = regTags[ra];
1201
break;
1202
}
1203
case LOP_NEWTABLE:
1204
case LOP_DUPTABLE:
1205
{
1206
int ra = LUAU_INSN_A(*pc);
1207
regTags[ra] = LBC_TYPE_TABLE;
1208
bcType.result = regTags[ra];
1209
break;
1210
}
1211
case LOP_FASTCALL:
1212
{
1213
int bfid = LUAU_INSN_A(*pc);
1214
int skip = LUAU_INSN_C(*pc);
1215
1216
Instruction call = pc[skip + 1];
1217
CODEGEN_ASSERT(LUAU_INSN_OP(call) == LOP_CALL);
1218
int ra = LUAU_INSN_A(call);
1219
1220
applyBuiltinCall(LuauBuiltinFunction(bfid), bcType);
1221
1222
regTags[ra + 1] = bcType.a;
1223
regTags[ra + 2] = bcType.b;
1224
regTags[ra + 3] = bcType.c;
1225
regTags[ra] = bcType.result;
1226
1227
refineRegType(bcTypeInfo, ra, i, bcType.result);
1228
1229
// Fastcall failure fallback is skipped from result propagation
1230
i += skip;
1231
break;
1232
}
1233
case LOP_FASTCALL1:
1234
case LOP_FASTCALL2K:
1235
{
1236
int bfid = LUAU_INSN_A(*pc);
1237
int skip = LUAU_INSN_C(*pc);
1238
1239
Instruction call = pc[skip + 1];
1240
CODEGEN_ASSERT(LUAU_INSN_OP(call) == LOP_CALL);
1241
int ra = LUAU_INSN_A(call);
1242
1243
applyBuiltinCall(LuauBuiltinFunction(bfid), bcType);
1244
1245
regTags[LUAU_INSN_B(*pc)] = bcType.a;
1246
regTags[ra] = bcType.result;
1247
1248
refineRegType(bcTypeInfo, ra, i, bcType.result);
1249
1250
// Fastcall failure fallback is skipped from result propagation
1251
i += skip;
1252
break;
1253
}
1254
case LOP_FASTCALL2:
1255
{
1256
int bfid = LUAU_INSN_A(*pc);
1257
int skip = LUAU_INSN_C(*pc);
1258
1259
Instruction call = pc[skip + 1];
1260
CODEGEN_ASSERT(LUAU_INSN_OP(call) == LOP_CALL);
1261
int ra = LUAU_INSN_A(call);
1262
1263
applyBuiltinCall(LuauBuiltinFunction(bfid), bcType);
1264
1265
regTags[LUAU_INSN_B(*pc)] = bcType.a;
1266
regTags[int(pc[1])] = bcType.b;
1267
regTags[ra] = bcType.result;
1268
1269
refineRegType(bcTypeInfo, ra, i, bcType.result);
1270
1271
// Fastcall failure fallback is skipped from result propagation
1272
i += skip;
1273
break;
1274
}
1275
case LOP_FASTCALL3:
1276
{
1277
int bfid = LUAU_INSN_A(*pc);
1278
int skip = LUAU_INSN_C(*pc);
1279
int aux = pc[1];
1280
1281
Instruction call = pc[skip + 1];
1282
CODEGEN_ASSERT(LUAU_INSN_OP(call) == LOP_CALL);
1283
int ra = LUAU_INSN_A(call);
1284
1285
applyBuiltinCall(LuauBuiltinFunction(bfid), bcType);
1286
1287
regTags[LUAU_INSN_B(*pc)] = bcType.a;
1288
regTags[LUAU_INSN_AUX_A(aux)] = bcType.b;
1289
regTags[LUAU_INSN_AUX_B(aux)] = bcType.c;
1290
regTags[ra] = bcType.result;
1291
1292
refineRegType(bcTypeInfo, ra, i, bcType.result);
1293
1294
// Fastcall failure fallback is skipped from result propagation
1295
i += skip;
1296
break;
1297
}
1298
case LOP_FORNPREP:
1299
{
1300
int ra = LUAU_INSN_A(*pc);
1301
1302
regTags[ra] = LBC_TYPE_NUMBER;
1303
regTags[ra + 1] = LBC_TYPE_NUMBER;
1304
regTags[ra + 2] = LBC_TYPE_NUMBER;
1305
1306
refineRegType(bcTypeInfo, ra, i, regTags[ra]);
1307
refineRegType(bcTypeInfo, ra + 1, i, regTags[ra + 1]);
1308
refineRegType(bcTypeInfo, ra + 2, i, regTags[ra + 2]);
1309
break;
1310
}
1311
case LOP_FORNLOOP:
1312
{
1313
int ra = LUAU_INSN_A(*pc);
1314
1315
// These types are established by LOP_FORNPREP and we reinforce that here
1316
regTags[ra] = LBC_TYPE_NUMBER;
1317
regTags[ra + 1] = LBC_TYPE_NUMBER;
1318
regTags[ra + 2] = LBC_TYPE_NUMBER;
1319
break;
1320
}
1321
case LOP_CONCAT:
1322
{
1323
int ra = LUAU_INSN_A(*pc);
1324
regTags[ra] = LBC_TYPE_STRING;
1325
bcType.result = regTags[ra];
1326
break;
1327
}
1328
case LOP_NEWCLOSURE:
1329
case LOP_DUPCLOSURE:
1330
{
1331
int ra = LUAU_INSN_A(*pc);
1332
regTags[ra] = LBC_TYPE_FUNCTION;
1333
bcType.result = regTags[ra];
1334
break;
1335
}
1336
case LOP_NAMECALL:
1337
{
1338
int ra = LUAU_INSN_A(*pc);
1339
int rb = LUAU_INSN_B(*pc);
1340
uint32_t kc = pc[1];
1341
1342
bcType.a = regTags[rb];
1343
bcType.b = getBytecodeConstantTag(proto, kc);
1344
1345
// While namecall might result in a callable table, we assume the function fast path
1346
regTags[ra] = LBC_TYPE_FUNCTION;
1347
1348
// Namecall places source register into target + 1
1349
regTags[ra + 1] = bcType.a;
1350
1351
bcType.result = LBC_TYPE_FUNCTION;
1352
1353
TString* str = gco2ts(function.proto->k[kc].value.gc);
1354
const char* field = getstr(str);
1355
1356
if (bcType.a == LBC_TYPE_VECTOR && hostHooks.vectorNamecallBytecodeType)
1357
knownNextCallResult = LuauBytecodeType(hostHooks.vectorNamecallBytecodeType(field, str->len));
1358
else if (isCustomUserdataBytecodeType(bcType.a) && hostHooks.userdataNamecallBytecodeType)
1359
knownNextCallResult = LuauBytecodeType(hostHooks.userdataNamecallBytecodeType(bcType.a, field, str->len));
1360
break;
1361
}
1362
case LOP_CALL:
1363
{
1364
int ra = LUAU_INSN_A(*pc);
1365
1366
if (knownNextCallResult != LBC_TYPE_ANY)
1367
{
1368
bcType.result = knownNextCallResult;
1369
1370
knownNextCallResult = LBC_TYPE_ANY;
1371
1372
regTags[ra] = bcType.result;
1373
}
1374
1375
refineRegType(bcTypeInfo, ra, i, bcType.result);
1376
break;
1377
}
1378
case LOP_GETUPVAL:
1379
{
1380
int ra = LUAU_INSN_A(*pc);
1381
int up = LUAU_INSN_B(*pc);
1382
1383
bcType.a = LBC_TYPE_ANY;
1384
1385
if (size_t(up) < bcTypeInfo.upvalueTypes.size())
1386
{
1387
uint8_t et = bcTypeInfo.upvalueTypes[up];
1388
1389
// TODO: if argument is optional, this might force a VM exit unnecessarily
1390
bcType.a = et & ~LBC_TYPE_OPTIONAL_BIT;
1391
}
1392
1393
regTags[ra] = bcType.a;
1394
bcType.result = regTags[ra];
1395
break;
1396
}
1397
case LOP_SETUPVAL:
1398
{
1399
int ra = LUAU_INSN_A(*pc);
1400
int up = LUAU_INSN_B(*pc);
1401
1402
refineUpvalueType(bcTypeInfo, up, regTags[ra]);
1403
break;
1404
}
1405
case LOP_GETGLOBAL:
1406
{
1407
int ra = LUAU_INSN_A(*pc);
1408
1409
regTags[ra] = LBC_TYPE_ANY;
1410
bcType.result = regTags[ra];
1411
break;
1412
}
1413
case LOP_SETGLOBAL:
1414
case LOP_RETURN:
1415
case LOP_JUMP:
1416
case LOP_JUMPBACK:
1417
case LOP_JUMPIF:
1418
case LOP_JUMPIFNOT:
1419
break;
1420
case LOP_JUMPIFEQ:
1421
case LOP_JUMPIFLE:
1422
case LOP_JUMPIFLT:
1423
case LOP_JUMPIFNOTEQ:
1424
case LOP_JUMPIFNOTLE:
1425
case LOP_JUMPIFNOTLT:
1426
{
1427
int ra = LUAU_INSN_A(*pc);
1428
int rb = pc[1];
1429
1430
bcType.a = regTags[ra];
1431
bcType.b = regTags[rb];
1432
break;
1433
}
1434
case LOP_JUMPX:
1435
case LOP_JUMPXEQKNIL:
1436
case LOP_JUMPXEQKB:
1437
case LOP_JUMPXEQKN:
1438
case LOP_JUMPXEQKS:
1439
case LOP_SETLIST:
1440
case LOP_CLOSEUPVALS:
1441
case LOP_FORGLOOP:
1442
case LOP_FORGPREP_NEXT:
1443
case LOP_FORGPREP_INEXT:
1444
break;
1445
case LOP_AND:
1446
case LOP_OR:
1447
{
1448
int ra = LUAU_INSN_A(*pc);
1449
int rb = LUAU_INSN_B(*pc);
1450
int rc = LUAU_INSN_C(*pc);
1451
1452
bcType.a = regTags[rb];
1453
bcType.b = regTags[rc];
1454
1455
regTags[ra] = LBC_TYPE_ANY;
1456
bcType.result = regTags[ra];
1457
break;
1458
}
1459
case LOP_ANDK:
1460
case LOP_ORK:
1461
{
1462
int ra = LUAU_INSN_A(*pc);
1463
int rb = LUAU_INSN_B(*pc);
1464
int kc = LUAU_INSN_C(*pc);
1465
1466
bcType.a = regTags[rb];
1467
bcType.b = getBytecodeConstantTag(proto, kc);
1468
1469
regTags[ra] = LBC_TYPE_ANY;
1470
bcType.result = regTags[ra];
1471
break;
1472
}
1473
case LOP_COVERAGE:
1474
break;
1475
case LOP_GETIMPORT:
1476
{
1477
int ra = LUAU_INSN_A(*pc);
1478
1479
regTags[ra] = LBC_TYPE_ANY;
1480
bcType.result = regTags[ra];
1481
break;
1482
}
1483
case LOP_CAPTURE:
1484
case LOP_PREPVARARGS:
1485
case LOP_GETVARARGS:
1486
case LOP_FORGPREP:
1487
break;
1488
default:
1489
CODEGEN_ASSERT(!"Unknown instruction");
1490
}
1491
1492
i += getOpLength(op);
1493
}
1494
}
1495
}
1496
1497
} // namespace CodeGen
1498
} // namespace Luau
1499
1500