Skip to content

Commit

Permalink
Implement DEC, INC_FIELD, INC_FIELD_PUSH (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
smarr authored Aug 10, 2024
2 parents ed7f335 + a031337 commit 64613d1
Show file tree
Hide file tree
Showing 19 changed files with 534 additions and 260 deletions.
27 changes: 16 additions & 11 deletions src/compiler/BytecodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,11 @@ void EmitPOPARGUMENT(MethodGenerationContext& mgenc, long idx, int ctx) {
void EmitPOPFIELD(MethodGenerationContext& mgenc, VMSymbol* field) {
const uint8_t idx = mgenc.GetFieldIndex(field);

if (idx == 0) {
Emit1(mgenc, BC_POP_FIELD_0, -1);
} else if (idx == 1) {
Emit1(mgenc, BC_POP_FIELD_1, -1);
} else {
Emit2(mgenc, BC_POP_FIELD, idx, -1);
if (mgenc.OptimizeIncField(idx)) {
return;
}

EmitPopFieldWithIndex(mgenc, idx);
}

void EmitSEND(MethodGenerationContext& mgenc, VMSymbol* msg) {
Expand Down Expand Up @@ -286,6 +284,14 @@ void EmitINC(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_INC, 0);
}

void EmitDEC(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_DEC, 0);
}

void EmitIncFieldPush(MethodGenerationContext& mgenc, uint8_t fieldIdx) {
Emit2(mgenc, BC_INC_FIELD_PUSH, fieldIdx, 1);
}

void EmitDupSecond(MethodGenerationContext& mgenc) {
Emit1(mgenc, BC_DUP_SECOND, 1);
}
Expand Down Expand Up @@ -359,19 +365,18 @@ void EmitPushFieldWithIndex(MethodGenerationContext& mgenc, uint8_t fieldIdx) {
Emit2(mgenc, BC_PUSH_FIELD, fieldIdx, 1);
}

void EmitPopFieldWithIndex(MethodGenerationContext& mgenc, uint8_t fieldIdx,
uint8_t ctxLevel) {
void EmitPopFieldWithIndex(MethodGenerationContext& mgenc, uint8_t fieldIdx) {
// if (ctxLevel == 0) {
if (fieldIdx == 0) {
Emit1(mgenc, BC_POP_FIELD_0, 1);
Emit1(mgenc, BC_POP_FIELD_0, -1);
return;
}

if (fieldIdx == 1) {
Emit1(mgenc, BC_POP_FIELD_1, 1);
Emit1(mgenc, BC_POP_FIELD_1, -1);
return;
}
// }

Emit2(mgenc, BC_POP_FIELD, fieldIdx, 1);
Emit2(mgenc, BC_POP_FIELD, fieldIdx, -1);
}
6 changes: 4 additions & 2 deletions src/compiler/BytecodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ void EmitRETURNNONLOCAL(MethodGenerationContext& mgenc);
void EmitRETURNFIELD(MethodGenerationContext& mgenc, size_t index);

void EmitINC(MethodGenerationContext& mgenc);
void EmitDEC(MethodGenerationContext& mgenc);
void EmitIncFieldPush(MethodGenerationContext& mgenc, uint8_t fieldIdx);

void EmitDupSecond(MethodGenerationContext& mgenc);

size_t EmitJumpOnBoolWithDummyOffset(MethodGenerationContext& mgenc,
Expand All @@ -73,5 +76,4 @@ size_t Emit3WithDummy(MethodGenerationContext& mgenc, uint8_t bytecode,
size_t stackEffect);

void EmitPushFieldWithIndex(MethodGenerationContext& mgenc, uint8_t fieldIdx);
void EmitPopFieldWithIndex(MethodGenerationContext& mgenc, uint8_t fieldIdx,
uint8_t ctxLevel);
void EmitPopFieldWithIndex(MethodGenerationContext& mgenc, uint8_t fieldIdx);
66 changes: 21 additions & 45 deletions src/compiler/Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,28 +176,7 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
bytecodes[bc_idx + 2]);
break;
}
case BC_PUSH_FIELD: {
long fieldIdx = bytecodes[bc_idx + 1];
if (method != nullptr && printObjects) {
VMClass* holder =
dynamic_cast<VMClass*>((VMObject*)method->GetHolder());
if (holder) {
VMSymbol* name = holder->GetInstanceFieldName(fieldIdx);
if (name != nullptr) {
DebugPrint("(index: %d) field: %s\n",
bytecodes[bc_idx + 1],
name->GetStdString().c_str());
} else {
DebugPrint("(index: %d) field: !nullptr!: error!\n",
bytecodes[bc_idx + 1]);
}
break;
}
}

DebugPrint("(index: %d)\n", bytecodes[bc_idx + 1]);
break;
}
case BC_PUSH_BLOCK: {
size_t indent_size = strlen(indent) + 1 + 1;
char* nindent = new char[indent_size];
Expand Down Expand Up @@ -258,15 +237,23 @@ void Disassembler::dumpMethod(uint8_t* bytecodes, size_t numberOfBytecodes,
DebugPrint("argument: %d, context: %d\n", bytecodes[bc_idx + 1],
bytecodes[bc_idx + 2]);
break;
case BC_POP_FIELD: {
case BC_INC_FIELD:
case BC_INC_FIELD_PUSH:
case BC_POP_FIELD:
case BC_PUSH_FIELD: {
long fieldIdx = bytecodes[bc_idx + 1];
if (method != nullptr && printObjects) {
VMClass* holder =
dynamic_cast<VMClass*>((VMObject*)method->GetHolder());
if (holder) {
VMSymbol* name = holder->GetInstanceFieldName(fieldIdx);
DebugPrint("(index: %d) field: %s\n", fieldIdx,
name->GetStdString().c_str());
if (name != nullptr) {
DebugPrint("(index: %d) field: %s\n", fieldIdx,
name->GetStdString().c_str());
} else {
DebugPrint("(index: %d) field: !nullptr!: error!\n",
fieldIdx);
}
} else {
DebugPrint(
"(index: %d) block holder is not a class!!\n",
Expand Down Expand Up @@ -450,24 +437,6 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, long bc_idx) {
DebugPrint("\n");
break;
}
case BC_PUSH_FIELD: {
VMFrame* ctxt = frame->GetOuterContext();
vm_oop_t arg = ctxt->GetArgumentInCurrentContext(0);
uint8_t field_index = BC_1;

vm_oop_t o = ((VMObject*)arg)->GetField(field_index);
VMClass* c = CLASS_OF(o);
VMSymbol* cname = c->GetName();
long fieldIdx = BC_1;
VMSymbol* name =
method->GetHolder()->GetInstanceFieldName(fieldIdx);
DebugPrint("(index: %d) field: %s <(%s) ", BC_1,
name->GetStdString().c_str(),
cname->GetStdString().c_str());
dispatch(o);
DebugPrint(">\n");
break;
}
case BC_PUSH_BLOCK: {
DebugPrint("block: (index: %d) ", BC_1);
VMMethod* meth = dynamic_cast<VMMethod*>(
Expand Down Expand Up @@ -540,14 +509,21 @@ void Disassembler::DumpBytecode(VMFrame* frame, VMMethod* method, long bc_idx) {
DebugPrint(">\n");
break;
}
case BC_INC_FIELD:
case BC_INC_FIELD_PUSH:
case BC_PUSH_FIELD:
case BC_POP_FIELD: {
vm_oop_t o = frame->GetStackElement(0);
VMFrame* ctxt = frame->GetOuterContext();
vm_oop_t arg = ctxt->GetArgumentInCurrentContext(0);
uint8_t fieldIndex = BC_1;

vm_oop_t o = ((VMObject*)arg)->GetField(fieldIndex);
VMClass* c = CLASS_OF(o);
VMSymbol* cname = c->GetName();
long fieldIdx = BC_1;
VMSymbol* name =
method->GetHolder()->GetInstanceFieldName(fieldIdx);
VMSymbol* cname = c->GetName();
DebugPrint("(index: %d) field: %s <(%s) ", fieldIdx,
DebugPrint("(index: %d) field: %s <(%s) ", BC_1,
name->GetStdString().c_str(),
cname->GetStdString().c_str());
dispatch(o);
Expand Down
85 changes: 81 additions & 4 deletions src/compiler/MethodGenerationContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ void MethodGenerationContext::RemoveLastPopForBlockLocalReturn() {
return;
}

if (lastBytecodeIsOneOf(0, IsPopSmthBytecode) &&
if (lastBytecodeIsOneOf(0, IsPopSmthBytecode) != BC_INVALID &&
!LastBytecodeIs(1, BC_DUP)) {
// we just removed the DUP and didn't emit the POP using
// optimizeDupPopPopSequence() so, to make blocks work, we need to
Expand All @@ -864,14 +864,17 @@ void MethodGenerationContext::RemoveLastPopForBlockLocalReturn() {
// need to push it.
last4Bytecodes[3] = BC_INC_FIELD_PUSH;

size_t bcOffset = bytecode.size() - 3;
size_t bcOffset = bytecode.size() - 2;

// since the bytecodes have the same length, we can just switch the
// opcode
assert(Bytecode::GetBytecodeLength(BC_INC_FIELD_PUSH) == 3);
assert(Bytecode::GetBytecodeLength(BC_INC_FIELD) == 3);
assert(Bytecode::GetBytecodeLength(BC_INC_FIELD_PUSH) == 2);
assert(Bytecode::GetBytecodeLength(BC_INC_FIELD) == 2);
assert(bytecode[bcOffset] == BC_INC_FIELD);
bytecode[bcOffset] = BC_INC_FIELD_PUSH;

currentStackDepth += 1;
maxStackDepth = max(maxStackDepth, currentStackDepth);
}
}

Expand Down Expand Up @@ -907,6 +910,80 @@ bool MethodGenerationContext::OptimizeDupPopPopSequence() {
return true;
}

bool MethodGenerationContext::optimizeIncFieldPush() {
assert(Bytecode::GetBytecodeLength(BC_INC_FIELD_PUSH) == 2);

size_t bcIdx = bytecode.size() - 2;
assert(bytecode.at(bcIdx) == BC_INC_FIELD_PUSH);

bytecode[bcIdx] = BC_INC_FIELD;
last4Bytecodes[3] = BC_INC_FIELD;

return true;
}

/**
* Try using a INC_FIELD bytecode instead of the following sequence.
*
* PUSH_FIELD
* INC
* DUP
* POP_FIELD
*
* return true, if it optimized it.
*/
bool MethodGenerationContext::OptimizeIncField(uint8_t fieldIdx) {
if (isCurrentlyInliningABlock) {
return false;
}

if (!LastBytecodeIs(0, BC_DUP)) {
return false;
}

if (!LastBytecodeIs(1, BC_INC)) {
return false;
}

uint8_t pushCandidate = lastBytecodeIsOneOf(2, IsPushFieldBytecode);
if (pushCandidate == BC_INVALID) {
return false;
}

assert(Bytecode::GetBytecodeLength(BC_DUP) == 1);
assert(Bytecode::GetBytecodeLength(BC_INC) == 1);

size_t bcOffset = 1 + 1 + Bytecode::GetBytecodeLength(pushCandidate);
uint8_t candidateFieldIdx = 0;

switch (pushCandidate) {
case BC_PUSH_FIELD_0:
candidateFieldIdx = 0;
break;
case BC_PUSH_FIELD_1:
candidateFieldIdx = 1;
break;
case BC_PUSH_FIELD: {
assert(bytecode.at(bytecode.size() - bcOffset) == pushCandidate);
candidateFieldIdx = bytecode.at((bytecode.size() - bcOffset) + 1);
break;
}

default:
ErrorExit("Unexpected bytecode");
break;
}

if (candidateFieldIdx == fieldIdx) {
removeLastBytecodes(3);
resetLastBytecodeBuffer();
EmitIncFieldPush(*this, fieldIdx);
return true;
}

return false;
}

bool MethodGenerationContext::OptimizeReturnField() {
if (isCurrentlyInliningABlock) {
return false;
Expand Down
6 changes: 2 additions & 4 deletions src/compiler/MethodGenerationContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class MethodGenerationContext {
void PatchJumpOffsetToPointToNextInstruction(size_t indexOfOffset);

bool OptimizeDupPopPopSequence();
bool OptimizeIncField(uint8_t fieldIdx);
bool OptimizeReturnField();

bool LastBytecodeIs(size_t indexFromEnd, uint8_t bytecode);
Expand All @@ -127,10 +128,7 @@ class MethodGenerationContext {
VMTrivialMethod* assembleFieldSetter();
VMTrivialMethod* assembleFieldGetterFromReturn(uint8_t returnCandidate);

bool optimizeIncFieldPush() {
// TODO: implement
return false;
}
bool optimizeIncFieldPush();

void removeLastBytecodes(size_t numBytecodes);
void removeLastBytecodeAt(size_t indexFromEnd);
Expand Down
31 changes: 31 additions & 0 deletions src/compiler/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,10 +604,41 @@ void Parser::unaryMessage(MethodGenerationContext& mgenc, bool super) {
}
}

bool Parser::tryIncOrDecBytecodes(VMSymbol* msg, bool isSuperSend,
MethodGenerationContext& mgenc) {
if (isSuperSend) {
return false;
}

bool isPlus = msg == load_ptr(symbolPlus);
bool isMinus = msg == load_ptr(symbolMinus);

if (!isPlus && !isMinus) {
return false;
}

if (sym != Integer || text != "1") {
return false;
}

expect(Integer);
if (isPlus) {
EmitINC(mgenc);
} else {
assert(isMinus);
EmitDEC(mgenc);
}
return true;
}

void Parser::binaryMessage(MethodGenerationContext& mgenc, bool super) {
std::string msgSelector(text);
VMSymbol* msg = binarySelector();

if (tryIncOrDecBytecodes(msg, super, mgenc)) {
return;
}

binaryOperand(mgenc);

if (!super && ((msgSelector == "||" && mgenc.InlineAndOr(true)) ||
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class Parser {
std::string variable();
void messages(MethodGenerationContext& mgenc, bool super);
void unaryMessage(MethodGenerationContext& mgenc, bool super);

bool tryIncOrDecBytecodes(VMSymbol* msg, bool isSuperSend,
MethodGenerationContext& mgenc);
void binaryMessage(MethodGenerationContext& mgenc, bool super);
bool binaryOperand(MethodGenerationContext& mgenc);
void keywordMessage(MethodGenerationContext& mgenc, bool super);
Expand Down
Loading

0 comments on commit 64613d1

Please sign in to comment.