[ARCHIVED] PluotSorbet is a J2ME-compatible virtual machine written in JavaScript.
Перейти к файлу
Brendan Dahl b9cf143f7a Add mangled name. 2015-03-02 15:55:50 -08:00
bench Merge pull request #1120 from marco-c/datainputstream_dataoutputstream 2015-02-23 08:39:36 -08:00
certs
config Merge branch 'master' of https://github.com/andreasgal/j2me.js into remove_instrument 2015-02-02 20:05:03 +01:00
img include placeholder icon to satisfy app validator 2015-01-13 01:06:10 -08:00
java Remove async exception synthetic code. 2015-02-25 17:31:08 -08:00
jit Fix compilation errors after merge. 2015-02-28 15:57:24 -08:00
libs Merge pull request #1139 from marco-c/compiled_method_cache_misc_memory_opts 2015-02-24 11:01:58 -08:00
midp Review comments 2015-02-24 11:25:16 -08:00
polyfill fix Chrome compat by using getAll shim in fs module 2015-01-28 16:30:13 -08:00
shumway Add missing newlines. 2015-01-13 16:47:42 -08:00
style Merge pull request #998 from marco-c/background_loading 2015-02-02 09:11:02 -08:00
tests Merge commit 'fcc61a07ef753974b3ea9c44a688ebdb62b2a521' into parse 2015-02-28 14:47:45 -08:00
tools package the vm/ dir 2015-02-23 09:29:00 -08:00
vm Fix compilation errors after merge. 2015-02-28 15:57:24 -08:00
.gitignore Download SlimerJS and XULRunner as part of the build process. Fixes #844 2015-02-19 17:46:19 +01:00
.travis.yml use commit_subject so IRC notices are correct for merge commits 2015-02-23 10:10:57 -08:00
LICENSE move GPL to top level and use version at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 2015-02-13 10:23:20 -08:00
Makefile Merge pull request #1144 from marco-c/fix_app_target 2015-02-24 11:24:50 -08:00
README.md Merge branch 'master' into clarify-licenses-hardest 2015-02-20 09:42:33 -08:00
actors.ts Merge commit 'fcc61a07ef753974b3ea9c44a688ebdb62b2a521' into parse 2015-02-28 14:47:45 -08:00
aot-methods.txt Use Class.java static initialization code. 2015-02-24 12:45:18 -08:00
benchmark.js Used gainedForground and don't start timers if not running. 2015-02-11 11:23:16 -08:00
bindings.ts Use Class.java static initialization code. 2015-02-24 12:45:18 -08:00
blackBox.js Add missing newlines. 2015-01-13 16:47:42 -08:00
bytecodes.ts Merge branch 'master' into clarify-licenses-harder 2015-01-23 16:39:55 -08:00
chrome_polyfills.js Fix polyfills. 2015-01-22 15:24:00 -08:00
config.ts.in Set values of the global variable release and profile by Makefile configuration 2015-01-29 13:04:09 +08:00
game-ui.js
index.html add build-time RELEASE flag that disables much logging 2015-01-21 16:46:42 -08:00
index.js.in Preprocess index.js to include gelocation related code when required. 2015-02-11 11:23:28 +08:00
interpreter.ts Merge commit 'fcc61a07ef753974b3ea9c44a688ebdb62b2a521' into parse 2015-02-28 14:47:45 -08:00
jsc.ts Remove more from the loadfiles call in jsc.ts 2015-02-06 11:56:24 -08:00
jsshell.js Make class structs derive from ByteStream. 2015-02-28 01:40:31 -08:00
legacy.js Fix chrome again. 2014-11-20 14:52:07 -08:00
main.html.in Merge branch 'master' of github.com:mozilla/j2me.js into self_host_SHA 2015-02-23 12:39:06 +01:00
main.js Link com/sun/cldc/isolate/Isolate at startup 2015-02-24 20:42:37 +01:00
manifest.webapp.in Don't precompile asm.js libraries, because it's slower than recompiling 2015-02-22 19:17:33 +01:00
metrics.ts Merge. 2014-12-11 16:04:20 -08:00
native.js Remove thread start synthetic code. 2015-02-25 16:29:15 -08:00
options.ts TSify more of the runtime. 2014-11-24 23:13:32 -08:00
override.js Remove async exception synthetic code. 2015-02-25 17:31:08 -08:00
parser.ts Add mangled name. 2015-03-02 15:55:50 -08:00
references-jsc.ts Snapshot. 2015-02-27 17:37:08 -08:00
references.ts Lazify parsing. 2015-02-25 17:41:43 -08:00
timer.js Reimplement setZeroTimeout with Promise. 2015-01-25 20:26:18 +08:00
types.ts Thoroughly check return values. 2015-01-29 18:12:56 -08:00
util.js Create the utf-8 TextDecoder when defining util 2015-02-25 16:09:09 +01:00
utilities.ts Set values of the global variable release and profile by Makefile configuration 2015-01-29 13:04:09 +08:00

