Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement DEC, INC_FIELD, INC_FIELD_PUSH #50

Merged
merged 4 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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