Title: 'NET Programming Language Research MSR Cambridge
1.NET Programming Language Research _at_ MSR Cambridge
- Nick Benton
- Microsoft Research
- Cambridge
2MSR Cambridge Programming Principles and Tools
Group
- Luca Cardelli
- Nick Benton
- Cedric Fournet
- Andy Gordon
- Tony Hoare
- Andrew Kennedy
- Simon Peyton Jones
- Don Syme
- Simon Marlow
- Claudio Russo
- Mark Shields
- visitors, PhD students, interns,
3.NET in MSR Programming Principles and Tools Group
- Verifier spec (POPL)
- CLR design feedback
- Project 7 (Babel)
- SML.NET (ICFP,ICFP,HOOTS)
- Generics for C and .NET (PLDI)
- Extended IL (Babel)
- Polyphonic C (FOOL, ECOOP)
- Stack-Walking Security analysis (POPL)
- Assertions
4Part 1SML.NET
- Nick Benton, Andrew Kennedy and Claudio Russo
5Advanced Programming Languages on the CLR
- .NET and the CLR provide a great opportunity for
programming language designers and implementers - The runtime provides services (execution engine,
garbage collection,) which make producing a good
implementation of your language easier - The frameworks libraries mean you can actually
do useful things with your new language
(graphics, networking, database access, web
services,) - Multi-language component-based programming makes
it much more practical for other people to use
your language in their own projects
6Our favourite language Standard ML
- A safe, modular, strict, higher-order,
functional, polymorphic programming language with
compile-time type checking and type inference,
garbage collection, exception handling, immutable
data types, pattern-matching and updatable
references, abstract data types, and parametric
modules. - with several efficient implementations
- and a formal definition with a proof of
soundness. - (Schemetypesreal syntax, Haskell with call by
value evaluation)
7Some SML
- datatype order LESS GREATER EQUAL
- datatype 'a Tree Empty
- Node of 'a ('a Tree) ('a
Tree) - fun contains compare (x, Empty) false
- contains compare (x, Node(v, left, right))
- (case compare (x,v) of
- LESS gt contains compare (x,left)
- GREATER gt contains compare (x, right)
- EQUAL gt true
- )
- contains ('a 'a -gt order) -gt ('a 'a Tree)
-gt bool
8What is SML.NET?
- Compiler for SML that targets verifiable CIL
- Research Issues
- Can we compile a polymorphic functional language
to a monomorphic, object-oriented runtime? - Yes
- How can we make it produce fast, compact code?
- Whole-program optimising compiler.
Monomorphisation. Representation tricks. Novel
typed intermediate language using monads to track
side-effects. - How can we make cross-language working easy?
- We extend SML to support all of the .NET CLS
(Common Language Specification), providing smooth
bidirectional interoperability with .NET
framework libraries other .NET languages
9Previous approaches to interop
- Bilateral interface with marshalling and explicit
calling conventions (e.g. JNI, OCaml interface
for C). - Awkward, ugly, tied to one implementation, only
for experts - Multilateral interface with IDL (e.g. COM, CORBA)
together with particular language mappings (e.g.
H/Direct, Caml COM, MCORBA). - Have to write IDL and use tools, tend to be
lowest-common denominator, memory management
often tricky
10Interop in .NET
- Languages share a common higher-level
infrastructure (CLR) - shared heap means no tricky cross-heap pointers
(cf reference counting in COM) - shared type system means no marshalling (cf
stringlt-gtchar marshalling for Javalt-gtC) - shared exception model supports cross-language
exception handling
11SML.NET interop
- Sounds great, but SML is not object-oriented
- So we are going to have to do some work
- Possible approaches to interop
- do not extend language instead provide wrappers
that give a functional view of a CLS library
(Haskell, Mercury). - Powerful functional type systems can go a very
long way towards modelling OO type systems - redesign the language (OO-SML?)
- Our approach a middle way
- re-use existing features where appropriate
(non-object-oriented subset) - extend language for convenient interop when fit
is bad (object-oriented features) - live with the CLS at boundaries dont try to
export complex ML types to other languages (what
would they do with them?)
12Re-use SML features
multiple args
tuple
void
unit
null
NONE
static field
val binding
SML
static method
fun binding
CLS
namespace
structure
delegate
first-class function
mutability
ref
open
using
private fields
local decls
13Extend language
type test
cast patterns
class definitions
classtype
instance method invocation
obj.meth
instance field access
obj.fld
custom attributes
attributes in classtype
casts
exp gt ty
CLS
SML
14Extract from WinForms interop
open System.Windows.Forms System.Drawing
System.ComponentModelfun selectXML () let
val fileDialog OpenFileDialog() in
fileDialog.set_DefaultExt("XML")
fileDialog.set_Filter("XML files (.xml)
.xml") if fileDialog.ShowDialog()
DialogResult.OK then case
fileDialog.get_FileName() of NONE gt ()
SOME name gt replaceTree (ReadXML.make
name, "XML file '" name "'") else ()
end
no args ML unit value
CLS Namespace ML structure
static method ML function
static constant field ML value
instance method invocation
CLS string ML string
null value NONE
And note that there are no explicit types in this
code
15Ray tracing in ML
- ICFP programming competition build a ray tracer
in under 3 days - 39 entries in all kinds of languages
- C, C, Clean, Dylan, Eiffel, Haskell, Java,
Mercury, ML, Perl, Python, Scheme, Smalltalk - ML (Caml) was in 1st and 2nd place
16Ray tracing in SML.NET
- Translate winning entry to SML
- Add WinForms interop
- Run on .NET CLR
- Performance on this example twice as good as
popular optimizing native compiler for SML - (though on others were twice as bad)
17Visual Studio Integration
- Bootstrap the compiler to produce a .NET
component for parsing, typechecking, etc. of SML - Use interlanguage working extensions to expose
that as a COM component which can be glued into
Visual Studio - Write new ML code to handle syntax highlighting,
tooltips, error reporting, etc.
18Part 2Generics in the CLR and C
- Andrew Kennedy and Don Syme
19Note This is not in V1 of the CLR ?It will be
in V2 ? ? ?
20Part 1 Introduction
21What are generics?
- Types which are parameterized by other types,
e.g. Stackltintgt, Stackltstringgt - Generics, templates, parametric polymorphism
- Ada, Eiffel, C, ML, Haskell, Mercury, Component
Pascal, - Promote code reuse, increase type safety, better
performance - Good for collections, higher-order programming
and generally building higher-level, reusable
abstractions
22Generic code in C today (1)
- class Stack private Object items private
int nitems Stack() nitems 0 items
new Object50 Object Pop() if
(nitems 0) throw new EmptyException()
return items--nitems - void Push(Object item) ... return
itemsnitems
23Generic code in C today (2)
- Stack s new Stack()
- s.Push(1)
- s.Push(2)
- int n (int)(s.Pop()) (int)(s.Pop())
- Whats wrong with that?
- Its inexpressive. Type system doesnt document
what should be in a particular stack. - Its unsafe. Type errors (s.Push(2) ) lead to
runtime exceptions instead of being caught by
compiler - Its ugly. Casts everywhere.
- Its slow. Casts are slow, and converting base
types (e.g. ints) to Objects involves expensive
boxing.
24Generic code in C tomorrow (1)
- class StackltTgt private T items private
int nitems Stack() nitems 0 items
new T50 T Pop() if (nitems 0)
throw new EmptyException() return
items--nitems - void Push(T item) if (items.Length
nitems) T temp items items
new Tnitems2 Array.CopyltTgt(temp,
items, nitems) itemsnitems
item
25Generics large design space
But can type instantiations can be non-reference?
Setltintgt Listltfloatgt
- Parameterized classes, interfaces, and methods
e.g.
Do you erase types at runtime?
// two-parameter class class DictltK,Dgt ...
// parameterized interface interface
IComparableltTgt ... // parameterized struct
struct PairltA,Bgt ... // generic method
T SliceltTgt(T arr, int start, int count)
Do we have exact runtime type information? if (x
is Setltintgt) ....
Do you share code?
Constraints? class CltT IFoo, IBargt ...
What goes in the CLR? What goes in the
compilers?
26Generic interfaces
- interface IDictionaryltK,Dgt
-
- D Lookup(K)
- ...
-
- class DictionaryltK,Dgt IDictionaryltK,Dgt
-
- D Lookup(K)
- ...
-
- DictionaryltString,Stringgt
-
27Generic methods
A generic method is just a family of methods,
indexed by type.
-
- static void SortltTgt (T) ...
- int x 5,4,3,2
- Sort(x)
28Explicit Constraints
interface IComparableltTgt static int
Compare(T,T) class BinaryTreeltT
IComparableltTgt gt void insert(T x)
switch (x.Compare(y)) ... T y
TreeltTgt left TreeltTgt right
Static constraints are available via interfaces.
29Part 2 Implementing Generics for the .NET CLR
30Generics Our design
- Parameterized classes, interfaces, structs,
methods, delegates Yes - Exact runtime types Yes
- if (x is Setltstringgt) ...
- Instantiations at value types Yes
- SetltStringgt Setltintgt Listltfloatgt
- Constraints Yes (by
interfaces) - class CltT IComponentgt
- Variance No
- SetltStringgt is not subtype-related to SetltObjectgt
31How does it work?
1a. Look for Stackltintgt1b. Nothing exists yet,
so create structures for Stackltintgt
Stackltintgt si new Stackltintgt()Stackltintgt si2
new Stackltintgt()Stackltstringgt ss new
Stackltstringgt()Stackltobjectgt so new
Stackltobjectgt()si.Push(5)ss.Push(Generics)
so.Push(myObj)
2a. Look for Stackltintgt2b. Type already loaded!
3a. Look for Stackltstringgt3b. ltstringgt not
compatible with ltintgt, so create structures for
Stackltstringgt
4a. Look for Stackltobjectgt4b. ltobjectgt
compatible with ltstringgt, so re-use Stackltstringgt
32How does it work?
Stackltintgt si new Stackltintgt()Stackltintgt si2
new Stackltintgt()Stackltstringgt ss new
Stackltstringgt()Stackltobjectgt so new
Stackltobjectgt()si.Push(5)ss.Push(Generics)
so.Push(myObj)
Compile code for Stackltintgt.Push
Compile code for Stackltstringgt.Push
Re-use code from Stackltstringgt.Push
33Implementing Generics (0)
- Dynamic loading JIT compilation change many
fundamental assumptions - Can consider code generation at runtime
- Can use more dynamic data structures
- The current challenge is to implement all of
- exact runtime types code sharing dynamic
loading non-uniform instantiations
34Implementing Generics (1)
- Our implementation
- 1. Dynamic code expansion and sharing
- Instantiating generic classes and methods is
handled by the CLR. - Generate/compile code as necessary
- Use JIT compiler
- Share code for compatible instantiations
- Compatibility is determined by the implementation
35Implementing Generics (2)
- Our implementation
- 1. Dynamic code expansion and sharing
- 2. Pass and store runtime type information
- Objects carry runtime type information
- We record this information by duplicating
vtables. - Other options are possible.
- Generic methods take an extra parameter
- The active type context is always recoverable
36Implementing Generics (3)
- Our implementation
- 1. Dynamic code expansion and sharing
- 2. Pass and store runtime type information
- 3. Optimized use of runtime type information
37Generics Performance
- 1. Instantiations at value types
- Stack with repeated push and pops of 0...N
elements - (a) List_int
- (b) List (i.e. existing collection class)
- (c) Listltintgt
- 5X speedup (c) v. (b)
- 2. No casts
- 20 speed on similar micro-benchmarks
- 3. Runtime type computations
- Generic allocation 10 slower in generic code
38Generics Design Comparison
39Comparison with C templates
- What C gets wrong
- Modularity
- need to see the template at link time
- Efficiency
- nearly all implementations code-expand
- Safety
- not checked at declaration use, but at link
time - Simplicity
- very complicated
40Comparison with C templates
- What we get right
- Modularity
- no need to see the generic IL until runtime
- Efficiency
- code expansion managed by the VM
- Safety
- check at declaration use
- Simplicity
- there are some corners, but the mechanism is
simple to explain use
41Summary
- A world first cross-language generics.
- A world first generics in a high-level virtual
machine design. - Implementation
- The virtual machine (runtime) level is the right
place to implement generics for .NET - Potential for
- Other implementation techniques (more aggressive
sharing, some boxing, etc.) - Further extensions (type functions, variance,
more expressive constraints) - Good performance
42Part 3Polyphonic C
- Nick Benton, Luca Cardelli and Cedric Fournet
43Introduction
44Programming in a networked world
- Developers now have to work in a
- Concurrent
- Distributed
- High latency
- ( low reliability, security sensitive,
multi-everything) - environment.
- Which is hard
- And theyre mostly not very good at it
- Try using Outlook over dialup ?
45Asynchronous communication
- Distribution gt concurrency latency
gt asynchrony gt more
concurrency - Message-passing, event-based programming,
dataflow models - For programming languages, coordination
(orchestration) languages frameworks, workflow
46Language support for concurrency
- Make invariants and intentions more apparent
(part of the interface) - Good software engineering
- Allows the compiler much more freedom to choose
different implementations - Also helps other tools
47.NET Today
- Multithreaded execution environment with lock per
object - C has lock keyword, libraries include
traditional shared-memory synchronization
primitives (mutexes, monitors, r/w locks) - Delegate-based asynchronous calling model,
events, messaging - Higher level frameworks built on that
- Hard to understand, use and get right
- Different models at different scales
- Support for asynchrony all on the caller side
little help building code to handle messages
(must be thread-safe, reactive, and deadlock-free)
48Polyphonic C
- An extension of the C language with new
concurrency constructs - Based on the join calculus
- A foundational process calculus like the
p-calculus but better suited to asynchronous,
distributed systems - A single model which works both for
- local concurrency (multiple threads on a single
machine) - distributed concurrency (asynchronous messaging
over LAN or WAN)
49The Language
50In one slide
- Objects have both synchronous and asynchronous
methods. - Values are passed by ordinary method calls
- If the method is synchronous, the caller blocks
until the method returns some result (as usual). - If the method is async, the call completes at
once and returns void. - A class defines a collection of synchronization
patterns (chords), which define what happens once
a particular set of methods have been invoked on
an object - When pending method calls match a pattern, its
body runs. - If there is no match, the invocations are queued
up. - If there are several matches, an unspecified
pattern is selected. - If a pattern containing only async methods fires,
the body runs in a new thread.
51A Simple Buffer
- class Buffer
- String get() async put(String s)
- return s
-
52A Simple Buffer
- class Buffer
- String get() async put(String s)
- return s
-
- An ordinary (synchronous) method with no
arguments, returning a string
53A Simple Buffer
- class Buffer
- String get() async put(String s)
- return s
-
- An ordinary (synchronous) method with no
arguments, returning a string - An asynchronous method (hence returning no
result), with a string argument
54A Simple Buffer
- class Buffer
- String get() async put(String s)
- return s
-
- An ordinary (synchronous) method with no
arguments, returning a string - An asynchronous method (hence returning no
result), with a string argument - Joined together in a chord
55A Simple Buffer
- class Buffer
- String get() async put(String s)
- return s
-
- Calls to put() return immediately (but are
internally queued if theres no waiting get()). - Calls to get() block until/unless theres a
matching put() - When theres a match the body runs, returning the
argument of the put() to the caller of get(). - Exactly which pairs of calls are matched up is
unspecified.
56A Simple Buffer
- class Buffer
- String get() async put(String s)
- return s
-
- Does example this involve spawning any threads?
- No. Though the calls will usually come from
different pre-existing threads. - So is it thread-safe? You dont seem to have
locked anything - Yes. The chord compiles into code which uses
locks. (And that doesnt mean everything is
synchronized on the object.) - Which method gets the returned result?
- The synchronous one. And there can be at most one
of those in a chord.
57Reader/Writer
- using threads and mutexes in Modula 3
- An introduction to programming with threads.
Andrew D. Birrell, January 1989.
58Reader/Writer in five chords
- class ReaderWriter
- void Exclusive() private async Idle()
- void ReleaseExclusive() Idle()
- void Shared() private async Idle() S(1)
- void Shared() private async S(int n)
S(n1) - void ReleaseShared() private async S(int n)
- if (n 1) Idle() else S(n-1)
-
- ReaderWriter() Idle()
-
- A single private message represents the state
- none ?? Idle() ?? S(1) ?? S(2) ?? S(3)
59Asynchronous Service Requests and Responses
- The service might export an async method which
takes parameters and somewhere to put the result - a buffer, or a channel, or
- a delegate (O-O function pointer)
delegate async IntCB(int v) class Service
public async request(String arg, IntCB
callback) int result // do something
interesting callback(result)
60Asynchronous Service Requests and Responses - join
- class Join2
- void wait(out int i, out int j)
- async first(int r1)
- async second(int r2)
- i r1 j r2 return
-
-
- // client code
- int i,j
- Join2 x new Join2()
- service1.request(arg1, new IntCB(x.first))
- service2.request(arg2, new IntCB(x.second))
- // do something useful
- // now wait until both results have come back
- x.wait(i,j)
- // do something with i and j
61Asynchronous Service Requests and Responses -
select
- class Select
- int wait()
- async reply(int r)
- return r
-
-
- // client code
- int i
- Select x new Select()
- service1.request(arg1, new IntCB(x.reply))
- service2.request(arg2, new IntCB(x.reply))
- // do something useful
- // now wait until one result has come back
- i x.wait()
- // do something with i
62Extending C with chords
- Classes can declare methods using generalized
chord-declarations instead of method-declarations
. - chord-declaration method-header
method-header body - method-header attributes modifiers
return-type async name (parms) -
- Interesting well-formedness conditions
- At most one header can have a return type (i.e.
be synchronous). - The inheritance restriction.
- ref and out parameters cannot appear in async
headers.
63Implementation
64Example Sum of Squares
add(1)
total(0,8)
add(4)
SumOfSquares
add(9)
add(64)
65Sum of Squares
total(1,7)
add(4)
SumOfSquares
add(9)
add(64)
66Sum of Squares Code
- class SumOfSquares
- private async loop(int i)
- if (i gt 0)
- add(i i)
- loop(i - 1)
-
-
- private int total(int r, int i) private async
add(int dr) - int rp r dr
- if (i gt 1) return total(rp, i - 1)
- return rp
-
- public SumOfSquares(int x)
- loop(x)
- int i total(0, x)
- System.Console.WriteLine("The result is 0.",
i) -
67Sum of Squares Translation
- using System
- using System.Collections
- using System.Threading
- class SyncQueueEntry
- public int pattern
- public System.Threading.Thread mythread
- public System.Object joinedentries
-
- class SumOfSquares
- Queue Q_totalint_int_ new Queue()
- Queue Q_addint_ new Queue()
- class loopint__runner
- SumOfSquares parent
- int field_0
- public loopint__runner(SumOfSquares p_p,int
p_0) - parent p_p
- field_0 p_0
- Thread t new Thread(new ThreadStart(this.do
it)) - t.Start()
- try
- Thread.Sleep(Timeout.Infinite)
- catch (ThreadInterruptedException)
- // wake up here
- matchindex qe.pattern
- joinlabel
- switch (matchindex)
- case 0 int r sync_p_0
- int i sync_p_1
- int dr (int)(qe.joinedentries)
- int rp r dr
- if (i gt 1) return total(rp, i - 1)
-
- return rp
-
68Sum of Squares Translation
- using System
- using System.Collections
- using System.Threading
- class SyncQueueEntry
- public int pattern
- public System.Threading.Thread mythread
- public System.Object joinedentries
-
- class SumOfSquares
- Queue Q_totalint_int_ new Queue()
- Queue Q_addint_ new Queue()
- class loopint__runner
- SumOfSquares parent
- int field_0
- public loopint__runner(SumOfSquares p_p,int
p_0) - parent p_p
- field_0 p_0
- Thread t new Thread(new ThreadStart(this.do
it)) - t.Start()
- try
- Thread.Sleep(Timeout.Infinite)
- catch (ThreadInterruptedException)
- // wake up here
- matchindex qe.pattern
- joinlabel
- switch (matchindex)
- case 0 int r sync_p_0
- int i sync_p_1
- int dr (int)(qe.joinedentries)
- int rp r dr
- if (i gt 1) return total(rp, i - 1)
-
- return rp
-
class SumOfSquares Queue Q_totalint_int_
new Queue() Queue Q_addint_ new Queue()
69Sum of Squares Translation
- using System
- using System.Collections
- using System.Threading
- class SyncQueueEntry
- public int pattern
- public System.Threading.Thread mythread
- public System.Object joinedentries
-
- class SumOfSquares
- Queue Q_totalint_int_ new Queue()
- Queue Q_addint_ new Queue()
- class loopint__runner
- SumOfSquares parent
- int field_0
- public loopint__runner(SumOfSquares p_p,int
p_0) - parent p_p
- field_0 p_0
- Thread t new Thread(new ThreadStart(this.do
it)) - t.Start()
- try
- Thread.Sleep(Timeout.Infinite)
- catch (ThreadInterruptedException)
- // wake up here
- matchindex qe.pattern
- joinlabel
- switch (matchindex)
- case 0 int r sync_p_0
- int i sync_p_1
- int dr (int)(qe.joinedentries)
- int rp r dr
- if (i gt 1) return total(rp, i - 1)
-
- return rp
-
private void add(int p_0) System.Threading.Moni
tor.Enter(Q_totalint_int_) if
(!(Q_totalint_int_.Count 0))
SyncQueueEntry sqe (SyncQueueEntry)(Q_totalin
t_int_.Dequeue()) sqe.joinedentries
p_0 System.Threading.Monitor.Exit(Q_totalint
_int_) sqe.pattern 0
sqe.mythread.Interrupt() return Q_addin
t_.Enqueue(p_0) System.Threading.Monitor.Exit(Q_
totalint_int_) return
70Current Work
- Examples and test cases
- Web combinators, adaptive scheduler, web services
(Terraserver), active objects and remoting (stock
trader) - Generally looking at integration with existing
mechanisms and frameworks - Language design
- Direct syntactic support for timeouts
- Solid Implementation
71Predictable Demo Dining Philosophers
waiting to eat
eating
waiting to eat
thinking
eating
72Code extract
- class Room
- public Room (int size) hasspaces(size)
- public void enter() private async
hasspaces(int n) - if (n gt 1) hasspaces(n-1)
- else isfull()
-
- public void leave() private async
hasspaces(int n) - hasspaces(n1)
-
- public void leave() private async isfull()
hasspaces(1) -
73Conclusions
- A clean, simple, new model for asynchronous
concurrency in C - Declarative, local synchronization
- Applicable in both local and distributed settings
- Efficiently compiled to queues and automata
- Easier to express and enforce concurrency
invariants - Compatible with existing constructs, though they
constrain our design somewhat - Solid foundations
- Works well in practice
74Thats all
- For more information, contact me
nick_at_microsoft.com or see - http//research.microsoft.com/nick,akenn,dsyme
75TimeoutBuffer
- class TimeoutBuffer
- TimeoutBuffer(int delay)
- Timer t new Timer(new TimerCallBack(this.tick)
, delay) - empty()
-
- async empty() void put(Object o) has(o)
- async empty() void tick() timeout()
- async timeout() void put(Object o)
timeout() - async timeout() Object get() timeout() throw
new TimeOutExn() - async has(Object o) Object get() has(o)
return o - async has(Object o) void tick() has(o)
76Why only one synchronous method in a chord?
- JoCaml allows multiple synchronous methods to be
joined, as in the following rendezvous - But in which thread does the body run? In C,
thread identity is very observable, since
threads are the holders of particular re-entrant
locks. So we rule this out in the interests of
keeping commutative. (Of course, its still
easy to code up an asymmetric rendezvous in
Polyphonic C.)
int f(int x) int g(int y) return y to f
return x to y
77The problem with inheritance
class C virtual void f() virtual async g()
virtual void f() virtual async h()
class D C override async g()
- Weve half overridden f
- Too easy to create deadlock or async leakage
void m(C x) x.g() x.f() m(new D())
78The Inheritance Restriction
- Inheritance may be used as usual, with a
restrictionto prevent the partial overriding of
patterns - For a given class, two methods f ang g are
co-declared if there is a chord in which they are
both declared. - Whenever a method is overriden,every codeclared
method must also be overriden. - Hence, the compiler rejects patterns such as
- public virtual void f() private async g()
- In general, inheritance and concurrency do not
mix well.Our restriction is simple it could be
made less restrictive.
79Types etc.
- async is a subtype of void
- Allow covariant return types on those two
- An async method may override a void one
- A void delegate may be created from an async
method - An async method may implement a void method in an
interface - async methods are automatically given the
OneWay attribute, so remote calls are
non-blocking
80Compiling chords
- Since synchronization is statically defined for
every class, we can compile it efficiently (state
automata). - We cache the synchronization state in a single
word. - We use a bit for every (polyphonic) method.
- We pre-compute bitmasks for every pattern.
- Simple version just looks up queue state directly
- For every polyphonic method, we allocate a
queuefor storing delayed threads (or pending
messages). - The compilation scheme can be optimized
- Some states are not reachable.
- Empty messages only need to be counted.
- The content of (single, private) messages can be
stored in local variables. Requires some
analysis.
81Implementation issues
- When compiling a polyphonic class, we add
- private fields for the synchronization state and
the queues - private methods for the body of asynchronous
patterns - some initialization code.
- The code handling the join patterns must be
thread-safe. - We use a single lock (from the first queue) to
protect the state word and all queues. - This is independent from the object lock and only
held briefly whilst queues are being manipulated. - For asynchronous methods, theres an auxiliary
class for storing the pending messages.
82Adding synchronization code
- When an asynchronous method is called
- add the message content to the queue
- if the method bit is 0, set it to 1 in the
synchronization stateand check for a completed
pattern - For every pattern containing the method,compare
the new state to the pattern mask. - If there is a match, then wake up a delayed
thread(or start a new thread if the pattern is
entirely asynchronous). - When a synchronous method is called
- if the method bit is 0, set it to 1 in the
synchronization stateand check for a completed
pattern - For every pattern containing the method,compare
the new state to the pattern mask. - If there is a match, dequeue the asynchronous
arguments,adjust the mask, and run the body for
that pattern. - Otherwise, enqueue the thread, go to sleep, then
retry.