<<

C a p ortable assembly language

that supp orts garbage collection

1 2 3

Simon Peyton Jones Norman Ramsey and Fermin Reig

1

simonpjmicrosoftcom Microsoft Research Ltd

2

nrcsvirginiaedu University of Virginia

3

reigdcsglaacuk University of Glasgow

Abstract For a compiler writer generating go o d machine co de for a

variety of platforms is hard work One might try to reuse a retargetable

co de generator but co de generators are complex and dicult to use

and they limit ones choice of implementation language One might try

to use C as a p ortable assembly language but C limits the compiler

writers exibility and the p erformance of the resulting co de The wide

use of C despite these drawbacks argues for a p ortable assembly lan

guage C is a new language designed expressly for this purp ose The

use of a p ortable assembly language introduces new problems in the sup

p ort of such highlevel runtime services as garbage collection exception

handling concurrency proling and debugging We address these prob

lems by combining the C language with a C runtime interface The

combination is designed to allow the compiler writer a choice of source

language semantics and implementation techniques while still providing

go o d p erformance

Introduction

Supp ose you are writing a compiler for a highlevel language How are you to

generate highquality machine co de You could do it yourself or you could try

to take advantage of the work of others by using an otheshelf co de gener

ator Curiously despite the huge amount of research in this area only three

retargetable optimizing co de generators app ear to b e freely available VPO

Benitez and Davidson MLRISC George and the gcc back end

Stallman Each of these impressive systems has a rich complex and ill

do cumented interface Of course these interfaces are quite dierent from one

another so once you start to use one you will b e unable to switch easily to an

other Furthermore they are languagesp ecic To use MLRISC you must write

your front end in ML to use the gcc back end you must write it in C and so on

All of this is most unsatisfactory It would b e much b etter to have one p ortable

assembly language that could b e generated by a front end and implemented by

any of the available co de generators So pressing is this need that it has b e

come common to use C as a p ortable assembly language Atkinson et al

Bartlett b Peyton Jones Tarditi Acharya and Lee Henderson

Conway and Somogyi Pettersson Serrano and Weis Unfortu

nately C was never intended for this purp ose it is a programming language

not an assembly language C lo cks the implementation into a particular calling

convention makes it imp ossible to compute targets of jumps provides no sup

p ort for garbage collection and provides very little supp ort for exceptions or

debugging Section

The obvious way forward is to design a language sp ecically as a compiler tar

get language Such a language should serve as the interface b etween a compiler

for a highlevel language the front end and a retargetable co de generator the

back end The language would not only make the compiler writers life much

easier but would also give the author of a new co de generator a readymade cus

tomer base In an earlier pap er we prop ose a design for just such a language C

Peyton Jones Oliva and Nordin but the story do es not end there Sepa

rating the front and back ends greatly complicates runtime supp ort In general

the front end back end and runtime system for a programming language are

designed together They co op erate intimately to supp ort such highlevel features

as garbage collection exception handling debugging proling and concurrency

highlevel runtime services If the back end is a p ortable assembler like C

we want the co op eration without the intimacy an implementation of C should

b e indep endent of the front ends with which it will b e used

One alternative is to make all these highlevel services part of the abstraction of

fered by the p ortable assembler For example the Java Virtual Machine which

provides garbage collection and exception handling has b een used as a tar

get for languages other than Java including Ada Taft ML Benton

Kennedy and Russell Scheme Clausen and Danvy and Haskell

Wakeling But a sophisticated platform like a virtual machine embo dies

to o many design decisions For a start the semantics of the virtual machine may

not match the semantics of the language b eing compiled eg the exception se

mantics Even if the semantics happ to match the engineering tradeos may

dier dramatically For example functional languages like Haskell or Scheme

allo cate like crazy Diwan Tarditi and Moss and JVM implementations

are typically not optimised for this case Finally a virtual machine typically

comes complete with a very large infrastructure class loaders veriers and

the like that may well b e inappropriate Our intended level of abstraction is

much much lower

Our problem is to enable a client to implement highlevel services while still

using C as a co de generator As we discuss in Section supp orting high

level services requires knowledge from both the front and back ends The insight

b ehind our solution is that C should include not only a lowlevel assembly

language for use by the compiler but also a lowlevel runtime system for use

by the front ends runtime system The only intimate co op eration required is

b etween the C back end and its runtime system the front end works with

C at arms length through a welldened language and a welldened run

time interface Section This interface adds something fundamentally new

the ability to insp ect and mo dify the state of a susp ended computation

It is not obvious that this approach is workable Can just a few assemblylanguage

capabilities supp ort many highlevel runtime services Can the frontend run

time system easily implement highlevel services using these capabilities How

much is overall eciency compromised by the armslength relationship b etween

the frontend runtime and the C runtime We cannot yet answer these ques

tions denitively Instead the primary contributions of this pap er are to identify

needs that are common to various highlevel services and to prop ose sp ecic

mechanisms to meet these needs We demonstrate only how to use C to im

plement the easiest of our intended services namely garbage collection Rening

our design to accommo date exceptions concurrency proling and debugging

has emerged as an interesting research challenge

Its imp ossible or its C

The dream of a p ortable assembler has b een around at least since UNCOL

Conway Is it an imp ossible dream then Clearly not Cs p opularity as

an assembler is clear evidence that a need exists and that something useful can

b e done

If C is so p opular then p erhaps C is p erfectly adequate Not so There are many

diculties of which the most fundamental are these

The C route rewards those who can map their highlevel language rather

directly onto C A highlevel language pro cedure b ecomes a C pro cedure

and so on But this mapping is often awkward and sometimes imp ossible

For example some source languages fundamentally require tailcall optimi

sation a pro cedure call whose result is returned to the caller of the current

pro cedure must b e executed in the stack frame of the current pro cedure This

optimisation allows iteration to b e implemented eciently using recursion

More generally it allows one to think of a pro cedure as a lab elled extended

basic blo ck that can b e jumped to rather than as subprogram that can only

b e called Such pro cedures give a front end the freedom to design its own

control ow

It is very dicult to implement the tailcall optimisation in C and no C com

piler known to us do es so across separately compiled mo dules Those using C

have b een very ingenious in nding ways around this deciency Steele

Tarditi Acharya and Lee Peyton Jones Henderson Conway and

Somogyi but the results are complex fragile and heavily tuned for

one particular implementation of C usually gcc

A C compiler may lay out its stack frames as it pleases This makes it dicult

for a garbage collector to nd the live p ointers Implementors either arrange

not to keep p ointers on the C stack or they use a conservative garbage

collector These restrictions are Draconian

The unknown stackframe layout also complicates supp ort for exception

handling debugging proling and concurrency For example an exception

handling mechanism needs to walk the stack p erhaps removing stack frames

as it go es Again C makes it essentially imp ossible to implement such mecha

nisms unless they can b e closely mapp ed onto what C provides ie setjmp

and longjmp

A C compiler has to b e very conservative ab out the p ossibility of memory

aliasing This seriously limits the ability of the instruction scheduler to p er

mute memory op erations or hoist them out of a lo op The frontend compiler

often knows that aliasing cannot o ccur but there is no way to convey this

information to the C compiler

So much for fundamental issues C also lacks the ability to control a number

of imp ortant lowlevel features including returning multiple values in registers

from a pro cedure misaligned memory accesses arithmetic data layout and

omitting range checks on multiway jumps

In short C is awkward to use as a p ortable assembler and many of these di

culties translate into p erformance hits A p ortable assembly language should b e

able to oer b etter p erformance as well as greater ease of use

An overview of C

In this section we give an overview of the design of C Fuller descriptions

can b e found in Peyton Jones Oliva and Nordin and in Reig and Peyton

Jones Figure gives examples of some C pro cedures that give a avour

of the language Despite its name C is by no means a subset of C as will b ecome

apparent C was simply our jumpingo p oint

What is a p ortable assember

C is an assembly language an abstraction of hardware not a highlevel

programming language Hardware provides computation control ow memory

and registers C provides corresp onding abstractions

C expressions and assignments are abstractions of computation C pro

vides a rich set of computational op erators but these op erators work only

on machinelevel data types bytes words etc The expression abstraction

Loops Ordinary recursion

export sp export sp

sp bits n sp bits n

bits s p bits s p

s p if n

return

loop else

if n s p sp n

return s p return sn pn

else

s sn

p pn

n n Tail recursion

goto loop export sp

sp bits n

jump sphelp n

sphelp bits n bits s bits p

if n

return s p

else

jump sphelp n sn pn

P Q

n n

Fig Three functions that compute the sum i and pro duct i written

i=1 i=1

in C

hides the particular combination of machine instructions needed to com

pute values and it hides the machine registers that may b e needed to hold

intermediate results

Cs goto and if statements are abstractions of control ow For conve

nience C also provides structured controlow constructs The if abstrac

tion hides the machines condition co des branch conditions are arbitrary

Bo olean expressions

C treats memory much as the machine do es except that addresses used

in C programs may b e arbitrary expressions This abstraction hides the

limitations of the machines addressing mo des

C variables are an abstraction of registers A C back end puts as many

variables as p ossible in registers others go in memory This abstraction hides

the number and conventional uses of the machines registers

In addition C provides a pro cedure abstraction the feature that lo oks least

like an abstraction of a hardware primitive However many pro cessor archi

tectures provide direct supp ort for pro cedures although the nature of that

supp ort varies widely pro cedure call or multiple register save instructions

register windows link registers branch prediction for return instructions

and so on Because of this variety calling conventions and activationstack

management are notoriously architecture dep endent and hard to sp ecify C

therefore oers pro dedures as a primitive abstraction alb eit in a slightly un

usual form Section

Our goal is to make it easy to retarget front ends not to make every C program

runnable everywhere Although every C program has a welldened semantics

that is indep endent of any machine a front end translating a single source pro

gram might need to generate two dierent C programs for two dierent target

architectures For example a C program generated for a machine without

oatingp oint instructions would b e dierent from a C program generated for

a machine without oatingp oint instructions

Our goal contrasts sharply with write once run anywhere the goal of such dis

tribution formats as Java class les Juice les Franz and ANDF or Ten

DRA Macrakis These formats are abstractions of highlevel languages

not of underlying machines Their purp ose is binary p ortability and they re

tain enough highlevel language semantics to p ermit eective compilation at the

remote installation site

Even though C exp oses a few architecturespecic details like word size the

whole p oint is to hide those details so that the front end job can largely inde

p endent of the target architecture A go o d C implementation therefore must

do substantial architecturedependent work For example

Register allo cation

Instruction selection exploiting complex instructions and addressing mo des

Instruction scheduling

Stackframe layout

Classic backend optimisations such as commonsub expression elimination

and copy propagation

Ifconversion for predicated architectures

Given these requirements C resembles a typical compilers intermediate lan

guage more than a typical machines assembly language

Types

C supp orts a bare minimum of data types a family of bits types bits

bits bits bits and a family of oatingp oint types float float

float These types enco de only the size in bits and the kind of register

generalpurp ose or oatingp oint required for the datum

Not all types are available on all machines for example a C program emitted

by a frontend compiler for a bit machine might b e rejected if fed to a C

implementation for a bit machine It is easy to tell a front end how big to

make its data types and doing so makes the front ends job easier in some ways

for example it can compute osets statically

The bits types are used for characters bit vectors integers and addresses

p ointers On each architecture a bits type is designated the native word

type of the machine A native codepointer type and native datapointer

type are also designated exp orted and imp orted names must have one of these

p ointer types On many machines all three types are the same eg bits

Static allo cation

C oers detailed control of static memory layout much as ordinary assem

blers do A data blo ck consists of a sequence of lab els initialised data values

uninitialised arrays and alignment directives For example

data

foo bits One bits initialised to

bits Four initialised bitss

bits Uninitialised array of bitss

baz

baz bits An uninitialised byte

end

Here foo is the address of the rst bits baz and baz are b oth the address

of the bits and end is the address of the byte after the bits The lab els

foo baz etc should b e thought of as addresses not as memory lo cations

They are all immutable constants of the native datap ointer type they cannot

b e assigned to

How then can one access the memory at lo cation foo Memory accesses loads

and stores are typed and denoted with square brackets Thus the statement

bitsfoo bitsfoo

loads a bits from the lo cation whose address is in foo adds one to it and

stores it at the same lo cation The mnemonic for this syntax is to think of bits

as a Clike array representing all of memory and bitsfoo as a particular

element of that array The semantics of the address is not Clike however the

expression in brackets is the byte address of the item Further foos type is

always the native datap ointer type the type of value stored at foo is sp ecied

by the load or store op eration itself So this is p erfectly legal

bitsfoo bitsfoo

This statement mo dies only the byte at address foo

Unlike C C has no implicit alignment or padding Therefore the address

relationships b etween the data items within a single data blo ck are machine

indep endent for example baz foo An explicit align directive provides

alignment where that is required

C supp orts multiple named data sections For example

data debug

This syntax declares the blo ck of data to b elong to the section named debug

Co de is by default placed in the section text and a data directive with no

explicit section name defaults to the section data Pro cedures can b e enclosed

in code mytext to place them in a named section mytext

C exp ects that when linking ob ject les the linker concatenates sections with

the same name For backwards compatibility with some existing linkers front

ends may wish to emit an alignment directive at the b eginning of each C

section C assigns no other semantics to the names of data sections but par

ticular implementations may assign machinedependent semantics For example

a MIPS implementation might assume that data in sections named rodata is

readonly

Pro cedures

C supp orts pro cedures that are b oth more and less general than C pro cedures

for example C pro cedures oer multiple results and full tail calls but they

have a xed number of arguments Sp ecically

A C pro cedure such as sp in Figure has parameters such as n and local

variables such as s and p Parameters and variables are mapp ed onto ma

chine registers where p ossible and only spilled to the stack when necessary

In this absolutely conventional way C abstracts away from the number of

machine registers actually available As with registers C provides no way

to take the address of a parameter or lo cal variable

C supp orts fully general tail calls identied as jumps Control do es not

return from jumps and C implementations must deallo cate the callers

stack frame b efore each jump For example the pro cedure sphelp in Fig

ure uses a jump to implement tail recursion

C supp orts pro cedures with multiple results just as it supp orts pro cedures

with multiple arguments Indeed a return is somewhat like a jump to a

pro cedure whose address happ ens to b e held in the topmost activation record

on the control stack rather than b eing sp ecied explicitly All the pro cedures

in Figure return two results pro cedure sp contains a call site for such a

pro cedure

A C pro cedure call is always a complete statement which passes expres

sions as parameters and assigns results to lo cal variables Although highlevel

languages allow a call to o ccur in an expression C forbids it For example

it is illegal to write

r f gx illegal

b ecause the result returned by gx cannot b e an argument to f Instead

one must write two separate calls

y gx

r fy

This restriction makes explicit the order of evaluation the lo cation of each

call site and the names and types of temp oraries used to hold the results

of calls For similar reasons assignments in C are statements not expres

sions and C op erators have no side eects In particular C provides no

analog of Cs p

To handle highlevel variables that cant b e represented using Cs primitive

types C can b e asked to allo cate named areas in the pro cedures activation

record

f bits x

bits y

stack p bits

q bits

Here p and q are the addresses of the relevant chunks

of data Their type is the native datapointer type

stack is rather like data it has the same syntax b etween the braces but it

allo cates on the stack As with data the names are b ound to the addresses

of the relevant lo cations and they are immutable C makes no provision

for dynamicallysized stack allo cation yet

The name of a pro cedure is a C expression of native co dep ointer type The

pro cedure sp ecied in a call statement can b e an arbitrary expression not

simply the staticallyvisible name of a pro cedure For example the following

statements are b oth valid assuming the pro cedure sp is dened in this

compilation unit or imp orted from another one

bitsptr sp Store procedure address

rs bitsptr Call stored procedure

A C pro cedure like sp in Figure may contain gotos and lab els but

they serve only to al low a textual representation of the controlow graph

Unlike pro cedure names lab els are not values and they have no represen

tation at run time Because this restriction makes it imp ossible for front

ends to build jump tables from lab els C includes a switch statement for

which the C back end generates ecient co de The most ecient mix of

conditional branches and indexed branches may dep end on the architecture

Bernstein

Jump tables of pro cedure addresses rather than lab els can b e built of

course and a C pro cedure can use the jump statement to make a tail call

to a computed address

Calling conventions

The calling convention for C pro cedures is entirely a matter for the C imple

mentation we call it the standard C calling convention In particular C

need not use the C calling convention

The standard calling convention places no restrictions on the number of argu

ments passed to a function or the number of results returned from a function The

only restrictions are that the number and types of actual parameters must match

those in the pro cedure declaration and similarly that the number and types of

values returned must match those exp ected at the call site These restrictions en

able ecient calling sequences with no dynamic checks A C implementation

need not check that C programs meet these restrictions

We note the following additional p oints

If a C function do es not escap e if all sites where it is called can

b e identied statically then the C back end is free to create and use

sp ecialised instances with sp ecialised calling conventions for each call site

Escap e analysis is necessarily conservative but a function may b e deemed

to escap e only if its name is used other than in a call or if it is named in

an export directive

Supp ort for unrestricted tail calls requires an unusual calling convention so

that a pro cedure making a tail call can deallo cate its activation record while

still leaving ro om for parameters that do not t in registers

C allows the programmer to sp ecify a particular calling convention chosen

from a small set of standard conventions for an individual pro cedure so that

C co de can interoperate with foreign co de For example even though Cs

standard calling convention may dier from Cs one can ask for a particular

pro cedure to use Cs convention so that the pro cedure can b e called from

an external C program Similarly external C pro cedures can b e called from

a C pro cedure by sp ecifying the calling convention at the call site

Some C implementations may provide two versions of Cs calling conven

tion The lightweight version would b e like an ordinary C call but it would b e

useful only when the C pro cedures terminate quickly if control were trans

ferred to the runtime system while a C pro cedure was active the runtime

system might not b e able to nd values that were in calleesaves registers

at the time of the call The heavyweight version would keep all its state on

the stack not in calleesaves registers so the runtime system could handle

a stack containing a mix of C and C activations

Miscellaneous

Like other assemblers C gives programmers the ability to name compiletime

constants eg by

const GC

C variables may b e declared global in which case the C compiler attempts

to put them in registers For example given the declaration

global

bits hp

the implementation attempts to put variable hp in a register but if no register

is available it puts hp in memory C programs use and assign to hp without

knowing whether it is in a register or in memory Unlike storage allo cated by

data there is no such thing as the address of a global so memory stores to

unknown addresses cannot aect the value of a global This p ermits a global to b e

held in a register and even if it has to b e held in memory the optimiser do es not

need to worry ab out reloading it after a store to an unknown memory address

All separately compiled mo dules must have identical global declarations or

horribly strange things will happ en

global declarations may name sp ecic implementationdependent registers

for example

global

bits hp ebx

bits hplim esi

We remarked in Section that the front end may know a great deal ab out

lack of aliasing b etween memory access op erations We do not yet have a way

to express such knowledge in C but an adaptation of Novack Hummel and

Nicolau lo oks promising

The problem of runtime supp ort

When a front end and back end are written together as part of a single compiler

they can co op erate intimately to supp ort highlevel runtime services such as

garbage collection exception handling proling concurrency and debugging In

the C framework the front and back ends work at arms length As mentioned

earlier our guiding principle is this

C should make it possible to implement highlevel runtime services

but it should not actually implement any of them Rather it should

provide just enough ho oks to allow the frontend runtime system to

implement them

Separating policy from mechanism in this way is easier said than done It might

app ear more palatable to incorp orate garbage collection exception handling

and debugging into the C language as say the Java Virtual Machine do es

But doing so would guarantee that C would never b e used Dierent source

languages require dierent supp ort dierent ob ject layouts and dierent excep

tion semantics esp ecially when p erformance matters No one back end could

satisfy all customers

Why is the separation b etween front and back end hard to achieve Highlevel

runtime services need to inspect and modify the state of a suspended program A

garbage collector must nd and p erhaps mo dify all live p ointers An exception

handler must navigate and p erhaps unwind the call stack A proler must

correlate ob jectco de lo cations with sourceco de lo cations and p ossibly navigate

the call stack A debugger must allow the user to insp ect and p erhaps mo dify

the values of variables All of these tasks require information from b oth front

and back ends The rest of this section elab orates

Finding ro ots for garbage collection If the highlevel language requires ac

curate garbage collection then the garbage collector must b e able to nd all

the roots that p oint into the heap If furthermore the collector supp orts

compaction the lo cations of heap ob jects may change during garbage col

lection and the collector must b e able to redirect each ro ot to p oint to the

new lo cation of the corresp onding heap ob ject

The diculty is that neither the front end nor the back end has all the knowl

edge needed to nd ro ots at run time Only the front end knows which source

language variables and therefore which C variables represent p ointers into

the heap Only the back end which maps variables to registers and stack

slots knows where those variables are lo cated at run time Even the back

end cant always identify exact lo cations variables mapp ed to calleesaves

registers may b e saved arbitrarily far away in the call stack at lo cations not

identiable until run time

Printing values in a debugger A debugger needs compiler supp ort to print

the values of variables For this task information is divided in much the

same way as for garbage collection Only the front end knows how source

language variables are mapp ed onto collections of C variables Only the

front end knows how to print the value of a variable eg as determined by

the variables highlevellanguage type Only the back end knows where to

nd the values of the C variables

Lo ci of control A debugger must b e able to identify the lo cus of control in

each activation and to asso ciate that lo cus with a sourceco de lo cation This

asso ciation is used b oth to plant breakp oints and to rep ort the sourceco de

lo cation when a program faults

An exception mechanism also needs to identify the lo cus of control b ecause

in some highlevel languages that lo cus determines which handler should

receive the exception When it identies a handler the exception mechanism

unwinds the stack and changes the lo cus of control to refer to the handler

A proler must map lo ci of control into entities that are proled pro cedures

statements sourceco de regions etc

At run time lo ci of control are represented by values of the program counter

eg return addresses but at the source level lo ci of control are asso ciated

with statements in a highlevel language or in C Only the front end knows

how to asso ciate highlevel source lo cations or exceptionhandler scop es with

C statements Only the back end knows how to asso ciate C statements

with the program counter

Liveness Dep ending on the semantics of the original source language the lo cus

of control may determine which variables of the highlevel language are vis

ible Dep ending on the optimizations p erformed by the back end the lo cus

of control may determine which C variables are live and therefore have

values Debuggers should not print dead variables Garbage collectors should

not trace them tracing dead p ointers could cause space leaks Worse trac

ing a register that once held a ro ot but now holds a nonp ointer value could

violate the collectors invariants Again only the front end knows which vari

ables are interesting for debugging or garbage collection but only the back

end knows which are live at a given lo cus of control

Exception values In addition to unwinding the stack and changing the lo cus

of control the exception mechanism may have to communicate a value to an

exception handler Only the front end knows which variable should receive

this value but only the back end knows where variables are lo cated

Succinctly stated each of these op erations must combine two kinds of informa

tion

Information that only the front end has

Which C parameters and lo cal variables are heap p ointers

How to map sourcelanguage variables to C variables and how to as

so ciate sourceco de lo cations with C statements

Which exception handlers are in scop e at which C statements and

which variables are visible at which C statements

Information that only the back end has

Whether each C lo cal variable and parameter is live where it is lo

cated if live and how this information changes as the program counter

changes

Which programcounter values corresp ond to which C statements

How to nd activations of all active pro cedures and how to unwind

stacks

Supp ort for highlevel runtime services

The main challenge then is arranging for the back end and front end to share

information without having to implement them as a single integrated unit In

this section we describ e a framework that allows this to b e done We fo cus on

garbage collection as our illustrative example Other highlevel runtime services

can t in the same framework but each requires servicesp ecic extensions we

sketch some ideas in Section

In what follows we use the term variable to mean either a parameter of the

pro cedure or a lo callydeclared variable

The framework

We assume that executable programs are divided into three parts each of which

may b e found in ob ject les libraries or a combination

The front end compiler translates the highlevel source program into one or

more C mo dules which are separately translated to generated object code

by the C compiler

The front end comes with a probably large frontend runtime system

This runtime system includes the garbage collector exception handler and

whatever else the source language needs It is written in a programming

language designed for humans not in C in what follows we assume that

the front end runtime system is written in C

Every C implementation comes with a hop efully small C runtime sys

tem The main goal of this runtime system is to maintain and provide access

to information that only the back end can know It makes this information

available to the front end runtime system through a Clanguage runtime

interface which we describ e in Section Dierent front ends may inter

op erate with the same C runtime system

To make an executable program we link generated ob ject co de with b oth run

time systems

In outline C can supp ort highlevel runtime services such as garbage collec

tion as follows When garbage collection is required control is transferred to

the frontend runtime system Section The garbage collector then walks

the C stack by calling access routines provided by the C runtime system

Section In each activation record on the C stack the garbage collector

nds the lo cation of each live variable using further pro cedures provided by

the C runtime However the C runtime cannot know which of these vari

ables holds a p ointer To answer this question the frontend compiler builds a

staticallyallo cated data blo ck that identies p ointer variables and it uses a span

directive Section to asso ciate this data blo ck with the corresp onding pro

cedures range of program counter values The garbage collector combines these

two sources of information to decide whether to treat the pro cedures variable

as a ro ot Section describ es one p ossible garbage collector in more detail

The C runtime interface

This section presents the core runtime interface provided by the C runtime

system Using this interface a frontend runtime system can insp ect and mo dify

the state of a susp ended C computation Rather than sp ecify representations of

a susp ended computation or its activation records we hide them b ehind simple

abstractions These abstractions are presented to the frontend runtime system

through a set of C pro cedures

The state of a C computation consists of some saved registers and a logical

stack of pro cedure activations This logical stack is usually implemented as some

sort of physical stack but the corresp ondence b etween the two may not b e very

direct Notably calleesaves registers that logically b elong with one activation are

not necessarily stored with that activation or even with the adjacent activation

they may b e stored in the physical record of an activation that is arbitrarily

far away This problem is the reason that Cs setjmp and longjmp functions

dont necessarily restore calleesaves registers which is why some C compilers

make p essimistic assumptions when compiling pro cedures containing setjmp

Harbison and Steele x

We hide this complexity b ehind a simple abstraction the activation The idea of

an activation of pro cedure P is that it approximates the state the machine wil l

be in when control returns to P The approximation is not completely accurate

b ecause other pro cedures may change the global store or Ps stack variables

b efore control returns to P At the machine level the activation corresp onds to

the abstract memory of Ramsey Chapter which gives the contents

of memory including Ps activation record stack frame and of registers

The activation abstraction hides machinedependent details and raises the level

of abstraction to the C sourceco de level In particular the abstraction hides

The layout of an activation record and the enco ding used to record that

layout for the b enet of the front end runtime

The details of manipulating calleesaves registers whether to use callee saves

registers is entirely up to the C implementation and

The direction in which the stack grows

All of these matters b ecome private to the back end and the C runtime

In the C runtime interface an activation record is represented by an activation

hand le which is a value of type activation Arbitrary registers and memory

addresses are represented by variables which are referred to by number

The pro cedures in the C runtime interface include

void FindVar activation a int varindex asks an activation han

dle for the lo cation of any parameter or lo cal variable in the activation

record to which the handle refers The variables of a pro cedure are indexed

by numbering them in the order in which they are declared in that pro cedure

starting with zero FindVar returns the address of the lo cation containing

the value of the sp ecied variable The front end is thereby able to examine

or mo dify the value FindVar returns NULL if the variable is dead It is a

checked runtime error to pass a varindex that is out of range

void FirstActivation tcb t activation a When execution of a

C program is susp ended its state is captured by the C runtime sys

tem FirstActivation uses that state to initialise an activation handle that

corresp onds to the pro cedure that will execute when the programs execution

is resumed

int NextActivation activation a mo dies the activation handle a to

refer to the activation record of as caller or more precisely to the activa

tion to which control will return when a returns NextActivation returns

nonzero if there is such an activation record and zero if there is not That is

NextActivationa returns zero if and only if activation handle a refers

to the b ottommost record on the C stack

Notice that FindVar always returns a p ointer to a memory lo cation even though

the sp ecied variable might b e held in a register at the moment at which gar

bage collection is required But by the time the garbage collector is walking the

stack the C implementation must have stored all the registers away in mem

ory somewhere and it is up to the C runtime system to gure out where the

variable is and to return the address of the lo cation holding it

Names b ound by stack declarations are considered variables for purp oses of

FindVar even though they are immutable For such names FindVar returns

the value that the name has in C source co de ie the address of the stack

allo cated blo ck of storage Storing through this address is meaningful it alters

the contents of the activation record a Stack lo cations are not sub ject to liveness

analysis

Frontend information

Supp ose the garbage collector is examining a particular activation record It can

use FindVar to lo cate variable number but how can it know whether that

variable is a p ointer The front end compiler co op erates with C to answer this

question as follows

The front end builds a static initialised data blo ck Section or descrip

tor that says which of the parameters and lo cal variables of a pro cedure are

heap p ointers The format of this data blo ck is known only to the frontend

compiler and runtime system the C runtime system do es not care

The front end tells C to asso ciate a particular range of program counters

with this descriptor using a span directive

The C runtime system provides a call GetDescriptor that maps an

activation handle to the descriptor asso ciated with the program counter at

which the activation is susp ended

We discuss each of these steps in more detail As an example supp ose we have

a function fx y with no other variables in which x holds a p ointer into

the heap and y holds an integer The front end can enco de the heapp ointer

information by emitting a data blo ck or descriptor asso ciating with x and

with y

data

gc bits this procedure has two variables

bits x is a pointer

bits y is a nonpointer

This enco ding do es not use the names of the variables instead each variable is

assigned an integer index based on the textual order in which it app ears in the

denition of f Therefore x has index and y has index

Many other enco dings are p ossible The front end might emit a table that uses

one bit p er variable instead of one byte It might emit a list of the indices of

variables that contain p ointers It might arrange for p ointer variables to have

1

continuous indices and emit only the rst and last such index The key prop erty

of our design is that the encoding matters only to the front end and its runtime

system C do es not know or care ab out the enco ding

To asso ciate the garbagecollection descriptor with f the front end places the

denition of f in a C span

span GC gc

f bits x bits y

code for f

A span may apply to a sequence of function denitions or to a sequence of

statements within a function denition In this case the span applies to all of f

There may b e several indep endent span mappings in use simultaneously eg

one for garbage collection one for exceptions one for debugging and so on

C uses integer tokens to distinguish these mappings from one another GC is

the token in the example ab ove C takes no interest in the tokens it simply

provides a map from a token PC pair to an address Token values are usually

dened using a const declaration Section

When the garbage collector say walks the stack using an activation handle a

it can call the following C runtime pro cedure

void GetDescriptor activation a int token returns the address of

the descriptor asso ciated with the smallest C span tagged with token and

containing the program p oint where the activation a is susp ended

There are no constraints on the form of the descriptor that gc lab els that form

is private to the front end and its runtime system All C do es is transform

span directives into mappings from program counters to values

The front end may emit descriptors and spans to supp ort other services not just

garbage collection For example to supp ort exception handling or debugging the

front end may record the scop es of exception handlers or the names and types

of variables C supp orts multiple spans but they must not overlap Spans can

nest however the innermost span b earing a given token takes precedence One

can achieve the eect of overlapping by binding the same data blo ck to multiple

spans

1

This scenario presumes the front end has the privilege of reordering parameters

otherwise it would have to use some other scheme for parameters

Garbage collection

This section explains in more detail how the C runtime interface might b e used

to help implement a garbage collector Our primary concern is how the collector

nds and p ossibly up dates ro ots Other tasks such as nding p ointers in heap

ob jects and compacting the heap can b e managed entirely by the frontend

runtime system allo cator and collector with no supp ort from the back end

C takes no resp onsibility for heap p ointers passed to co de written in other

languages It is up to the front end to pin such p ointers or to negotiate changing

them with the foreign co de We defer until Section the question of how control

is transferred from running C co de to the garbage collector

To help the collector nd ro ots in global variables the front end can arrange to

dep osit the addresses of such variables in a sp ecial data section To nd ro ots in

lo cal variables the collector must walk the activation stack For each activation

handle a it calls GetDescriptora GC to get the garbagecollection descrip

tor dep osited by the front end The descriptor tells it how many variables there

are and which contain p ointers For each p ointer variable it gets the address

of that variable by calling FindVar If the result is NULL the variable is dead

and need not b e traced Otherwise the collector marks or moves the ob ject the

variable p oints to and it may redirect the variable to p oint to the ob jects new

lo cation Note that the collector need not know which variables were stored on

the stack and which were kept in calleesaves registers FindVar provides the

lo cation of the variable no matter where it is Figure shows a simple copying

collector based on App el targeted to the C runtime interface and the

descriptors shown in Section

A more complicated collector might have to do more work to decide which vari

ables represent heap p ointers TIL is the most complicated example we know of

Tarditi et al In TIL whether a parameter is a p ointer may dep end on

the value of another parameter For example a C pro cedure generated by TIL

might lo ok like this

f bits ty bits a bits b

The rst parameter ty is a p ointer to a heapallo cated type record It is not

statically known however whether a is a heap p ointer At run time the rst eld

of the type record that ty p oints to describ es whether a is a p ointer Similarly

the second eld of the type record describ es whether b is a p ointer

To supp ort garbage collection we attach to fs b o dy a span that p oints to a

statically allo cated descriptor which enco des precisely the information in the

preceding How this enco ding is done is a private matter b etween the

front end and the garbage collector even this rather complicated situation is

easily handled with no further supp ort from C

struct gcdescriptor

unsigned varcount

char heapptr

void gcvoid

activation a

FirstActivationtcb a

for

struct gcdescriptor d GetDescriptora GC

if d NULL

int i

for i i dvarcount i

if dheapptri

typedef void pointer

pointer rootp FindVara i

if rootp NULL rootp gcforwardrootp

copying forward as in Appel if live

if NextActivationa NULL

break

gccopy fromspace to tospace as in Appel

Fig Part of a simple copying garbage collector

Implementing the C runtime interface

Can spans and the C runtime interface b e implemented eciently By sketch

ing a p ossible implementation we argue that they can Because the implementa

