Skip to content

Commit 4d7cb15

Browse files
authored
Implement inlining for #ifNil:*, #ifNotNil:* selectors (#59)
This PR uses the existing support for inlining of `ifTrue:` etc to also support `ifNil:` etc. The inlining logic is mostly unchanged, just generalized to support the different bytecodes. The new bytecodes are, incl. JUMP2 omitted here: ``` BC_JUMP_ON_NOT_NIL_POP 50 BC_JUMP_ON_NIL_POP 51 BC_JUMP_ON_NOT_NIL_TOP_TOP 52 BC_JUMP_ON_NIL_TOP_TOP 53 ``` The bytecodes check for `nil` and may keep the top element (`TOP_TOP` to be read as top is set to top), or pop it on success. The PR also resolves some lint issues and improve the disassembler. When integers are not tagged, BC_INC now needs a GC check, to avoid running out of memory on the `IfNil` benchmark.
2 parents 7e1d863 + 77cdbb7 commit 4d7cb15

23 files changed

+472
-139
lines changed

src/compiler/BytecodeGenerator.cpp

+20-9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "../vmobjects/Signature.h"
3939
#include "../vmobjects/VMMethod.h"
4040
#include "../vmobjects/VMSymbol.h"
41+
#include "MethodGenerationContext.h"
4142

