diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 00000000..c6c20ac8 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,6 @@ +find_package(benchmark REQUIRED) + +add_executable(objc_msgSend objc_msgSend.cpp TestClass.m) + +target_compile_options(objc_msgSend PRIVATE "-fobjc-runtime=gnustep-2.0") +target_link_libraries(objc_msgSend benchmark::benchmark objc) diff --git a/benchmarks/TestClass.m b/benchmarks/TestClass.m new file mode 100644 index 00000000..d3d85a28 --- /dev/null +++ b/benchmarks/TestClass.m @@ -0,0 +1,10 @@ +@interface TestClass +- (int)answer; +@end + +@implementation TestClass +- (int)answer +{ + return 42; +} +@end diff --git a/benchmarks/objc_msgSend.cpp b/benchmarks/objc_msgSend.cpp new file mode 100644 index 00000000..5f073168 --- /dev/null +++ b/benchmarks/objc_msgSend.cpp @@ -0,0 +1,23 @@ +#include +#include "../objc/runtime.h" +#include + +static id testClass; +static SEL answerSel; + +static void objc_msgSendSetup(const benchmark::State& state) { + testClass = objc_getClass("TestClass"); + answerSel = sel_registerName("answer"); +} + +static void objc_msgSend(benchmark::State& state) { + for (auto _ : state) + { + id a = objc_msgSend(testClass, answerSel); + assert((uintptr_t)a == 42); + } + } + // Register the function as a benchmark + BENCHMARK(objc_msgSend)->Setup(objc_msgSendSetup)->Repetitions(25); + + BENCHMARK_MAIN(); diff --git a/objc_msgSend.x86-64.S b/objc_msgSend.x86-64.S index 10ecd163..067016a0 100644 --- a/objc_msgSend.x86-64.S +++ b/objc_msgSend.x86-64.S @@ -35,6 +35,8 @@ mov (\receiver), %r10 # Load the dtable from the class 1: # classLoaded mov DTABLE_OFFSET(%r10), %r10 # Load the dtable from the class into r10 + test %r10, %r10 # If the dtable is nil + jz 4f # return nil mov %rax, -8(%rsp) # %rax contains information for variadic calls mov %rbx, -16(%rsp) # On the fast path, spill into the red zone mov (\sel), %eax # Load the selector index into %eax