tion is private to the back end and the backend runtime system there is wide

latitude for exp erimentation Any technique is acceptable provided it implements

the semantics ab ove at reasonable cost We argue b elow that wellunderstoo d

techniques do just that

Implementing spans The span mappings of Section take their inspi

ration from table mappings for exception handling and the key pro cedure

GetDescriptor can b e implemented in similar ways a The main

challenge is to build a mapping from ob jectco de lo cations p ossible values of the

program counter to sourceco de lo cation ranges spans The most common way

is to use tables sorted by program counter If suitable linker supp ort is available

tables for dierent tokens can go in dierent sections and they will automat

ically b e concatenated at link time Otherwise tables can b e chained together

or consolidated by an initialisation pro cedure called when the program starts Bottom of stack

Activation handle Activation Pointer to an record activation record

Pointer to first callee-save register

Pointer to second callee-save register

Top of stack

The activation handle p oints to an activation record which

may contain values of some lo cal variables Other lo cal vari

ables may b e stored in calleesaves registers in which case

their values are not saved in the current activation record

but in the activation records of one or more called pro cedures

These activation records cant b e determined until run time

so the stack walker incrementally builds a map of the lo ca

tions of calleesave registers by noting the saved lo cations of

each pro cedure

Fig Walking a stack

Implementing stack walking In our sketch implementation the call stack is

a contiguous stack of activation records An activation handle is a static record

consisting of a p ointer to an activation record on the stack together with p ointers

2

to the lo cations containing the values that the nonvolatile registers had at the

moment when control left the activation record Figure FirstActivation

initialises the activation handle to p oint to the topmost activation record on the

stack and to the private lo cations in the C runtime that hold the values of

registers Dep ending on the mechanism used to susp end execution the runtime

2

The nonvolatile registers are those registers whose values are unchanged after return

from a pro cedure call They include not only the classic calleesaves registers but

also registers like the frame p ointer which must b e saved and restored but which

arent always thought of as calleesaves registers

might have values of all registers or only of nonvolatile registers but this detail

is hidden b ehind the runtime interface Ramsey discusses retargetable

stack walking in Chapters and

The runtime system executes only when execution of C pro cedures is sus

p ended We assume that C execution is susp ended only at a safe p oint

Broadly sp eaking a safe p oint is a p oint at which the C runtime system is

guaranteed to work we discuss the details in Section For each safe p oint

the C co de generator builds a staticallyallo cated activationrecord descriptor

that gives

The size of the activation record NextActivation can use this to move to

the next activation record

The liveness of each lo cal variable and the lo cations of live variables indexed

by variable number The lo cation of a live variable might b e an oset

within the activation record or it might b e the name of a calleesaves register

GetVar uses this lo cation to nd the address of the true memory lo cation

containing the variables value either by computing an address within the

activation record itself or by returning the address of the lo cation holding

the appropriate calleesaves register as recorded in the activation handle

Figure

If the safe p oint is a call site the lo cations where the callee is exp ected to

put results returned from the call

The lo cations where the callers calleesaves registers may b e found Again

these may b e lo cations within the activation record or they may b e this

activations calleesaves registers NextActivation uses this information to

up date the p ointerstocalleesavesregisters in the activation handle

The C runtime can map activations to descriptors using the same mechanism

it uses to implement the span mappings of Section The runtime interface

can cache these descriptors in the activation handle so the lo okup need b e done

only when NextActivation is called ie when walking the stack An alternative

that avoids the lo okup is to store a p ointer to the descriptor in the co de space

immediately following the call and for the call to return to the instruction after

the p ointer The SPARC C calling convention uses a similar trick for functions

returning structures SPARC App endix D

The details of descriptors and mapping of activations to descriptors are im

p ortant for p erformance At issue is the space overhead of storing descriptors

and maps and the time overhead of nding descriptors that corresp ond to PCs

Liskov and Snyder suggests that sharing descriptors b etween dierent call

sites has a signicant on p erformance Because these details are private

b etween the back end and the backend runtime system we can exp eriment

with dierent techniques without changing the approach the runtime interface

or the front end

Rening the design

The basic idea of providing a runtime interface that allows the state of a sus

p ended C computation to b e insp ected and mo died seems quite exible and

robust But working out the detailed application of this idea to a variety of

runtime services and sp ecifying precisely what the semantics of the resulting

language is remains challenging In this section we elab orate some of the de

tails that were not covered in the preceding section and discuss mechanisms

that supp ort runtime services other than garbage collection Our design is not

nalised so this section is somewhat sp eculative

Susp ension and introspection

All our intended highlevel runtime services must b e able to susp end a C

computation insp ect its state and mo dify it b efore resuming execution

In many implementations of highlevel languages the runtime system runs on

the same physical stack as the program itself In such implementations walking

the stack or unwinding the stack requires a thorough understanding of system

calling conventions esp ecially if an interrupt can cause a transfer of control

from generated co de to the runtime system We prefer not to exp ose this im

plementation technique through the C runtime interface but to take a more

abstract view The C runtime therefore op erates as if the generated co de and

the runtime system run on separate stacks as separate threads

The system thread runs on the system stack supplied by the op erating sys

tem The frontend runtime system runs in the system thread and it can

easily insp ect and mo dify the state of the C thread

The C thread runs on a separate C stack When execution of the C

thread is susp ended the state of the C thread is saved in the C thread

control block or TCB

We have to say how a C thread is created and how control is transferred

b etween the system thread and a C thread

The system thread calls InitTCB to create a new thread In addition to pass

ing the program counter for a C pro cedure without parameters the system

thread must provide space for a stack on which the thread can execute as

well as space for a threadcontrol blo ck

The system thread calls Resume to transfer control to a susp ended C

thread

Execution of a C thread continues until that thread calls the C pro cedure

yield which susp ends execution of the C thread and causes a return from

the system threads Resume call The C thread passes a yield code which

is returned as the result of Resume

For example garbage collection can b e invoked via a call to yield when the

allo cator runs out of space Here is how the co de might lo ok if allo cation takes

place in a single contiguous area p ointed to by a heap p ointer hp and b ounded

by heaplimit

f bits abc

while hp heaplimit

yield GC Need to GC

hp hp

It may seem unusual even undesirable to sp eak of two threads in a completely

sequential setting In a more tightlyintegrated system it would b e more usual

simply to call the garbage collector But simply making a foreign call to the

garbage collector will not work here How is the garbage collector to nd the top

of the C p ortion of the stack that it must traverse What if live variables such

as a b c are stored in Cs calleesaves registers across the call to the garbage

collector Such complications aect not only the garbage collector but any high

level runtime service that needs to walk the stack Our twothread conceptual

mo del abstracts away from these complications by allowing the system thread

to insp ect and mo dify a tidily frozen C thread

Using threads do es not imply a high implementation cost Though we call

them threads coroutines may b e a more accurate term The system thread

never runs concurrently with the C thread and the two can b e implemented

by a single op eratingsystem thread

Another merit of this twothread view is that it extends smo othly to accommo

