Skip to content

Commit 68e80de

Browse files
committed
Add parse errors to ensure we do fit arguments into the bytecode restrictions
Signed-off-by: Stefan Marr <git@stefan-marr.de>
1 parent ae02e17 commit 68e80de

17 files changed

+300
-173
lines changed

src/compiler/BytecodeGenerator.cpp

Lines changed: 114 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <cassert>
3030
#include <cstddef>
3131
#include <cstdint>
32+
#include <limits>
3233

3334
#include "../interpreter/bytecodes.h"
3435
#include "../vm/Globals.h"
@@ -39,19 +40,20 @@
3940
#include "../vmobjects/VMMethod.h"
4041
#include "../vmobjects/VMSymbol.h"
4142
#include "MethodGenerationContext.h"
43+
#include "Parser.h"
4244

4345
void Emit1(MethodGenerationContext& mgenc, uint8_t bytecode,
4446
int64_t stackEffect) {
4547
mgenc.AddBytecode(bytecode, stackEffect);
4648
}
4749

48-
void Emit2(MethodGenerationContext& mgenc, uint8_t bytecode, size_t idx,
50+
void Emit2(MethodGenerationContext& mgenc, uint8_t bytecode, uint8_t idx,
4951
int64_t stackEffect) {
5052
mgenc.AddBytecode(bytecode, stackEffect);
5153
mgenc.AddBytecodeArgument(idx);
5254
}
5355

54-
void Emit3(MethodGenerationContext& mgenc, uint8_t bytecode, size_t idx,
56+
void Emit3(MethodGenerationContext& mgenc, uint8_t bytecode, uint8_t idx,
5557
size_t ctx, int64_t stackEffect) {
5658
mgenc.AddBytecode(bytecode, stackEffect);
5759
mgenc.AddBytecodeArgument(idx);
@@ -66,9 +68,23 @@ void EmitDUP(MethodGenerationContext& mgenc) {
6668
Emit1(mgenc, BC_DUP, 1);
6769
}
6870

69-
void EmitPUSHLOCAL(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
70-
assert(idx >= 0);
71-
assert(ctx >= 0);
71+
void EmitPUSHLOCAL(MethodGenerationContext& mgenc, const Parser& parser,
72+
size_t index, size_t context) {
73+
if (index > std::numeric_limits<uint8_t>::max()) {
74+
parser.ParseError(
75+
"The method has too many local variables. You may be able to split "
76+
"up this method into multiple to avoid the issue.");
77+
}
78+
79+
if (context > std::numeric_limits<uint8_t>::max()) {
80+
parser.ParseError(
81+
"This block is too deeply nested. You may be able to split up this "
82+
"method into multiple to avoid the issue.");
83+
}
84+
85+
const uint8_t idx = index;
86+
const uint8_t ctx = context;
87+
7288
if (ctx == 0) {
7389
if (idx == 0) {
7490
Emit1(mgenc, BC_PUSH_LOCAL_0, 1);
@@ -86,9 +102,22 @@ void EmitPUSHLOCAL(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
86102
Emit3(mgenc, BC_PUSH_LOCAL, idx, ctx, 1);
87103
}
88104

89-
void EmitPUSHARGUMENT(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
90-
assert(idx >= 0);
91-
assert(ctx >= 0);
105+
void EmitPUSHARGUMENT(MethodGenerationContext& mgenc, const Parser& parser,
106+
size_t index, size_t context) {
107+
if (index > std::numeric_limits<uint8_t>::max()) {
108+
parser.ParseError(
109+
"The method has too many arguments. You may be able to split up "
110+
"this method into multiple to avoid the issue.");
111+
}
112+
113+
if (context > std::numeric_limits<uint8_t>::max()) {
114+
parser.ParseError(
115+
"This block is too deeply nested. You may be able to split up this "
116+
"method into multiple to avoid the issue.");
117+
}
118+
119+
const uint8_t idx = index;
120+
const uint8_t ctx = context;
92121

93122
if (ctx == 0) {
94123
if (idx == 0) {
@@ -109,23 +138,27 @@ void EmitPUSHARGUMENT(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
109138
Emit3(mgenc, BC_PUSH_ARGUMENT, idx, ctx, 1);
110139
}
111140

112-
void EmitPUSHFIELD(MethodGenerationContext& mgenc, VMSymbol* field) {
113-
const uint8_t idx = mgenc.GetFieldIndex(field);
114-
if (idx == 0) {
115-
Emit1(mgenc, BC_PUSH_FIELD_0, 1);
116-
} else if (idx == 1) {
117-
Emit1(mgenc, BC_PUSH_FIELD_1, 1);
118-
} else {
119-
Emit2(mgenc, BC_PUSH_FIELD, idx, 1);
141+
void EmitPUSHFIELD(MethodGenerationContext& mgenc, const Parser& parser,
142+
VMSymbol* field) {
143+
const int64_t idx = mgenc.GetFieldIndex(field);
144+
if (idx < 0 || idx > std::numeric_limits<uint8_t>::max()) {
145+
parser.ParseError(
146+
"The method tries to access a field that cannot be represented in "
147+
"the SOM++ bytecodes. Make sure this class and its superclasses "
148+
"have less than 256 fields in total.");
120149
}
150+
151+
EmitPushFieldWithIndex(mgenc, idx);
121152
}
122153

123-
void EmitPUSHBLOCK(MethodGenerationContext& mgenc, VMInvokable* block) {
124-
const uint8_t idx = mgenc.AddLiteralIfAbsent(block);
154+
void EmitPUSHBLOCK(MethodGenerationContext& mgenc, const Parser& parser,
155+
VMInvokable* block) {
156+
const uint8_t idx = mgenc.AddLiteralIfAbsent(block, parser);
125157
Emit2(mgenc, BC_PUSH_BLOCK, idx, 1);
126158
}
127159

128-
void EmitPUSHCONSTANT(MethodGenerationContext& mgenc, vm_oop_t cst) {
160+
void EmitPUSHCONSTANT(MethodGenerationContext& mgenc, const Parser& parser,
161+
vm_oop_t cst) {
129162
// this isn't very robust with respect to initialization order
130163
// so, we check here, and hope it's working, but alternatively
131164
// we also make sure that we don't miss anything in the else
@@ -148,7 +181,7 @@ void EmitPUSHCONSTANT(MethodGenerationContext& mgenc, vm_oop_t cst) {
148181
return;
149182
}
150183

151-
const uint8_t idx = mgenc.AddLiteralIfAbsent(cst);
184+
const uint8_t idx = mgenc.AddLiteralIfAbsent(cst, parser);
152185
if (idx == 0) {
153186
Emit1(mgenc, BC_PUSH_CONSTANT_0, 1);
154187
return;
@@ -173,15 +206,16 @@ void EmitPUSHCONSTANTString(MethodGenerationContext& mgenc, VMString* str) {
173206
Emit2(mgenc, BC_PUSH_CONSTANT, mgenc.FindLiteralIndex(str), 1);
174207
}
175208

176-
void EmitPUSHGLOBAL(MethodGenerationContext& mgenc, VMSymbol* global) {
209+
void EmitPUSHGLOBAL(MethodGenerationContext& mgenc, const Parser& parser,
210+
VMSymbol* global) {
177211
if (global == SymbolFor("nil")) {
178-
EmitPUSHCONSTANT(mgenc, load_ptr(nilObject));
212+
EmitPUSHCONSTANT(mgenc, parser, load_ptr(nilObject));
179213
} else if (global == SymbolFor("true")) {
180-
EmitPUSHCONSTANT(mgenc, load_ptr(trueObject));
214+
EmitPUSHCONSTANT(mgenc, parser, load_ptr(trueObject));
181215
} else if (global == SymbolFor("false")) {
182-
EmitPUSHCONSTANT(mgenc, load_ptr(falseObject));
216+
EmitPUSHCONSTANT(mgenc, parser, load_ptr(falseObject));
183217
} else {
184-
const uint8_t idx = mgenc.AddLiteralIfAbsent(global);
218+
const uint8_t idx = mgenc.AddLiteralIfAbsent(global, parser);
185219
Emit2(mgenc, BC_PUSH_GLOBAL, idx, 1);
186220
}
187221
}
@@ -192,9 +226,23 @@ void EmitPOP(MethodGenerationContext& mgenc) {
192226
}
193227
}
194228

195-
void EmitPOPLOCAL(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
196-
assert(idx >= 0);
197-
assert(ctx >= 0);
229+
void EmitPOPLOCAL(MethodGenerationContext& mgenc, const Parser& parser,
230+
size_t index, size_t context) {
231+
if (index > std::numeric_limits<uint8_t>::max()) {
232+
parser.ParseError(
233+
"The method has too many local variables. You may be able to split "
234+
"up this method into multiple to avoid the issue.");
235+
}
236+
237+
if (context > std::numeric_limits<uint8_t>::max()) {
238+
parser.ParseError(
239+
"This block is too deeply nested. You may be able to split up this "
240+
"method into multiple to avoid the issue.");
241+
}
242+
243+
const uint8_t idx = index;
244+
const uint8_t ctx = context;
245+
198246
if (ctx == 0) {
199247
if (idx == 0) {
200248
Emit1(mgenc, BC_POP_LOCAL_0, -1);
@@ -215,12 +263,32 @@ void EmitPOPLOCAL(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
215263
Emit3(mgenc, BC_POP_LOCAL, idx, ctx, -1);
216264
}
217265

218-
void EmitPOPARGUMENT(MethodGenerationContext& mgenc, size_t idx, size_t ctx) {
266+
void EmitPOPARGUMENT(MethodGenerationContext& mgenc, const Parser& parser,
267+
size_t idx, size_t ctx) {
268+
if (idx > std::numeric_limits<uint8_t>::max()) {
269+
parser.ParseError(
270+
"The method has too many arguments. You may be able to split up "
271+
"this method into multiple to avoid the issue.");
272+
}
273+
274+
if (ctx > std::numeric_limits<uint8_t>::max()) {
275+
parser.ParseError(
276+
"This block is too deeply nested. You may be able to split up this "
277+
"method into multiple to avoid the issue.");
278+
}
279+
219280
Emit3(mgenc, BC_POP_ARGUMENT, idx, ctx, -1);
220281
}
221282

222-
void EmitPOPFIELD(MethodGenerationContext& mgenc, VMSymbol* field) {
223-
const uint8_t idx = mgenc.GetFieldIndex(field);
283+
void EmitPOPFIELD(MethodGenerationContext& mgenc, const Parser& parser,
284+
VMSymbol* field) {
285+
const int64_t idx = mgenc.GetFieldIndex(field);
286+
if (idx < 0 || idx > std::numeric_limits<uint8_t>::max()) {
287+
parser.ParseError(
288+
"The method tries to access a field that cannot be represented in "
289+
"the SOM++ bytecodes. Make sure this class and its superclasses "
290+
"have less than 256 fields in total.");
291+
}
224292

225293
if (mgenc.OptimizeIncField(idx)) {
226294
return;
@@ -229,17 +297,19 @@ void EmitPOPFIELD(MethodGenerationContext& mgenc, VMSymbol* field) {
229297
EmitPopFieldWithIndex(mgenc, idx);
230298
}
231299

232-
void EmitSEND(MethodGenerationContext& mgenc, VMSymbol* msg) {
233-
const uint8_t idx = mgenc.AddLiteralIfAbsent(msg);
300+
void EmitSEND(MethodGenerationContext& mgenc, const Parser& parser,
301+
VMSymbol* msg) {
302+
const uint8_t idx = mgenc.AddLiteralIfAbsent(msg, parser);
234303

235304
const uint8_t numArgs = Signature::GetNumberOfArguments(msg);
236305
const int64_t stackEffect = -numArgs + 1; // +1 for the result
237306

238307
Emit2(mgenc, numArgs == 1 ? BC_SEND_1 : BC_SEND, idx, stackEffect);
239308
}
240309

241-
void EmitSUPERSEND(MethodGenerationContext& mgenc, VMSymbol* msg) {
242-
const uint8_t idx = mgenc.AddLiteralIfAbsent(msg);
310+
void EmitSUPERSEND(MethodGenerationContext& mgenc, const Parser& parser,
311+
VMSymbol* msg) {
312+
const uint8_t idx = mgenc.AddLiteralIfAbsent(msg, parser);
243313
const uint8_t numArgs = Signature::GetNumberOfArguments(msg);
244314
const int64_t stackEffect = -numArgs + 1; // +1 for the result
245315

@@ -251,8 +321,8 @@ void EmitRETURNSELF(MethodGenerationContext& mgenc) {
251321
Emit1(mgenc, BC_RETURN_SELF, 0);
252322
}
253323

254-
void EmitRETURNLOCAL(MethodGenerationContext& mgenc) {
255-
if (!mgenc.OptimizeReturnField()) {
324+
void EmitRETURNLOCAL(MethodGenerationContext& mgenc, const Parser& parser) {
325+
if (!mgenc.OptimizeReturnField(parser)) {
256326
Emit1(mgenc, BC_RETURN_LOCAL, 0);
257327
}
258328
}
@@ -261,18 +331,21 @@ void EmitRETURNNONLOCAL(MethodGenerationContext& mgenc) {
261331
Emit1(mgenc, BC_RETURN_NON_LOCAL, 0);
262332
}
263333

264-
void EmitRETURNFIELD(MethodGenerationContext& mgenc, size_t index) {
265-
assert(index <= 2);
334+
void EmitRETURNFIELD(MethodGenerationContext& mgenc, const Parser& parser,
335+
size_t index) {
336+
if (index > 2) {
337+
parser.ParseError(
338+
"Internal Error: EmitRETURNFIELD has unsupported argument");
339+
}
340+
266341
uint8_t bc = 0;
267342
switch (index) {
268343
case 0:
269344
bc = BC_RETURN_FIELD_0;
270345
break;
271-
272346
case 1:
273347
bc = BC_RETURN_FIELD_1;
274348
break;
275-
276349
case 2:
277350
bc = BC_RETURN_FIELD_2;
278351
break;

src/compiler/BytecodeGenerator.h

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,43 @@
3434

3535
void Emit1(MethodGenerationContext& mgenc, uint8_t bytecode,
3636
int64_t stackEffect);
37-
void Emit2(MethodGenerationContext& mgenc, uint8_t bytecode, size_t idx,
37+
void Emit2(MethodGenerationContext& mgenc, uint8_t bytecode, uint8_t idx,
3838
int64_t stackEffect);
39-
void Emit3(MethodGenerationContext& mgenc, uint8_t bytecode, size_t idx,
39+
void Emit3(MethodGenerationContext& mgenc, uint8_t bytecode, uint8_t idx,
4040
size_t ctx, int64_t stackEffect);
4141

4242
void EmitHALT(MethodGenerationContext& mgenc);
4343
void EmitDUP(MethodGenerationContext& mgenc);
44-
void EmitPUSHLOCAL(MethodGenerationContext& mgenc, size_t idx, size_t ctx);
45-
void EmitPUSHARGUMENT(MethodGenerationContext& mgenc, size_t idx, size_t ctx);
46-
void EmitPUSHFIELD(MethodGenerationContext& mgenc, VMSymbol* field);
47-
void EmitPUSHBLOCK(MethodGenerationContext& mgenc, VMInvokable* block);
48-
void EmitPUSHCONSTANT(MethodGenerationContext& mgenc, vm_oop_t cst);
44+
void EmitPUSHLOCAL(MethodGenerationContext& mgenc, const Parser& parser,
45+
size_t index, size_t context);
46+
void EmitPUSHARGUMENT(MethodGenerationContext& mgenc, const Parser& parser,
47+
size_t index, size_t context);
48+
void EmitPUSHFIELD(MethodGenerationContext& mgenc, const Parser& parser,
49+
VMSymbol* field);
50+
void EmitPUSHBLOCK(MethodGenerationContext& mgenc, const Parser& parser,
51+
VMInvokable* block);
52+
void EmitPUSHCONSTANT(MethodGenerationContext& mgenc, const Parser& parser,
53+
vm_oop_t cst);
4954
void EmitPUSHCONSTANT(MethodGenerationContext& mgenc, uint8_t literalIndex);
5055
void EmitPUSHCONSTANTString(MethodGenerationContext& mgenc, VMString* str);
51-
void EmitPUSHGLOBAL(MethodGenerationContext& mgenc, VMSymbol* global);
56+
void EmitPUSHGLOBAL(MethodGenerationContext& mgenc, const Parser& parser,
57+
VMSymbol* global);
5258
void EmitPOP(MethodGenerationContext& mgenc);
53-
void EmitPOPLOCAL(MethodGenerationContext& mgenc, size_t idx, size_t ctx);
54-
void EmitPOPARGUMENT(MethodGenerationContext& mgenc, size_t idx, size_t ctx);
55-
void EmitPOPFIELD(MethodGenerationContext& mgenc, VMSymbol* field);
56-
void EmitSEND(MethodGenerationContext& mgenc, VMSymbol* msg);
57-
void EmitSUPERSEND(MethodGenerationContext& mgenc, VMSymbol* msg);
59+
void EmitPOPLOCAL(MethodGenerationContext& mgenc, const Parser& parser,
60+
size_t index, size_t context);
61+
void EmitPOPARGUMENT(MethodGenerationContext& mgenc, const Parser& parser,
62+
size_t idx, size_t ctx);
63+
void EmitPOPFIELD(MethodGenerationContext& mgenc, const Parser& parser,
64+
VMSymbol* field);
65+
void EmitSEND(MethodGenerationContext& mgenc, const Parser& parser,
66+
VMSymbol* msg);
67+
void EmitSUPERSEND(MethodGenerationContext& mgenc, const Parser& parser,
68+
VMSymbol* msg);
5869
void EmitRETURNSELF(MethodGenerationContext& mgenc);
59-
void EmitRETURNLOCAL(MethodGenerationContext& mgenc);
70+
void EmitRETURNLOCAL(MethodGenerationContext& mgenc, const Parser& parser);
6071
void EmitRETURNNONLOCAL(MethodGenerationContext& mgenc);
61-
void EmitRETURNFIELD(MethodGenerationContext& mgenc, size_t index);
72+
void EmitRETURNFIELD(MethodGenerationContext& mgenc, const Parser& parser,
73+
size_t index);
6274

6375
void EmitINC(MethodGenerationContext& mgenc);
6476
void EmitDEC(MethodGenerationContext& mgenc);

0 commit comments

Comments
 (0)