4243
void Emit1(MethodGenerationContext& mgenc, uint8_t bytecode,
4344
int64_t stackEffect) {
@@ -298,21 +299,31 @@ void EmitDupSecond(MethodGenerationContext& mgenc) {
298299
Emit1(mgenc, BC_DUP_SECOND, 1);
299300
}
300301

301-
size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc,
302-
bool isIfTrue, bool needsPop) {
302+
size_t EmitJumpOnWithDummyOffset(MethodGenerationContext& mgenc,
303+
JumpCondition condition, bool needsPop) {
303304
// Remember: true and false seem flipped here.
304305
// This is because if the test passes, the block is inlined directly.
305306
// But if the test fails, we need to jump.
306307
// Thus, an `#ifTrue:` needs to generated a jump_on_false.
307308
uint8_t bc = 0;
308-
int64_t stackEffect = 0;
309+
int64_t const stackEffect = needsPop ? -1 : 0;
309310

310-
if (needsPop) {
311-
bc = isIfTrue ? BC_JUMP_ON_FALSE_POP : BC_JUMP_ON_TRUE_POP;
312-
stackEffect = -1;
313-
} else {
314-
bc = isIfTrue ? BC_JUMP_ON_FALSE_TOP_NIL : BC_JUMP_ON_TRUE_TOP_NIL;
315-
stackEffect = 0;
311+
switch (condition) {
312+
case JumpCondition::ON_TRUE:
313+
bc = needsPop ? BC_JUMP_ON_TRUE_POP : BC_JUMP_ON_TRUE_TOP_NIL;
314+
break;
315+
316+
case JumpCondition::ON_FALSE:
317+
bc = needsPop ? BC_JUMP_ON_FALSE_POP : BC_JUMP_ON_FALSE_TOP_NIL;
318+
break;
319+
320+
case JumpCondition::ON_NIL:
321+
bc = needsPop ? BC_JUMP_ON_NIL_POP : BC_JUMP_ON_NIL_TOP_TOP;
322+
break;
323+
324+
case JumpCondition::ON_NOT_NIL:
325+
bc = needsPop ? BC_JUMP_ON_NOT_NIL_POP : BC_JUMP_ON_NOT_NIL_TOP_TOP;
326+
break;
316327
}
317328

318329
Emit1(mgenc, bc, stackEffect);

src/compiler/BytecodeGenerator.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ void EmitIncFieldPush(MethodGenerationContext& mgenc, uint8_t fieldIdx);
6666

6767
void EmitDupSecond(MethodGenerationContext& mgenc);
6868

69-
size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc,
70-
bool isIfTrue, bool needsPop);
69+
size_t EmitJumpOnWithDummyOffset(MethodGenerationContext& mgenc,
70+
JumpCondition condition, bool needsPop);
7171
size_t EmitJumpWithDumyOffset(MethodGenerationContext& mgenc);
7272
size_t EmitJumpIfGreaterWithDummyOffset(MethodGenerationContext& mgenc);
7373
void EmitJumpBackwardWithOffset(MethodGenerationContext& mgenc,

src/compiler/Disassembler.cpp

+137-44
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,8 @@ void Disassembler::Dump(VMClass* cl) {
9696
VMSymbol* cname = cl->GetName();
9797
DebugDump("%s>>%s = ", cname->GetStdString().c_str(),
9898
sig->GetStdString().c_str());
99-
if (inv->IsPrimitive()) {
100-
DebugPrint("<primitive>\n");
101-
continue;
102-
}
103-
// output actual method
104-
DumpMethod(static_cast<VMMethod*>(inv), "\t");
99+
100+
inv->Dump("\t", true);
105101
}
106102
}
107103

@@ -154,6 +150,12 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
154150
}
155151

156152
switch (bytecode) {
153+
case BC_PUSH_0:
154+
case BC_PUSH_1:
155+
case BC_PUSH_NIL: {
156+
// no more details to be printed
157+
break;
158+
}
157159
case BC_PUSH_LOCAL_0: {
158160
DebugPrint("local: 0, context: 0\n");
159161
break;
@@ -199,11 +201,16 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
199201
if (method != nullptr && printObjects) {
200202
vm_oop_t constant = method->GetConstant(bc_idx);
201203
VMClass* cl = CLASS_OF(constant);
202-
VMSymbol* cname = cl->GetName();
203-
204-
DebugPrint("(index: %d) value: (%s) ",
205-
bytecodes[bc_idx + 1],
206-
cname->GetStdString().c_str());
204+
if (cl == nullptr) {
205+
DebugPrint("(index: %d) value: (%s) ",
206+
bytecodes[bc_idx + 1],
207+
"class==nullptr");
208+
} else {
209+
VMSymbol* cname = cl->GetName();
210+
DebugPrint("(index: %d) value: (%s) ",
211+
bytecodes[bc_idx + 1],
212+
cname->GetStdString().c_str());
213+
}
207214
dispatch(constant);
208215
} else {
209216
DebugPrint("(index: %d)", bytecodes[bc_idx + 1]);
@@ -235,6 +242,15 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
235242
DebugPrint("local: %d, context: %d\n", bytecodes[bc_idx + 1],
236243
bytecodes[bc_idx + 2]);
237244
break;
245+
case BC_POP_LOCAL_0:
246+
DebugPrint("local: 0, context: 0\n");
247+
break;
248+
case BC_POP_LOCAL_1:
249+
DebugPrint("local: 1, context: 0\n");
250+
break;
251+
case BC_POP_LOCAL_2:
252+
DebugPrint("local: 2, context: 0\n");
253+
break;
238254
case BC_POP_ARGUMENT:
239255
DebugPrint("argument: %d, context: %d\n", bytecodes[bc_idx + 1],
240256
bytecodes[bc_idx + 2]);
@@ -266,7 +282,8 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
266282
}
267283
break;
268284
}
269-
case BC_SEND: {
285+
case BC_SEND:
286+
case BC_SEND_1: {
270287
if (method != nullptr && printObjects) {
271288
auto* name =
272289
static_cast<VMSymbol*>(method->GetConstant(bc_idx));
@@ -295,12 +312,22 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
295312
case BC_JUMP_ON_TRUE_POP:
296313
case BC_JUMP_ON_FALSE_TOP_NIL:
297314
case BC_JUMP_ON_TRUE_TOP_NIL:
315+
case BC_JUMP_ON_NOT_NIL_POP:
316+
case BC_JUMP_ON_NIL_POP:
317+
case BC_JUMP_ON_NOT_NIL_TOP_TOP:
318+
case BC_JUMP_ON_NIL_TOP_TOP:
319+
case BC_JUMP_IF_GREATER:
298320
case BC_JUMP_BACKWARD:
299321
case BC_JUMP2:
300322
case BC_JUMP2_ON_FALSE_POP:
301323
case BC_JUMP2_ON_TRUE_POP:
302324
case BC_JUMP2_ON_FALSE_TOP_NIL:
303325
case BC_JUMP2_ON_TRUE_TOP_NIL:
326+
case BC_JUMP2_ON_NOT_NIL_POP:
327+
case BC_JUMP2_ON_NIL_POP:
328+
case BC_JUMP2_ON_NOT_NIL_TOP_TOP:
329+
case BC_JUMP2_ON_NIL_TOP_TOP:
330+
case BC_JUMP2_IF_GREATER:
304331
case BC_JUMP2_BACKWARD: {
305332
uint16_t const offset =
306333
ComputeOffset(bytecodes[bc_idx + 1], bytecodes[bc_idx + 2]);
@@ -331,6 +358,47 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
331358
#define BC_1 method->GetBytecode(bc_idx + 1)
332359
#define BC_2 method->GetBytecode(bc_idx + 2)
333360

361+
void Disassembler::printArgument(uint8_t idx, uint8_t ctx, VMClass* cl,
362+
VMFrame* frame) {
363+
vm_oop_t o = frame->GetArgument(idx, ctx);
364+
DebugPrint("argument: %d, context: %d", idx, ctx);
365+
366+
if (cl != nullptr) {
367+
VMClass* c = CLASS_OF(o);
368+
VMSymbol* cname = c->GetName();
369+
370+
DebugPrint("<(%s) ", cname->GetStdString().c_str());
371+
dispatch(o);
372+
DebugPrint(">");
373+
}
374+
DebugPrint("\n");
375+
}
376+
377+
void Disassembler::printPopLocal(uint8_t idx, uint8_t ctx, VMFrame* frame) {
378+
vm_oop_t o = frame->GetStackElement(0);
379+
VMClass* c = CLASS_OF(o);
380+
VMSymbol* cname = c->GetName();
381+
382+
DebugPrint("popped local: %d, context: %d <(%s) ", idx, ctx,
383+
cname->GetStdString().c_str());
384+
dispatch(o);
385+
DebugPrint(">\n");
386+
}
387+
388+
void Disassembler::printNth(uint8_t idx, VMFrame* frame, const char* op) {
389+
vm_oop_t o = frame->GetStackElement(idx);
390+
if (o != nullptr) {
391+
VMClass* c = CLASS_OF(o);
392+
VMSymbol* cname = c->GetName();
393+
394+
DebugPrint("<to %s: (%s) ", op, cname->GetStdString().c_str());
395+
dispatch(o);
396+
} else {
397+
DebugPrint("<to %s: address: %p", op, (void*)o);
398+
}
399+
DebugPrint(">\n");
400+
}
401+
334402
/**
335403
* Dump bytecode from the frame running
336404
*/
@@ -361,22 +429,30 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method,
361429
}
362430

363431
switch (bc) {
432+
case BC_PUSH_0:
433+
case BC_PUSH_1:
434+
case BC_PUSH_NIL: {
435+
// no more details to be printed
436+
break;
437+
}
364438
case BC_HALT: {
365439
DebugPrint("<halting>\n\n\n");
366440
break;
367441
}
368442
case BC_DUP: {
369-
vm_oop_t o = frame->GetStackElement(0);
370-
if (o != nullptr) {
371-
VMClass* c = CLASS_OF(o);
372-
VMSymbol* cname = c->GetName();
373-
374-
DebugPrint("<to dup: (%s) ", cname->GetStdString().c_str());
375-
dispatch(o);
376-
} else {
377-
DebugPrint("<to dup: address: %p", (void*)o);
378-
}
379-
DebugPrint(">\n");
443+
printNth(0, frame, "dup");
444+
break;
445+
}
446+
case BC_DUP_SECOND: {
447+
printNth(1, frame, "dup-second");
448+
break;
449+
}
450+
case BC_INC: {
451+
printNth(0, frame, "inc");
452+
break;
453+
}
454+
case BC_DEC: {
455+
printNth(0, frame, "dec");
380456
break;
381457
}
382458
case BC_PUSH_LOCAL: {
@@ -425,21 +501,22 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method,
425501
DebugPrint(">\n");
426502
break;
427503
}
504+
case BC_PUSH_SELF: {
505+
printArgument(0, 0, cl, frame);
506+
break;
507+
}
508+
case BC_PUSH_ARG_1: {
509+
printArgument(1, 0, cl, frame);
510+
break;
511+
}
512+
case BC_PUSH_ARG_2: {
513+
printArgument(2, 0, cl, frame);
514+
break;
515+
}
428516
case BC_PUSH_ARGUMENT: {
429517
uint8_t const bc1 = BC_1;
430518
uint8_t const bc2 = BC_2;
431-
vm_oop_t o = frame->GetArgument(bc1, bc2);
432-
DebugPrint("argument: %d, context: %d", bc1, bc2);
433-
434-
if (cl != nullptr) {
435-
VMClass* c = CLASS_OF(o);
436-
VMSymbol* cname = c->GetName();
437-
438-
DebugPrint("<(%s) ", cname->GetStdString().c_str());
439-
dispatch(o);
440-
DebugPrint(">");
441-
}
442-
DebugPrint("\n");
519+
printArgument(bc1, bc2, cl, frame);
443520
break;
444521
}
445522
case BC_PUSH_BLOCK: {
@@ -493,14 +570,19 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method,
493570
break;
494571
}
495572
case BC_POP_LOCAL: {
496-
vm_oop_t o = frame->GetStackElement(0);
497-
VMClass* c = CLASS_OF(o);
498-
VMSymbol* cname = c->GetName();
499-
500-
DebugPrint("popped local: %d, context: %d <(%s) ", BC_1, BC_2,
501-
cname->GetStdString().c_str());
502-
dispatch(o);
503-
DebugPrint(">\n");
573+
printPopLocal(BC_1, BC_2, frame);
574+
break;
575+
}
576+
case BC_POP_LOCAL_0: {
577+
printPopLocal(0, 0, frame);
578+
break;
579+
}
580+
case BC_POP_LOCAL_1: {
581+
printPopLocal(1, 0, frame);
582+
break;
583+
}
584+
case BC_POP_LOCAL_2: {
585+
printPopLocal(2, 0, frame);
504586
break;
505587
}
506588
case BC_POP_ARGUMENT: {
@@ -535,7 +617,8 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method,
535617
break;
536618
}
537619
case BC_SUPER_SEND:
538-
case BC_SEND: {
620+
case BC_SEND:
621+
case BC_SEND_1: {
539622
auto* sel = static_cast<VMSymbol*>(method->GetConstant(bc_idx));
540623

541624
DebugPrint("(index: %d) signature: %s (", BC_1,
@@ -567,12 +650,22 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method,
567650
case BC_JUMP_ON_TRUE_POP:
568651
case BC_JUMP_ON_FALSE_TOP_NIL:
569652
case BC_JUMP_ON_TRUE_TOP_NIL:
653+
case BC_JUMP_ON_NOT_NIL_POP:
654+
case BC_JUMP_ON_NIL_POP:
655+
case BC_JUMP_ON_NOT_NIL_TOP_TOP:
656+
case BC_JUMP_ON_NIL_TOP_TOP:
657+
case BC_JUMP_IF_GREATER:
570658
case BC_JUMP_BACKWARD:
571659
case BC_JUMP2:
572660
case BC_JUMP2_ON_FALSE_POP:
573661
case BC_JUMP2_ON_TRUE_POP:
574662
case BC_JUMP2_ON_FALSE_TOP_NIL:
575663
case BC_JUMP2_ON_TRUE_TOP_NIL:
664+
case BC_JUMP2_ON_NOT_NIL_POP:
665+
case BC_JUMP2_ON_NIL_POP:
666+
case BC_JUMP2_ON_NOT_NIL_TOP_TOP:
667+
case BC_JUMP2_ON_NIL_TOP_TOP:
668+
case BC_JUMP2_IF_GREATER:
576669
case BC_JUMP2_BACKWARD: {
577670
uint16_t const offset =
578671
ComputeOffset(method->GetBytecode(bc_idx + 1),

src/compiler/Disassembler.h

+8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class Disassembler {
3737
static void DumpMethod(VMMethod* method, const char* indent,
3838
bool printObjects = true);
3939
static void DumpMethod(MethodGenerationContext* mgenc, const char* indent);
40+
static void extracted(uint8_t bc1, uint8_t bc2, VMClass* cl,
41+
VMFrame* frame);
42+
4043
static void DumpBytecode(VMFrame* frame, VMMethod* method, size_t bc_idx);
4144

4245
private:
@@ -45,4 +48,9 @@ class Disassembler {
4548
static void dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
4649
const char* indent, VMMethod* method,
4750
bool printObjects);
51+
52+
static void printArgument(uint8_t idx, uint8_t ctx, VMClass* cl,
53+
VMFrame* frame);
54+
static void printPopLocal(uint8_t idx, uint8_t ctx, VMFrame* frame);
55+
static void printNth(uint8_t idx, VMFrame* frame, const char* op);
4856
};

0 commit comments

Comments
 (0)