260 likes | 465 Views
Compiling Java for Low-End Embedded Systems. Based on joint work with:. Motivation. Scenario: baggage control system Family of tiny embedded systems (e.g., ½K RAM, 4K ROM) Opportunities for software reuse… across hardware platforms across device types Immediate solution: use C ++
E N D
Compiling Java for Low-End Embedded Systems Based on joint work with:
Motivation • Scenario: baggage control system • Family of tiny embedded systems (e.g., ½K RAM, 4K ROM) • Opportunities for software reuse… • across hardware platforms • across device types • Immediate solution: use C++ • Large minimal memory footprint when using virtuals • Unneeded library/framework code included CASSIS'04
Motivation • Scenario: baggage control system • Family of tiny embedded systems (e.g., ½K RAM, 4K ROM) • Opportunities for software reuse… • across hardware platforms • across device types • Immediate solution: use C++ • Large minimal memory footprint when using virtuals • Unneeded library/framework code included This talk: use compiled “Java” instead! CASSIS'04
Motivation • Scenario: baggage control system • Family of tiny embedded systems (e.g., ½K RAM, 4K ROM) • Opportunities for software reuse… • across hardware platforms • across device types • Immediate solution: use C++ • Large minimal memory footprint when using virtuals • Unneeded library/framework code included Relevance to JavaCard? CASSIS'04
Relevance of a Java compiler Standard approach Alternative approach (this talk) (c.f. Jean-Jacques Vandewalle, #3) Runtime system (also in Java!) JavaCard software (1) compile statically (1) download bytecode (2) produce cheap cards Binary executable image +JAVA (2) run on JVM (3) execute directly on card CASSIS'04
Outline • Low-end embedded systems vs. Java • Our solution: JEPES • Non-intrusive configuration (IDC) • Stack size analysis • Experiments • Conclusion & future work CASSIS'04
Low-end embedded systems vs. Java • Pervasive computing • 8/16 bit devices vs. 32-bit devices: • cheaper, more robust, lower power consumption, more predictable • resource constrained (RAM, ROM, CPU) This talk: 8-bit devices with very little memory • Java pros and cons: • object-oriented, simple, platform independent • automatic memory management • inefficient execution CASSIS'04
Our solution: JEPES • Scalable Java execution platform for low-end embedded systems • Language: larger than JavaCard, smaller than J2ME (different API, no dynamic class loading, static/stack allocation [more], …) • Compiler: ahead-of-time compiler outputs Atmel AVR, Hitachi H8, x86, or Java bytecode; bare-bones execution; space-saving optimizations driven by global analyses [more]; stack size analysis [more] • Hardware-close programming: interface-directed configuration [more]; API with hardware access (streams, interrupts, ...) CASSIS'04
Compiler optimizations • No pointers => easy to optimize • Interprocedural CHA, inlining, stack allocation, tree shaking, etc. • Ghost allocation: … Stream getStream() { Serial port=new Serial(); port.setBaudRate(9600); port.setHandShake(Serial.HS_HW); return port; } … Stream s=io.getStream(); s.writeByte(b); • Constant propagation and method inlining allows serial port object to be completely eliminated CASSIS'04
InterruptEHandler.java interface InterruptEHandler {} InterruptEHandler.jid Handler.java InterruptEHandler { methods { static void handlerE() { vector = 0x0E; } } } class Handler implements InterruptEHandler { … static void handlerE() { … } } Interface-directed configuration: basic idea • Problem: need for extra configuration information (e.g., interrupt handlers need alternate call semantics) • Solution: use Java interfaces to attach semantic properties to classes (Java example: java.io.Serializable) • JEPES example: interrupt handler for vector 0x0E CASSIS'04
Interface-directed configuration • Non-intrusive • no special syntax needed • specific information declared elsewhere • No “magic” names • Used in JEPES for • interrupt handlers and interrupt control [more] • assembly macros for direct hardware access • forcing ghost allocation and stack allocation [more] • external access • … CASSIS'04
interface StackedIterator extends Iterator, StackAlloc {} class SetIterator implements StackedIterator { … } Iterator i = new SetIterator(…); printAll(i); jepes/lang/StackAlloc.jid StackAlloc { class { stack-allocate; } } Memory management • Heap allocation (not relevant here: ½K RAM) • Static allocation • Stack allocation • can be forced using IDC, forced when no GC • intuition: type checking static final queue = new Queue(…); CASSIS'04
Stack size analysis: what • Each stack frame has fixed size (including stack-allocated objects) • Memory consumed at run-time bounded by: • statically allocated objects, plus • highest sum of stack frame sizes in approximated call graph (assuming fixed-size arrays) • But: interrupts are part of the call graph! void process() { Iterator i = …; while(i.hasNext()) { Record c = (Record)i.next(); c.update(…); } static void handle_INT0() { Context c = …; … } INT0 CASSIS'04
Stack size analysis: how • Solution: interrupt-aware analysis [Brylow, Damgaard, Palsberg: ICSE’01] • Caveats: • interrupt control is low-level • analysis is complex (although efficient) void criticalOperation(byte[] data) { int old_mask = System.getInterruptMask(); System.setInterruptMaskXOR(Atmel.INT0); … System.setInterruptMask(old_mask); } CASSIS'04
Simple stack size analysis (1) • Use IDC to declaratively control interrupts • Simple static analysis propagates interrupt enable/disable at method granularity public class InputProcessor implements DisableINT0 { void criticalOperation(byte[] data) { … } } process() { } criticalOperation() {INT0 disable} handle_INT7() {global disable} INT7 handle_INT0() {global disable} INT0 storeData() {INT7 disable} CASSIS'04
Simple stack size analysis (1) • Use IDC to declaratively control interrupts • Simple static analysis propagates interrupt enable/disable at method granularity public class InputProcessor implements DisableINT0 { void criticalOperation(byte[] data) { … } } none disabled INT0 disabled process() { } criticalOperation() {INT0 disable} handle_INT7() {global disable} INT7 all disabled handle_INT0() {global disable} INT0 storeData() {INT7 disable} all disabled CASSIS'04 INT0,INT7 disabled
Simple stack size analysis (2) • Construct interrupt-aware call graph which includes potential interrupt handler calls • Compute stack depth on interrupt-aware call graph (cycle means unbounded) none disabled INT0 disabled process() { } criticalOperation() {INT0 disable} handle_INT7() {global disable} INT7 all disabled handle_INT0() {global disable} INT0 storeData() {INT7 disable} all disabled CASSIS'04 INT0,INT7 disabled
Simple stack size analysis (2) • Construct interrupt-aware call graph which includes potential interrupt handler calls • Compute stack depth on interrupt-aware call graph (cycle means unbounded) none disabled INT0 disabled process() { } criticalOperation() {INT0 disable} handle_INT7() {global disable} INT7 all disabled handle_INT0() {global disable} INT0 storeData() {INT7 disable} all disabled CASSIS'04 INT0,INT7 disabled
Simple stack size analysis (2) • Construct interrupt-aware call graph which includes potential interrupt handler calls • Compute stack depth on interrupt-aware call graph (cycle means unbounded) none disabled INT0 disabled process() { } criticalOperation() {INT0 disable} handle_INT7() {global disable} INT7 all disabled handle_INT0() {global disable} INT0 storeData() {INT7 disable} all disabled CASSIS'04 INT0,INT7 disabled
Experiments KVM demo (avg. size: 68K) average: 32.6% JEPES demo (avg. size: 8K) native average: 18.9% footprint: 1511B ROM, 50B RAM CASSIS'04
Future work • Compilation of JavaCard programs • Real experiments: • large, realistic programs instantiated from frameworks (Bang & Olufsen A/V infrastructure?) • smart dust • More aggressive program configuration using partial evaluation techniques CASSIS'04
Summary • JEPES allows ”Java” to be used on a ½K RAM 4K ROM embedded system • Interface-directed configuration: • non-intrusive, Java-style • assembly macro, interrupt handler, force stack allocation, … • Static memory (stack) size analysis • Initial experiments: • CHA essential • stack allocation discipline acceptable • stack size analysis would benefit from context sensitivity [Availability: commercial product from Mjølner, GPL version pending] CASSIS'04
JEPES concurrency model • Interrupts: event-driven concurrency • Threads: interface to underlying OS (example: LegOS) • Standard thread API for embedded devices? • Interaction between threads and interrupts? Method granularity (declarative) Statement level System.disableInterrupts(); … // critical code System.enableInterrupts(); public class IP implements DisableINT7 { void process(byte[] data) { … } } CASSIS'04
JDK 1.5 Annotation Types • JDK 1.5 supports source-level program annotations (compiled into class file attributes) • Usable in JEPES for • interrupt handlers, interrupts masking • assembly macros, external access, … public class InputHandler { @DisableInterrupt({Atmel.INT0,Atmel.INT7}) void handle(byte b) { … } } CASSIS'04
jepes/io/bus/SerialImp.java class SerialImp implements jepes.io.ISerialImp { byte readByte() { return 0; } void writeByte(byte b) { ; } } jepes/io/bus/ISerialImp/AVR/readByte__B.asm Receive: SBI UCR,RXEN SBIS USR,RXC RJMP Receive ; Wait until ready IN <@R>,UDR ; Write data to return register CBI UCR,RXEN ; Clear receive flag on UART Interface-directed configuration: assembly macros Assembly macros • High-performance, complement native methods, simulation code easy to implement CASSIS'04