Invoking a method on a object in Java
Polymorphic dispatch
xxxxxxxxxx191class A {2 void ping() {...}3 void pong() {...}4}5class B extends A {6 void ping() {...}7 void pong() {...}8 void wiff() {...}9}1011static void foo(A a) {12 a.ping();13 a.pong();14}1516static void bar() {17 foo(new A());18 foo(new B());19}Method address is determined dynamically
Class Jump table
Function pointer
A variable that stores a pointer to a procedure
Declared:
<return-type> (*<var-name>)(<argument-list>);
Dynamic call uses same format as regular function call:
<var-name> (<arguments>);
Example:
Use a struct to store jump table:
Class jump table declaration:
xxxxxxxxxx41struct A_class {2 void (*ping) (void *);3 void (*pong) (void *);4};Instance methods:
xxxxxxxxxx21void A_ping (void *this) {...}2void A_pong (void *this) {...}Static class object:
struct A_class A_class_obj = {A_ping, A_pong};
Object (instance of class)
xxxxxxxxxx31struct A {2 struct A_class *class;3} xxxxxxxxxx51struct A *new_A() {2 struct A *obj = malloc(sizeof(struct A));3 obj->class = &A_class_obj;4 return obj;5}Object use:
struct A *a = new_A();
a->class->ping(a);
a->class->pong(a);
Extending a Class
xxxxxxxxxx51struct B_class {2 void (*ping) (void *);3 void (*pong) (void *); // or struct A_class super_class;4 void (*wiff) (void *);5} xxxxxxxxxx31void B_ping (void *this) {...}2void B_wiff (void *this) {...}3struct B_class B_class_obj = {B_ping, A_pong, B_wiff} xxxxxxxxxx81void foo (struct A* a) {2 a->class->ping(a);3 a->class->pong(a);4}5void bar () {6 foo (new_A());7 foo ((struct A *) new_B());8}a->class->ping(a);
a->class in r[1])pc <- m[r[1] + 4]
Currently we support
We can convert the above to:
xxxxxxxxxx21r[2] <- m[r[1] + 4] # ld 4(r1), r22pc <- r[2] # j(r2)
Can we join both instructions in one?
Double-indirect jump: jump to address stored in memory
xxxxxxxxxx121ld (r5), r0 # r0 = a2ld (r0), r1 # r1 = a->class3deca r5 # allocate argument frame4st r0, (r5) # store a as 1st argument in stack5gpc $2, r6 # save return address6j *0(r1) # a->class->ping(a)7inca r5 # free argument frame8deca r5 # allocate argument frame9st r0, (r5) # store a as 1st argument in stack10gpc $2, r6 # save return address11j *4(r1) # a->class->pong(a)12inca r5 # free argument frame xxxxxxxxxx121struct node {2 int key;3 int value;4 struct node *next;5};6// ..7void print_list(struct node *list){8 while(list) {9 printf("%d: %d\n", list->key, list->value);10 list = list->next;11 }12}The function print_list is very specific:
Solution: function pointer
print_list: what to do with each key-value pair. xxxxxxxxxx131void follow_list(struct node *list,2 void (*fn)(int, int)) {3 while(list) {4 fn(list->key, list->value);5 list = list->next;6 }7}89void print_element(int key, int value) {10 printf("%10d: %10d\n", list->key, list->value)11}12// Print all elements in the list13follow_list(list, print_element);map receives a function and two lists, applies function to pairs of elements
(map + (list 1 4 3) (list 7 2 5) => (list 8 6 8))
(map (lambda (a b) (+ a b)) (list 1 4 3) (list 7 2 5))(map max (list 1 4 3) (list 7 2 5)) => (list 7 4 5)
Other iterators:
(foldl + 0 (list 1 2 3))(filter (lambda (a) (> a 3)) (list 1 2 3 4 5))Other languages also include "lambda" calculation
xxxxxxxxxx121void map(int (*fn)(int, int), int n, int *s0, int *s1, int *d) {2 int i;3 for (i = 0; i < n; i++) {4 d[i] = fn(s0[i], s1[i])5 }6}78int add(int a, int b) {9 return a+b;10}11// ...12map(add, 3, a, b, c); xxxxxxxxxx131int foldl(int (*fn)(int, int), int v, int *a, int n) {2 int i;3 for (i = 0; i < n; i++) {4 v = fn(v, a[i])5 }6 return v;7}89int add(int a, int b) {10 return a+b;11}12// ...13printf("%d\n", foldl(add, 0, a, 3));Semantics the same as simplified nested if statements
Assembly implementation: sequence of branches?
xxxxxxxxxx121switch (i) {2 case 0:3 j = 10; break;4 case 1:5 j = 11; break;6 case 2:7 j = 12; break;8 case 3:9 j = 13; break;10 default:11 j = 14; break;12}Switch models a common idion
Switch statements have interesting restrictions
Case labels must be static, cardinal values
Case labels must be compared for equality to a single expression
Note that each case label represents a code starting line
Implementation can work with:
Computation can be more efficient
xxxxxxxxxx141 void *jt[4] = { &&L0, &&L1, &&L2, &&L3 };2 if (i < 0 || i > 3) goto DEFAULT;3 else goto *jt[i];4L0: j = 10;5 goto CONTINUE;6L1: j = 11;7 goto CONTINUE;8L2: j = 12;9 goto CONTINUE;10L3: j = 13;11 goto CONTINUE;12DEFAULT:j = 14;13 goto CONTINUE;14CONTINUE:Jump table have a limitation:
Special consideration:
Strategy depends on case
Jump table implementation
xxxxxxxxxx61switch (i) {2 case 20: j = 10; break;3 case 21: j = 11; break;4 case 23: j = 13; break;5 default: j = 14; break;6} xxxxxxxxxx141 static const void* jt[4] = 2 { &&L20, &&L21, &&DEFAULT, &&L23 };3 if (i < 20 || i > 23) goto DEFAULT;4 goto *jt [i-20];5L20: j = 10;6 goto CONT;7L21: j = 11;8 goto CONT;9L23: j = 13;10 goto CONT;11DEFAULT:12 j = 14;13 goto CONT;14CONT: xxxxxxxxxx271foo: ld $i, r0 # r0 = &i2 ld 0x0(r0), r0 # r0 = i3 ld $0xffffffed, r1 # r1 = -194 add r0, r1 # r0 = i - 195 bgt r1, l0 # goto l0 if i>196 br default # goto default if i<207l0: ld $0xffffffe9, r1 # r1 = -238 add r0, r1 # r1 = i-239 bgt r1, default # goto default if i>2310 ld $0xffffffec, r1 # r1 = -2011 add r1, r0 # r0 = i-2012 ld $jmptable, r1 # r1 = &jmptable13 j *(r1, r0, 4) # goto jmptable[i-20]14case20: ld $0xa, r1 # r1 = 1015 br done # goto done16case21: ld $0xb, r1 # r1 = 1117 br done # goto done18...19default:ld $0xe, r1 # r1 = 1420done: ld $j, r0 # r0 = &j21 st r1, 0x0(r0) # j = r122...23jmptable:24 .long case20 # & (case 20)25 .long case21 # & (case 21)26 .long default # & (case 22)27 .long case23 # & (case 23)Existing double-indirect jump:
We need a new double-indirect jump: