There are two portions of SquirrelJME, the SquirrelJME Virtual Machine and the SquirrelJME Runtime. The virtual machine is the one which executes the program and provides an environment that runs on the operating system or other bare hardware. The runtime is the class libraries which provide a standard set of classes and interfaces which are used by Java programs. This document describes the requirements which are needed to have a virtual machine which can use the SquirrelJME runtime.
Note that J2ME was renamed to Java ME, so any mentions of Java ME retroactively mentions J2ME.
There are two cases where the runtime is used, those two cases are pure and hosted. There are two major differences between the two:
- All of the classes in the runtime are solely provided by SquirrelJME.
- More consistent.
- Portability is increased because there is less code to be ported.
- More likely to be less complicated.
- Requires more implementation work
- Runs an extra SquirrelJME APIs on top of an existing virtual machine.
- Hacks will be required for correct operation to match the semantics of Java ME.
- May have compatibility issues.
- Requires maintaining two separate programs.
- Faster to implement non-provided APIs, there is no need to implement the core APIs because the host environment provides them.
- Does not need a virtual machine to be modified to support SquirrelJME.
SquirrelJME operates in one of two fashions: Single Program Mode where only a single program is ran at once which eventually terminates, and Launcher Mode where a launcher is available and multiple programs can be launched and ran at the same time.
- Single Program Mode
- Simple to implement, only need to worry about a single program running at a time.
- Not possible to run other programs.
- Class initialization and static initialization is easier.
- Launcher Mode
- Potentially allows JARs to be loaded at run-time to run other programs.
- Provides an interface for selecting JARs to be ran.
- Allows multiple programs to be ran at the same time.
- Requires that different program execution domains be supported, this is because static variables need to be initialized for each program.
Requirements of Java ME
Java ME is different from Java SE and operates in a slightly different fashion. However, every conforming Java SE JVM can run Java ME programs but the same is not possible in most cases because Java ME is a subset of Java SE.
JAR Resource Lookup
Class.getResourceAsStream() in Java ME, there is a strict method
in how resource lookup is performed. A single JAR is considered to be a single
unit where resources and classes are located. A class within one unit is not
able to access the resources in another unit. Class files should not be visible
to this method and not accessible as resources, the reason for this is that
output executables may be ROMized which would destroy the class files that
executable code is derived from.
As an example, here is a set of two JAR files:
This would be the result of multiple
Class.getResourceAsStream() calls from
Foo-> onlyinfoo.txt: Returns foo.jar/onlyinfoo.txt.
Foo-> onlyinbar.txt: Returns
Foo-> inboth.txt: Returns foo.jar/inboth.txt.
Foo-> Foo.class: Should return
Foo-> Bar.class: Should return
Bar-> onlyinfoo.txt: Returns
Bar-> onlyinbar.txt: Returns bar.jar/onlyinbar.txt
Bar-> inboth.txt: Returns bar.jar/inboth.txt.
Bar-> Foo.class: Should return
Bar-> Bar.class: Should return
This reason for this is that in each JAR, there is a resource called META-INF/MANIFEST.MF. This resource is used and looked up my programs which are MIDlets in order to obtain their application properties. It also is used by the run-time to determine what a JAR is and what it supports.
Class Loading And Lookup
Unlike Java SE, there are no
ClassLoaders. Java ME operates entirely on a
single two tier approach. The first tier are classes which are built-in and
available to every program. The second tier are classes which are not
built-in and which have been loaded dynamically from the launcher. When a
class is looked up, the order is always built-in classes first. If a program is
currently being executed then it may only look up classes which exist in its
execution context. If two programs are loaded they are both in two different
execution contexts and they cannot lookup each others classes. Thus if two
JARs have the same class, it will only use the class that is in their same
For simplicity, sanity, and portability; SquirrelJME has a very simple means to provide support for many systems and is designed in a way to reduce the amount of work that is required to support various systems. This means that porting SquirrelJME will be very simple and straightforward once the base semantics of the virtual machine are implemented.
net.multiphasicapps.squirreljme.unsafe is a very special package
which contains the methods which are used as a bridge to native code or
other bridging code. The package is designed in a public and private fashion.
Since the methods will be needed across many methods in other packages, the
first major interface are the public interfaces. The public interfaces allow
for checks to be performed so that sane values and such are used on input for
the private implementation. The private implementation are the ones that
porters will implement to provide functionality, all of these classes are in
the form of
foo is the functionality group. These classes
are only visible to the
net.multiphasicapps.squirreljme.unsafe package which
means that they do not have to worry as much of being exposed for exploitive
purposes. This also allows for virtual functionality to be provided and a means
for backwards compatibility and migration.
The public classes call into the private classes, but due to the hidden nature
it is not required for the classes to actually exist, just that they have the
functionality provided. For example, the JVM can replace any instance of a call
unsafe package to the private class with just a function pointer while
disregarding the actual class. This would mean that these private classes
could just be declared
native and be linked by the JVM as required.
Since SquirrelJME's JVM is not being used, there are some requirements of how some of these classes are implemented.
SquirrelJME uses a basic service system similar to
ServiceLoader except it
provides services on a system level. Unlike
ServiceLoader which provides
multiple services, only single services are available at a time and once a
service object is initialized it will remain available to the program until it
exits always returning the same instance (that is, it is a singleton).
As an example, the JVM may provide a framebuffer which needs to be accessed
by SquirrelJME's LCDUI API. In this case the
net.multiphasicapps.squirreljme.lcdui.DisplayManager class needs to be
implemented. In this example environment, that class is implemented as
foo.FooDisplayManager. In order for the runtime to find that class, the
full name of the class must be returned in the
__Ext_systemenvironment__.mapService() method. When that service is
requested, that class will be loaded and stored and returned so that the LCDUI
code may use it to provide a display interface.
__Ext_systemvm__.isSquirrelJMEJVM() should always return
using just the run-time is not using the JVM.