On PCs, the JVM is known for being relatively memory-hungry, so it's interesting to wonder about how low-end can JVMs go, and how do they do it?
interestingly, at the time Java was introduced, 'Java: an overview' says:
"The size of the basic interpreter and class support is about 30K bytes, adding the basic standard libraries and thread support (essentially a self-contained microkernel) brings it up to about 120K. "
" Unlike traditional JVMs, KESO is designed to operate in tandem with an RTOS, leaving to the RTOS many functions traditional JVMs might take on. For example, it does not implement thread scheduling and thread synchronization, but uses an existing RTOS to do these tasks. As with most Java implementations, it makes selective use of garbage collection, but when it does, it uses a bare-bone, primitive form that assumes operation in a priority-based scheduling environment, another function it lets devolve to the RTOS. Also, rather than depend on the traditional Java VM compiler to generate executable Java code, KESO is provided with a companion compiler called “jino” that generates native C code in an ahead-of-time fashion, making possible a very slim run time environment and fast execution times. ... Rather than just any C code, KESO generates ISO-C90 code, which has a number of advantages. First, because it makes use of a standard C compiler available for most embedded microcontrollers, there is no need for a compiler backend for each target microcontroller. ... In the 8-bit domain, a typical memory configuration is about 8 kilobytes of flash and about 500 to 600 bytes or so of internal SRAM.
The current compiler backend for KESO requires an OSEK/VDK or an AUTOSAR-compatible OS, the most common platforms used in automotive designs. In that environment, KESO takes advantage of the fact that OSEK/VDX is at its core little more than a scheduler based on static priorities. "
"A really low footprint (< 10 Kb) Java VM and replacement firmware for the Lego Mindstorms RCX microcontroller"
http://tinyvm.sourceforge.net/
" TinyVM?'s footprint is about 10 Kb in the RCX. Additionally, program class files are compacted considerably (i.e. resolved) before they are downloaded to the RCX. A small program can access around 16 Kb of RAM. The overhead for each object is 4 bytes, and there is no alignment of fields (e.g. a byte field always requires one byte).
Features of TinyVM? that aren't always found in other RCX programming systems are listed below.
Great object oriented language (Java)
Preemptive threads
Exceptions
Synchronization
Arrays, including multidimensional ones
Recursion
Access to RCX buttons
No need to install a cross-compiler
Fairly easy to install, even under CygWin
TinyVM's firmware allows itself to be replaced
Comes with an emulation tool
Nicely documented APIs Since 0.2.0:
You can rerun a program.
Full object persistence across runs.
tinyvm.rcx.Time with sleep() and currentTimeMillis().
Timers (tinyvm.rcx.Timer).
Random numbers (java.util.Random).
LCD characters (tinyvm.rcx.TextLCD). Since 0.2.2:
Auto power off
Limitations Evidently, it isn't feasible to put a complete Java runtime in 32 Kb, let alone 10 Kb. The most important limitations and missing features of TinyVM? are:
No garbage collection
No floating point support
No switch statements
String constants are ignored Floating point arithmetic and string constants have already been implemented in leJOS, and it's likely that the other limitations will also be addressed there. There are a lot of interesting features that could be added to TinyVM? and/or leJOS, and contributions are always welcome. "
http://dmitry.gr/index.php?r=05.Projects&proj=12.%20uJ%20-%20a%20micro%20JVM
" The VM size depends on the options selected and the CPU architecture at hand. For example a VM with all options enabled takes up about 80K of codespace on an AVR device, and only 60K on a PIC24 device. To fit into an Atmega64, disabling the "DOUBLE" is all it takes. Of course, if you need double, you can disable something else like "FLOAT" and "LONG" to free up the needed code space. You can also play with optimization options. For example Microchip's "Procedural Abstraction" optimization can reduce the code size by 30%, but at the cost of a 10% decrease in speed. "
" RAM
The VM memory footprint is of utmost importance on a microcontroller, of course. To provide the kind of heap a java VM requires, it is pointless to try and use a normal C-style heap, so uJ implements its own heap manager. This means that your microcontroller need not have an implementation of malloc/free for uJ to work. All uJ memory is allocated in uJ's heap. This makes it very easy to limit uJ to a certain size, or to use the maximum memory that your microcontroller will give you efficiently. All chunks in uJ's heap can be relocated and are referenced by handles. This allows the garbage collector to move memory chunks that are not locked, which is essential when you only have a few kilobytes of RAM. Each heap chunk's header is 2-4 bytes depending on heap size and heap alignment requirements. Each loaded class takes up about 28 bytes (plus any static variables it may have). All objetcs are about 2 bytes more than the sum of the sizes of their instance variables. Each thread takes up about 20 bytes plus stack size (192 bytes by default) plus 3%. Thus even on a small memory footprint it is possible to run reasonably-sized programs. "
" Garbage Collector
The uJ garbage collector is optimized for code size and small heaps. If you give it many megabytes of memory, it will get quite slow - it is not made for such a case. The GC itself is a simple design. Each chunk has a 3-state "mark" field. First we set all of then to zero. Then we walk all the threads' stacks and mark all objects we discover to "1", same for global static variables. Then we loop until no more chunks are left with a "1" mark: find first chunk with a "1" mark, mark it "2", mark all of its children as 1. At the end of this the heap will have objetcs marked "2" and marked "0". All those marked "0" can be freed. Then all unlocked chunks are moved towards the end, so as to make more contigious heap space. Classes are all loaded at the start of the VM, and are non-movable chunks in the end of the heap. Being in the end is how they manage to not fragment the heap space. "
" Strings
As pointed out above, any class can be either native or Java. uJ does not currently support classes that are both, so that leaves us in a pretty unpleasant place regarding the String class. String is the only class in Java that the JVM needs to construct by itself. However, String has a lot of methods that would waste a lot of code space to implement. How do we solve this problem? There is a native class uj.lang.MiniString? that String inherits from. MiniString? implements the most basic things a string does - storing a set of bytes and accessing them. It implements, by default, just three methods - a constructor, XbyteAt?_, and Xlen_, which do exactly what you'd expect them to. The rest of the string class is implemented in Java, including UTF-8 parsing from bytes and all. Yes, indeed this can be slow, so the VM has an option to instead implement length() and charAt in C, significantly speeding those up. Threads
uJ implementes threading, and you can run as many threads as you can fit into RAM. I did not [yet?] implement the entire Thread class, so right now a thread starts immediately when you create a new instance of Thread. This seems fine for me, for now, and I'll work on expanding the thread class soon. Threading introduces synchronization issues, of course, and uJ is ready! The synchronized keyword is fully supported in all possible cases, and functions as expected. Runtime Exceptions
Java has a set of exceptions that the runtime can throw, like NullPointer? and DivideByZero?. uJ could throw those, but that would require you to have a class file for each, wasting 28 bytes of RAM, so instead uJ terminates the runtime and returns the error. This can easily be changed (all the code is there) but I choose not to do this by default. If you want to enable this, it is very easy. "
"
Java class file format is incredibly inefficient to use as is. It was never really meant to be used directly, from what I can tell. It is meant to be loaded into a complex structure in RAM. Needless to say, I haven't got any desire to waste RAM like this - it does not grow on trees. This leaves us with a problem - very inefficient ways of accessing class data (methods, fields, interfaces, etc...). uJ still supports java class files, but it is slow. To solve the problem, at least partially, a different format is used: UJC. UJC stands for "uJ class". Not too creative, I know. What is so special about it?
Some file-level optimizations
Unused constants from the original class file are discarded, to avoid empty slots in the constant table, constants are renumbered and the code is adjusted accordingly.
A table of contents is created for constants, methods, and fields so that the N-th constant can be located in the file without reading the previous N-1.
Some constants at times refer to other constants, for example nametypeinfo refers to name and type by index. This introduces extra lookups. Such references are replaced with direct offsets, removing the unneeded constant lookups. This places us in a position where we need the constant data for some constants, but they are never referenced by index. We can do that, thanks to the abovementioned constant renumbering - they are stored in the file, but have no index pointing to them.
Some instruction-level optimizations
Some constants are moved directly into the code: ldc and ldc2 that load floats or integers are replaced with a custon instruction 0xFE, folowed by the 4 bytes of the constant itself. This significantly speeds up usage of integers > 32767 in java code.
Static and private method calls to the same class's methods are optimized by finding the index of the method in the class, so that we no longer need to search for it by name. This is impossible for virtual and interface functions, of course. This variant of the invokestatic and invokespecial instructions is encoded using a wide prefix instruction before them.
Field accesses in the same class (static and instance both) are optimized, replacing the constant index describing the variable with just a type and offset, since it is known already. This variant of the getfield, putfield, getstatic and putstatic instructions is encoded using a wide prefix instruction before them.So what does this give us? The resulting files are smaller (20% typical) and much faster (depending on the workload, up to 3x) . How do we do all this? The tool I created is called classCvt and it is a rather cool piece of code. It reads the java class file into RAM, with complete understanding of what each chunk of it is. Then it goes over all the code pieces, and breaks them into code blocks. A code block is a piece of code which has a single entry point; that is to say there exist no jumps anywhere else that land you in the middle of this chunk of code. Once we have these blocks, we know for sure that we can freely change their lengths, without disturbing any jumps. We then go over them and modify the instructions as we see fit. We also note which constants from the pool get used, so that we can throw away the ones that aren't and rearrange the rest. After we're done with all the changs, we can reassemble the code back into a single stream. This is not very complex, since, except the first one, the rest of the chunks can be arranged in any order. One possible caveat here: java jumps use 16-bit offsets, so if somehow our changes grow the code size, we can end up in a situation where we cannot fit some jumps into the offset. In this case classCvt will print an error, as expected. "
http://www.harbaum.org/till/nanovm/index.shtml
"What's left? The VM itself is finished. It is not a full Java VM, since it does not support exceptions, threads, floating point arithmetic and various other things like e.g. inheritance from native classes. Due to memory limitations, these things will probably never be implemented for the Asuro and its ATmega8 CPU (keep in mind, that everything has to fit into 8kBytes of code memory). The generic version lacks a complete set of native classes in order to be really useful to the end user. "
"Requires less than 8kBytes of code memory"
" The ATmega8 will very likely be the smallest AVR capable of running the NanoVM?. There's not much memory left in its 8kBytes flash (about 700 bytes are still free), so there isn't space for plenty of generic native classes. With the bigger CPUs (there are AVRs with up to 32 times the code memory of the ATmega8), even the most complex native classes should be possible incl. e.g. networking and wireless support. "
"The low-power Atmel 8-bit AVR RISC-based microcontroller combines 8KB of programmable flash memory, 1KB of SRAM, 512K EEPROM, and a 6 or 8 channel 10-bit A/D converter. The device supports throughput of 16 MIPS at 16 MHz and operates between 2.7-5.5 volts."
http://nanovm.cvs.sourceforge.net/viewvc/nanovm/nanovm/vm/src/opcodes.h?view=markup
" Did you read the restrictions on the JVM you linked? It includes the following problems:
As little as 512 bytes of program memory (not KB, and definitely not MB)
As little as 768 bytes of RAM (where your variables go. You're limited to 768 characters of strings by this restriction.)
About 20k Java opcodes per second on 8 Mhz AVR.
Only includes java.lang.Object, java.lang.System, java.io.PrintStream, java.lang.StringBuffer, a JVM control class, and a native IO class. You will not be able to do an import java.util.*; and get all the classes not in this list.If you're not familiar with what these restrictions mean, make sure that you have a plan B if it turns out that you can't actually do the project with Java due to the space and speed restrictions. "
130 kB of RAM and 350 kB of ROM
http://hackaday.com/2012/10/09/bringing-java-to-the-world-of-microcontrollers/
" OneEighty? released an 8-bit jvm for smartcard app. They're saying they got the footprint down to 55k.
http://www.origin-j.com/products/index.shtml#orij
Which would suck up a little under 50% of the atmega128 program storage resource. "
"A typical Java Card device has an 8- or 16-bit CPU running at 3.7MHz, with 1K of RAM and more than 16K of non-volatile memory (EEPROM or flash). High-performance smart cards come with a separate processor and cryptographic chip and memory for encryption, and some come with a 32-bit CPU."
http://www.oracle.com/technetwork/java/javacard/javacard1-139251.html
https://en.wikipedia.org/wiki/Java_Card
" Java Card vs. Java Language
At the language level, Java Card is a precise subset of Java: all language constructs of Java Card exist in Java and behave identically. This goes to the point that as part of a standard build cycle, a Java Card program is compiled into a Java class file by a Java compiler, without any special option (the class file is post-processed by tools specific to the Java Card platform). However, many Java language features are not supported by Java Card (in particular types char, double, float and long; the transient qualifier; enums; arrays of more than one dimension; finalization; object cloning; threads). Further, some common features of Java are not provided at runtime by many actual smart cards (in particular type int, which is the default type of a Java expression; and garbage collection of objects). Bytecode
Java Card bytecode run by the Java Card Virtual Machine is a functional subset of Java 2 bytecode run by a standard Java Virtual Machine but with a different encoding to optimized for size. A Java Card applet thus typically uses less bytecode than the hypothetical Java applet obtained by compiling the same Java source code. This conserves memory, a necessity in resource constrained devices like smart cards. As a design tradeoff, there is no support for some Java language features (as mentioned above), and size limitations. Techniques exist for overcoming the size limitations, such as dividing the application's code into packages below the 64 KiB? limit. Library and runtime
Standard Java Card class library and runtime support differs a lot from that in Java, and the common subset is minimal. For example, the Java Security Manager class is not supported in Java Card, where security policies are implemented by the Java Card Virtual Machine; and transients (non-persistent, fast RAM variables that can be class members) are supported via a Java Card class library, while they have native language support in Java. Specific features
The Java Card runtime and virtual machine also support features that are specific to the Java Card platform:
Persistence With Java Card, objects are by default stored in persistent memory (RAM is very scarce on smart cards, and it is only used for temporary or security-sensitive objects). The runtime environment as well as the bytecode have therefore been adapted to manage persistent objects. Atomicity As smart cards are externally powered and rely on persistent memory, persistent updates must be atomic. The individual write operations performed by individual bytecode instructions and API methods are therefore guaranteed atomic, and the Java Card Runtime includes a limited transaction mechanism. Applet isolation The Java Card firewall is a mechanism that isolates the different applets present on a card from each other. It also includes a sharing mechanism that allows an applet to explicitly make an object available to other applets.
"
The Java Card Virtual Machine Instruction Set:
aaload aastore aconst_null aload aload_ anewarray areturn arraylength astore astore_ athrow baload bastore bipush bspush checkcast dup dup_x dup2 getfield_<t> getfield_<t>_this getfield_<t>_w getstatic_<t> goto goto_w i2b i2s iadd iaload iand iastore icmp iconst_ idiv if_acmp<cond> if_acmp<cond>_w if_scmp<cond> if_scmp<cond>_w if<cond> if<cond>_w ifnonnull ifnonnull_w ifnull ifnull_w iinc iinc_w iipush iload iload_<n> ilookupswitch imul ineg instanceof invokeinterface invokespecial invokestatic invokevirtual ior irem ireturn ishl ishr istore istore_<n> isub itableswitch iushr ixor jsr new newarray nop pop pop2 putfield_<t> putfield_<t>_this putfield_<t>_w putstatic_<t> ret return s2b s2i sadd saload sand sastore sconst_ sdiv sinc sinc_w sipush sload sload_<n> slookupswitch smul sneg sor srem sreturn sshl sshr sspush sstore sstore_<n> ssub stableswitch sushr swap_x sxor
" A Subset of the Java Virtual Machine 2 This chapter describes the subset of the Java virtual machine and language that is supported in the Java Card 3 platform. 2.1 Why a Subset is Needed It would be ideal if programs for smart cards could be written using all of the Java programming language, but a full implementation of the Java virtual machine is far too large to fit on even the most advanced resource-constrained devices available today. A typical resource-constrained device has on the order of 1.2K of RAM, 16K of non-volatile memory (EEPROM or flash) and 32K-48K of ROM. The code for implementing string manipulation, single and double-precision floating point arithmetic, and thread management would be larger than the ROM space on such a device. Even if it could be made to fit, there would be no space left over for class libraries or application code. RAM resources are also very limited. The only workable option is to implement Java Card technology as a subset of the Java platform. 2.2 Java Card Platform Language Subset Applets written for the Java Card platform are written in the Java programming language. They are compiled using Java compilers. Java Card technology uses a subset of the Java language, and familiarity with the Java platform is required to understand the Java Card platform. The items discussed in this section are not described to the level of a language specification. For complete documentation on the Java programming language, see The Java Language Specification. 2.2.1 Unsupported Items The items listed in this section are elements of the Java programming language and platform that are not supported by the Java Card platform. 2.2.1.1 Unsupported Features The following features are not supported. 2.2.1.1.1 Dynamic Class Loading Dynamic class loading is not supported in the Java Card platform. An implementation of the Java Card platform is not able to load classes dynamically. Classes are either masked into the card during manufacturing or downloaded through an installation process after the card has been issued. Programs executing on the card may only refer to classes that already exist on the card, since there is no way to download classes during the normal execution of application code. 2.2.1.1.2 Security Manager Security management in the Java Card platform differs significantly from that of the Java platform. In the Java platform, there is a Security Manager class (java.lang.SecurityManager?) responsible for implementing security features. In the Java Card platform, language security policies are implemented by the virtual machine. There is no Security Manager class that makes policy decisions on whether to allow operations. 2.2.1.1.3 Finalization Finalization is also not supported. finalize() will not be called automatically by the Java Card virtual machine. 2.2.1.1.4 Threads The Java Card virtual machine does not support multiple threads of control. Programs for the Java Card platform (“Java Card programs”) cannot use class Thread or any of the thread-related keywords in the Java programming language. 2.2.1.1.5 Cloning The Java Card platform does not support cloning of objects. Java Card API class Object does not implement a clone method, and there is no Cloneable interface provided. 2.2.1.1.6 Access Control in Java Packages The Java Card platform language subset supports the package access control defined in the Java language. However, the cases that are not supported are as follows. ■ ■ ■ ■ ■ ■ ■ If a class implements a method with package access visibility, a subclass cannot override the method and change the access visibility of the method to protected or public. A public class cannot contain a public or protected field of type reference to a package-visible class. A public class cannot contain a public or protected method with a return type of type reference to a package-visible class. A public or protected method in a public class cannot contain a formal parameter of type reference to a package-visible class. A package-visible class that is extended by a public class cannot define any public or protected methods or fields. A package-visible interface that is implemented by a public class cannot define any fields. A package-visible interface cannot be extended by an interface with public access visibility. 2.2.1.1.7 Typesafe Enums The Java Card platform language subset does not support the enumerated type facility and the keyword enum. 2.2.1.1.8 Enhanced for Loop The Java Card platform language subset does not support the enhanced for loop language construct. Support for the enhanced for loop construct requires support for array indexing using the integer data type. The Java Card platform only supports array indexing using the short data type. 2.2.1.1.9 Varargs The Java Card platform language subset does not support variable-length argument lists. The variable-length argument construct requires the compiler to generate code that creates a new array object each time a variable-length argument array method is invoked, thereby causing implicit memory allocations in Java Card runtime memory heap. 2.2.1.1.10 Runtime Visible Metadata (Annotations) The Java Card platform does not support this language feature which lets you introduce meta-data information into the runtime environment to be accessed reflectively. The Java Card platform does not support reflection. 2.2.1.1.11 Assertions The Java Card runtime does not provide runtime support for statements in the Java programming language called assertions that are used to test assumptions about program functionality. 2.2.1.2 Unsupported Keywords The following keywords indicate unsupported options related to native methods, threads, floating point, memory management, and debugging. Table 2–1 Unsupported Keywords Unsupported Keywords native strictfp synchronized enum transient assert volatile 2.2.1.3 Unsupported Types The Java Card platform does not support types char, double, float and long. It also does not support arrays of more than one dimension. 2.2.1.4 Unsupported Classes In general, none of the Java programming language core API classes are supported in the Java Card platform. Some classes from the java.lang package are supported (see Section 2.2.2.4, "Supported Classes"), but none of the rest are. For example, classes that are not supported are String, Thread (and all thread-related classes), wrapper classes such as Boolean and Integer, and class Class. 2.2.1.4.1 System Class java.lang.System is not supported. Java Card technology supplies a class javacard.framework.JCSystem, which provides an interface to system behavior. 2.2.2 Supported Items If a language feature is not explicitly described as unsupported, it is part of the supported subset. Notable supported features are described in this section. 2.2.2.1 Supported Features The following features are the more important supported features. 2.2.2.1.1 Packages Software written for the Java Card platform follows the standard rules for the Java platform packages. Java Card API classes are written as Java source files, which include package designations. Package mechanisms are used to identify and control access to classes, static fields and static methods. Except as noted in “Access Control in Java Packages” (Section 2.2.1.1, "Unsupported Features"), packages in the Java Card platform are used exactly the way they are in the Java platform. 2.2.2.1.2 Dynamic Object Creation The Java Card platform programs supports dynamically created objects, both class instances and arrays. This is done, as usual, by using the new operator. Objects are allocated out of the heap. A Java Card virtual machine will not necessarily garbage collect objects. Any object allocated by a virtual machine may continue to exist and consume resources even after it becomes unreachable. Section 2.2.3.2, "Object Deletion Mechanism" for more information regarding support for an optional object deletion mechanism. 2.2.2.1.3 Virtual Methods Since Java Card technology-based objects (“Java Card objects”) are Java programming language objects, invoking virtual methods on objects in a program written for the Java Card platform is exactly the same as in a program written for the Java platform. Inheritance is supported, including the use of the super keyword. 2.2.2.1.4 Interfaces Java Card API classes may define or implement interfaces as in the Java programming language. Invoking methods on interface types works as expected. Type checking and the instanceof operator also work correctly with interfaces. 2.2.2.1.5 Exceptions Java Card programs may define, throw and catch exceptions, as in Java programs. Class Throwable and its relevant subclasses are supported. Some Exception and Error subclasses are omitted, since those exceptions cannot occur in the Java Card platform. Section 2.3.3, "Exceptions" for specification of errors and exceptions. 2.2.2.1.6 Generics This Java language facility allows a type or method to operate on objects of various types while providing compile-time type safety. It adds compile-time type safety and eliminates the need for casting. 2.2.2.1.7 Static Import This Java language facility lets you avoid importing an entire class simply to access its static members or qualifying static members with class names each time it is used. 2.2.2.1.8 Runtime Invisible Metadata (Annotations) This language feature lets you avoid writing boilerplate code under many circumstances by enabling tools to generate it from annotations in the source code. The Java Card platform language subset supports the use of annotations which are not visible at runtime. These annotations do not themselves use the runtime visible meta-data annotation @Retention(RetentionPolicy?.RUNTIME). 2.2.2.2 Supported Keywords The following keywords are supported. Their use is the same as in the Java programming language. able 2–2 Supported Keywords Supported Keywords abstract boolean break byte case catch class continue default do else extends final finally for goto if implements import instanceof int interface new package private protected public return short static super switch this throw throws try void while
2.2.2.3 Supported Types Java programming language types boolean, byte, short, and int are supported. Objects (class instances and single-dimensional arrays) are also supported. Arrays can contain the supported primitive data types, objects, and other arrays. Some Java Card implementations might not support use of the int data type. (Refer to Section 2.2.3.1, "Integer Data Type"). 2.2.2.4 Supported Classes Most of the classes in the java.lang package are not supported on the Java Card platform. The following classes from java.lang are supported on the card in a limited form. 2.2.2.4.1 Object Java Card API classes descend from java.lang.Object, just as in the Java programming language. Most of the methods of Object are not available in the Java Card API, but the class itself exists to provide a root for the class hierarchy. 2.2.2.4.2 Throwable Class Throwable and its subclasses are supported. Most of the methods of Throwable are not available in the Java Card API, but the class itself exists to provide a common ancestor for all exceptions. 2.2.3 Optionally Supported Items This section describes the optional features of the Java Card platform. An optional feature is not required to be supported in a Java Card platform-compatible implementation. However, if an implementation does include support for an optional feature, it must be supported fully, and exactly as specified in this document. 2.2.3.1 Integer Data Type The int keyword and 32-bit integer data type need not be supported in a Java Card implementation. A Java Card virtual machine that does not support the int data type will reject programs which use the int data type or 32-bit intermediate values. The result of an arithmetic expression produced by a Java Card virtual machine must be equal to the result produced by a Java virtual machine, regardless of the input values. A Java Card virtual machine that does not support the int data type must reject expressions that could produce a different result. 2.2.3.2 Object Deletion Mechanism The Java Card 3 platform offers an optional, object deletion mechanism. Applications designed to run on these implementations can use the facility by invoking the appropriate API. See Application Programming Interface, Java Card 3 Platform, v3.0.4, Classic Edition. But, the facility is best suited for updating large objects such as certificates and keys atomically. Therefore, application programmers should conserve on the allocation of objects.
2.2.4 Limitations of the Java Card Virtual Machine The limitations of resource-constrained hardware prevent Java Card virtual machines from supporting the full range of functionality of certain Java platform features. The features in question are supported, but a particular virtual machine may limit the range of operation to less than that of the Java platform. To ensure a level of portability for application code, this section establishes a minimum required level for partial support of these language features. The limitations here are listed as maximums from the application programmer’s perspective. Java packages that do not violate these maximum values can be converted into Java Card technology-based CAP files (“Java Card CAP files”), and will be portable across all Java Card implementations. From the Java Card virtual machine implementer’s perspective, each maximum listed indicates a minimum level of support that will allow portability of applets. 2.2.4.1 Limitations of Packages The following are limitations of packages. 2.2.4.1.1 Package References A package can reference at most 128 other packages. 2.2.4.1.2 Package Name The fully qualified name of a package may contain a maximum of 255 characters. The package name size is further limited if it contains one or more characters which, when represented in UTF-8 format, requires multiple bytes. 2.2.4.2 Limitations of Classes The following are limitations of classes. 2.2.4.2.1 Classes in a Package A package can contain at most 255 classes and interfaces. 2.2.4.2.2 Interfaces A class can implement at most 15 interfaces, including interfaces implemented by superclasses. An interface can inherit from at most 14 superinterfaces. 2.2.4.2.3 Static Fields A class in an applet package can have at most 256 public or protected static non-final fields. A class in a library package can have at most 255 public or protected static non-final fields. There is no limit on the number of static final fields (constants) declared in a class. 2.2.4.2.4 Static Methods A class in an applet package can have at most 256 public or protected static methods. A class in a library package can have at most 255 public or protected static methods. 2.2.4.3 Limitations of Objects The following are limitations of objects. 2.2.4.3.1 Methods A class can implement a maximum of 128 public or protected instance methods, and a maximum of 128 instance methods with package visibility. These limits include inherited methods. 2.2.4.3.2 Class Instances Class instances can contain a maximum of 255 fields, where an int data type is counted as occupying two fields. These limits include inherited fields.
2.2.4.3.3 Arrays Arrays can hold a maximum of 32767 components. 2.2.4.4 Limitations of Methods The maximum number of variables that can be used in a method is 255. This limit includes local variables, method parameters, and, in the case of an instance method invocation, a reference to the object on which the instance method is being invoked (meaning, this). An int data type is counted as occupying two local variables. A method can have at most 32767 Java Card virtual machine bytecodes. The number of Java Card technology-based bytecodes (“Java Card bytecodes”) may differ from the number of Java bytecodes in the Java virtual machine implementation of that method. The maximum depth of an operand stack associated with a method is 255 16-bit cells. 2.2.4.5 Limitations of Switch Statements The format of the Java Card virtual machine switch instructions limits switch statements to a maximum of 65536 cases. This limit is far greater than the limit imposed by the maximum size of methods (Section 2.2.4.4, "Limitations of Methods"). 2.2.4.6 Limitations of Class Initialization The Java Card virtual machine contains limited support for class initialization because there is no general mechanism for executing <clinit> methods. Support for <clinit> methods is limited to the initialization of static field values with the following constraints: ■ ■ ■ Static fields of applet packages may only be initialized to primitive compile-time constant values, or arrays of primitive compile-time constants. Static fields of user libraries may only be initialized to primitive compile-time constant values. Only static fields declared in the current class may be initialized in the <clinit> method. Primitive constant data types include boolean, byte, short, and int. Given Java technology source files that adhere to these language-level constraints on static field initialization, it is expected that reasonable Java compilers will: ■ ■ Inline constants in the bytecodes that reference static final primitive fields that are initialized in the declaration statement. Produce only the following bytecodes: ■ load a value on the stack: iconst_[m1,0-5], [b
| s]ipush, ldc, ldc_w, | ||
| short | boolean | int] ) |
| i | s]astore, putstatic |
2.3.1 Class File Subset The operation of the Java Card virtual machine can be defined in terms of standard Java platform class files. Since the Java Card virtual machine supports only a subset of the behavior of the Java virtual machine, it also supports only a subset of the standard class file format. 2.3.1.1 Not Supported in Class Files The following items are not supported in class files. 2.3.1.1.1 Class Access Flags In class_info and interface_info structures, the access flag ACC_ENUM is not supported. 2.3.1.1.2 Field Descriptors Field descriptors may not contain BaseType? characters C, D, F or J. ArrayType? descriptors for arrays of more than one dimension may not be used. 2.3.1.1.3 Constant Pool Constant pool table entries with the following tag values are not supported. Table 2–3 Unsupported Java Constant Pool Tags Constant Type Value CONSTANT_String 8 CONSTANT_Float 4 CONSTANT_Long 5 CONSTANT_Double 6 2.3.1.1.4 Fields In field_info structures, the access flags ACC_VOLATILE, ACC_ TRANSIENT and ACC_ENUM are not supported. 2.3.1.1.5 Methods In method_info structures, the access flags ACC_SYNCHRONIZED, ACC_STRICT, ACC_NATIVE, and ACC_VARARGS are not supported. 2.3.1.2 Supported in Class Files The following items are supported in class files. 2.3.1.2.1 ClassFile? All items in the ClassFile? structure are supported. 2.3.1.2.2 Field Descriptors Field descriptors may contain BaseType? characters B, I, S and Z, as well as any ObjectType?. ArrayType? descriptors for arrays of a single dimension may also be used. 2.3.1.2.3 Method Descriptors All forms of method descriptors are supported. 2.3.1.2.4 Constant Pool Constant pool table entry with the following tag values are supported.
able 2–4 Supported Java Constant Pool Tags Constant Type Value CONSTANT_Class 7 CONSTANT_Fieldref 9 CONSTANT_Methodref 10 CONSTANT_InterfaceMethodref? 11 CONSTANT_Integer 3 CONSTANT_NameAndType? 12 CONSTANT_Utf8 1 2.3.1.2.5 Fields In field_info structures, the supported access flags are ACC_ PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC and ACC_FINAL. The remaining components of field_info structures are fully supported. 2.3.1.2.6 Methods In method_info structures, the supported access flags are ACC_ PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL and ACC_ ABSTRACT. The remaining components of method_info structures are fully supported. 2.3.1.2.7 Attributes The attribute_info structure is supported. The Code, ConstantValue?, Exceptions, LocalVariableTable?, Synthetic, InnerClasses?, RuntimeInvisibleAnnotations?, RuntimeInvisibleParameterAnnotations?