cpsc 213
play

CPSC 213 2.7.4, 2.7.7-2.7.8 Text Switch Statements, Understanding - PowerPoint PPT Presentation

Reading Companion CPSC 213 2.7.4, 2.7.7-2.7.8 Text Switch Statements, Understanding Pointers 2ed: 3.6.7, 3.10 - yup, 3.10 again - mainly "Function pointers" box 1ed: 3.6.6, 3.11 Introduction to Computer Systems


  1. Reading ‣ Companion CPSC 213 •2.7.4, 2.7.7-2.7.8 ‣ Text •Switch Statements, Understanding Pointers •2ed: 3.6.7, 3.10 - yup, 3.10 again - mainly "Function pointers" box •1ed: 3.6.6, 3.11 Introduction to Computer Systems Unit 1g Dynamic Control Flow Polymorphism and Switch Statements 1 2 Back to Procedure Calls ‣ Static Method Invocations and Procedure Calls •target method/procedure address is known statically ‣ in Java public class A { • static methods are class methods static void ping () {} } - invoked by naming the class, not an object Polymorphism public class Foo { static void foo () { A.ping (); } } ‣ in C void ping () {} •specify procedure name void foo () { ping (); } 3 4

  2. Polymorphism Polymorphic Dispatch ‣ Invoking a method on an object in Java ‣ Method address is determined dynamically • variable that stores the object has a static type • compiler can not hardcode target address in procedure call • object reference is dynamic and so is its type • instead, compiler generates code to lookup procedure address at runtime - object’s type must implement the type of the referring variable • address is stored in memory in the object’s class jump table - but object’s type may override methods of this base type ‣ Class Jump table ‣ Polymorphic Dispatch • every class is represented by class object • target method address depends on the type of the referenced object • the class object stores the class’s jump table • one call site can invoke different methods at different times • the jump table stores the address of every method implemented by the class • objects store a pointer to their class object class A { static void foo (A a) { void ping () {} Which ping gets called? a.ping (); ‣ Static and dynamic of method invocation void pong () {} a.pong (); } } • address of jump table is determined dynamically static void bar () { • method’s offset into jump table is determined statically foo (new A()); class B extends A { foo (new B()); void ping () {} } void wiff () {} } 5 6 Example of Java Dispatch Dynamic Jumps in C class A { void ping () {} void pong () {} } ‣ Function pointer Class A A.ping () {} class B extends A { •a variable that stores a pointer to a procedure ping void ping () {} pong void wiff () {} •declared A.pong () {} } - <return-type> (*<variable-name>)(<formal-argument-list>); Class B static void foo (A a) { •used to make dynamic call B.ping () {} a.ping (); ping a.pong (); - <variable-name> (<actual-argument-list>); pong } ‣ Example wiff B.wiff () {} static void bar () { foo (new A()); foo (new B()); } void ping () {} void foo () { an A a B void (*aFunc) (); foo (a) r5 r5 a a aFunc = ping; r[0] ← m[r[5]] # r0 = a calls ping aFunc (); r[1] ← m[r[0]] # r1 = a.class pc ← m[r[1]+0*4] # a.ping () } pc ← m[r[1]+1*4] # a.pong () Runtime Stack 7 8

  3. Simplified Polymorphism in C (SA-dynamic-call.c) •and B ... Declaration of B’s jump table and code ‣ Use a struct to store jump table struct B { void (*ping)(); •drawing on previous example of A ... void (*pong)(); Declaration of A’s jump table and code void (*wiff)(); }; struct A { void (*ping) (); void B_ping () { printf ("B_ping\n"); } void (*pong) (); void B_wiff () { printf ("B_wiff\n"); } }; void A_ping () { printf ("A_ping\n"); } Create an instance of B’s jump table void A_pong () { printf ("A_pong\n"); } struct B* new_B () { struct B* b = (struct B*) malloc (sizeof (struct B)); Create an instance of A’s jump table b->ping = B_ping; b->pong = A_pong; struct A* new_A () { b->wiff = B_wiff; struct A* a = (struct A*) malloc (sizeof (struct A)); return b; a->ping = A_ping; } a->pong = A_pong; return a; } 9 10 Dispatch Diagram for C (data layout) •invoking ping and pong on an A and a B ... void foo (struct A* a) { a->ping (); struct A void A_ping () {} A_ping () {} a->pong (); void A_pong () {} ping } void B_ping () {} pong void B_wiff () {} A_pong () {} void bar () { foo (new_A ()); foo ((struct A*) new_B ()); Struct B B_ping () {} } ping pong wiff B_wiff () {} struct A { struct B { void (*ping) (); void (*ping)(); void (*pong) (); void (*pong)(); }; void (*wiff)(); }; struct A* new_A () { struct A* a = (struct A*) malloc ( sizeof (struct A) ); struct B* new_B () { a->ping = A_ping; struct B* b = (struct B*) malloc ( sizeof (struct B) ); a->pong = A_pong; b->ping = B_ping; return a; b->pong = A_pong; } b->wiff = B_wiff; return b; } 11 12

  4. Dispatch Diagram for C (the dispatch) ISA for Polymorphic Dispatch void foo (struct A* a) { r[0] ← m[r[5]] # r0 = a pc ← m[r[1]+0*4] # a->ping () struct A void A_ping () {} a->ping (); A_ping () {} pc ← m[r[1]+1*4] # a->pong () void A_pong () {} a->pong (); ping void B_ping () {} } pong void B_wiff () {} A_pong () {} ‣ How do we compile Struct B B_ping () {} ping • a->ping () ? void foo (struct A* a) { pong ‣ Pseudo code a->ping (); B_wiff () {} wiff a->pong (); } • pc ← m[r[1]+0*4] void bar () { ‣ Current jumps supported by ISA foo (new_A ()); foo ( (struct A*) new_B ()); } Name Semantics Assembly Machine jump immediate pc ← a j a b--- aaaaaaaa jump base+offset pc ← r[ s ] + ( o == pp *2) j o (r s ) cspp foo (a) r5 r5 a ‣ We will benefit from a new instruction in the ISA a r[0] ← m[r[5]] # r0 = a pc ← m[r[0]+0*4] # a->ping () pc ← m[r[0]+1*4] # a->pong () • that jumps to an address that is stored in memory Runtime Stack 13 14 Question 1 ‣ Indirect jump instruction (b+o) •jump to address stored in memory using base+offset addressing ‣ What is the difference between these two C snippets? Name Semantics Assembly Machine jump immediate pc ← a j a b--- aaaaaaaa (1) (2) void foo () {printf ("foo \n";} void foo () {printf ("foo \n";} jump base+offset pc ← r[ s ] + ( o == pp *2) j o (r s ) cspp void go(void (*proc)()) { void go() { indir jump b+o pc ← m[r[ s ] + ( o == pp *4)] j * o (r s ) dspp proc(); foo(); } } go (foo); go(); •[A] (2) calls foo, but (1) does not •[B] (1) is not valid C •[C] (1) jumps to foo using a dynamic address and (2) a static address •[D] They both call foo using dynamic addresses •[E] They both call foo using static addresses Now, implement proc() and foo() assembly code 15 16

  5. Switch Statement int i; void bar () { int j; if (i==0) j=10; void foo () { else if (i==1) switch (i) { j = 11; case 0: j=10; break; else if (i==2) case 1: j=11; break; j = 12; case 2: j=12; break; else if (i==3) case 3: j=13; break; j = 13; default: j=14; break; else } j = 14; Switch Statements } } ‣ Semantics the same as simplified nested if statements • where condition of each if tests the same variable • unless you leave the break the end of the case block ‣ So, why bother putting this in the language? • is it for humans, facilitate writing and reading of code? • is it for compilers, permitting a more efficient implementation? ‣ Implementing switch statements • we already know how to implement if statements; is there anything more to consider? 17 18 Human vs Compiler Why Compilers like Switch Statements ‣ Benefits for humans ‣ Notice what we have • switch condition evaluates to a number • the syntax models a common idiom: choosing one computation from a set • each case arm has a distinct number ‣ But, switch statements have interesting restrictions ‣ And so, the implementation has a simplified form • case labels must be static , cardinal values • build a table with the address of every case arm, indexed by case value • switch by indexing into this table and jumping to matching case arm - a cardinal value is a number that specifies a position relative to the beginning of an ordered set ‣ For example - for example, integers are cardinal values, but strings are not • case labels must be compared for equality to a single dynamic expression switch (i) { label jumpTable[4] = { L0, L1, L2, L3 }; case 0: j=10; break; if (i < 0 || i > 3) goto DEFAULT; - some languages permit the expression to be an inequality case 1: j=11; break; goto jumpTable[i]; ‣ Do these restrictions benefit humans? case 2: j=12; break; L0: j = 10; case 3: j=13; break; goto CONT; default: j=14; break; L1: j = 11; • have you ever wanted to do something like this? } goto CONT; L2: j = 12; goto CONT; switch (treeName) { switch (i,j) { L3: j = 13; case "larch": case i>0: goto CONT; case "cedar": case i==0 & j>a: DEFAULT: case "hemlock": case i<0 & j==a: j = 14; } default: goto CONT; CONT: } 19 20

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend