Skip to content

Commit

Permalink
Specialize calling of unary sends and reduce unnecessary updating of …
Browse files Browse the repository at this point in the history
…bytecode indexes (#52)
  • Loading branch information
smarr authored Aug 11, 2024
2 parents 39b2f00 + 0d94d1a commit 11d1094
Show file tree
Hide file tree
Showing 20 changed files with 244 additions and 83 deletions.
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

0 comments on commit 11d1094

Please sign in to comment.