Skip to content

Commit

Permalink
Implement testing and bytecodes for common sequences (#21)
Browse files Browse the repository at this point in the history
In addition to the bytecodes, this PR also adds tests for bytecode
generation to be able to check bytecode-level optimizations.

Added bytecodes:
 - `BC_PUSH_LOCAL_0`, `BC_PUSH_LOCAL_1`, `BC_PUSH_LOCAL_2`
 - `BC_PUSH_SELF`, `BC_PUSH_ARG_1`, `BC_PUSH_ARG_2`
 - `BC_PUSH_FIELD_0`, `BC_PUSH_FIELD_1`
 - `BC_PUSH_CONSTANT_0`, `BC_PUSH_CONSTANT_1`, `BC_PUSH_CONSTANT_2`
 - `BC_PUSH_0`, `BC_PUSH_1`, `BC_PUSH_NIL`
 - `BC_POP_LOCAL_0`, `BC_POP_LOCAL_1`, `BC_POP_LOCAL_2`
 - `BC_POP_FIELD_0`, `BC_POP_FIELD_1`

The speedup for this is small, with a run-time change of median -8%
(min. -16%, max. 2%).
See:
https://rebench.dev/SOMpp/compare/38d3768ba58ea25ed70758dbb64f1af0491613d3..2d21504c7b287112c3afb30123d972020eb63515
  • Loading branch information
smarr authored Jul 13, 2024
2 parents 38d3768 + 2d21504 commit 540d972
Show file tree
Hide file tree
Showing 16 changed files with 1,999 additions and 109 deletions.
131 changes: 122 additions & 9 deletions src/compiler/BytecodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
THE SOFTWARE.
*/

#include <assert.h>

#include "BytecodeGenerator.h"
#include <vm/Universe.h>

#include <vmobjects/VMObject.h>
#include <vmobjects/VMMethod.h>
Expand Down Expand Up @@ -52,25 +55,97 @@ void BytecodeGenerator::EmitDUP(MethodGenerationContext* mgenc) {

void BytecodeGenerator::EmitPUSHLOCAL(MethodGenerationContext* mgenc, long idx,
int ctx) {
assert(idx >= 0);
assert(ctx >= 0);
if (ctx == 0) {
if (idx == 0) {
EMIT1(BC_PUSH_LOCAL_0);
return;
}
if (idx == 1) {
EMIT1(BC_PUSH_LOCAL_1);
return;
}
if (idx == 2) {
EMIT1(BC_PUSH_LOCAL_2);
return;
}
}
EMIT3(BC_PUSH_LOCAL, idx, ctx);
}

void BytecodeGenerator::EmitPUSHARGUMENT(MethodGenerationContext* mgenc,
long idx, int ctx) {
assert(idx >= 0);
assert(ctx >= 0);

if (ctx == 0) {
if (idx == 0) {
EMIT1(BC_PUSH_SELF);
return;
}

if (idx == 1) {
EMIT1(BC_PUSH_ARG_1);
return;
}

if (idx == 2) {
EMIT1(BC_PUSH_ARG_2);
return;
}
}
EMIT3(BC_PUSH_ARGUMENT, idx, ctx);
}

void BytecodeGenerator::EmitPUSHFIELD(MethodGenerationContext* mgenc, VMSymbol* field) {
EMIT2(BC_PUSH_FIELD, mgenc->GetFieldIndex(field));
uint8_t idx = mgenc->GetFieldIndex(field);
if (idx == 0) {
EMIT1(BC_PUSH_FIELD_0);
} else if (idx == 1) {
EMIT1(BC_PUSH_FIELD_1);
} else {
EMIT2(BC_PUSH_FIELD, idx);
}
}

void BytecodeGenerator::EmitPUSHBLOCK(MethodGenerationContext* mgenc, VMMethod* block) {
EMIT2(BC_PUSH_BLOCK, mgenc->FindLiteralIndex(block));
int8_t idx = mgenc->AddLiteralIfAbsent(block);
EMIT2(BC_PUSH_BLOCK, idx);
}

void BytecodeGenerator::EmitPUSHCONSTANT(MethodGenerationContext* mgenc,
vm_oop_t cst) {
EMIT2(BC_PUSH_CONSTANT, mgenc->FindLiteralIndex(cst));
void BytecodeGenerator::EmitPUSHCONSTANT(MethodGenerationContext* mgenc, vm_oop_t cst) {
if (CLASS_OF(cst) == load_ptr(integerClass)) {
if (INT_VAL(cst) == 0ll) {
EMIT1(BC_PUSH_0);
return;
}
if (INT_VAL(cst) == 1ll) {
EMIT1(BC_PUSH_1);
return;
}
}

if (cst == load_ptr(nilObject)) {
EMIT1(BC_PUSH_NIL);
return;
}

int8_t idx = mgenc->AddLiteralIfAbsent(cst);
if (idx == 0) {
EMIT1(BC_PUSH_CONSTANT_0);
return;
}
if (idx == 1) {
EMIT1(BC_PUSH_CONSTANT_1);
return;
}
if (idx == 2) {
EMIT1(BC_PUSH_CONSTANT_2);
return;
}

EMIT2(BC_PUSH_CONSTANT, idx);
}

void BytecodeGenerator::EmitPUSHCONSTANT(MethodGenerationContext* mgenc,
Expand All @@ -84,7 +159,16 @@ void BytecodeGenerator::EmitPUSHCONSTANTString(MethodGenerationContext* mgenc,
}

void BytecodeGenerator::EmitPUSHGLOBAL(MethodGenerationContext* mgenc, VMSymbol* global) {
EMIT2(BC_PUSH_GLOBAL, mgenc->FindLiteralIndex(global));
if (global == GetUniverse()->SymbolFor("nil")) {
EmitPUSHCONSTANT(mgenc, load_ptr(nilObject));
} else if (global == GetUniverse()->SymbolFor("true")) {
EmitPUSHCONSTANT(mgenc, load_ptr(trueObject));
} else if (global == GetUniverse()->SymbolFor("false")) {
EmitPUSHCONSTANT(mgenc, load_ptr(falseObject));
} else {
int8_t idx = mgenc->AddLiteralIfAbsent(global);
EMIT2(BC_PUSH_GLOBAL, idx);
}
}

void BytecodeGenerator::EmitPOP(MethodGenerationContext* mgenc) {
Expand All @@ -93,6 +177,25 @@ void BytecodeGenerator::EmitPOP(MethodGenerationContext* mgenc) {

void BytecodeGenerator::EmitPOPLOCAL(MethodGenerationContext* mgenc, long idx,
int ctx) {
assert(idx >= 0);
assert(ctx >= 0);
if (ctx == 0) {
if (idx == 0) {
EMIT1(BC_POP_LOCAL_0);
return;
}

if (idx == 1) {
EMIT1(BC_POP_LOCAL_1);
return;
}

if (idx == 2) {
EMIT1(BC_POP_LOCAL_2);
return;
}
}

EMIT3(BC_POP_LOCAL, idx, ctx);
}

Expand All @@ -102,15 +205,25 @@ void BytecodeGenerator::EmitPOPARGUMENT(MethodGenerationContext* mgenc,
}

void BytecodeGenerator::EmitPOPFIELD(MethodGenerationContext* mgenc, VMSymbol* field) {
EMIT2(BC_POP_FIELD, mgenc->GetFieldIndex(field));
uint8_t idx = mgenc->GetFieldIndex(field);

if (idx == 0) {
EMIT1(BC_POP_FIELD_0);
} else if (idx == 1) {
EMIT1(BC_POP_FIELD_1);
} else {
EMIT2(BC_POP_FIELD, idx);
}
}

void BytecodeGenerator::EmitSEND(MethodGenerationContext* mgenc, VMSymbol* msg) {
EMIT2(BC_SEND, mgenc->FindLiteralIndex(msg));
int8_t idx = mgenc->AddLiteralIfAbsent(msg);
EMIT2(BC_SEND, idx);
}

void BytecodeGenerator::EmitSUPERSEND(MethodGenerationContext* mgenc, VMSymbol* msg) {
EMIT2(BC_SUPER_SEND, mgenc->FindLiteralIndex(msg));
int8_t idx = mgenc->AddLiteralIfAbsent(msg);
EMIT2(BC_SUPER_SEND, idx);
}

void BytecodeGenerator::EmitRETURNLOCAL(MethodGenerationContext* mgenc) {
Expand Down
41 changes: 37 additions & 4 deletions src/compiler/Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, cons
}

switch(bytecode) {
case BC_PUSH_LOCAL_0:
DebugPrint("local: 0, context: 0\n"); break;
case BC_PUSH_LOCAL_1:
DebugPrint("local: 1, context: 0\n"); break;
case BC_PUSH_LOCAL_2:
DebugPrint("local: 2, context: 0\n"); break;
case BC_PUSH_LOCAL:
DebugPrint("local: %d, context: %d\n", bytecodes[bc_idx+1], bytecodes[bc_idx+2]); break;
case BC_PUSH_ARGUMENT:
Expand All @@ -178,10 +184,12 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, cons
size_t indent_size = strlen(indent)+1+1;
char* nindent = new char[indent_size];
DebugPrint("block: (index: %d) ", bytecodes[bc_idx+1]);
snprintf(nindent, indent_size, "%s\t", indent);


if (method != nullptr) {
snprintf(nindent, indent_size, "%s\t", indent);
Disassembler::DumpMethod(static_cast<VMMethod*>(method->GetConstant(bc_idx)), nindent);
} else {
DebugPrint("\n");
}
break;
}
Expand All @@ -195,7 +203,7 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes, cons
bytecodes[bc_idx+1], cname->GetStdString().c_str());
dispatch(constant);
} else {
DebugPrint("(index: %d)");
DebugPrint("(index: %d)", bytecodes[bc_idx+1]);
}
DebugPrint("\n");
break;
Expand Down Expand Up @@ -343,6 +351,31 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, long bc_idx) {
DebugPrint(">\n");
break;
}
case BC_PUSH_LOCAL_0:
case BC_PUSH_LOCAL_1:
case BC_PUSH_LOCAL_2: {
uint8_t bc1;
uint8_t bc2;
switch (bc) {
case BC_PUSH_LOCAL_0: bc1 = 0; bc2 = 0; break;
case BC_PUSH_LOCAL_1: bc1 = 1; bc2 = 0; break;
case BC_PUSH_LOCAL_2: bc1 = 2; bc2 = 0; break;
default:
DebugPrint("Unexpected bytecode");
return;
}

vm_oop_t o = frame->GetLocal(bc1, bc2);
VMClass* c = CLASS_OF(o);
VMSymbol* cname = c->GetName();

DebugPrint("local: %d, context: %d <(%s) ",
BC_1, BC_2, cname->GetStdString().c_str());
//dispatch
dispatch(o);
DebugPrint(">\n");
break;
}
case BC_PUSH_ARGUMENT: {
uint8_t bc1 = BC_1, bc2 = BC_2;
vm_oop_t o = frame->GetArgument(bc1, bc2);
Expand All @@ -362,7 +395,7 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, long bc_idx) {
}
case BC_PUSH_FIELD: {
VMFrame* ctxt = frame->GetOuterContext();
vm_oop_t arg = ctxt->GetArgument(0, 0);
vm_oop_t arg = ctxt->GetArgumentInCurrentContext(0);
uint8_t field_index = BC_1;

vm_oop_t o = ((VMObject*) arg)->GetField(field_index);
Expand Down
42 changes: 37 additions & 5 deletions src/compiler/MethodGenerationContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,22 +130,50 @@ uint8_t MethodGenerationContext::ComputeStackDepth() {
i++;
break;
case BC_DUP:
case BC_PUSH_LOCAL_0:
case BC_PUSH_LOCAL_1:
case BC_PUSH_LOCAL_2:
case BC_PUSH_SELF:
case BC_PUSH_ARG_1:
case BC_PUSH_ARG_2:
depth++;
i++;
i += 1;
break;
case BC_PUSH_LOCAL:
case BC_PUSH_ARGUMENT:
depth++;
i += 3;
break;
case BC_PUSH_FIELD_0:
case BC_PUSH_FIELD_1:
depth++;
i += 1;
break;
case BC_PUSH_FIELD:
case BC_PUSH_BLOCK:
case BC_PUSH_CONSTANT:
depth++;
i += 2;
break;
case BC_PUSH_CONSTANT_0:
case BC_PUSH_CONSTANT_1:
case BC_PUSH_CONSTANT_2:
case BC_PUSH_0:
case BC_PUSH_1:
case BC_PUSH_NIL:
depth++;
i += 1;
break;
case BC_PUSH_GLOBAL:
depth++;
i += 2;
break;
case BC_POP:
case BC_POP_LOCAL_0:
case BC_POP_LOCAL_1:
case BC_POP_LOCAL_2:
case BC_POP_FIELD_0:
case BC_POP_FIELD_1:
depth--;
i++;
break;
Expand Down Expand Up @@ -249,11 +277,15 @@ bool MethodGenerationContext::AddLocalIfAbsent(const StdString& local) {
return true;
}

bool MethodGenerationContext::AddLiteralIfAbsent(vm_oop_t lit) {
if (literals.IndexOf(lit) != -1) return false;
literals.PushBack(lit);
return true;
int8_t MethodGenerationContext::AddLiteralIfAbsent(vm_oop_t lit) {
int8_t idx = literals.IndexOf(lit);
if (idx == -1) {
literals.PushBack(lit);
idx = literals.Size() - 1;
}
return idx;
}

void MethodGenerationContext::SetFinished(bool finished) {
this->finished = finished;
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/MethodGenerationContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class MethodGenerationContext {
void UpdateLiteral(vm_oop_t oldValue, uint8_t index, vm_oop_t newValue);
bool AddArgumentIfAbsent(const StdString& arg);
bool AddLocalIfAbsent(const StdString& local);
bool AddLiteralIfAbsent(vm_oop_t lit);
int8_t AddLiteralIfAbsent(vm_oop_t lit);
void SetFinished(bool finished = true);

ClassGenerationContext* GetHolder();
Expand Down
Loading

0 comments on commit 540d972

Please sign in to comment.