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

Specialize calling of unary sends and reduce unnecessary updating of bytecode indexes #52

Merged
merged 5 commits into from
Aug 11, 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
2 changes: 1 addition & 1 deletion src/compiler/BytecodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ void EmitSEND(MethodGenerationContext& mgenc, VMSymbol* msg) {
const int numArgs = Signature::GetNumberOfArguments(msg);
const size_t stackEffect = -numArgs + 1; // +1 for the result

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

void EmitSUPERSEND(MethodGenerationContext& mgenc, VMSymbol* msg) {
Expand Down
44 changes: 40 additions & 4 deletions src/interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,8 @@ void Interpreter::send(VMSymbol* signature, VMClass* receiverClass) {
Universe::callStats[name].noPrimitiveCalls++;
}
#endif
// since an invokable is able to change/use the frame, we have to write
// cached values before, and read cached values after calling
GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal);

invokable->Invoke(GetFrame());
bytecodeIndexGlobal = GetFrame()->GetBytecodeIndex();
} else {
triggerDoesNotUnderstand(signature);
}
Expand Down Expand Up @@ -366,6 +363,45 @@ void Interpreter::doSend(long bytecodeIndex) {
send(signature, receiverClass);
}

void Interpreter::doUnarySend(long bytecodeIndex) {
VMSymbol* signature =
static_cast<VMSymbol*>(method->GetConstant(bytecodeIndex));

const int numOfArgs = 1;

vm_oop_t receiver = frame->GetStackElement(numOfArgs - 1);

assert(IsValidObject(receiver));
// make sure it is really a class
assert(dynamic_cast<VMClass*>(CLASS_OF(receiver)) != nullptr);

VMClass* receiverClass = CLASS_OF(receiver);

assert(IsValidObject(receiverClass));

#ifdef LOG_RECEIVER_TYPES
Universe::receiverTypes[receiverClass->GetName()->GetStdString()]++;
#endif

VMInvokable* invokable = receiverClass->LookupInvokable(signature);

if (invokable != nullptr) {
#ifdef LOG_RECEIVER_TYPES
std::string name = receiverClass->GetName()->GetStdString();
if (Universe::callStats.find(name) == Universe::callStats.end()) {
Universe::callStats[name] = {0, 0};
}
Universe::callStats[name].noCalls++;
if (invokable->IsPrimitive()) {
Universe::callStats[name].noPrimitiveCalls++;
}
#endif
invokable->Invoke1(GetFrame());
} else {
triggerDoesNotUnderstand(signature);
}
}

void Interpreter::doSuperSend(long bytecodeIndex) {
VMSymbol* signature =
static_cast<VMSymbol*>(method->GetConstant(bytecodeIndex));
Expand Down
3 changes: 3 additions & 0 deletions src/interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class Interpreter {

static void SendUnknownGlobal(VMSymbol* globalName);

static inline long GetBytecodeIndex() { return bytecodeIndexGlobal; }

private:
static vm_oop_t GetSelf();

Expand Down Expand Up @@ -105,6 +107,7 @@ class Interpreter {
static void doPopField(long bytecodeIndex);
static void doPopFieldWithIndex(uint8_t fieldIndex);
static void doSend(long bytecodeIndex);
static void doUnarySend(long bytecodeIndex);
static void doSuperSend(long bytecodeIndex);
static void doReturnLocal();
static void doReturnNonLocal();
Expand Down
6 changes: 6 additions & 0 deletions src/interpreter/InterpreterLoop.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ vm_oop_t Start() {
&&LABEL_BC_POP_FIELD_0,
&&LABEL_BC_POP_FIELD_1,
&&LABEL_BC_SEND,
&&LABEL_BC_SEND_1,
&&LABEL_BC_SUPER_SEND,
&&LABEL_BC_RETURN_LOCAL,
&&LABEL_BC_RETURN_NON_LOCAL,
Expand Down Expand Up @@ -253,6 +254,11 @@ vm_oop_t Start() {
doSend(bytecodeIndexGlobal - 2);
DISPATCH_GC();

LABEL_BC_SEND_1:
PROLOGUE(2);
doUnarySend(bytecodeIndexGlobal - 2);
DISPATCH_GC();

LABEL_BC_SUPER_SEND:
PROLOGUE(2);
doSuperSend(bytecodeIndexGlobal - 2);
Expand Down
52 changes: 27 additions & 25 deletions src/interpreter/bytecodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const uint8_t Bytecode::bytecodeLengths[] = {
1, // BC_POP_FIELD_0
1, // BC_POP_FIELD_1
2, // BC_SEND
2, // BC_SEND_1
2, // BC_SUPER_SEND
1, // BC_RETURN_LOCAL
1, // BC_RETURN_NON_LOCAL
Expand Down Expand Up @@ -126,31 +127,32 @@ const char* Bytecode::bytecodeNames[] = {
"POP_FIELD_0 ", // 30
"POP_FIELD_1 ", // 31
"SEND ", // 32
"SUPER_SEND ", // 33
"RETURN_LOCAL ", // 34
"RETURN_NON_LOCAL", // 35
"RETURN_SELF ", // 36
"RETURN_FIELD_0 ", // 37
"RETURN_FIELD_1 ", // 38
"RETURN_FIELD_2 ", // 39
"INC ", // 40
"DEC ", // 41
"INC_FIELD ", // 42
"INC_FIELD_PUSH ", // 43
"JUMP ", // 44
"JUMP_ON_FALSE_POP", // 45
"JUMP_ON_TRUE_POP", // 46
"JUMP_ON_FALSE_TOP_NIL", // 47
"JUMP_ON_TRUE_TOP_NIL", // 48
"JUMP_IF_GREATER ", // 49
"JUMP_BACKWARD ", // 50
"JUMP2 ", // 51
"JUMP2_ON_FALSE_POP", // 52
"JUMP2_ON_TRUE_POP", // 53
"JUMP2_ON_FALSE_TOP_NIL", // 54
"JUMP2_ON_TRUE_TOP_NIL", // 55
"JUMP2_IF_GREATER", // 56
"JUMP2_BACKWARD ", // 57
"SEND_1 ", // 33
"SUPER_SEND ", // 34
"RETURN_LOCAL ", // 35
"RETURN_NON_LOCAL", // 36
"RETURN_SELF ", // 37
"RETURN_FIELD_0 ", // 38
"RETURN_FIELD_1 ", // 39
"RETURN_FIELD_2 ", // 40
"INC ", // 41
"DEC ", // 42
"INC_FIELD ", // 43
"INC_FIELD_PUSH ", // 44
"JUMP ", // 45
"JUMP_ON_FALSE_POP", // 46
"JUMP_ON_TRUE_POP", // 47
"JUMP_ON_FALSE_TOP_NIL", // 48
"JUMP_ON_TRUE_TOP_NIL", // 49
"JUMP_IF_GREATER ", // 50
"JUMP_BACKWARD ", // 51
"JUMP2 ", // 52
"JUMP2_ON_FALSE_POP", // 53
"JUMP2_ON_TRUE_POP", // 54
"JUMP2_ON_FALSE_TOP_NIL", // 55
"JUMP2_ON_TRUE_TOP_NIL", // 56
"JUMP2_IF_GREATER", // 57
"JUMP2_BACKWARD ", // 58
};

bool IsJumpBytecode(uint8_t bc) {
Expand Down
52 changes: 26 additions & 26 deletions src/interpreter/bytecodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,31 +66,32 @@
#define BC_POP_FIELD_0 30
#define BC_POP_FIELD_1 31
#define BC_SEND 32
#define BC_SUPER_SEND 33
#define BC_RETURN_LOCAL 34
#define BC_RETURN_NON_LOCAL 35
#define BC_RETURN_SELF 36
#define BC_RETURN_FIELD_0 37
#define BC_RETURN_FIELD_1 38
#define BC_RETURN_FIELD_2 39
#define BC_INC 40
#define BC_DEC 41
#define BC_INC_FIELD 42
#define BC_INC_FIELD_PUSH 43
#define BC_JUMP 44
#define BC_JUMP_ON_FALSE_POP 45
#define BC_JUMP_ON_TRUE_POP 46
#define BC_JUMP_ON_FALSE_TOP_NIL 47
#define BC_JUMP_ON_TRUE_TOP_NIL 48
#define BC_JUMP_IF_GREATER 49
#define BC_JUMP_BACKWARD 50
#define BC_JUMP2 51
#define BC_JUMP2_ON_FALSE_POP 52
#define BC_JUMP2_ON_TRUE_POP 53
#define BC_JUMP2_ON_FALSE_TOP_NIL 54
#define BC_JUMP2_ON_TRUE_TOP_NIL 55
#define BC_JUMP2_IF_GREATER 56
#define BC_JUMP2_BACKWARD 57
#define BC_SEND_1 33
#define BC_SUPER_SEND 34
#define BC_RETURN_LOCAL 35
#define BC_RETURN_NON_LOCAL 36
#define BC_RETURN_SELF 37
#define BC_RETURN_FIELD_0 38
#define BC_RETURN_FIELD_1 39
#define BC_RETURN_FIELD_2 40
#define BC_INC 41
#define BC_DEC 42
#define BC_INC_FIELD 43
#define BC_INC_FIELD_PUSH 44
#define BC_JUMP 45
#define BC_JUMP_ON_FALSE_POP 46
#define BC_JUMP_ON_TRUE_POP 47
#define BC_JUMP_ON_FALSE_TOP_NIL 48
#define BC_JUMP_ON_TRUE_TOP_NIL 49
#define BC_JUMP_IF_GREATER 50
#define BC_JUMP_BACKWARD 51
#define BC_JUMP2 52
#define BC_JUMP2_ON_FALSE_POP 53
#define BC_JUMP2_ON_TRUE_POP 54
#define BC_JUMP2_ON_FALSE_TOP_NIL 55
#define BC_JUMP2_ON_TRUE_TOP_NIL 56
#define BC_JUMP2_IF_GREATER 57
#define BC_JUMP2_BACKWARD 58

#define _LAST_BYTECODE BC_JUMP2_BACKWARD

Expand All @@ -104,7 +105,6 @@
#define BC_SEND_N 250
#define BC_SEND_3 249
#define BC_SEND_2 248
#define BC_SEND_1 247
// clang-format on

// properties of the bytecodes
Expand Down
30 changes: 15 additions & 15 deletions src/unitTests/BytecodeGenerationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void BytecodeGenerationTest::testSendDupPopFieldReturnLocal() {
auto bytecodes = methodToBytecode("test = ( ^ field := self method )");

check(bytecodes,
{BC_PUSH_SELF, BC(BC_SEND, 0), BC_DUP, BC_POP_FIELD_0,
{BC_PUSH_SELF, BC(BC_SEND_1, 0), BC_DUP, BC_POP_FIELD_0,
BC_RETURN_LOCAL});
}

Expand All @@ -136,7 +136,7 @@ void BytecodeGenerationTest::testSendDupPopFieldReturnLocalPeriod() {
auto bytecodes = methodToBytecode("test = ( ^ field := self method. )");

check(bytecodes,
{BC_PUSH_SELF, BC(BC_SEND, 0), BC_DUP, BC_POP_FIELD_0,
{BC_PUSH_SELF, BC(BC_SEND_1, 0), BC_DUP, BC_POP_FIELD_0,
BC_RETURN_LOCAL});
}

Expand Down Expand Up @@ -377,7 +377,7 @@ void BytecodeGenerationTest::ifTrueWithLiteralReturn(std::string literal,
bytecode.bytecode == BC_PUSH_BLOCK;

check(bytecodes,
{BC_PUSH_SELF, BC(BC_SEND, 0),
{BC_PUSH_SELF, BC(BC_SEND_1, 0),
BC(BC_JUMP_ON_FALSE_TOP_NIL, twoByte2 ? 5 : 4, 0), bytecode, BC_POP,
BC_RETURN_SELF});

Expand Down Expand Up @@ -418,7 +418,7 @@ void BytecodeGenerationTest::ifTrueWithSomethingAndLiteralReturn(
bytecode.bytecode == BC_PUSH_BLOCK;

check(bytecodes,
{BC_PUSH_SELF, BC(BC_SEND, 0),
{BC_PUSH_SELF, BC(BC_SEND_1, 0),
BC(BC_JUMP_ON_FALSE_TOP_NIL, twoByte2 ? 7 : 6, 0),
BC_PUSH_CONSTANT_1, BC_POP, bytecode, BC_POP, BC_RETURN_SELF});

Expand All @@ -433,7 +433,7 @@ void BytecodeGenerationTest::testIfTrueIfFalseArg() {
) )""");

check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1),
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1),
BC(BC_JUMP_ON_FALSE_POP, 7, 0), BC_PUSH_ARG_1, BC(BC_JUMP, 4, 0),
BC_PUSH_ARG_2, BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_SELF});
}
Expand All @@ -446,7 +446,7 @@ void BytecodeGenerationTest::testIfTrueIfFalseNlrArg1() {
) )""");

check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1),
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1),
BC(BC_JUMP_ON_FALSE_POP, 8, 0), BC_PUSH_ARG_1, BC_RETURN_LOCAL,
BC(BC_JUMP, 4, 0), BC_PUSH_ARG_2, BC_POP, BC_PUSH_CONSTANT_2,
BC_RETURN_SELF});
Expand All @@ -460,7 +460,7 @@ void BytecodeGenerationTest::testIfTrueIfFalseNlrArg2() {
) )""");

check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1),
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1),
BC(BC_JUMP_ON_FALSE_POP, 7, 0), BC_PUSH_ARG_1, BC(BC_JUMP, 5, 0),
BC_PUSH_ARG_2, BC_RETURN_LOCAL, BC_POP, BC_PUSH_CONSTANT_2,
BC_RETURN_SELF});
Expand Down Expand Up @@ -552,7 +552,7 @@ void BytecodeGenerationTest::ifArg(std::string selector, int8_t jumpBytecode) {

auto bytecodes = methodToBytecode(source.data());
check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1),
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1),
BC(jumpBytecode, 4, 0), BC_PUSH_ARG_1, BC_POP, BC_PUSH_CONSTANT_2,
BC_RETURN_SELF});

Expand Down Expand Up @@ -588,7 +588,7 @@ void BytecodeGenerationTest::ifReturnNonLocal(std::string selector,

auto bytecodes = methodToBytecode(source.data());
check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1),
{BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND_1, 1),
BC(jumpBytecode, 5, 0), BC_PUSH_ARG_1, BC_RETURN_LOCAL, BC_POP,
BC_PUSH_CONSTANT_2, BC_RETURN_SELF});

Expand Down Expand Up @@ -813,7 +813,7 @@ void BytecodeGenerationTest::testBlockIfTrueArg() {

check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC(BC_PUSH_ARGUMENT, 0, 1),
BC(BC_SEND, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 4, 0), BC_PUSH_ARG_1,
BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 4, 0), BC_PUSH_ARG_1,
BC_POP, BC_PUSH_CONSTANT_2, BC_RETURN_LOCAL});
}

Expand All @@ -829,7 +829,7 @@ void BytecodeGenerationTest::testBlockIfTrueMethodArg() {
] )""");

check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC(BC_PUSH_ARGUMENT, 0, 1),
BC(BC_SEND, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 6, 0),
BC(BC_SEND_1, 1), BC(BC_JUMP_ON_FALSE_TOP_NIL, 6, 0),
BC(BC_PUSH_ARGUMENT, 1, 1), BC_POP, BC_PUSH_CONSTANT_2,
BC_RETURN_LOCAL});
}
Expand All @@ -844,9 +844,9 @@ void BytecodeGenerationTest::ifTrueIfFalseReturn(std::string sel1,
sel1 + " [ ^ arg1 ] " + sel2 + " [ arg2 ] )";
auto bytecodes = methodToBytecode(source.data());

check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF, BC(BC_SEND, 1),
bc, BC_PUSH_ARG_1, BC_RETURN_LOCAL, BC(BC_JUMP, 4, 0),
BC_PUSH_ARG_2, BC_RETURN_LOCAL});
check(bytecodes, {BC_PUSH_CONSTANT_0, BC_POP, BC_PUSH_SELF,
BC(BC_SEND_1, 1), bc, BC_PUSH_ARG_1, BC_RETURN_LOCAL,
BC(BC_JUMP, 4, 0), BC_PUSH_ARG_2, BC_RETURN_LOCAL});
tearDown();
}

Expand All @@ -867,7 +867,7 @@ void BytecodeGenerationTest::blockIfReturnNonLocal(std::string sel, BC bc) {
auto bytecodes = blockToBytecode(source.data());
check(bytecodes,
{BC_PUSH_CONSTANT_0, BC_POP, BC(BC_PUSH_ARGUMENT, 0, 1),
BC(BC_SEND, 1), bc, BC_PUSH_ARG_1, BC_RETURN_NON_LOCAL, BC_POP,
BC(BC_SEND_1, 1), bc, BC_PUSH_ARG_1, BC_RETURN_NON_LOCAL, BC_POP,
BC_PUSH_CONSTANT_2, BC_RETURN_LOCAL});

tearDown();
Expand Down
5 changes: 5 additions & 0 deletions src/vm/IsValidObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ bool IsSetter(vm_oop_t obj) {
return get_vtable(AS_OBJ(obj)) == vt_setter;
}

bool IsSafeUnaryPrim(vm_oop_t obj) {
assert(vt_safe_un_primitive != nullptr);
return get_vtable(AS_OBJ(obj)) == vt_safe_un_primitive;
}

void obtain_vtables_of_known_classes(VMSymbol* someValidSymbol) {
// These objects are allocated on the heap. So, they will get GC'ed soon
// enough.
Expand Down
1 change: 1 addition & 0 deletions src/vm/IsValidObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ bool IsLiteralReturn(vm_oop_t obj);
bool IsGlobalReturn(vm_oop_t obj);
bool IsGetter(vm_oop_t obj);
bool IsSetter(vm_oop_t obj);
bool IsSafeUnaryPrim(vm_oop_t obj);

void set_vt_to_null();

Expand Down
Loading