The Layers of Larcenys FFI Felix S Klock II pnkfelix@ccs.neu.edu - - PowerPoint PPT Presentation

the layers of larceny s ffi
SMART_READER_LITE
LIVE PREVIEW

The Layers of Larcenys FFI Felix S Klock II pnkfelix@ccs.neu.edu - - PowerPoint PPT Presentation

The Layers of Larcenys FFI Felix S Klock II pnkfelix@ccs.neu.edu Northeastern University 1 Larcenys Foreign Function Interface Larceny GC, compiler research FFI cannot constrain system design Experience report For implementors . .


slide-1
SLIDE 1

The Layers of Larceny’s FFI

Felix S Klock II pnkfelix@ccs.neu.edu Northeastern University

1

slide-2
SLIDE 2

Larceny’s Foreign Function Interface

Larceny GC, compiler research FFI cannot constrain system design Experience report For implementors . . . and curious users

2

2

Experience report on design and implementation of Larceny’s FFI. (just describing design choices; I’m pretty certain none are innovations) (What parts worked well for us)

slide-3
SLIDE 3

Foreign Function Interfaces: Why

Low-level facilities (. . . but but but!) Code reuse!

3

3

Access to low-level facilities via interfaces targeting other languages (e.g. C) Do not reimplement OpenGL, GTK+, etc Life is too short!

slide-4
SLIDE 4

Goals for Larceny FFI

Constraint: precise, copying garbage collector FFI design cannot constrain Larceny VM design Scheme closures as C function pointers (“callbacks”) as well as “callouts” Write glue in Scheme, not C

4

4

slide-5
SLIDE 5

Side-benefits of Larceny FFI

Automatic relinking on heap reload Header file processing Support code oblivious to Larceny VM design

5

5

Latter is not a user-visible benefit; it is solely appreciated by the Larceny developers.

slide-6
SLIDE 6

Layered FFI

Upper: interfacing with C (processing header files) Middle: interfacing with C (value marshaling policies) Lower: runtime support, ABI, callouts, callbacks

6

6

Presentation won’t address the middle (it is discussed in the paper)

slide-7
SLIDE 7

Layered FFI

Upper: interfacing with C (processing header files) Middle: interfacing with C (value marshaling policies) Lower: runtime support, ABI, callouts, callbacks 1

6

6

Presentation won’t address the middle (it is discussed in the paper)

slide-8
SLIDE 8

Layered FFI

Upper: interfacing with C (processing header files) Middle: interfacing with C (value marshaling policies) Lower: runtime support, ABI, callouts, callbacks 1 2

6

6

Presentation won’t address the middle (it is discussed in the paper)

slide-9
SLIDE 9

Larceny Architecture

7

slide-10
SLIDE 10

Larceny Architecture

Larceny Virtual Machine (aka VM) Runtime (supports VM); written in mostly C Register assignment Calling convention

8

8

Virtual Machine has own processor configuration for running compiled Scheme code. Larceny Runtime is mostly implemented in C and thus adheres to ABI specifications. Register usage conventions. (E.g. Larceny chooses all reg roles; C: registers ABI specified.) E.g. prev mapped %sp to GLOBALS array Calling conventions: all parameters are caller-save in Larceny. Scheme code evaluated in MacScheme, but Runtime (FileSystem interaction & GC) are part of the C world. Consider a change-directory operation...

slide-11
SLIDE 11

Context Switches

Some functionality outside compiled Scheme File system commands Garbage collector interactions Implemented by Larceny runtime Larceny Scheme syscall procedure

9

9

slide-12
SLIDE 12

Control Flow between Scheme and C

Larceny VM world C / ABI world

10

invoke the changedir syscall change the working directory!

(current-directory “..”) chdir(“..”)

10

Low-level operation like “chdir”: shift the processor state so runtime C code happy with invocation

  • context. Likewise, return to Scheme must shift processor back to MacScheme-compatible state.

All *already* implemented in Larceny’s syscall support.

slide-13
SLIDE 13

Control Flow between Scheme and C

Larceny VM world C / ABI world

10

invoke the changedir syscall change the working directory!

(current-directory “..”) chdir(“..”)

built into runtime; we’re not talking FFI yet

10

Low-level operation like “chdir”: shift the processor state so runtime C code happy with invocation

  • context. Likewise, return to Scheme must shift processor back to MacScheme-compatible state.

All *already* implemented in Larceny’s syscall support.

slide-14
SLIDE 14

Low Level Challenges

11

slide-15
SLIDE 15

Our tasks

Callout: given C function (name/address) and its signature, create compatible Scheme procedure Callback: given Scheme closure and C function signature, create C function pointer that invokes the closure

12

12

slide-16
SLIDE 16

A use case

(define-gtk-enum gtkwindowtype (toplevel "GTK_WINDOW_TOPLEVEL") (popup "GTK_WINDOW_POPUP")) (define gtk-window-new (foreign-procedure “gtk_window_new” ‘(gtkwindowtype) gtkwindow*)) (define window (gtk-window-new ‘toplevel)) (define (key-press w e) (write `(key-press ,(gdk-event-keyval e))) (newline)) (g-signal-connect window “key_press_event” key-press)

library code client code

13

slide-17
SLIDE 17

Why this is hard

Value correspondence (“Symbol? Pair?”) Value formats differ (fixnum bitwidth, tags) VM mismatch No apply in C C function pointers are only code; Scheme closures are code plus environment

14

Scheme values are tagged; C’s are not. VM invocation is not a C invocation; and must establish proper processor context C does not have a way to apply function to a *package* holding its arguments

slide-18
SLIDE 18

Some solutions. . .

Problem Solution

Value domains and formats differ Map to/from primitive domains, strip/add tags VM mismatch Reuse runtime context switch from syscalls No apply in C ? C function pointers are not Scheme closures ?

15

slide-19
SLIDE 19

C does not have apply ...

C alone can only approximate apply (poorly) via fixed size dispatch table Plus, types matter float not same as int One long long not same as two long’s 4 types, 10 args : 1,048,576 entries

16

16

slide-20
SLIDE 20

f

... so make an apply elsewhere

Given address & signature of foreign function f Construct machine code for “C function” g g takes array holding arguments to f g places arguments according to ABI calling convention, and then invokes f (more like specialized apply than apply)

17

17

slide-21
SLIDE 21

...and one more thing

Callout/callback glue generation is implemented as Scheme code Machine code held in heap-allocated bytevectors! garbage collectable (but nonrelocatable) Do not be fooled: g expects to run in C context

18

See paper for details.

slide-22
SLIDE 22

...and one more thing

Callout/callback glue generation is implemented as Scheme code Machine code held in heap-allocated bytevectors! garbage collectable (but nonrelocatable) Do not be fooled: g expects to run in C context

18

See paper for details.

slide-23
SLIDE 23

...and one more thing

Callout/callback glue generation is implemented as Scheme code Machine code held in heap-allocated bytevectors! garbage collectable (but nonrelocatable) Do not be fooled: g expects to run in C context

18

See paper for details.

slide-24
SLIDE 24

(alternatives, but ...)

apply not expressible in C, but g = apply Could generate C code for g, compile, and dynamically link into running Larceny system But that requires users to have C compiler available Plus: dynamic code generation solves callback problem (encode closure address in g-code)

19

f

19

slide-25
SLIDE 25

Problems, Solutions

Problem Solution

Value domains and formats differ Map to/from primitive domains, strip/add tags VM mismatch Reuse runtime context switch from syscalls No apply in C Generate callout g-code from signature C function pointers are not Scheme closures Generate callback g-code from signature

20

Scheme values are tagged; C’s are not.

slide-26
SLIDE 26

> (define unix/opendir (foreign-procedure "opendir" '(string) 'uint)) #<PROCEDURE>

Callout Creation, Usage

> (unix/opendir “/tmp”) 1050560 Constructs glue (as in g-code) for C opendir function Invocation of unix/opendir passes g and marshaled arg list to Runtime syscall ffi callout; returns dir_ent* (aka “uint”)

21

slide-27
SLIDE 27

Callout Control Flow

Larceny VM world C / ABI world

invoke ffi callout syscall, passing g and arglist = (a1 a2 ...) massage arglist into argarr and invoke g(argarr) distribute argarr, calling f(a1, a2, ...) (whatever f does)

(for foreign function f)

22

slide-28
SLIDE 28

Callout Control Flow

Larceny VM world C / ABI world

invoke ffi callout syscall, passing g and arglist = (a1 a2 ...) massage arglist into argarr and invoke g(argarr) distribute argarr, calling f(a1, a2, ...) (whatever f does)

(for foreign function f)

22

slide-29
SLIDE 29

Callout/Callback glue follows C ABI

Ten years ago there was no x86 native Larceny VM (only C backend) We recently implemented x86 native FFI continued working

23

Tell story of:

  • 1. Lars dev’d x86 FFI atop Petit Larceny
  • 2. Felix dev’d native x86 Larceny
  • 3. Lars’ x86 FFI worked transparently, orthogonal to transition!
slide-30
SLIDE 30

Why again?

Heap dump/reload (with library reloading); see paper Glue uses ABI call convention, not Larceny VM call convention (robust to VM design changes) FFI does not constrain Larceny VM design Drawback: generating machine code for g

  • urselves (instead of using e.g. libffi)

24

24

We’ve adopted this control/heap structure for a number of reasons; the tramp objects allow us to relink foreign objects during a heap load. (See paper for more details.) I cannot stress enough the idea of separating the MacScheme calling convention from the C calling

  • convention. (It took me a long time to understand, and longer to appeciate.)

On the drawback: there is significant initial development (and also maintenance) overhead for our FFI design. E.g. we still do not have a PowerPC port of the FFI.

slide-31
SLIDE 31

High Level Interfacing Problems

25

Now that I’ve shown you the low level details of the kernel of the Larceny FFI, lets talk about a higher level problem and the solution we adopted.

slide-32
SLIDE 32

How to hack with C?

Many libraries have implementation (shared

  • bject code) and interface (C header file)

Would be nice if interface were not encoded as a C header file (see FFIGEN Manifesto [Hansen,1996]) We accept standard operating procedure and treat the header file as the expected interface

26

26

slide-33
SLIDE 33

Two kinds of libraries

C libraries with all functionality exported via functions over “simple” types C libraries assuming that clients can/will use constants and type definitions of header files

27

27

Very simple FFI’s suffjce for the former category. Unfortunately, vast majority of libraries fall into latter category

slide-34
SLIDE 34

Example: The UNIX Filesystem

A tale from the Larceny source tree Larceny does not have a list-directory primitive operation or syscall But FFI-based implementation was available

28

28

Felix decided to see if the code for list-directory worked

slide-35
SLIDE 35

29

> (list-directory ".") ("." ".." "122.jpg" "DCP_104.JPG" "jackson.jpg" "SOUNDAV2.JPG")

Linux (Intel x86)

29

Felix tried the code on Linux. Lo and behold, it worked!

slide-36
SLIDE 36

30

> (list-directory ".") ("" "" ".jpg" "_104.JPG" "kson.jpg" "NDAV2.JPG")

Mac OS X (Intel x86)

30

Encouraged, Felix tried the code on Mac OS X. Here’s the result.

slide-37
SLIDE 37

;; list-directory : String -> [Listof String] (define (list-directory dirname) (let ((dir (unix/opendir dirname))) (if (zero? dir) (error 'list-directory path) (let loop ((files '())) (let ((ent (unix/readdir dir))) (if (zero? ent) (begin (unix/closedir dir) (reverse files)) (loop (cons (dirent->name ent) files))))))))

31

The Investigation

31

So Felix started looking at the code. list-directory is a pretty standard function. (Easy to port from C for loop in example code.) It just opens the directory, iterates through its entries (building up a list of names from each), and closes the directory.

slide-38
SLIDE 38

;; list-directory : String -> [Listof String] (define (list-directory dirname) (let ((dir (unix/opendir dirname))) (if (zero? dir) (error 'list-directory path) (let loop ((files '())) (let ((ent (unix/readdir dir))) (if (zero? ent) (begin (unix/closedir dir) (reverse files)) (loop (cons (dirent->name ent) files))))))))

32

The Investigation

32

If somethings wrong, it seems like it would be something in unix/opendir, unix/readdir, unix/ closedir, or dirent->name

slide-39
SLIDE 39

;; The offsets in the dirent accessors ;; are probably x86-Linux-specific!! (define unix/opendir (foreign-procedure "opendir" '(string) 'uint)) (define unix/readdir (foreign-procedure "readdir" '(uint) 'uint)) (define unix/closedir (foreign-procedure "closedir" '(uint) 'int)) (define (dirent->name ent) (%peek-string (+ ent 11)))

33

The Culprit

33

So Felix inspects the definitions of those functions, elsewhere in the file. And there we find the problem (pointed out directly in Lars’s comments). The uints are dirent memory addresses; the int is an error return code. (To learn more about the interface to foreign-procedure, see the paper.)

slide-40
SLIDE 40

;; The offsets in the dirent accessors ;; are probably x86-Linux-specific!! (define unix/opendir (foreign-procedure "opendir" '(string) 'uint)) (define unix/readdir (foreign-procedure "readdir" '(uint) 'uint)) (define unix/closedir (foreign-procedure "closedir" '(uint) 'int)) (define (dirent->name ent) (%peek-string (+ ent 11)))

34

The Culprit

34

%peek-string is an (unsafe) memory accessor in Larceny. Here’s we’re just calculating the memory address of the entry’s name by adding 11 to the entry’s start.

slide-41
SLIDE 41

“Portable” code

Referring to field names is portable, but not field offsets On UNIX, “struct dirent” must have a “d_name” field holding filename characters On our Linux system, “d_name” is at offset 11 But not on Mac OS X

35

35

slide-42
SLIDE 42

“Portable” code

One solution:

  • 1. Transcribe desired structure definition into

Scheme special forms

  • 2. Macro-expand forms to offsets according to

target’s ABI

36

36

slide-43
SLIDE 43

“Portable” code

One solution:

  • 1. Transcribe desired structure definition into

Scheme special forms

  • 2. Macro-expand forms to offsets according to

target’s ABI

37

37

slide-44
SLIDE 44

“Portable” code

Library developers (often) have freedom to extend structure definitions with new fields E.g. “struct dirent” definitions differ Transcribed structure definitions are not portable

38

38

slide-45
SLIDE 45

“Portable” code

Portability requires extracting information from the header file Did not want to write a C parser Insight: generating C programs that extract info (e.g. field offsets) is much easier task Procedural macros allow one to generate, compile, and execute such a program statically!

39

39

Mention that the trick is also used by Haskell FFI. (and GNU configure set a precedent for generating small C pgms to reflect on the host system.) BUT we’re doing it as a macro!

slide-46
SLIDE 46

define-c-info form

40

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

40

I will now illustrate the idea behind the define-c-info syntax by showing how its expansion works in

  • ne case.

Here we interface to a C pair struct, and we want access to two of its fields.

slide-47
SLIDE 47

define-c-info form

41

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

;; pair.h struct pair { int id; int x; char c; int y; };

(begin (define x-offs 4) (define y-offs 12))

41

I will now illustrate the idea behind the define-c-info syntax by showing how its expansion works in

  • ne case.

Here we interface to a C pair struct, and we want access to two of its fields.

slide-48
SLIDE 48

define-c-info form

42

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

42

I will now illustrate the idea behind the define-c-info syntax by showing how its expansion works in

  • ne case.

Here we interface to a C pair struct, and we want access to two of its fields.

slide-49
SLIDE 49

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

43

43

slide-50
SLIDE 50

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

43

#include “pair.h” #include <stdio.h> int main() { printf(“\n(\n”); { struct pair s; printf(“%ld ”,((long)((char*)&s.x- (char*)&s))); } { struct pair s; printf(“%ld ”,((long)((char*)&s.y- (char*)&s))); } printf(“\n)\n”); return 0; }

  • 1. generate C code

43

slide-51
SLIDE 51

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

43

#include “pair.h” #include <stdio.h> int main() { printf(“\n(\n”); { struct pair s; printf(“%ld ”,((long)((char*)&s.x- (char*)&s))); } { struct pair s; printf(“%ld ”,((long)((char*)&s.y- (char*)&s))); } printf(“\n)\n”); return 0; }

43

slide-52
SLIDE 52

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

44

#include “pair.h” #include <stdio.h> int main() { printf(“\n(\n”); { struct pair s; printf(“%ld ”,((long)((char*)&s.x- (char*)&s))); } { struct pair s; printf(“%ld ”,((long)((char*)&s.y- (char*)&s))); } printf(“\n)\n”); return 0; }

44

slide-53
SLIDE 53

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

44

#include “pair.h” #include <stdio.h> int main() { printf(“\n(\n”); { struct pair s; printf(“%ld ”,((long)((char*)&s.x- (char*)&s))); } { struct pair s; printf(“%ld ”,((long)((char*)&s.y- (char*)&s))); } printf(“\n)\n”); return 0; }

  • 2. compile to a.out

a.out

44

slide-54
SLIDE 54

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

44

a.out

44

slide-55
SLIDE 55

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

45

a.out

45

slide-56
SLIDE 56

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

45

  • 3. run a.out, piping results to temp file

a.out

( 4 12 )

45

slide-57
SLIDE 57

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

45

( 4 12 )

45

slide-58
SLIDE 58

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

46

( 4 12 )

46

slide-59
SLIDE 59

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

46

  • 4. read temp file and generate binding form

( 4 12 )

(begin (define x-offs 4) (define y-offs 12))

46

slide-60
SLIDE 60

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

46

(begin (define x-offs 4) (define y-offs 12))

46

slide-61
SLIDE 61

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

47

(begin (define x-offs 4) (define y-offs 12))

;; pair.h struct pair { int id; int x; char c; int y; };

47

slide-62
SLIDE 62

(define-c-info (include “pair.h”) (struct “pair” (x-offs “x”) (y-offs “y”)))

define-c-info form

47

(begin (define x-offs 4) (define y-offs 12))

(Actual numbers depend

  • n contents of

“pair.h”)

;; pair.h struct pair { int id; int x; char c; int y; };

47

slide-63
SLIDE 63

Fixed/Portable UNIX Filesystem Interface

48

(define (dirent->name ent) (%peek-string (+ ent 11))) (define (dirent->name ent) (define-c-info (include<> “dirent.h”) (struct “dirent” (name-offs “d_name”))) (%peek-string (+ ent name-offs)))

This version works on Linux, Mac OS X, Solaris Windows: same idea, but different API

48

slide-64
SLIDE 64

More High Level Interface Syntax

define-c-info has proven to be a useful core construct, though low-level Foundation for other syntax define-c-struct define-c-enum, define-c-enum-set

49

49

see paper for details on the other macros

slide-65
SLIDE 65

Related Work: FFI’s for Scheme

(vast amount of Lisp FFI material) esh [Rose and Muller, 1992]: tight integration, tight constraints SRFI-50 [Kelsey and Sperber, 2003]: client writes glue in C PLT Scheme [Barzilay and Orlovsky, 2004]: “stay in the fun world”

50

50

I only begin to skim the surface of interfacing Lisp/C in the related work section.

slide-66
SLIDE 66

Related Work: interface extraction

esh [Rose and Muller, 1992]: maps headers to UNIX object files SWIG [Beazley, 1996]: processes subset of C and C++ into scripting language FIG [Reppy and Song, 2006]: process header files via a declarative DSL

51

51

esh: C macros become Scheme functions! SWIG: you have you write your interface in a C-like language; it won’t handle arbitrary headers directly FIG: combines declarative DSL and term-rewriting to derive interfaces to foreign libraries

slide-67
SLIDE 67

Conclusion

Larceny’s low-level FFI structure largely orthogonal to Larceny VM design not simple; but much complexity is kept in Scheme code, not C code Larceny’s high-level FFI functionality: simple macros that process header files

52

52

slide-68
SLIDE 68

thanks!

53

slide-69
SLIDE 69

54

slide-70
SLIDE 70

Low Level Heap Structure

(how to satisfy the garbage collector)

55

I’ve shown control flow details so far; now I’m going to show how the objects implementing that control are distributed throughout the heap. But first I need to explain the diagram conventions.

slide-71
SLIDE 71

Ovals: GC traced objects Rectangles: untraced objects/memory / code

Heap Diagram legend

56

56

Ovals are e.g. closures, pairs. Rectangles are e.g. machine code, C runtime fcns, Scheme string contents “Foreign State” in lower right corner is a fuzzy abstraction of the C memory state

slide-72
SLIDE 72

Heap Diagram legend

Solid arrows: GC traced references Dashed arrows: untraced (encoded) addresses

57

57

slide-73
SLIDE 73

Scheme managed versus foreign memory non-moving vs relocatable memory

Heap Diagram legend

58

58

slide-74
SLIDE 74

Heap Diagram rules

Solid arrows only originate at ovals Dashed arrows cannot point to relocatable Solid arrows cannot point to C runtime state

59

59

slide-75
SLIDE 75

Heap Structure: Callouts

CALLOUT CONTROL FLOW

60

60

We start ofg with the Runtime functions and Foreign Target; we get to create the MacScheme stufg. (keep in mind that final control flow is going to follow the “Z”) ... get to start by creating a Trampoline object

slide-76
SLIDE 76

Heap Structure: Callouts

CALLOUT CONTROL FLOW

60

60

We start ofg with the Runtime functions and Foreign Target; we get to create the MacScheme stufg. (keep in mind that final control flow is going to follow the “Z”) ... get to start by creating a Trampoline object

slide-77
SLIDE 77

Heap Structure: Callouts

CALLOUT CONTROL FLOW

60

60

We start ofg with the Runtime functions and Foreign Target; we get to create the MacScheme stufg. (keep in mind that final control flow is going to follow the “Z”) ... get to start by creating a Trampoline object

slide-78
SLIDE 78

Heap Structure: Callouts

CALLOUT CONTROL FLOW

60

60

We start ofg with the Runtime functions and Foreign Target; we get to create the MacScheme stufg. (keep in mind that final control flow is going to follow the “Z”) ... get to start by creating a Trampoline object

slide-79
SLIDE 79

Heap Structure: Callouts

61

I’m a call instruction! I’m a function pointer!

61

Q: What are these dashed arrows? ... this Tramp Object just represents the target; its *not* what Scheme client code directly invokes.

slide-80
SLIDE 80

Heap Structure: Callouts

61

I’m a call instruction! I’m a function pointer!

61

Q: What are these dashed arrows? ... this Tramp Object just represents the target; its *not* what Scheme client code directly invokes.

slide-81
SLIDE 81

Heap Structure: Callouts

61

I’m a call instruction! I’m a function pointer!

61

Q: What are these dashed arrows? ... this Tramp Object just represents the target; its *not* what Scheme client code directly invokes.

slide-82
SLIDE 82

Heap Structure: Callouts

62

I’m the entry point your Scheme code invokes!

62

This is the closure that client code invokes. It extracts the ARG ENCODING and TRAMP GLUE, and passes them along to the runtime callout. (... but there’s one last detail: C function invocations push return addresses onto the C stack...)

slide-83
SLIDE 83

Heap Structure: Callouts

62

I’m the entry point your Scheme code invokes!

62

This is the closure that client code invokes. It extracts the ARG ENCODING and TRAMP GLUE, and passes them along to the runtime callout. (... but there’s one last detail: C function invocations push return addresses onto the C stack...)

slide-84
SLIDE 84

Heap Structure: Callouts

63

I’m the C stack

63

So to properly represent the references from the foreign memory, we add these dashed arrows. and with this, we have an accurate diagram that also satisfies all of the rules. Q: to ponder: does it actually matter that a reference into the Trampoline Glue is on the C stack? When/how could the GC be invoked while its on the stack?

slide-85
SLIDE 85

Heap Structure: Callouts

63

I’m the C stack

63

So to properly represent the references from the foreign memory, we add these dashed arrows. and with this, we have an accurate diagram that also satisfies all of the rules. Q: to ponder: does it actually matter that a reference into the Trampoline Glue is on the C stack? When/how could the GC be invoked while its on the stack?

slide-86
SLIDE 86

Heap Structure: Callbacks

CALLBACK CONTROL FLOW

64

64

Distributing control amongst heap objects. Remember: we start at the foreign invocation, go through trampoline, then runtime, and finally hit the target closure (the “Z” in reverse).

slide-87
SLIDE 87

Heap Structure: Callbacks

CALLBACK CONTROL FLOW

64

64

Distributing control amongst heap objects. Remember: we start at the foreign invocation, go through trampoline, then runtime, and finally hit the target closure (the “Z” in reverse).

slide-88
SLIDE 88

Heap Structure: Callbacks

CALLBACK CONTROL FLOW

64

64

Distributing control amongst heap objects. Remember: we start at the foreign invocation, go through trampoline, then runtime, and finally hit the target closure (the “Z” in reverse).

slide-89
SLIDE 89

Heap Structure: Callbacks

CALLBACK CONTROL FLOW

64

64

Distributing control amongst heap objects. Remember: we start at the foreign invocation, go through trampoline, then runtime, and finally hit the target closure (the “Z” in reverse).

slide-90
SLIDE 90

Heap Structure: Callbacks

CALLBACK CONTROL FLOW

64

64

Distributing control amongst heap objects. Remember: we start at the foreign invocation, go through trampoline, then runtime, and finally hit the target closure (the “Z” in reverse).

slide-91
SLIDE 91

Heap Structure: Callbacks

65

I’m the goal!

65

Here, we will start with the target closure, and the goal is to come up with the right glue to make the foreign invocation work from C. The machine code of the closure is not enough; we need its environment as well. Somewhere in the glue code we need to get our hands on that closure object.

slide-92
SLIDE 92

Heap Structure: Callbacks

65

I’m the goal!

65

Here, we will start with the target closure, and the goal is to come up with the right glue to make the foreign invocation work from C. The machine code of the closure is not enough; we need its environment as well. Somewhere in the glue code we need to get our hands on that closure object.

slide-93
SLIDE 93

Heap Structure: Callbacks

66

I describe the interface to the target

66

When we construct a callback, we create a trampoline object that creates the machine code as well as a description of the argument encoding. Both the target closure and the arg encoding need to be passed into the runtime glue code. Can we put references from the trampoline glue to these objects? (Why not direct? Why not indirect?) How can we do this without violating our heap structure invariants?

slide-94
SLIDE 94

Heap Structure: Callbacks

66

I describe the interface to the target

66

When we construct a callback, we create a trampoline object that creates the machine code as well as a description of the argument encoding. Both the target closure and the arg encoding need to be passed into the runtime glue code. Can we put references from the trampoline glue to these objects? (Why not direct? Why not indirect?) How can we do this without violating our heap structure invariants?

slide-95
SLIDE 95

Heap Structure: Callbacks

67

We’re handles for relocatable objects

67

We solve the problem by introducing a level of indirection. These handles are allocated as non-relocatable, so the trampoline glue can encode indirect references to them, while they themselves can have direct references to the relocatable part of the Scheme heap.

slide-96
SLIDE 96

Heap Structure: Callbacks

67

We’re handles for relocatable objects

67

We solve the problem by introducing a level of indirection. These handles are allocated as non-relocatable, so the trampoline glue can encode indirect references to them, while they themselves can have direct references to the relocatable part of the Scheme heap.

slide-97
SLIDE 97

Heap Structure: Callbacks

68

I’m holding the callbacks

68

Finally, to complete the picture, when we pass a callback into the foreign world, the foreign state will have a reference to the trampoline glue (that, as far as C is concerned, is just some C function pointer). (This is the most complex picture; it is explained in the paper as well.)

slide-98
SLIDE 98

Heap Structure: Callbacks

68

I’m holding the callbacks

68

Finally, to complete the picture, when we pass a callback into the foreign world, the foreign state will have a reference to the trampoline glue (that, as far as C is concerned, is just some C function pointer). (This is the most complex picture; it is explained in the paper as well.)