date multiple C threads Indeed though it is not the fo cus of this pap er we

intend that C should supp ort many very lightweight threads in the style of

Concurrent ML Reppy Concurrent Haskell Peyton Jones Gordon and

Finne and many others

Safe p oints

When can the system thread safely take control We say a programcounter

value within a pro cedure is a safe if it is safe to susp end execution of the

pro cedure at that p oint and to insp ect and mo dify its variables We require the

following precondition for execution in the frontend runtime system

A C thread can b e susp ended only at a safe p oint

A call to yield must b e a safe p oint and b ecause any pro cedure could call

yield the co de generator must ensure that every call site is a safe p oint This

safe p oint is asso ciated with the state in which the call has b een made and

the pro cedure is susp ended awaiting the return C do es not guarantee that

every instruction is a safe p oint recording lo calvariable liveness and lo cation

information for every instruction might increase the size of the program by a

signicant fraction Stichnoth Lueh and Cierniak

So far we have suggested that a C program can only yield control voluntarily

through a yield call What happ ens if an interrupt or fault o ccurs transferring

control to the frontend runtime system and the currently executing C pro

cedure is not at a safe p oint This may happ en if a user delib erately causes an

interrupt eg to request that the stack b e unwound or the debugger invoked It

may happ en if a hardware exception eg divide by zero is to b e converted to

a software exception It may happ en in a concurrent program if timer interrupts

are used to preempt threads The answer to the question remains a topic for

research asynchronous preemption is dicult to implement not only in C but

in any system Chase b and Shivers Clark and McGrath discuss

some of the problems One common technique is to ensure that every lo op is

cut by a safe p oint and to p ermit an interrupted program to execute until it

reaches a safe p oint C therefore enables the front end to insert safe p oints by

inserting the C statement

safepoint

Callsite invariants

In the presence of garbage collection and debugging calls have an unusual prop

erty live local variables are potentially modied by any call For example a com

pacting garbage collector might mo dify p ointers saved across a call Consider

this function in which a is a common sub expression

f bits a

bitsa put in bit word at address a

g a

bitsa put in bit word at address a

return

If g invokes the garbage collector the collector might mo dify a during the call

to g so the co de generator must recompute a after the call it would b e

unsafe to save a across the call The same constraint supp orts a debugger that

might change the values of lo cal variables Calls may also mo dify C values that

are declared to b e allo cated on the stack

A compiler writer might reasonably ob ject to the p erformance p enalty imp osed

by this constraint the back end pays for compacting garbage collection whether

the front end needs it or not To eliminate this p enalty the front end can

mark C parameters and variables as invariant across calls using the keyword

invariant thus

f invariant bits a

invariant bits b

bits c

g a b c a and b are not modified

by the call but c might be

The invariant keyword places an obligation on the frontend runtime system

not on the caller of f The keyword constitutes a promise to the C compiler

that the value of an invariant variable will not change unexp ectedly across a

call The runtime system and debugger may not change the values of invariant

variables

If variables will not b e changed by a debugger a front end can safely mark non

p ointer variables as invariant across calls and front ends using mostlycopying

collectors Bartlett Bartlett a or noncompacting collectors Bo ehm

and Weiser can safely mark al l variables as invariant across calls

Exceptions and other services

In Section we argued that many highlevel runtime services share at least

some requirements in common In general they all need to susp end a running

C thread and to insp ect and mo dify its state The spans of Section and the

runtime interface of Section provide this basic service but each highlevel

runtime service requires extra sp ecialpurp ose supp ort Garbage collection is

enhanced by the invariant annotation of Section Exception handling re

quires rich mechanisms for changing the ow of control Interruptbased proling

requires the ability to insp ect alb eit in a very mo dest way the state of a thread

interrupted asynchronously Debugging requires all of the ab ove and more b e

sides We b elieve that our design can b e extended to deal with these situations

and that many of Cs capabilities will b e used by more than one highlevel

service Here we give an indicative discussion of just one other service exception

handling

Making a single back end supp ort a variety of dierent exceptionhandling mech

anisms is signicantly harder than supp orting a variety of garbage collectors in

part b ecause exceptions alter the control ow of the program If raising an ex

ception could change the program counter arbitrarily chaos would ensue two

dierent program p oints may hold their live variables in dierent lo cations and

they may have dierent ideas ab out the layout of the activation record and

the contents of calleesaves registers They may even have dierent ideas ab out

which variables are alive and which are dead In other words unconstrained

dynamic changes in lo cus of control make life hard for the register allo cator and

the optimiser if the program counter can change arbitrarily there is no such

thing as dead co de and a variable live anywhere is live everywhere

Typically handling an exception involves rst unwinding the stack to the caller

of the current pro cedure or its caller etc and then directing control to an excep

tion handler Many of the mechanisms used for garbage collection are also useful

for exception handling for example stack walking and spans can b e used to nd

exactly which handler should catch a particular exception But the mechanisms

we have describ ed so far dont allow for changes in control ow C controls

such changes by requiring annotations on pro cedure calls

The key idea is that in the presence of exceptions a call might return to more

than one location and every C program species explicitly al l the locations to

which a call could return In eect a call has many p ossible continuations instead

of just one When an activation is susp ended at a call site three outcomes are

p ossible

The call returns normally and execution continues at the statement following

the call

The call raises an exception that is handled in the activation so the call

terminates by transferring control to a dierent lo cation in that activation

The call raises an exception that is not handled in the current activation

so the activation is ab orted and the runtime system transfers control to a

handler in some calling pro cedure

Cs callsite annotations sp ecify these outcomes in detail

We are currently rening a design that supp orts suitable annotations plus a

variety of mechanisms for transfer of control Ramsey and Peyton Jones

Exception dispatch might unwind the stack one frame at a time lo oking for

a handler or it might use an auxiliary data structure to nd the handler then

cut the stack directly to that handler in constant time Our design also p ermits

exception dispatch to b e implemented either in the frontend runtime system

or in generated co de The C runtime system provides supp orting pro cedures

that can unwind the stack change the address to which a call returns and pass

values to exception handlers

Status and conclusions

The core design of C is stable and an implementation based on MLRISC

is freely available from the authors This implementation supp orts the features

describ ed in Section but it do es not yet include the span directive or a C

runtime system

Many op en questions remain What small set of mechanisms might supp ort the

entire gamut of highlevel language exception semantics How ab out the range of

known implementation techniques Supp ort for debugging is even harder than

dealing with exceptions Exactly what is the meaning of a breakp oint How

should breakp oints interact with optimization What are the primitive ho oks

required for concurrency supp ort How should C cop e with preemption

These questions are not easily answered but the prize is considerable Reuse

of co de generators is a critically imp ortant problem for language implementors

Co de generators embedded in C compilers have b een widely reused but the

nature of C makes it imp ossible to use the b est known implementations of high

level runtime services like garbage collection exception handling debugging

and concurrency C imp oses a ceiling on reuse

We hop e to break through this ceiling by taking a new approach design a low

level reusable compilertarget language in tandem with a lowlevel reusable

runtime system Together C and its runtime system should succeed in hiding

machinedependent details of calling conventions and stackframe layout They

should eliminate the distinction b etween variables living in registers and variables

living on the stack By doing so they should

Permit sophisticated register allo cation even in the presence of a garbage

collector or debugger

Make the results of liveness analyses available at run time eg to a garbage

collector

Supp ort the b est known garbagecollection techniques and p ossibly enable

exp erimentation with new techniques

Although the details are b eyond the scop e of this pap er we have some reason to

b elieve C can also supp ort the b est known techniques for exception handling

as well as supp orting proling concurrency and debugging

Acknowledgements

We thank Xavier Leroy Simon Marlow Gopalan Nadathur Mike ODonnell

and Julian Seward for their helpful feedback on earlier drafts of this pap er We

also thank Richard Black Lal George Thomas Johnsson Greg Morrisett Nikhil

Olin Shivers and David Watt for feedback on the design of C

References

App el Andrew W February Simple generational garbage collection and

fast allo cation SoftwarePractice Experience

Atkinson Russ Alan Demers Carl Hauser Chnristian Jacobi Peter Kessler

and Mark Weiser July Exp eriences creating a p ortable Cedar

Proceedings of the SIGPLAN Conference on Programming Language

Design and Implementation SIGPLAN Notices

Bartlett Jo el F February Compacting garbage collection with ambigu

ous ro ots Technical Rep ort DEC WRL Hamilton Avenue Palo

Alto California

a Octob er Mostlycopying garbage collection picks up generations

and C Technical Rep ort TN DEC WRL Hamilton Avenue Palo

Alto California

b SCHEME to C A p ortable SchemetoC compiler Technical

Rep ort RR DEC WRL

Benitez Manuel E and Jack W Davidson July A p ortable global opti

mizer and linker In ACM Conference on Programming Languages Design

and Implementation PLDI pages ACM

Benton Nick Andrew Kennedy and George Russell September Com

piling Standard ML to Java bytecodes In ACM Sigplan International Con

ference on Functional Programming ICFP pages Balitmore

Bernstein Rob ert L Octob er Pro ducing go o d co de for the case state

ment Software Practice and Experience

Bo ehm HansJuergen and Mark Weiser September Garbage collec

tion in an unco op erative environment Software Practice and Experience

Chase David a June Implementation of exception handling Part I The

Journal of C Language Translation

b September Implementation of exception handling Part I I

Calling conventions asynchrony optimizers and debuggers The Journal

of C Language Translation

Clausen LR and O Danvy April Compiling prop er tail recursion and

rstclass continuations Scheme on the Java virtual machine Technical

rep ort Department of Computer Science University of Aarhus BRICS

Conway ME Octob er Prop osal for an UNCOL Communications of the

ACM

Diwan A D Tarditi and E Moss January Memory subsystem p erfor

mance of programs using copying garbage collection In st ACM Sym

posium on Principles of Programming Languages POPL pages

Charleston ACM

Franz Michael Octob er Beyond Java An infrastructure for high

p erformance mobile co de on the World Wide Web In Lob o dzinski S

and I Tomek editors Proceedings of WebNet World Conference of the

WWW Internet and Intranet pages Asso ciation for the Advance

ment of Computing in Education

George Lal MLRISC Customizable and reusable co de generators Un

published rep ort available from httpwwwcsbelllabscom george

Harbison Samuel P and Guy L Steele Jr C A Reference Manual fourth

edition Englewoo d Clis NJ Prentice Hall

Henderson Fergus Thomas Conway and Zoltan Somogyi Compiling

logic programs to C using GNU C as a p ortable assembler In ILPS

Postconference Workshop on Sequential Implementation Technologies for

Logic Programming pages Portland Or

Liskov Barbara H and Alan Snyder November Exception handling in

CLU IEEE Transactions on Software Engineering SE

Macrakis Stavros January The Structure of ANDF Principles and

Examples Op en Systems Foundation

Novack Steven Joseph Hummel and Alexandru Nicolau A Simple Mecha

nism for Improving the Accuracy and Eciency of Instructionlevel Disam

biguation chapter Lecture Notes in Computer Science Springer Verlag

Pettersson M Simulating tail calls in C Technical rep ort Department

of Computer Science Linkoping University

Peyton Jones Simon L A J Gordon and S O Finne January Con

current Haskell In rd ACM Symposium on Principles of Programming

Languages POPL pages St Petersburg Beach Florida

Peyton Jones SL D Oliva and T Nordin C A p ortable assembly

language In Proceedings of the Workshop on Implementing Func

tional Languages IFL Lecture Notes in Computer Science pages

Springer Verlag

Peyton Jones Simon L April Implementing lazy functional languages

on sto ck hardware The spineless tagless Gmachine Journal of Functional

Programming

Ramsey Norman and Simon L Peyton Jones Exceptions need not b e

exceptional Draft available from httpwwwcsvirginiaedunr

Ramsey Norman December A Retargetable Debugger PhD thesis

Princeton University Department of Computer Science Also Technical

Rep ort CSTR

Reig F and SL Peyton Jones The C manual Technical rep ort Depart

ment of Computing Science University of Glasgow

Reppy JH June CML a higherorder concurrent language In

ACM Conference on Programming Languages Design and Implementation

PLDI ACM

Serrano Manuel and Pierre Weis September Biglo o a p ortable and

optimizing compiler for strict functional languages In nd Static Analysis

Symposium Lecture Notes in Computer Science pages Glasgow

Scotland

Shivers Olin James W Clark and Roland McGrath September Atomic

heap transactions and negrain interrupts In ACM Sigplan International

Conference on Functional Programming ICFP Paris

SPARC International The SPARC Architecture Manual Version En

glewoo d Clis NJ Prentice Hall

Stallman Richard M February Using and Porting GNU CC Version

Free Software Foundation

Steele Guy L Jr May Rabbit A compiler for Scheme Technical Rep ort

AITR Articial Intelligence Lab oratory MIT Cambridge MA

Stichnoth JM GY Lueh and M Cierniak May Suppp ort for garbage

collection at every instruction in a Java compiler In ACM Conference

on Programming Languages Design and Implementation PLDI pages

Atlanta

Taft Tucker Programming the Internet in Ada In Strohmeier Al

fred editor AdaEurope International Conference on Reliable Software

Technologies Vol of Lecture Notes in Computer Science pages

Berlin Available through wwwappletmagiccom

Tarditi David Anurag Acharya and Peter Lee No assembly required

compiling Standard ML to C ACM Letters on Programming Languages

and Systems

Tarditi D G Morrisett P Cheng C Stone R Harp er and P Lee May

TIL A typedirected optimizing compiler for ML In ACM Conference

on Programming Languages Design and Implementation PLDI pages

Philadelphia ACM

Wakeling D September Mobile Haskell compiling lazy functional lan

guages for the Java virtual machine In Proceedings of the th International

Symposium on Programming Languages Implementations Logics and Pro

grams PLILP Pisa