README.md

j2me.js Build Status

j2me.js is a J2ME virtual machine in JavaScript.

The current goals of j2me.js are:

  1. Run MIDlets in a way that emulates the reference implementation of phone ME Feature MR4 (b01)
  2. Keep j2me.js simple and small: Leverage the phoneME JDK/infrastructure and existing Java code as much as we can, and implement as little as possible in JavaScript

Building j2me.js

Make sure you have a JRE installed

Get the j2me.js repo if you don't have it already

    git clone https://github.com/mozilla/j2me.js

Build using make:

    cd j2me.js
    make

Running apps & MIDlets, Debugging

index.html is a webapp that runs j2me.js. The URL parameters you pass to index.html control the specific behavior of j2me.js.

URL parameters

You can specify URL parameters to override the configuration. See the full list of parameters at config/urlparams.js.

  • main - default is com/sun/midp/main/MIDletSuiteLoader
  • midletClassName - must be set to the main class to run. Only valid when default main parameter is used. Defaults to RunTests
  • autosize - if set to 1, j2me app will fill the page.
  • gamepad - if set to 1, gamepad will be visible/available.

Desktop

To run a MIDlet on desktop, you must first start an http server that will host index.html. You can then connect to the http server, passing URL parameters to index.html

    python tests/httpServer.py &
    http://localhost:8000/index.html?jad=ExampleApp.jad&jars=ExampleApp.jar&midletClassName=com.example.yourClassNameHere

Example - Asteroids

    python tests/httpServer.py &
    http://localhost:8000/index.html?midletClassName=asteroids.Game&jars=tests/tests.jar&gamepad=1

Some apps require access to APIs that aren't enabled by default on Desktop Firefox and there is no UI built in to Desktop Firefox to enable them. APIs matching this description include:

  • mozTCPSocket
  • mozContacts
  • mozbrowser
  • notifications

To enable this type of API for a MIDlet you're running, use Myk's API Enabler Addon

FirefoxOS device (or emulator)

To run a MIDlet on a FirefoxOS device, update the launch_path property in manifest.webapp. The midletClassName URL parameter needs to point to an app.

Once you've updated manifest.webapp, connect to the device or emulator as described in the FirefoxOS Developer Phone Guide and select your j2me.js directory (the one containing manifest.webapp) when choosing the app to push to device.

Example - Asteroids

    "launch_path": "/index.html?midletClassName=asteroids.Game&jars=tests/tests.jar&logConsole=web&autosize=1&gamepad=1"

Tests

You can run the test suite with make test. The main driver for the test suite is automation.js which uses the Casper.js testing framework and slimer.js (a Gecko backend for casper.js). This test suite runs on every push (continuous integration) thanks to Travis.

If you want to pass additional casperJS command line options, look at the "test" target in Makefile and place additional command line options before the automation.js filename.

gfx tests use image comparison; a reference image is provided with the test and the output of the test must match the reference image. The output is allowed to differ from the reference image by a number of pixels specified in automation.js.

The main set of unit tests that automation.js runs is the set covered by the RunTests MIDlet. The full list of RunTests tests available in the tests/Testlets.java generated file. RunTests runs a number of "Testlets" (Java classes that implement the Testlet interface).

Running a single test

If the test you want to run is a class with a main method, specify a main URL parameter to index.html, e.g.:

    main=gnu/testlet/vm/SystemTest&jars=tests/tests.jar

If the test you want to run is a MIDlet, specify midletClassName and jad URL parameters to index.html (main will default to the MIDletSuiteLoader), e.g.:

    midletClassName=tests/alarm/MIDlet1&jad=tests/midlets/alarm/alarm.jad&jars=tests/tests.jar

If the test you want to run is a Testlet , specify an args URL parameter to index.html. You can specify multiple Testlets separated by commas, and you can use either '.' or '/' in the class name, e.g.:

    args=java.lang.TestSystem,javax.crypto.TestRC4,com/nokia/mid/ui/TestVirtualKeyboard

If the testlet uses sockets, you must start 4 servers (instead of just the http server):

    python tests/httpServer.py &
    python tests/echoServer.py &
    cd tests && python httpsServer.py &
    cd tests && python sslEchoServer.py &

Failures (and what to do)

Frequent causes of failure include:

  • timeout: Travis machines are generally slower than dev machines and so tests that pass locally will fail in the continuous integration tests
  • Number of differing pixels in a gfx/rendering test exceeds the threshold allowed in automation.js. This will often happen because slimerJS uses a different version of Firefox than the developer. This can also happen because the test renders text, whose font rendering can vary from machine to machine, perhaps even with the same font.

gfx/rendering tests will print a number next to the error message. That number is the number of differing pixels. If it is close to the threshold you can probably just increase the threshold in automation.js with no ill effect.

The test output will include base64 encoded images; copy this into your browser's URL bar as a data URL to see what the actual test output looked like.

When running make test, verbose test output will be printed to your terminal. Check that for additional info on the failures that occurred.

Logging

See logConsole and logLevel URL params in libs/console.js

Running j2me.js in the SpiderMonkey shell

  1. Download the SpiderMonkey shell

  2. Execute the jsshell.js file as follows:

     js jsshell.js package.ClassName
    

Coding Style

In general, stick with whatever style exists in the file you are modifying.

If you're creating a new file, use 4-space indents for Java and 2-space indents of JS.

Use JavaDoc to document public APIs in Java.

Modeline for Java files:

/* vim: set filetype=java shiftwidth=4 tabstop=4 autoindent cindent expandtab : */

Modelines for JS files:

/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

Profiling

JS profiling

One way to profile j2me.js is to use the JS profiler available in Firefox Dev Tools. This will tell us how well the JVM is working and how well natives work. This type of profiling will not measure time that is taken waiting for async callbacks to be called (for example, when using the native JS filesystem API).

Benchmarks

Startup Benchmark

The startup benchmark measures from when the benchmark.js file loads to the call of DisplayDevice.gainedForeground0. Included in a benchmark build are helpers to build baseline scores so that subsequent runs of the benchmark can be compared. A t-test is used in the comparison to see if the changes were significant.

To use:

It is recommended that a dedicated Firefox profile is used with the about:config preference of security.turn_off_all_security_so_that_viruses_can_take_over_this_computer set to true so garbage collection and cycle collection can be run in between test rounds

  1. Checkout the version you want to be the baseline(usually mozilla/master).
  2. Build a benchmark build RELEASE=1 BENCHMARK=1 make "RELEASE=1" is not required, but is recommended to avoid debug code from changing execution behavior.
  3. Open the midlet you want to test with &logLevel=log appended to the url and click Build Benchmark Baseline
  4. When finished, the message FINISHED BUILDING BASELINE will show up in the log.
  5. Apply/checkout your changes to the code
  6. Rebuild RELEASE=1 BENCHMARK=1 make
  7. Refresh the midlet
  8. Click Run Startup Benchmark
  9. Once done, the benchmark will dump results to the log. If it says "FASTER" or "SLOWER" the t-test has determined the results were significant. If it says "INSIGNIFICANT RESULT" the changes were likely not enough to be differentiated from the noise of the test.

Filesystem

midp/fs.js contains native implementations of various midp filesystem APIs.

Those implementations call out to lib/fs.js which is a JS implementation of a filesystem.

Java APIs are sync, so our implementation stores files in memory and makes them available mostly synchronously.

Implementing Java functions in native code

native keyword tells Java that the function is implemented in native code

e.g.:

public static native long currentTimeMillis();

Java compiler will do nothing to ensure that implementation actually exists. At runtime, implementation better be available or you'll get a runtime exception.

We use Native object in JS to handle creation and registration of native functions. See native.js

Native.create("name/of/function.(parameterTypes)returnType", jsFuncToCall, isAsync)

e.g.:

Native.create("java/lang/System.arraycopy.(Ljava/lang/Object;ILjava/lang/Object;II)V", function(src, srcOffset, dst, dstOffset, length) {...});

If you need to implement a method in JS but you can't declare it native in Java, use Override.

e.g.:

Override["java/lang/Math.min.(II)I"] = function(a, b) {
  return Math.min(a, b);
};

If raising a Java Exception, throw new instance of Java Exception class as defined in vm/runtime.ts, e.g.:

throw $.newNullPointerException("Cannot copy to/from a null array.");

Remember:

  • Return types are automatically converted to Java types, but parameters are not automatically converted from Java types to JS types
  • Pass true as last param if JS will make async calls and return a Promise
  • this will be available in any context that this would be available to the Java method. i.e. this will be null for static methods.
  • Context is last param to every function registered using Native.create or Override.create
  • Parameter types are specified in JNI

Packaging

The repository includes tools for packaging j2me.js into an Open Web App. It's possible to simply package the entire contents of your working directory, but these tools will produce a better app.

Compiling With AOT Compiler

make aot compiles some Java code into JavaScript with an ahead-of-time (AOT) compiler.

To use it, first install a recent version of the JavaScript shell.

Compiling With Closure

make closure compiles some JavaScript code with the Closure compiler.

To use it, first download this custom version of the compiler to tools/closure.jar:

wget https://github.com/mykmelez/closure-compiler/releases/download/v0.1/closure.jar -P tools/