Created
May 5, 2015 05:44
-
-
Save avshabanov/078859e818ec32e6b552 to your computer and use it in GitHub Desktop.
InvokeInterface: Java vs C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc invoke_interface.c -std=c99 -O2 -o /tmp/iin | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/time.h> | |
/* Common */ | |
struct ClassMeta { | |
void ** itbls; | |
int itblsCount; | |
int size; | |
}; | |
struct Object { | |
struct ClassMeta * _class; | |
}; | |
struct InterfaceVtbl { | |
int _interfaceId; | |
}; | |
/* Modify interface definition */ | |
#define MODIFY_INTERFACE_ID (1000234234) | |
struct ModifyVtbl { | |
int _interfaceId; | |
// methods | |
int (* apply)(void * self, int value); | |
}; | |
/* AddOne */ | |
struct AddOne { | |
struct ClassMeta * _class; | |
}; | |
static int AddOne_apply(void * self, int value) { | |
return value + 1; | |
} | |
static struct ModifyVtbl g_AddOne_ModifyVtbl = { | |
MODIFY_INTERFACE_ID, | |
&AddOne_apply | |
}; | |
static void* g_AddOne_itbls[] = { | |
&g_AddOne_ModifyVtbl | |
}; | |
static struct ClassMeta g_AddOne_ClassMeta = { | |
.size = sizeof(struct AddOne), | |
.itbls = g_AddOne_itbls, | |
.itblsCount = 1 | |
}; | |
/* DecOne */ | |
struct DecOne { | |
struct ClassMeta * _class; | |
}; | |
static int DecOne_apply(void * self, int value) { | |
return value - 1; | |
} | |
static struct ModifyVtbl g_DecOne_ModifyVtbl = { | |
MODIFY_INTERFACE_ID, | |
&DecOne_apply | |
}; | |
static void* g_DecOne_itbls[] = { | |
&g_DecOne_ModifyVtbl | |
}; | |
static struct ClassMeta g_DecOne_ClassMeta = { | |
.size = sizeof(struct DecOne), | |
.itbls = g_DecOne_itbls, | |
.itblsCount = 1 | |
}; | |
/* MulTwo */ | |
struct MulTwo { | |
struct ClassMeta * _class; | |
}; | |
static int MulTwo_apply(void * self, int value) { | |
return value * 2; | |
} | |
static struct ModifyVtbl g_MulTwo_ModifyVtbl = { | |
MODIFY_INTERFACE_ID, | |
&MulTwo_apply | |
}; | |
static void* g_MulTwo_itbls[] = { | |
&g_MulTwo_ModifyVtbl | |
}; | |
static struct ClassMeta g_MulTwo_ClassMeta = { | |
.size = sizeof(struct MulTwo), | |
.itbls = g_MulTwo_itbls, | |
.itblsCount = 1 | |
}; | |
/* MulInc */ | |
struct MulInc { | |
struct ClassMeta * _class; | |
int a; | |
int b; | |
}; | |
static int MulInc_apply(void * self, int value) { | |
struct MulInc * $this = self; | |
return value * $this->a + $this->b; | |
} | |
static struct ModifyVtbl g_MulInc_ModifyVtbl = { | |
MODIFY_INTERFACE_ID, | |
&MulInc_apply | |
}; | |
static void* g_MulInc_itbls[] = { | |
&g_MulInc_ModifyVtbl | |
}; | |
static struct ClassMeta g_MulInc_ClassMeta = { | |
.size = sizeof(struct MulInc), | |
.itbls = g_MulInc_itbls, | |
.itblsCount = 1 | |
}; | |
/* Helpers */ | |
static struct InterfaceVtbl * | |
jb2c_rt_find_interface_unopt(int interfaceId, void ** itbls, int count) { | |
int i; | |
for (i = 1; i < count; ++i) { | |
struct InterfaceVtbl * iv = itbls[i]; | |
if (iv->_interfaceId == interfaceId) { | |
return iv; | |
} | |
} | |
fprintf(stderr, "Unable to find interface %d", interfaceId); | |
abort(); | |
return NULL; | |
} | |
static inline struct InterfaceVtbl * | |
jb2c_rt_find_interface(struct Object * o, int interfaceId) { | |
void ** itbls = o->_class->itbls; | |
int count = o->_class->itblsCount; | |
struct InterfaceVtbl * iv = itbls[0]; // we should have at least one interface here due to compile check | |
// optimized version: if first element is a vtbl - return it at once | |
if (iv->_interfaceId == interfaceId) { | |
return iv; | |
} | |
return jb2c_rt_find_interface_unopt(interfaceId, itbls, count); | |
} | |
/* tests */ | |
static void demo_add_one() { | |
struct AddOne addOne; | |
addOne._class = &g_AddOne_ClassMeta; | |
// helper | |
struct ModifyVtbl * $i1 = ((struct ModifyVtbl *) jb2c_rt_find_interface((struct Object *) &addOne, MODIFY_INTERFACE_ID)); | |
int result = $i1->apply(&addOne, 1000); | |
fprintf(stdout, "result=%d\n\n", result); | |
} | |
static struct Object ** mod_create(int count) { | |
char * mem = malloc(sizeof(struct MulInc) * count); | |
char * p = mem; | |
struct Object ** arr = malloc(sizeof(struct Object *) * count); | |
for (int i = 0; i < count; ++i, p += sizeof(struct MulInc)) { | |
if (i < 3) { | |
struct MulInc * r = (struct MulInc *) p; // new MulInc(i + 1, i) | |
r->_class = &g_MulInc_ClassMeta; | |
r->a = i + 1; // ctor | |
r->b = i; // ctor | |
arr[i] = (struct Object *) r; | |
continue; | |
} | |
if (i % 2 == 1) { | |
struct DecOne * r = (struct DecOne *) p; // new DecOne() | |
r->_class = &g_DecOne_ClassMeta; | |
arr[i] = (struct Object *) r; | |
continue; | |
} | |
if (i % 7 == 1) { | |
struct MulTwo * r = (struct MulTwo *) p; // new MulTwo() | |
r->_class = &g_MulTwo_ClassMeta; | |
arr[i] = (struct Object *) r; | |
continue; | |
} | |
{ | |
struct AddOne * r = (struct AddOne *) p; // new AddOne() | |
r->_class = &g_AddOne_ClassMeta; | |
arr[i] = (struct Object *) r; | |
continue; | |
} | |
} | |
return arr; | |
} | |
int main(int argc, char ** argv) { | |
int count = 10; | |
int n; | |
int i; | |
int j; | |
struct timeval start; | |
struct timeval stop; | |
if (argc == 3) { | |
demo_add_one(); | |
return 1; | |
} | |
if (argc > 1) { | |
count = atoi(argv[1]); | |
} | |
struct Object ** mods = mod_create(count); | |
fprintf(stdout, "created, count=%d\n", count); | |
for (j = 0; j < 10; ++j) { | |
n = 1; | |
gettimeofday(&start, NULL); | |
for (i = 0; i < count; ++i) { | |
struct Object * o = mods[i]; | |
struct ModifyVtbl * $i1 = ((struct ModifyVtbl *) jb2c_rt_find_interface(o, MODIFY_INTERFACE_ID)); | |
n = $i1->apply(o, n); | |
//fprintf(stdout, " [tmp] n=%d\n", n); | |
} | |
gettimeofday(&stop, NULL); | |
/* print the elapsed time */ | |
long long diff = (stop.tv_usec - start.tv_usec) / 1000L; | |
fprintf(stdout, "Time=%lld ms, n = %d\n", diff, n); | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author Alexander Shabanov | |
*/ | |
public class InvokeInterfaceCost { | |
public interface Modify { | |
int apply(int value); | |
} | |
public static final class DecOne implements Modify { | |
@Override | |
public int apply(int value) { | |
return value - 1; | |
} | |
} | |
public static final class AddOne implements Modify { | |
@Override | |
public int apply(int value) { | |
return value + 1; | |
} | |
} | |
public static final class MulTwo implements Modify { | |
@Override | |
public int apply(int value) { | |
return value * 2; | |
} | |
} | |
public static final class MulInc implements Modify { | |
private final int a; | |
private final int b; | |
public MulInc(int a, int b) { | |
this.a = a; | |
this.b = b; | |
} | |
@Override | |
public int apply(int value) { | |
return value * a + b; | |
} | |
} | |
public static void main(String[] args) { | |
int count = 10; | |
if (args.length > 0) { | |
count = Integer.parseInt(args[0]); | |
} | |
System.out.println("count=" + count); | |
Modify[] m = create(count); | |
for (int i = 0; i < 10; ++i) { | |
System.out.println("Run #" + i); | |
final long start = System.currentTimeMillis(); | |
int n = 1; | |
for (int j = 0; j < count; ++j) { | |
n = m[j].apply(n); | |
//System.out.println(" [tmp] n = " + n); | |
} | |
final long delta = System.currentTimeMillis() - start; | |
System.out.println(" Time=" + delta + "ms, n=" + n); | |
} | |
} | |
private static Modify[] create(int count) { | |
final Modify[] arr = new Modify[count]; | |
for (int i = 0; i < count; ++i) { | |
if (i < 3) { | |
arr[i] = new MulInc(i + 1, i); | |
continue; | |
} | |
if (i % 2 == 1) { | |
arr[i] = new DecOne(); | |
continue; | |
} | |
if (i % 7 == 1) { | |
arr[i] = new MulTwo(); | |
continue; | |
} | |
arr[i] = new AddOne(); | |
} | |
return arr; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment