Merge branch 'master' of https://github.com/andreasgal/j2me.js into background_not_running
Conflicts: index.js manifest.webapp
|
@ -6,14 +6,13 @@ certs/j2se_main.ks
|
|||
certs/j2se_test.ks
|
||||
tests/Testlets.java
|
||||
output/
|
||||
build/
|
||||
|
||||
# These are generated by the Java pre-processor. They're generated from
|
||||
# their *.jpp equivalents. Keep them up-to-date when you add *.jpp files!
|
||||
java/midp/com/sun/j2me/location/PlatformLocationProvider.java
|
||||
java/midp/com/sun/j2me/pim/AbstractPIMItem.java
|
||||
java/midp/com/sun/j2me/pim/AbstractPIMList.java
|
||||
java/midp/com/sun/midp/chameleon/input/NativeInputMode.java
|
||||
java/midp/com/sun/midp/chameleon/skins/resources/SkinResourcesImpl.java
|
||||
java/midp/com/sun/midp/events/EventQueue.java
|
||||
java/midp/com/sun/midp/io/ConnectionBaseAdapter.java
|
||||
java/midp/com/sun/midp/io/j2me/sms/Protocol.java
|
||||
|
@ -44,6 +43,7 @@ java/midp/com/sun/jsr082/bluetooth/SDDB.java
|
|||
java/midp/com/sun/jsr082/bluetooth/ServiceDiscovererFactory.java
|
||||
java/midp/com/sun/jsr082/bluetooth/btl2cap/L2CAPNotifierImpl.java
|
||||
java/midp/com/sun/jsr082/bluetooth/btspp/BTSPPNotifierImpl.java
|
||||
java/custom/javax/microedition/lcdui/Display.java
|
||||
|
||||
# These files are generated by java_cup
|
||||
tools/jasmin-2.4/src/jasmin/parser.java
|
||||
|
|
63
LICENSE
|
@ -252,35 +252,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
libs/forge/*: New BSD License (3-clause)
|
||||
Copyright (c) 2010, Digital Bazaar, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Digital Bazaar, Inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL DIGITAL BAZAAR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
---
|
||||
|
||||
tests/gnu/testlet/vm/StringBufferTest.java (additional tests): Apache
|
||||
|
@ -332,37 +303,3 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||
|
||||
[1]: http://eligrey.com
|
||||
|
||||
---
|
||||
|
||||
tests/QUnit:
|
||||
|
||||
Copyright 2006, 2014 jQuery Foundation and other contributors,
|
||||
https://jquery.org/
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals. For exact contribution history, see the revision history
|
||||
available at https://github.com/jquery/qunit
|
||||
|
||||
The following license applies to all parts of this software except as
|
||||
documented below:
|
||||
|
||||
====
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
44
Makefile
|
@ -1,6 +1,9 @@
|
|||
.PHONY: all test tests java certs app clean jasmin
|
||||
.PHONY: all test tests j2me java certs app clean jasmin aot shumway
|
||||
BASIC_SRCS=$(shell find . -maxdepth 2 -name "*.ts" -not -path "./build/*")
|
||||
JIT_SRCS=$(shell find jit -name "*.ts" -not -path "./build/*")
|
||||
SHUMWAY_SRCS=$(shell find shumway -name "*.ts")
|
||||
|
||||
all: java jasmin tests
|
||||
all: java jasmin tests j2me shumway
|
||||
|
||||
test: all
|
||||
tests/runtests.py
|
||||
|
@ -8,6 +11,42 @@ test: all
|
|||
jasmin:
|
||||
make -C tools/jasmin-2.4
|
||||
|
||||
build/j2me.js: $(BASIC_SRCS) $(JIT_SRCS)
|
||||
@echo "Building J2ME"
|
||||
node tools/tsc.js --sourcemap --target ES5 references.ts -d --out build/j2me.js
|
||||
|
||||
build/j2me-jsc.js: $(BASIC_SRCS) $(JIT_SRCS)
|
||||
@echo "Building J2ME JSC"
|
||||
node tools/tsc.js --sourcemap --target ES5 references-jsc.ts -d --out build/j2me-jsc.js
|
||||
|
||||
build/jsc.js: jsc.ts build/j2me-jsc.js
|
||||
@echo "Building J2ME JSC CLI"
|
||||
node tools/tsc.js --sourcemap --target ES5 jsc.ts --out build/jsc.js
|
||||
|
||||
j2me: build/j2me.js build/jsc.js
|
||||
|
||||
aot: java j2me
|
||||
@echo "Compiling ..."
|
||||
js build/jsc.js -cp java/classes.jar -d -jf java/classes.jar > build/classes.jar.js
|
||||
js build/jsc.js -cp java/classes.jar tests/tests.jar -d -jf tests/tests.jar > build/tests.jar.js
|
||||
if test -f program.jar; then \
|
||||
js build/jsc.js -cp java/classes.jar program.jar -d -jf program.jar > build/program.jar.js; \
|
||||
fi
|
||||
@echo "Done"
|
||||
|
||||
closure: build/j2me.js aot
|
||||
java -jar tools/closure.jar --language_in ECMASCRIPT5 -O SHUMWAY_OPTIMIZATIONS build/j2me.js > build/j2me.cc.js \
|
||||
&& mv build/j2me.cc.js build/j2me.js
|
||||
java -jar tools/closure.jar --language_in ECMASCRIPT5 -O SIMPLE build/classes.jar.js > build/classes.jar.cc.js \
|
||||
&& mv build/classes.jar.cc.js build/classes.jar.js
|
||||
if test -f build/program.jar.js; then \
|
||||
java -jar tools/closure.jar --language_in ECMASCRIPT5 -O SIMPLE build/program.jar.js > build/program.jar.cc.js \
|
||||
&& mv build/program.jar.cc.js build/program.jar.js; \
|
||||
fi
|
||||
|
||||
shumway: $(SHUMWAY_SRCS)
|
||||
node tools/tsc.js --sourcemap --target ES5 shumway/references.ts --out build/shumway.js
|
||||
|
||||
tests:
|
||||
make -C tests
|
||||
|
||||
|
@ -23,6 +62,7 @@ app: java certs
|
|||
|
||||
clean:
|
||||
rm -f j2me.js `find . -name "*~"`
|
||||
rm -rf build
|
||||
make -C tools/jasmin-2.4 clean
|
||||
make -C tests clean
|
||||
make -C java clean
|
||||
|
|
29
README.md
|
@ -197,11 +197,9 @@ e.g.:
|
|||
Override.create("com/ibm/oti/connection/file/Connection.decode.(Ljava/lang/String;)Ljava/lang/String;", function(...) {...});
|
||||
|
||||
|
||||
If raising a Java `Exception`, throw new instance of Java `Exception` class
|
||||
If raising a Java `Exception`, throw new instance of Java `Exception` class as defined in runtime.ts, e.g.:
|
||||
|
||||
e.g.:
|
||||
|
||||
throw new JavaException("java/lang/NullPointerException", "Cannot copy to/from a null array.");
|
||||
throw $.newNullPointerException("Cannot copy to/from a null array.");
|
||||
|
||||
Remember:
|
||||
|
||||
|
@ -210,3 +208,26 @@ Remember:
|
|||
* `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](http://www.iastate.edu/~java/docs/guide/nativemethod/types.doc.html)
|
||||
|
||||
## 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](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Introduction_to_the_JavaScript_shell).
|
||||
|
||||
### Compiling With Closure
|
||||
|
||||
`make closure` compiles some JavaScript code with the Closure compiler.
|
||||
|
||||
To use it, first download Shumway's version of the compiler to tools/closure.jar:
|
||||
|
||||
```
|
||||
wget https://github.com/mozilla/shumway/raw/master/utils/closure.jar -P tools/
|
||||
```
|
||||
|
|
|
@ -0,0 +1,617 @@
|
|||
module J2ME {
|
||||
declare var Native, Override;
|
||||
declare var missingNativeImpl;
|
||||
declare var CC;
|
||||
declare var Signature;
|
||||
declare var classObjects;
|
||||
declare var util;
|
||||
|
||||
import BlockMap = Bytecode.BlockMap;
|
||||
|
||||
export interface ConstantPoolEntry {
|
||||
tag: TAGS;
|
||||
name_index: number;
|
||||
bytes: string;
|
||||
class_index: number;
|
||||
name_and_type_index: number;
|
||||
signature_index: number;
|
||||
string_index: number;
|
||||
integer: number;
|
||||
float: number;
|
||||
double: number;
|
||||
highBits: number;
|
||||
lowBits: number;
|
||||
}
|
||||
|
||||
export interface ExceptionHandler {
|
||||
start_pc: number;
|
||||
end_pc: number;
|
||||
handler_pc: number;
|
||||
catch_type: number;
|
||||
}
|
||||
|
||||
export class SourceLocation {
|
||||
constructor(public className: string, public sourceFile: string, public lineNumber: number) {
|
||||
// ...
|
||||
}
|
||||
toString() {
|
||||
return this.sourceFile + ":" + this.lineNumber;
|
||||
}
|
||||
equals(other: SourceLocation): boolean {
|
||||
if (!other) {
|
||||
return false;
|
||||
}
|
||||
return this.sourceFile === other.sourceFile &&
|
||||
this.lineNumber === other.lineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
export class FieldInfo {
|
||||
private static _nextiId = 0;
|
||||
id: number;
|
||||
isStatic: boolean ;
|
||||
constantValue: any;
|
||||
mangledName: string;
|
||||
key: string;
|
||||
kind: Kind;
|
||||
|
||||
constructor(public classInfo: ClassInfo, public access_flags: number, public name: string, public signature: string) {
|
||||
this.id = FieldInfo._nextiId++;
|
||||
this.isStatic = AccessFlags.isStatic(access_flags);
|
||||
this.constantValue = undefined;
|
||||
this.mangledName = undefined;
|
||||
this.key = undefined;
|
||||
this.kind = getSignatureKind(signature);
|
||||
}
|
||||
|
||||
get(object: java.lang.Object) {
|
||||
return object[this.mangledName];
|
||||
}
|
||||
|
||||
set(object: java.lang.Object, value: any) {
|
||||
object[this.mangledName] = value
|
||||
}
|
||||
|
||||
getStatic() {
|
||||
return this.get(this.classInfo.getStaticObject($.ctx));
|
||||
}
|
||||
|
||||
setStatic(value: any) {
|
||||
return this.set(this.classInfo.getStaticObject($.ctx), value);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return "[field " + this.name + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Required params:
|
||||
* - name
|
||||
* - signature
|
||||
* - classInfo
|
||||
*
|
||||
* Optional params:
|
||||
* - attributes (defaults to [])
|
||||
* - code (if not provided, pulls from attributes)
|
||||
* - isNative, isPublic, isStatic, isSynchronized
|
||||
*/
|
||||
export class MethodInfo {
|
||||
name: string;
|
||||
classInfo: ClassInfo;
|
||||
code: Uint8Array;
|
||||
isNative: boolean;
|
||||
isPublic: boolean;
|
||||
isStatic: boolean;
|
||||
isSynchronized: boolean;
|
||||
isAbstract: boolean;
|
||||
isFinal: boolean;
|
||||
|
||||
/**
|
||||
* There is a compiled version of this method.?
|
||||
*/
|
||||
state: MethodState;
|
||||
|
||||
exception_table: ExceptionHandler [];
|
||||
max_locals: number;
|
||||
max_stack: number;
|
||||
|
||||
argumentSlots: number;
|
||||
|
||||
/**
|
||||
* The number of arguments to pop of the stack when calling this function.
|
||||
*/
|
||||
consumeArgumentSlots: number;
|
||||
|
||||
hasTwoSlotArguments: boolean;
|
||||
signatureDescriptor: SignatureDescriptor;
|
||||
signature: string;
|
||||
implKey: string;
|
||||
key: string;
|
||||
alternateImpl: {()};
|
||||
fn: {()};
|
||||
attributes: any [];
|
||||
mangledName: string;
|
||||
mangledClassAndMethodName: string;
|
||||
|
||||
blockMap: BlockMap;
|
||||
|
||||
line_number_table: {start_pc: number; line_number: number} [];
|
||||
|
||||
/**
|
||||
* Approximate number of bytecodes executed in this method.
|
||||
*/
|
||||
bytecodeCount: number;
|
||||
|
||||
/**
|
||||
* Approximate number of times this method was called.
|
||||
*/
|
||||
callCount: number;
|
||||
|
||||
/**
|
||||
* Approximate number of times this method was called.
|
||||
*/
|
||||
interpreterCallCount: number;
|
||||
|
||||
/**
|
||||
* Approximate number of times a backward branch was taken.
|
||||
*/
|
||||
backwardsBranchCount: number;
|
||||
|
||||
/**
|
||||
* Number of times this method's counters were reset.
|
||||
*/
|
||||
resetCount: number;
|
||||
|
||||
/**
|
||||
* Whether this method's bytecode has been optimized for quicker interpretation.
|
||||
*/
|
||||
isOptimized: boolean;
|
||||
|
||||
constructor(opts) {
|
||||
this.name = opts.name;
|
||||
this.signature = opts.signature;
|
||||
this.classInfo = opts.classInfo;
|
||||
this.attributes = opts.attributes || [];
|
||||
|
||||
// Use code if provided, otherwise search for the code within attributes.
|
||||
if (opts.code) {
|
||||
this.code = opts.code;
|
||||
this.exception_table = [];
|
||||
this.max_locals = undefined; // Unused for now.
|
||||
} else {
|
||||
for (var i = 0; i < this.attributes.length; i++) {
|
||||
var a = this.attributes[i];
|
||||
if (a.info.type === ATTRIBUTE_TYPES.Code) {
|
||||
this.code = new Uint8Array(a.info.code);
|
||||
this.exception_table = a.info.exception_table;
|
||||
this.max_locals = a.info.max_locals;
|
||||
this.max_stack = a.info.max_stack;
|
||||
|
||||
var codeAttributes = a.info.attributes;
|
||||
for (var j = 0; j < codeAttributes.length; j++) {
|
||||
var b = codeAttributes[j];
|
||||
if (b.info.type === ATTRIBUTE_TYPES.LineNumberTable) {
|
||||
this.line_number_table = b.info.line_number_table;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.isNative = opts.isNative;
|
||||
this.isPublic = opts.isPublic;
|
||||
this.isStatic = opts.isStatic;
|
||||
this.isSynchronized = opts.isSynchronized;
|
||||
this.isAbstract = opts.isAbstract;
|
||||
this.isFinal = opts.isAbstract;
|
||||
this.state = MethodState.Cold;
|
||||
this.key = (this.isStatic ? "S." : "I.") + this.name + "." + this.signature;
|
||||
this.implKey = this.classInfo.className + "." + this.name + "." + this.signature;
|
||||
|
||||
|
||||
this.mangledName = mangleMethod(this);
|
||||
this.mangledClassAndMethodName = mangleClassAndMethod(this);
|
||||
|
||||
this.signatureDescriptor = SignatureDescriptor.makeSignatureDescriptor(this.signature);
|
||||
this.hasTwoSlotArguments = this.signatureDescriptor.hasTwoSlotArguments();
|
||||
this.argumentSlots = this.signatureDescriptor.getArgumentSlotCount();
|
||||
this.consumeArgumentSlots = this.argumentSlots;
|
||||
if (!this.isStatic) {
|
||||
this.consumeArgumentSlots ++;
|
||||
}
|
||||
|
||||
this.callCount = 0;
|
||||
this.resetCount = 0;
|
||||
this.interpreterCallCount = 0;
|
||||
this.backwardsBranchCount = 0;
|
||||
this.bytecodeCount = 0;
|
||||
|
||||
this.isOptimized = false;
|
||||
this.blockMap = null;
|
||||
}
|
||||
|
||||
public getReturnKind(): Kind {
|
||||
return this.signatureDescriptor.typeDescriptors[0].kind;
|
||||
}
|
||||
|
||||
getSourceLocationForPC(pc: number): SourceLocation {
|
||||
var sourceFile = this.classInfo.sourceFile || null;
|
||||
if (!sourceFile) {
|
||||
return null;
|
||||
}
|
||||
var lineNumber = -1;
|
||||
if (this.line_number_table && this.line_number_table.length) {
|
||||
var table = this.line_number_table;
|
||||
for (var i = 0; i < table.length; i++) {
|
||||
if (pc >= table[i].start_pc) {
|
||||
lineNumber = table[i].line_number;
|
||||
} else if (pc < table[i].start_pc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new SourceLocation(this.classInfo.className, sourceFile, lineNumber)
|
||||
}
|
||||
}
|
||||
|
||||
var classID = 0;
|
||||
|
||||
export class ClassInfo {
|
||||
className: string;
|
||||
c: string;
|
||||
superClass: ClassInfo;
|
||||
superClassName: string;
|
||||
interfaces: ClassInfo [];
|
||||
fields: FieldInfo [];
|
||||
methods: MethodInfo [];
|
||||
staticInitializer: MethodInfo;
|
||||
classes: any [];
|
||||
subClasses: ClassInfo [];
|
||||
allSubClasses: ClassInfo [];
|
||||
constant_pool: ConstantPoolEntry [];
|
||||
resolved_constant_pool: any [];
|
||||
isArrayClass: boolean;
|
||||
elementClass: ClassInfo;
|
||||
klass: Klass;
|
||||
access_flags: number;
|
||||
vmc: any;
|
||||
vfc: any;
|
||||
mangledName: string;
|
||||
thread: any;
|
||||
id: number;
|
||||
|
||||
sourceFile: string;
|
||||
|
||||
static createFromObject(object) {
|
||||
var classInfo = Object.create(ClassInfo.prototype, object);
|
||||
classInfo.resolved_constant_pool = new Array(classInfo.constant_pool.length);
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
constructor(classBytes) {
|
||||
this.id = classID ++;
|
||||
enterTimeline("getClassImage");
|
||||
var classImage = getClassImage(classBytes);
|
||||
leaveTimeline("getClassImage");
|
||||
var cp = classImage.constant_pool;
|
||||
this.className = cp[cp[classImage.this_class].name_index].bytes;
|
||||
this.superClassName = classImage.super_class ? cp[cp[classImage.super_class].name_index].bytes : null;
|
||||
this.access_flags = classImage.access_flags;
|
||||
this.constant_pool = cp;
|
||||
this.resolved_constant_pool = new Array(cp.length);
|
||||
this.subClasses = [];
|
||||
this.allSubClasses = [];
|
||||
// Cache for virtual methods and fields
|
||||
this.vmc = {};
|
||||
this.vfc = {};
|
||||
|
||||
this.mangledName = mangleClass(this);
|
||||
|
||||
var self = this;
|
||||
|
||||
this.interfaces = [];
|
||||
for (var i = 0; i < classImage.interfaces.length; i++) {
|
||||
var j = classImage.interfaces[i];
|
||||
var int = CLASSES.loadClass(cp[cp[j].name_index].bytes);
|
||||
self.interfaces.push(int);
|
||||
self.interfaces = self.interfaces.concat(int.interfaces);
|
||||
}
|
||||
|
||||
this.fields = [];
|
||||
for (var i = 0; i < classImage.fields.length; i++) {
|
||||
var f = classImage.fields[i];
|
||||
var field = new FieldInfo(self, f.access_flags, cp[f.name_index].bytes, cp[f.descriptor_index].bytes);
|
||||
f.attributes.forEach(function (attribute) {
|
||||
if (cp[attribute.attribute_name_index].bytes === "ConstantValue")
|
||||
field.constantValue = new DataView(attribute.info).getUint16(0, false);
|
||||
});
|
||||
self.fields.push(field);
|
||||
}
|
||||
|
||||
enterTimeline("methods");
|
||||
this.methods = [];
|
||||
|
||||
for (var i = 0; i < classImage.methods.length; i++) {
|
||||
var m = classImage.methods[i];
|
||||
var methodInfo = new MethodInfo({
|
||||
name: cp[m.name_index].bytes,
|
||||
signature: cp[m.signature_index].bytes,
|
||||
classInfo: self,
|
||||
attributes: m.attributes,
|
||||
isNative: AccessFlags.isNative(m.access_flags),
|
||||
isPublic: AccessFlags.isPublic(m.access_flags),
|
||||
isStatic: AccessFlags.isStatic(m.access_flags),
|
||||
isSynchronized: AccessFlags.isSynchronized(m.access_flags),
|
||||
isAbstract: AccessFlags.isAbstract(m.access_flags),
|
||||
isFinal: AccessFlags.isFinal(m.access_flags)
|
||||
});
|
||||
this.methods.push(methodInfo);
|
||||
if (methodInfo.name === "<clinit>") {
|
||||
this.staticInitializer = methodInfo;
|
||||
}
|
||||
}
|
||||
leaveTimeline("methods");
|
||||
|
||||
var classes = this.classes = [];
|
||||
for (var i = 0; i < classImage.attributes.length; i++) {
|
||||
var a = classImage.attributes[i];
|
||||
if (a.info.type === ATTRIBUTE_TYPES.InnerClasses) {
|
||||
a.info.classes.forEach(function (c) {
|
||||
classes.push(cp[cp[c.inner_class_info_index].name_index].bytes);
|
||||
if (c.outer_class_info_index)
|
||||
classes.push(cp[cp[c.outer_class_info_index].name_index].bytes);
|
||||
});
|
||||
} else if (a.info.type === ATTRIBUTE_TYPES.SourceFile) {
|
||||
self.sourceFile = cp[a.info.sourcefile_index].bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public complete() {
|
||||
enterTimeline("mangleFields");
|
||||
this._mangleFields();
|
||||
leaveTimeline("mangleFields");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class hierarchy in derived -> base order.
|
||||
*/
|
||||
private _getClassHierarchy(): ClassInfo [] {
|
||||
var classHierarchy = [];
|
||||
var classInfo = this;
|
||||
do {
|
||||
classHierarchy.push(classInfo);
|
||||
classInfo = classInfo.superClass;
|
||||
} while (classInfo);
|
||||
return classHierarchy;
|
||||
}
|
||||
|
||||
private _mangleFields() {
|
||||
if (false) {
|
||||
// Safe mangling that includes className, fieldName and signature.
|
||||
var fields = this.fields;
|
||||
for (var j = 0; j < fields.length; j++) {
|
||||
var fieldInfo = fields[j];
|
||||
fieldInfo.mangledName = "$" + escapeString(fieldInfo.classInfo.className + "_" + fieldInfo.name + "_" + fieldInfo.signature);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep track of how many times a field name was used and resolve conflicts by
|
||||
// prefixing filed names with numbers.
|
||||
var classInfo: ClassInfo;
|
||||
var classHierarchy = this._getClassHierarchy();
|
||||
var count = Object.create(null);
|
||||
for (var i = classHierarchy.length - 1; i >= 0; i--) {
|
||||
classInfo = classHierarchy[i];
|
||||
var fields = classInfo.fields;
|
||||
for (var j = 0; j < fields.length; j++) {
|
||||
var field = fields[j];
|
||||
var fieldName = field.name;
|
||||
if (count[field.name] === undefined) {
|
||||
count[fieldName] = 0;
|
||||
}
|
||||
var fieldCount = count[fieldName];
|
||||
// Only mangle this classInfo's fields.
|
||||
if (i === 0) {
|
||||
field.mangledName = "$" + (fieldCount ? "$" + fieldCount : "") + field.name;
|
||||
}
|
||||
count[fieldName] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get isInterface() : boolean {
|
||||
return AccessFlags.isInterface(this.access_flags);
|
||||
}
|
||||
|
||||
get isFinal() : boolean {
|
||||
return AccessFlags.isFinal(this.access_flags);
|
||||
}
|
||||
|
||||
implementsInterface(iface) : boolean {
|
||||
var classInfo = this;
|
||||
do {
|
||||
var interfaces = classInfo.interfaces;
|
||||
for (var n = 0; n < interfaces.length; ++n) {
|
||||
if (interfaces[n] === iface)
|
||||
return true;
|
||||
}
|
||||
classInfo = classInfo.superClass;
|
||||
} while (classInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
isAssignableTo(toClass: ClassInfo) : boolean {
|
||||
if (this === toClass || toClass === CLASSES.java_lang_Object)
|
||||
return true;
|
||||
if (AccessFlags.isInterface(toClass.access_flags) && this.implementsInterface(toClass))
|
||||
return true;
|
||||
if (this.elementClass && toClass.elementClass)
|
||||
return this.elementClass.isAssignableTo(toClass.elementClass);
|
||||
return this.superClass ? this.superClass.isAssignableTo(toClass) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* java.lang.Class object for this class info. This is a not where static properties
|
||||
* are stored for this class.
|
||||
*/
|
||||
getClassObject(): java.lang.Class {
|
||||
return getRuntimeKlass($, this.klass).classObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object that holds static properties for this class.
|
||||
*/
|
||||
getStaticObject(ctx: Context): java.lang.Object {
|
||||
return <java.lang.Object><any>getRuntimeKlass(ctx.runtime, this.klass);
|
||||
}
|
||||
|
||||
getField(fieldKey: string) : FieldInfo {
|
||||
return CLASSES.getField(this, fieldKey);
|
||||
}
|
||||
|
||||
getClassInitLockObject(ctx: Context) {
|
||||
if (!(this.className in ctx.runtime.classInitLockObjects)) {
|
||||
ctx.runtime.classInitLockObjects[this.className] = {
|
||||
classInfo: this
|
||||
};
|
||||
}
|
||||
return ctx.runtime.classInitLockObjects[this.className];
|
||||
}
|
||||
|
||||
toString() {
|
||||
return "[class " + this.className + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a constant pool reference.
|
||||
*/
|
||||
resolve(index: number, isStatic: boolean) {
|
||||
var rp = this.resolved_constant_pool;
|
||||
var constant: any = rp[index];
|
||||
if (constant !== undefined) {
|
||||
return constant;
|
||||
}
|
||||
var cp = this.constant_pool;
|
||||
var entry = this.constant_pool[index];
|
||||
switch (entry.tag) {
|
||||
case TAGS.CONSTANT_Integer:
|
||||
constant = entry.integer;
|
||||
break;
|
||||
case TAGS.CONSTANT_Float:
|
||||
constant = entry.float;
|
||||
break;
|
||||
case TAGS.CONSTANT_String:
|
||||
constant = $.newStringConstant(cp[entry.string_index].bytes);
|
||||
break;
|
||||
case TAGS.CONSTANT_Long:
|
||||
constant = Long.fromBits(entry.lowBits, entry.highBits);
|
||||
break;
|
||||
case TAGS.CONSTANT_Double:
|
||||
constant = entry.double;
|
||||
break;
|
||||
case TAGS.CONSTANT_Class:
|
||||
constant = CLASSES.getClass(cp[entry.name_index].bytes);
|
||||
break;
|
||||
case TAGS.CONSTANT_Fieldref:
|
||||
var classInfo = this.resolve(entry.class_index, isStatic);
|
||||
var fieldName = cp[cp[entry.name_and_type_index].name_index].bytes;
|
||||
var signature = cp[cp[entry.name_and_type_index].signature_index].bytes;
|
||||
constant = CLASSES.getField(classInfo, (isStatic ? "S" : "I") + "." + fieldName + "." + signature);
|
||||
if (!constant) {
|
||||
throw $.newRuntimeException(
|
||||
classInfo.className + "." + fieldName + "." + signature + " not found");
|
||||
}
|
||||
break;
|
||||
case TAGS.CONSTANT_Methodref:
|
||||
case TAGS.CONSTANT_InterfaceMethodref:
|
||||
var classInfo = this.resolve(entry.class_index, isStatic);
|
||||
var methodName = cp[cp[entry.name_and_type_index].name_index].bytes;
|
||||
var signature = cp[cp[entry.name_and_type_index].signature_index].bytes;
|
||||
constant = CLASSES.getMethod(classInfo, (isStatic ? "S" : "I") + "." + methodName + "." + signature);
|
||||
if (!constant) {
|
||||
constant = CLASSES.getMethod(classInfo, (isStatic ? "S" : "I") + "." + methodName + "." + signature);
|
||||
throw $.newRuntimeException(
|
||||
classInfo.className + "." + methodName + "." + signature + " not found");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("not support constant type");
|
||||
}
|
||||
return rp[index] = constant;
|
||||
}
|
||||
}
|
||||
|
||||
export class ArrayClassInfo extends ClassInfo {
|
||||
constructor(className: string, elementClass?) {
|
||||
false && super(null);
|
||||
this.className = className;
|
||||
// TODO this may need to change for compiled code.
|
||||
this.mangledName = className;
|
||||
this.superClass = CLASSES.java_lang_Object;
|
||||
this.superClassName = "java/lang/Object";
|
||||
this.access_flags = 0;
|
||||
this.elementClass = elementClass;
|
||||
this.vmc = {};
|
||||
this.vfc = {};
|
||||
}
|
||||
implementsInterface(iface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayClassInfo.prototype.fields = [];
|
||||
ArrayClassInfo.prototype.methods = [];
|
||||
ArrayClassInfo.prototype.interfaces = [];
|
||||
ArrayClassInfo.prototype.isArrayClass = true;
|
||||
|
||||
export class PrimitiveClassInfo extends ClassInfo {
|
||||
constructor(className: string, mangledName: string) {
|
||||
false && super(null);
|
||||
this.className = className;
|
||||
this.mangledName = mangledName;
|
||||
}
|
||||
static Z = new PrimitiveClassInfo("Z", "boolean");
|
||||
static C = new PrimitiveClassInfo("C", "char");
|
||||
static F = new PrimitiveClassInfo("F", "float");
|
||||
static D = new PrimitiveClassInfo("D", "double");
|
||||
static B = new PrimitiveClassInfo("B", "byte");
|
||||
static S = new PrimitiveClassInfo("S", "short");
|
||||
static I = new PrimitiveClassInfo("I", "int");
|
||||
static J = new PrimitiveClassInfo("J", "long");
|
||||
}
|
||||
|
||||
PrimitiveClassInfo.prototype.fields = [];
|
||||
PrimitiveClassInfo.prototype.methods = [];
|
||||
PrimitiveClassInfo.prototype.interfaces = [];
|
||||
|
||||
export class PrimitiveArrayClassInfo extends ArrayClassInfo {
|
||||
constructor(className: string, elementClass?) {
|
||||
super(className, elementClass);
|
||||
}
|
||||
|
||||
get superClass() {
|
||||
return CLASSES.java_lang_Object;
|
||||
}
|
||||
|
||||
static Z = new PrimitiveArrayClassInfo("[Z", PrimitiveClassInfo.Z);
|
||||
static C = new PrimitiveArrayClassInfo("[C", PrimitiveClassInfo.C);
|
||||
static F = new PrimitiveArrayClassInfo("[F", PrimitiveClassInfo.F);
|
||||
static D = new PrimitiveArrayClassInfo("[D", PrimitiveClassInfo.D);
|
||||
static B = new PrimitiveArrayClassInfo("[B", PrimitiveClassInfo.B);
|
||||
static S = new PrimitiveArrayClassInfo("[S", PrimitiveClassInfo.S);
|
||||
static I = new PrimitiveArrayClassInfo("[I", PrimitiveClassInfo.I);
|
||||
static J = new PrimitiveArrayClassInfo("[J", PrimitiveClassInfo.J);
|
||||
}
|
||||
|
||||
PrimitiveClassInfo.prototype.fields = [];
|
||||
PrimitiveClassInfo.prototype.methods = [];
|
||||
PrimitiveClassInfo.prototype.interfaces = [];
|
||||
}
|
||||
|
||||
var FieldInfo = J2ME.FieldInfo;
|
||||
var MethodInfo = J2ME.MethodInfo;
|
||||
var ClassInfo = J2ME.ClassInfo;
|
21
arrays.js
|
@ -1,21 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
function LongArray(size) {
|
||||
var array = Array(size);
|
||||
array.class = CLASSES.getClass("[J");
|
||||
return array;
|
||||
}
|
||||
|
||||
var ARRAYS = {
|
||||
'Z': Uint8Array,
|
||||
'C': Uint16Array,
|
||||
'F': Float32Array,
|
||||
'D': Float64Array,
|
||||
'B': Int8Array,
|
||||
'S': Int16Array,
|
||||
'I': Int32Array,
|
||||
'J': LongArray,
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
As this software was developed as part of work done by the United States
|
||||
Government, it is not subject to copyright, and is in the public domain.
|
||||
We would, however, appreciate acknowledgements if this work is found useful.
|
||||
Note that according to GNU.org public domain is compatible with GPL.
|
||||
|
||||
- http://math.nist.gov/scimark2/credits.html
|
|
@ -0,0 +1,12 @@
|
|||
SRCS=$(shell find ./scimark2src/jnt -name *.java)
|
||||
|
||||
|
||||
scimark2.jar: $(SRCS)
|
||||
rm -rf build
|
||||
mkdir build
|
||||
javac -source 1.3 -target 1.3 -encoding UTF-8 -extdirs "" -d ./build $(SRCS) > /dev/null
|
||||
cd build && jar cvf0 ../scimark2.jar *
|
||||
rm -rf build
|
||||
|
||||
clean:
|
||||
rm -f `find . -name "*.jar"`
|
|
@ -0,0 +1,37 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
public class Constants
|
||||
{
|
||||
|
||||
public static final double RESOLUTION_DEFAULT = 2.0; /*secs*/
|
||||
public static final int RANDOM_SEED = 101010;
|
||||
|
||||
// default: small (cache-contained) problem sizes
|
||||
//
|
||||
public static final int FFT_SIZE = 1024; // must be a power of two
|
||||
public static final int SOR_SIZE =100; // NxN grid
|
||||
public static final int SPARSE_SIZE_M = 1000;
|
||||
public static final int SPARSE_SIZE_nz = 5000;
|
||||
public static final int LU_SIZE = 100;
|
||||
|
||||
// large (out-of-cache) problem sizes
|
||||
//
|
||||
public static final int LG_FFT_SIZE = 1048576; // must be a power of two
|
||||
public static final int LG_SOR_SIZE =1000; // NxN grid
|
||||
public static final int LG_SPARSE_SIZE_M = 100000;
|
||||
public static final int LG_SPARSE_SIZE_nz =1000000;
|
||||
public static final int LG_LU_SIZE = 1000;
|
||||
|
||||
// tiny problem sizes (used to mainly to preload network classes
|
||||
// for applet, so that network download times
|
||||
// are factored out of benchmark.)
|
||||
//
|
||||
public static final int TINY_FFT_SIZE = 16; // must be a power of two
|
||||
public static final int TINY_SOR_SIZE =10; // NxN grid
|
||||
public static final int TINY_SPARSE_SIZE_M = 10;
|
||||
public static final int TINY_SPARSE_SIZE_N = 10;
|
||||
public static final int TINY_SPARSE_SIZE_nz = 50;
|
||||
public static final int TINY_LU_SIZE = 10;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
/** Computes FFT's of complex, double precision data where n is an integer power of 2.
|
||||
* This appears to be slower than the Radix2 method,
|
||||
* but the code is smaller and simpler, and it requires no extra storage.
|
||||
* <P>
|
||||
*
|
||||
* @author Bruce R. Miller bruce.miller@nist.gov,
|
||||
* @author Derived from GSL (Gnu Scientific Library),
|
||||
* @author GSL's FFT Code by Brian Gough bjg@vvv.lanl.gov
|
||||
*/
|
||||
|
||||
/* See {@link ComplexDoubleFFT ComplexDoubleFFT} for details of data layout.
|
||||
*/
|
||||
|
||||
public class FFT {
|
||||
|
||||
public static final double num_flops(int N)
|
||||
{
|
||||
double Nd = (double) N;
|
||||
double logN = (double) log2(N);
|
||||
|
||||
return (5.0*Nd-2)*logN + 2*(Nd+1);
|
||||
}
|
||||
|
||||
|
||||
/** Compute Fast Fourier Transform of (complex) data, in place.*/
|
||||
public static void transform (double data[]) {
|
||||
transform_internal(data, -1); }
|
||||
|
||||
/** Compute Inverse Fast Fourier Transform of (complex) data, in place.*/
|
||||
public static void inverse (double data[]) {
|
||||
transform_internal(data, +1);
|
||||
// Normalize
|
||||
int nd=data.length;
|
||||
int n =nd/2;
|
||||
double norm=1/((double) n);
|
||||
for(int i=0; i<nd; i++)
|
||||
data[i] *= norm;
|
||||
}
|
||||
|
||||
/** Accuracy check on FFT of data. Make a copy of data, Compute the FFT, then
|
||||
* the inverse and compare to the original. Returns the rms difference.*/
|
||||
public static double test(double data[]){
|
||||
int nd = data.length;
|
||||
// Make duplicate for comparison
|
||||
double copy[] = new double[nd];
|
||||
System.arraycopy(data,0,copy,0,nd);
|
||||
// Transform & invert
|
||||
transform(data);
|
||||
inverse(data);
|
||||
// Compute RMS difference.
|
||||
double diff = 0.0;
|
||||
for(int i=0; i<nd; i++) {
|
||||
double d = data[i]-copy[i];
|
||||
diff += d*d; }
|
||||
return Math.sqrt(diff/nd); }
|
||||
|
||||
/** Make a random array of n (complex) elements. */
|
||||
public static double[] makeRandom(int n){
|
||||
int nd = 2*n;
|
||||
double data[] = new double[nd];
|
||||
for(int i=0; i<nd; i++)
|
||||
data[i]= Math.random();
|
||||
return data; }
|
||||
|
||||
/** Simple Test routine. */
|
||||
public static void main(String args[]){
|
||||
if (args.length == 0) {
|
||||
int n = 1024;
|
||||
System.out.println("n="+n+" => RMS Error="+test(makeRandom(n))); }
|
||||
for(int i=0; i<args.length; i++) {
|
||||
int n = Integer.parseInt(args[i]);
|
||||
System.out.println("n="+n+" => RMS Error="+test(makeRandom(n))); }
|
||||
}
|
||||
/* ______________________________________________________________________ */
|
||||
|
||||
protected static int log2 (int n){
|
||||
int log = 0;
|
||||
for(int k=1; k < n; k *= 2, log++);
|
||||
if (n != (1 << log))
|
||||
throw new Error("FFT: Data length is not a power of 2!: "+n);
|
||||
return log; }
|
||||
|
||||
protected static void transform_internal (double data[], int direction) {
|
||||
if (data.length == 0) return;
|
||||
int n = data.length/2;
|
||||
if (n == 1) return; // Identity operation!
|
||||
int logn = log2(n);
|
||||
|
||||
/* bit reverse the input data for decimation in time algorithm */
|
||||
bitreverse(data) ;
|
||||
|
||||
/* apply fft recursion */
|
||||
/* this loop executed log2(N) times */
|
||||
for (int bit = 0, dual = 1; bit < logn; bit++, dual *= 2) {
|
||||
double w_real = 1.0;
|
||||
double w_imag = 0.0;
|
||||
|
||||
double theta = 2.0 * direction * Math.PI / (2.0 * (double) dual);
|
||||
double s = Math.sin(theta);
|
||||
double t = Math.sin(theta / 2.0);
|
||||
double s2 = 2.0 * t * t;
|
||||
|
||||
/* a = 0 */
|
||||
for (int b = 0; b < n; b += 2 * dual) {
|
||||
int i = 2*b ;
|
||||
int j = 2*(b + dual);
|
||||
|
||||
double wd_real = data[j] ;
|
||||
double wd_imag = data[j+1] ;
|
||||
|
||||
data[j] = data[i] - wd_real;
|
||||
data[j+1] = data[i+1] - wd_imag;
|
||||
data[i] += wd_real;
|
||||
data[i+1]+= wd_imag;
|
||||
}
|
||||
|
||||
/* a = 1 .. (dual-1) */
|
||||
for (int a = 1; a < dual; a++) {
|
||||
/* trignometric recurrence for w-> exp(i theta) w */
|
||||
{
|
||||
double tmp_real = w_real - s * w_imag - s2 * w_real;
|
||||
double tmp_imag = w_imag + s * w_real - s2 * w_imag;
|
||||
w_real = tmp_real;
|
||||
w_imag = tmp_imag;
|
||||
}
|
||||
for (int b = 0; b < n; b += 2 * dual) {
|
||||
int i = 2*(b + a);
|
||||
int j = 2*(b + a + dual);
|
||||
|
||||
double z1_real = data[j];
|
||||
double z1_imag = data[j+1];
|
||||
|
||||
double wd_real = w_real * z1_real - w_imag * z1_imag;
|
||||
double wd_imag = w_real * z1_imag + w_imag * z1_real;
|
||||
|
||||
data[j] = data[i] - wd_real;
|
||||
data[j+1] = data[i+1] - wd_imag;
|
||||
data[i] += wd_real;
|
||||
data[i+1]+= wd_imag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static void bitreverse(double data[]) {
|
||||
/* This is the Goldrader bit-reversal algorithm */
|
||||
int n=data.length/2;
|
||||
int nm1 = n-1;
|
||||
int i=0;
|
||||
int j=0;
|
||||
for (; i < nm1; i++) {
|
||||
|
||||
//int ii = 2*i;
|
||||
int ii = i << 1;
|
||||
|
||||
//int jj = 2*j;
|
||||
int jj = j << 1;
|
||||
|
||||
//int k = n / 2 ;
|
||||
int k = n >> 1;
|
||||
|
||||
if (i < j) {
|
||||
double tmp_real = data[ii];
|
||||
double tmp_imag = data[ii+1];
|
||||
data[ii] = data[jj];
|
||||
data[ii+1] = data[jj+1];
|
||||
data[jj] = tmp_real;
|
||||
data[jj+1] = tmp_imag; }
|
||||
|
||||
while (k <= j)
|
||||
{
|
||||
//j = j - k ;
|
||||
j -= k;
|
||||
|
||||
//k = k / 2 ;
|
||||
k >>= 1 ;
|
||||
}
|
||||
j += k ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
public class Jacobi
|
||||
{
|
||||
public static final double num_flops(int M, int N, int num_iterations)
|
||||
{
|
||||
double Md = (double) M;
|
||||
double Nd = (double) N;
|
||||
double num_iterD = (double) num_iterations;
|
||||
|
||||
return (Md-1)*(Nd-1)*num_iterD*6.0;
|
||||
}
|
||||
|
||||
public static final void SOR(double omega, double G[][], int num_iterations)
|
||||
{
|
||||
int M = G.length;
|
||||
int N = G[0].length;
|
||||
|
||||
double omega_over_four = omega * 0.25;
|
||||
double one_minus_omega = 1.0 - omega;
|
||||
|
||||
// update interior points
|
||||
//
|
||||
int Mm1 = M-1;
|
||||
int Nm1 = N-1;
|
||||
for (int p=0; p<num_iterations; p++)
|
||||
{
|
||||
for (int i=1; i<Mm1; i++)
|
||||
{
|
||||
double[] Gi = G[i];
|
||||
double[] Gim1 = G[i-1];
|
||||
double[] Gip1 = G[i+1];
|
||||
for (int j=1; j<Nm1; j++)
|
||||
Gi[j] = omega_over_four * (Gim1[j] + Gip1[j] + Gi[j-1]
|
||||
+ Gi[j+1]) + one_minus_omega * Gi[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
/**
|
||||
LU matrix factorization. (Based on TNT implementation.)
|
||||
Decomposes a matrix A into a triangular lower triangular
|
||||
factor (L) and an upper triangular factor (U) such that
|
||||
A = L*U. By convnetion, the main diagonal of L consists
|
||||
of 1's so that L and U can be stored compactly in
|
||||
a NxN matrix.
|
||||
|
||||
|
||||
*/
|
||||
public class LU
|
||||
{
|
||||
/**
|
||||
Returns a <em>copy</em> of the compact LU factorization.
|
||||
(useful mainly for debugging.)
|
||||
|
||||
@return the compact LU factorization. The U factor
|
||||
is stored in the upper triangular portion, and the L
|
||||
factor is stored in the lower triangular portion.
|
||||
The main diagonal of L consists (by convention) of
|
||||
ones, and is not explicitly stored.
|
||||
*/
|
||||
|
||||
|
||||
public static final double num_flops(int N)
|
||||
{
|
||||
// rougly 2/3*N^3
|
||||
|
||||
double Nd = (double) N;
|
||||
|
||||
return (2.0 * Nd *Nd *Nd/ 3.0);
|
||||
}
|
||||
|
||||
protected static double[] new_copy(double x[])
|
||||
{
|
||||
int N = x.length;
|
||||
double T[] = new double[N];
|
||||
for (int i=0; i<N; i++)
|
||||
T[i] = x[i];
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
protected static double[][] new_copy(double A[][])
|
||||
{
|
||||
int M = A.length;
|
||||
int N = A[0].length;
|
||||
|
||||
double T[][] = new double[M][N];
|
||||
|
||||
for (int i=0; i<M; i++)
|
||||
{
|
||||
double Ti[] = T[i];
|
||||
double Ai[] = A[i];
|
||||
for (int j=0; j<N; j++)
|
||||
Ti[j] = Ai[j];
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int[] new_copy(int x[])
|
||||
{
|
||||
int N = x.length;
|
||||
int T[] = new int[N];
|
||||
for (int i=0; i<N; i++)
|
||||
T[i] = x[i];
|
||||
return T;
|
||||
}
|
||||
|
||||
protected static final void insert_copy(double B[][], double A[][])
|
||||
{
|
||||
int M = A.length;
|
||||
int N = A[0].length;
|
||||
|
||||
int remainder = N & 3; // N mod 4;
|
||||
|
||||
for (int i=0; i<M; i++)
|
||||
{
|
||||
double Bi[] = B[i];
|
||||
double Ai[] = A[i];
|
||||
for (int j=0; j<remainder; j++)
|
||||
Bi[j] = Ai[j];
|
||||
for (int j=remainder; j<N; j+=4)
|
||||
{
|
||||
Bi[j] = Ai[j];
|
||||
Bi[j+1] = Ai[j+1];
|
||||
Bi[j+2] = Ai[j+2];
|
||||
Bi[j+3] = Ai[j+3];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public double[][] getLU()
|
||||
{
|
||||
return new_copy(LU_);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a <em>copy</em> of the pivot vector.
|
||||
|
||||
@return the pivot vector used in obtaining the
|
||||
LU factorzation. Subsequent solutions must
|
||||
permute the right-hand side by this vector.
|
||||
|
||||
*/
|
||||
public int[] getPivot()
|
||||
{
|
||||
return new_copy(pivot_);
|
||||
}
|
||||
|
||||
/**
|
||||
Initalize LU factorization from matrix.
|
||||
|
||||
@param A (in) the matrix to associate with this
|
||||
factorization.
|
||||
*/
|
||||
public LU( double A[][] )
|
||||
{
|
||||
int M = A.length;
|
||||
int N = A[0].length;
|
||||
|
||||
//if ( LU_ == null || LU_.length != M || LU_[0].length != N)
|
||||
LU_ = new double[M][N];
|
||||
|
||||
insert_copy(LU_, A);
|
||||
|
||||
//if (pivot_.length != M)
|
||||
pivot_ = new int[M];
|
||||
|
||||
factor(LU_, pivot_);
|
||||
}
|
||||
|
||||
/**
|
||||
Solve a linear system, with pre-computed factorization.
|
||||
|
||||
@param b (in) the right-hand side.
|
||||
@return solution vector.
|
||||
*/
|
||||
public double[] solve(double b[])
|
||||
{
|
||||
double x[] = new_copy(b);
|
||||
|
||||
solve(LU_, pivot_, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
LU factorization (in place).
|
||||
|
||||
@param A (in/out) On input, the matrix to be factored.
|
||||
On output, the compact LU factorization.
|
||||
|
||||
@param pivit (out) The pivot vector records the
|
||||
reordering of the rows of A during factorization.
|
||||
|
||||
@return 0, if OK, nozero value, othewise.
|
||||
*/
|
||||
public static int factor(double A[][], int pivot[])
|
||||
{
|
||||
|
||||
|
||||
|
||||
int N = A.length;
|
||||
int M = A[0].length;
|
||||
|
||||
int minMN = Math.min(M,N);
|
||||
|
||||
for (int j=0; j<minMN; j++)
|
||||
{
|
||||
// find pivot in column j and test for singularity.
|
||||
|
||||
int jp=j;
|
||||
|
||||
double t = Math.abs(A[j][j]);
|
||||
for (int i=j+1; i<M; i++)
|
||||
{
|
||||
double ab = Math.abs(A[i][j]);
|
||||
if ( ab > t)
|
||||
{
|
||||
jp = i;
|
||||
t = ab;
|
||||
}
|
||||
}
|
||||
|
||||
pivot[j] = jp;
|
||||
|
||||
// jp now has the index of maximum element
|
||||
// of column j, below the diagonal
|
||||
|
||||
if ( A[jp][j] == 0 )
|
||||
return 1; // factorization failed because of zero pivot
|
||||
|
||||
|
||||
if (jp != j)
|
||||
{
|
||||
// swap rows j and jp
|
||||
double tA[] = A[j];
|
||||
A[j] = A[jp];
|
||||
A[jp] = tA;
|
||||
}
|
||||
|
||||
if (j<M-1) // compute elements j+1:M of jth column
|
||||
{
|
||||
// note A(j,j), was A(jp,p) previously which was
|
||||
// guarranteed not to be zero (Label #1)
|
||||
//
|
||||
double recp = 1.0 / A[j][j];
|
||||
|
||||
for (int k=j+1; k<M; k++)
|
||||
A[k][j] *= recp;
|
||||
}
|
||||
|
||||
|
||||
if (j < minMN-1)
|
||||
{
|
||||
// rank-1 update to trailing submatrix: E = E - x*y;
|
||||
//
|
||||
// E is the region A(j+1:M, j+1:N)
|
||||
// x is the column vector A(j+1:M,j)
|
||||
// y is row vector A(j,j+1:N)
|
||||
|
||||
|
||||
for (int ii=j+1; ii<M; ii++)
|
||||
{
|
||||
double Aii[] = A[ii];
|
||||
double Aj[] = A[j];
|
||||
double AiiJ = Aii[j];
|
||||
for (int jj=j+1; jj<N; jj++)
|
||||
Aii[jj] -= AiiJ * Aj[jj];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Solve a linear system, using a prefactored matrix
|
||||
in LU form.
|
||||
|
||||
|
||||
@param LU (in) the factored matrix in LU form.
|
||||
@param pivot (in) the pivot vector which lists
|
||||
the reordering used during the factorization
|
||||
stage.
|
||||
@param b (in/out) On input, the right-hand side.
|
||||
On output, the solution vector.
|
||||
*/
|
||||
public static void solve(double LU[][], int pvt[], double b[])
|
||||
{
|
||||
int M = LU.length;
|
||||
int N = LU[0].length;
|
||||
int ii=0;
|
||||
|
||||
for (int i=0; i<M; i++)
|
||||
{
|
||||
int ip = pvt[i];
|
||||
double sum = b[ip];
|
||||
|
||||
b[ip] = b[i];
|
||||
if (ii==0)
|
||||
for (int j=ii; j<i; j++)
|
||||
sum -= LU[i][j] * b[j];
|
||||
else
|
||||
if (sum == 0.0)
|
||||
ii = i;
|
||||
b[i] = sum;
|
||||
}
|
||||
|
||||
for (int i=N-1; i>=0; i--)
|
||||
{
|
||||
double sum = b[i];
|
||||
for (int j=i+1; j<N; j++)
|
||||
sum -= LU[i][j] * b[j];
|
||||
b[i] = sum / LU[i][i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private double LU_[][];
|
||||
private int pivot_[];
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
/**
|
||||
Estimate Pi by approximating the area of a circle.
|
||||
|
||||
How: generate N random numbers in the unit square, (0,0) to (1,1)
|
||||
and see how are within a radius of 1 or less, i.e.
|
||||
<pre>
|
||||
|
||||
sqrt(x^2 + y^2) < r
|
||||
|
||||
</pre>
|
||||
since the radius is 1.0, we can square both sides
|
||||
and avoid a sqrt() computation:
|
||||
<pre>
|
||||
|
||||
x^2 + y^2 <= 1.0
|
||||
|
||||
</pre>
|
||||
this area under the curve is (Pi * r^2)/ 4.0,
|
||||
and the area of the unit of square is 1.0,
|
||||
so Pi can be approximated by
|
||||
<pre>
|
||||
# points with x^2+y^2 < 1
|
||||
Pi =~ -------------------------- * 4.0
|
||||
total # points
|
||||
|
||||
</pre>
|
||||
|
||||
*/
|
||||
|
||||
public class MonteCarlo
|
||||
{
|
||||
final static int SEED = 113;
|
||||
|
||||
public static final double num_flops(int Num_samples)
|
||||
{
|
||||
// 3 flops in x^2+y^2 and 1 flop in random routine
|
||||
|
||||
return ((double) Num_samples)* 4.0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static final double integrate(int Num_samples)
|
||||
{
|
||||
|
||||
Random R = new Random(SEED);
|
||||
|
||||
|
||||
int under_curve = 0;
|
||||
for (int count=0; count<Num_samples; count++)
|
||||
{
|
||||
double x= R.nextDouble();
|
||||
double y= R.nextDouble();
|
||||
|
||||
if ( x*x + y*y <= 1.0)
|
||||
under_curve ++;
|
||||
|
||||
}
|
||||
|
||||
return ((double) under_curve / Num_samples) * 4.0;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
/* Random.java based on Java Numerical Toolkit (JNT) Random.UniformSequence
|
||||
class. We do not use Java's own java.util.Random so that we can compare
|
||||
results with equivalent C and Fortran coces.
|
||||
*/
|
||||
|
||||
public class Random {
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------
|
||||
CLASS VARIABLES
|
||||
------------------------------------------------------------------------------ */
|
||||
|
||||
int seed = 0;
|
||||
|
||||
private int m[];
|
||||
private int i = 4;
|
||||
private int j = 16;
|
||||
|
||||
private final int mdig = 32;
|
||||
private final int one = 1;
|
||||
private final int m1 = (one << mdig-2) + ((one << mdig-2)-one);
|
||||
private final int m2 = one << mdig/2;
|
||||
|
||||
/* For mdig = 32 : m1 = 2147483647, m2 = 65536
|
||||
For mdig = 64 : m1 = 9223372036854775807, m2 = 4294967296
|
||||
*/
|
||||
|
||||
private double dm1 = 1.0 / (double) m1;
|
||||
|
||||
private boolean haveRange = false;
|
||||
private double left = 0.0;
|
||||
private double right = 1.0;
|
||||
private double width = 1.0;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------
|
||||
CONSTRUCTORS
|
||||
------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
Initializes a sequence of uniformly distributed quasi random numbers with a
|
||||
seed based on the system clock.
|
||||
*/
|
||||
public Random () {
|
||||
initialize( (int) System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a sequence of uniformly distributed quasi random numbers on a
|
||||
given half-open interval [left,right) with a seed based on the system
|
||||
clock.
|
||||
|
||||
@param <B>left</B> (double)<BR>
|
||||
|
||||
The left endpoint of the half-open interval [left,right).
|
||||
|
||||
@param <B>right</B> (double)<BR>
|
||||
|
||||
The right endpoint of the half-open interval [left,right).
|
||||
*/
|
||||
public Random ( double left, double right) {
|
||||
initialize( (int) System.currentTimeMillis() );
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
width = right - left;
|
||||
haveRange = true;
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a sequence of uniformly distributed quasi random numbers with a
|
||||
given seed.
|
||||
|
||||
@param <B>seed</B> (int)<BR>
|
||||
|
||||
The seed of the random number generator. Two sequences with the same
|
||||
seed will be identical.
|
||||
*/
|
||||
public Random (int seed) {
|
||||
initialize( seed);
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a sequence of uniformly distributed quasi random numbers
|
||||
with a given seed on a given half-open interval [left,right).
|
||||
|
||||
@param <B>seed</B> (int)<BR>
|
||||
|
||||
The seed of the random number generator. Two sequences with the same
|
||||
seed will be identical.
|
||||
|
||||
@param <B>left</B> (double)<BR>
|
||||
|
||||
The left endpoint of the half-open interval [left,right).
|
||||
|
||||
@param <B>right</B> (double)<BR>
|
||||
|
||||
The right endpoint of the half-open interval [left,right).
|
||||
*/
|
||||
public Random (int seed, double left, double right) {
|
||||
initialize( seed);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
width = right - left;
|
||||
haveRange = true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------
|
||||
PUBLIC METHODS
|
||||
------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
Returns the next random number in the sequence.
|
||||
*/
|
||||
public final synchronized double nextDouble () {
|
||||
|
||||
int k;
|
||||
double nextValue;
|
||||
|
||||
k = m[i] - m[j];
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
|
||||
if (i == 0)
|
||||
i = 16;
|
||||
else i--;
|
||||
|
||||
if (j == 0)
|
||||
j = 16 ;
|
||||
else j--;
|
||||
|
||||
if (haveRange)
|
||||
return left + dm1 * (double) k * width;
|
||||
else
|
||||
return dm1 * (double) k;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the next N random numbers in the sequence, as
|
||||
a vector.
|
||||
*/
|
||||
public final synchronized void nextDoubles (double x[])
|
||||
{
|
||||
|
||||
int N = x.length;
|
||||
int remainder = N & 3; // N mod 4
|
||||
|
||||
if (haveRange)
|
||||
{
|
||||
for (int count=0; count<N; count++)
|
||||
{
|
||||
int k = m[i] - m[j];
|
||||
|
||||
if (i == 0) i = 16;
|
||||
else i--;
|
||||
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
|
||||
if (j == 0) j = 16;
|
||||
else j--;
|
||||
|
||||
x[count] = left + dm1 * (double) k * width;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for (int count=0; count<remainder; count++)
|
||||
{
|
||||
int k = m[i] - m[j];
|
||||
|
||||
if (i == 0) i = 16;
|
||||
else i--;
|
||||
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
|
||||
if (j == 0) j = 16;
|
||||
else j--;
|
||||
|
||||
|
||||
x[count] = dm1 * (double) k;
|
||||
}
|
||||
|
||||
for (int count=remainder; count<N; count+=4)
|
||||
{
|
||||
int k = m[i] - m[j];
|
||||
if (i == 0) i = 16;
|
||||
else i--;
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
if (j == 0) j = 16;
|
||||
else j--;
|
||||
x[count] = dm1 * (double) k;
|
||||
|
||||
|
||||
k = m[i] - m[j];
|
||||
if (i == 0) i = 16;
|
||||
else i--;
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
if (j == 0) j = 16;
|
||||
else j--;
|
||||
x[count+1] = dm1 * (double) k;
|
||||
|
||||
|
||||
k = m[i] - m[j];
|
||||
if (i == 0) i = 16;
|
||||
else i--;
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
if (j == 0) j = 16;
|
||||
else j--;
|
||||
x[count+2] = dm1 * (double) k;
|
||||
|
||||
|
||||
k = m[i] - m[j];
|
||||
if (i == 0) i = 16;
|
||||
else i--;
|
||||
if (k < 0) k += m1;
|
||||
m[j] = k;
|
||||
if (j == 0) j = 16;
|
||||
else j--;
|
||||
x[count+3] = dm1 * (double) k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
PRIVATE METHODS
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
private void initialize (int seed) {
|
||||
|
||||
int jseed, k0, k1, j0, j1, iloop;
|
||||
|
||||
this.seed = seed;
|
||||
|
||||
m = new int[17];
|
||||
|
||||
jseed = Math.min(Math.abs(seed),m1);
|
||||
if (jseed % 2 == 0) --jseed;
|
||||
k0 = 9069 % m2;
|
||||
k1 = 9069 / m2;
|
||||
j0 = jseed % m2;
|
||||
j1 = jseed / m2;
|
||||
for (iloop = 0; iloop < 17; ++iloop)
|
||||
{
|
||||
jseed = j0 * k0;
|
||||
j1 = (jseed / m2 + j0 * k1 + j1 * k0) % (m2 / 2);
|
||||
j0 = jseed % m2;
|
||||
m[iloop] = j0 + m2 * j1;
|
||||
}
|
||||
i = 4;
|
||||
j = 16;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
public class SOR
|
||||
{
|
||||
public static final double num_flops(int M, int N, int num_iterations)
|
||||
{
|
||||
double Md = (double) M;
|
||||
double Nd = (double) N;
|
||||
double num_iterD = (double) num_iterations;
|
||||
|
||||
return (Md-1)*(Nd-1)*num_iterD*6.0;
|
||||
}
|
||||
|
||||
public static final void execute(double omega, double G[][], int
|
||||
num_iterations)
|
||||
{
|
||||
int M = G.length;
|
||||
int N = G[0].length;
|
||||
|
||||
double omega_over_four = omega * 0.25;
|
||||
double one_minus_omega = 1.0 - omega;
|
||||
|
||||
// update interior points
|
||||
//
|
||||
int Mm1 = M-1;
|
||||
int Nm1 = N-1;
|
||||
for (int p=0; p<num_iterations; p++)
|
||||
{
|
||||
for (int i=1; i<Mm1; i++)
|
||||
{
|
||||
double[] Gi = G[i];
|
||||
double[] Gim1 = G[i-1];
|
||||
double[] Gip1 = G[i+1];
|
||||
for (int j=1; j<Nm1; j++)
|
||||
Gi[j] = omega_over_four * (Gim1[j] + Gip1[j] + Gi[j-1]
|
||||
+ Gi[j+1]) + one_minus_omega * Gi[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
public class SparseCompRow
|
||||
{
|
||||
/* multiple iterations used to make kernel have roughly
|
||||
same granulairty as other Scimark kernels. */
|
||||
|
||||
public static double num_flops(int N, int nz, int num_iterations)
|
||||
{
|
||||
/* Note that if nz does not divide N evenly, then the
|
||||
actual number of nonzeros used is adjusted slightly.
|
||||
*/
|
||||
int actual_nz = (nz/N) * N;
|
||||
return ((double)actual_nz) * 2.0 * ((double) num_iterations);
|
||||
}
|
||||
|
||||
|
||||
/* computes a matrix-vector multiply with a sparse matrix
|
||||
held in compress-row format. If the size of the matrix
|
||||
in MxN with nz nonzeros, then the val[] is the nz nonzeros,
|
||||
with its ith entry in column col[i]. The integer vector row[]
|
||||
is of size M+1 and row[i] points to the begining of the
|
||||
ith row in col[].
|
||||
*/
|
||||
|
||||
public static void matmult( double y[], double val[], int row[],
|
||||
int col[], double x[], int NUM_ITERATIONS)
|
||||
{
|
||||
int M = row.length - 1;
|
||||
|
||||
for (int reps=0; reps<NUM_ITERATIONS; reps++)
|
||||
{
|
||||
|
||||
for (int r=0; r<M; r++)
|
||||
{
|
||||
double sum = 0.0;
|
||||
int rowR = row[r];
|
||||
int rowRp1 = row[r+1];
|
||||
for (int i=rowR; i<rowRp1; i++)
|
||||
sum += x[ col[i] ] * val[i];
|
||||
y[r] = sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
/**
|
||||
|
||||
Provides a stopwatch to measure elapsed time.
|
||||
|
||||
<P>
|
||||
<DL>
|
||||
<DT><B>Example of use:</B></DT>
|
||||
<DD>
|
||||
<p>
|
||||
<pre>
|
||||
Stopwatch Q = new Stopwatch;
|
||||
<p>
|
||||
Q.start();
|
||||
//
|
||||
// code to be timed here ...
|
||||
//
|
||||
Q.stop();
|
||||
System.out.println("elapsed time was: " + Q.read() + " seconds.");
|
||||
</pre>
|
||||
|
||||
@author Roldan Pozo
|
||||
@version 14 October 1997, revised 1999-04-24
|
||||
*/
|
||||
public class Stopwatch
|
||||
{
|
||||
private boolean running;
|
||||
private double last_time;
|
||||
private double total;
|
||||
|
||||
|
||||
/**
|
||||
Return system time (in seconds)
|
||||
|
||||
*/
|
||||
public final static double seconds()
|
||||
{
|
||||
return (System.currentTimeMillis() * 0.001);
|
||||
}
|
||||
|
||||
/**
|
||||
Return system time (in seconds)
|
||||
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
running = false;
|
||||
last_time = 0.0;
|
||||
total=0.0;
|
||||
}
|
||||
|
||||
public Stopwatch()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Start (and reset) timer
|
||||
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
if (!running)
|
||||
{
|
||||
running = true;
|
||||
total = 0.0;
|
||||
last_time = seconds();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Resume timing, after stopping. (Does not wipe out
|
||||
accumulated times.)
|
||||
|
||||
*/
|
||||
public void resume()
|
||||
{
|
||||
if (!running)
|
||||
{
|
||||
last_time = seconds();
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Stop timer
|
||||
|
||||
*/
|
||||
public double stop()
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
total += seconds() - last_time;
|
||||
running = false;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Display the elapsed time (in seconds)
|
||||
|
||||
*/
|
||||
public double read()
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
total += seconds() - last_time;
|
||||
last_time = seconds();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
SciMark2: A Java numerical benchmark measuring performance
|
||||
of computational kernels for FFTs, Monte Carlo simulation,
|
||||
sparse matrix computations, Jacobi SOR, and dense LU matrix
|
||||
factorizations.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
public class commandline
|
||||
{
|
||||
|
||||
/* Benchmark 5 kernels with individual Mflops.
|
||||
"results[0]" has the average Mflop rate.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
public static void main(String args[])
|
||||
{
|
||||
// default to the (small) cache-contained version
|
||||
|
||||
double min_time = Constants.RESOLUTION_DEFAULT;
|
||||
|
||||
int FFT_size = Constants.FFT_SIZE;
|
||||
int SOR_size = Constants.SOR_SIZE;
|
||||
int Sparse_size_M = Constants.SPARSE_SIZE_M;
|
||||
int Sparse_size_nz = Constants.SPARSE_SIZE_nz;
|
||||
int LU_size = Constants.LU_SIZE;
|
||||
|
||||
// look for runtime options
|
||||
|
||||
if (args.length > 0)
|
||||
{
|
||||
|
||||
if (args[0].equalsIgnoreCase("-h") ||
|
||||
args[0].equalsIgnoreCase("-help"))
|
||||
{
|
||||
System.out.println("Usage: [-large] [minimum_time]");
|
||||
return;
|
||||
}
|
||||
|
||||
int current_arg = 0;
|
||||
if (args[current_arg].equalsIgnoreCase("-large"))
|
||||
{
|
||||
FFT_size = Constants.LG_FFT_SIZE;
|
||||
SOR_size = Constants.LG_SOR_SIZE;
|
||||
Sparse_size_M = Constants.LG_SPARSE_SIZE_M;
|
||||
Sparse_size_nz = Constants.LG_SPARSE_SIZE_nz;
|
||||
LU_size = Constants.LG_LU_SIZE;
|
||||
|
||||
current_arg++;
|
||||
}
|
||||
|
||||
if (args.length > current_arg)
|
||||
min_time = Double.valueOf(args[current_arg]).doubleValue();
|
||||
}
|
||||
|
||||
|
||||
// run the benchmark
|
||||
|
||||
double res[] = new double[6];
|
||||
Random R = new Random(Constants.RANDOM_SEED);
|
||||
|
||||
res[1] = kernel.measureFFT( FFT_size, min_time, R);
|
||||
res[2] = kernel.measureSOR( SOR_size, min_time, R);
|
||||
res[3] = kernel.measureMonteCarlo(min_time, R);
|
||||
res[4] = kernel.measureSparseMatmult( Sparse_size_M,
|
||||
Sparse_size_nz, min_time, R);
|
||||
res[5] = kernel.measureLU( LU_size, min_time, R);
|
||||
|
||||
|
||||
res[0] = (res[1] + res[2] + res[3] + res[4] + res[5]) / 5;
|
||||
|
||||
|
||||
// print out results
|
||||
|
||||
System.out.println();
|
||||
System.out.println("SciMark 2.0a");
|
||||
System.out.println();
|
||||
System.out.println("Composite Score: " + res[0]);
|
||||
System.out.print("FFT ("+FFT_size+"): ");
|
||||
if (res[1]==0.0)
|
||||
System.out.println(" ERROR, INVALID NUMERICAL RESULT!");
|
||||
else
|
||||
System.out.println(res[1]);
|
||||
|
||||
System.out.println("SOR ("+SOR_size+"x"+ SOR_size+"): "
|
||||
+ " " + res[2]);
|
||||
System.out.println("Monte Carlo : " + res[3]);
|
||||
System.out.println("Sparse matmult (N="+ Sparse_size_M+
|
||||
", nz=" + Sparse_size_nz + "): " + res[4]);
|
||||
System.out.print("LU (" + LU_size + "x" + LU_size + "): ");
|
||||
if (res[5]==0.0)
|
||||
System.out.println(" ERROR, INVALID NUMERICAL RESULT!");
|
||||
else
|
||||
System.out.println(res[5]);
|
||||
|
||||
// print out System info
|
||||
System.out.println();
|
||||
System.out.println("java.vendor: " +
|
||||
System.getProperty("java.vendor"));
|
||||
System.out.println("java.version: " +
|
||||
System.getProperty("java.version"));
|
||||
System.out.println("os.arch: " +
|
||||
System.getProperty("os.arch"));
|
||||
System.out.println("os.name: " +
|
||||
System.getProperty("os.name"));
|
||||
System.out.println("os.version: " +
|
||||
System.getProperty("os.version"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
package jnt.scimark2;
|
||||
|
||||
public class kernel
|
||||
{
|
||||
// each measurement returns approx Mflops
|
||||
|
||||
|
||||
public static double measureFFT(int N, double mintime, Random R)
|
||||
{
|
||||
// initialize FFT data as complex (N real/img pairs)
|
||||
|
||||
double x[] = RandomVector(2*N, R);
|
||||
double oldx[] = NewVectorCopy(x);
|
||||
long cycles = 1;
|
||||
Stopwatch Q = new Stopwatch();
|
||||
|
||||
while(true)
|
||||
{
|
||||
Q.start();
|
||||
for (int i=0; i<cycles; i++)
|
||||
{
|
||||
FFT.transform(x); // forward transform
|
||||
FFT.inverse(x); // backward transform
|
||||
}
|
||||
Q.stop();
|
||||
if (Q.read() >= mintime)
|
||||
break;
|
||||
|
||||
cycles *= 2;
|
||||
}
|
||||
// approx Mflops
|
||||
|
||||
final double EPS = 1.0e-10;
|
||||
if ( FFT.test(x) / N > EPS )
|
||||
return 0.0;
|
||||
|
||||
return FFT.num_flops(N)*cycles/ Q.read() * 1.0e-6;
|
||||
}
|
||||
|
||||
|
||||
public static double measureSOR(int N, double min_time, Random R)
|
||||
{
|
||||
double G[][] = RandomMatrix(N, N, R);
|
||||
|
||||
Stopwatch Q = new Stopwatch();
|
||||
int cycles=1;
|
||||
while(true)
|
||||
{
|
||||
Q.start();
|
||||
SOR.execute(1.25, G, cycles);
|
||||
Q.stop();
|
||||
if (Q.read() >= min_time) break;
|
||||
|
||||
cycles *= 2;
|
||||
}
|
||||
// approx Mflops
|
||||
return SOR.num_flops(N, N, cycles) / Q.read() * 1.0e-6;
|
||||
}
|
||||
|
||||
public static double measureMonteCarlo(double min_time, Random R)
|
||||
{
|
||||
Stopwatch Q = new Stopwatch();
|
||||
|
||||
int cycles=1;
|
||||
while(true)
|
||||
{
|
||||
Q.start();
|
||||
MonteCarlo.integrate(cycles);
|
||||
Q.stop();
|
||||
if (Q.read() >= min_time) break;
|
||||
|
||||
cycles *= 2;
|
||||
}
|
||||
// approx Mflops
|
||||
return MonteCarlo.num_flops(cycles) / Q.read() * 1.0e-6;
|
||||
}
|
||||
|
||||
|
||||
public static double measureSparseMatmult(int N, int nz,
|
||||
double min_time, Random R)
|
||||
{
|
||||
// initialize vector multipliers and storage for result
|
||||
// y = A*y;
|
||||
|
||||
double x[] = RandomVector(N, R);
|
||||
double y[] = new double[N];
|
||||
|
||||
// initialize square sparse matrix
|
||||
//
|
||||
// for this test, we create a sparse matrix wit M/nz nonzeros
|
||||
// per row, with spaced-out evenly between the begining of the
|
||||
// row to the main diagonal. Thus, the resulting pattern looks
|
||||
// like
|
||||
// +-----------------+
|
||||
// +* +
|
||||
// +*** +
|
||||
// +* * * +
|
||||
// +** * * +
|
||||
// +** * * +
|
||||
// +* * * * +
|
||||
// +* * * * +
|
||||
// +* * * * +
|
||||
// +-----------------+
|
||||
//
|
||||
// (as best reproducible with integer artihmetic)
|
||||
// Note that the first nr rows will have elements past
|
||||
// the diagonal.
|
||||
|
||||
int nr = nz/N; // average number of nonzeros per row
|
||||
int anz = nr *N; // _actual_ number of nonzeros
|
||||
|
||||
|
||||
double val[] = RandomVector(anz, R);
|
||||
int col[] = new int[anz];
|
||||
int row[] = new int[N+1];
|
||||
|
||||
row[0] = 0;
|
||||
for (int r=0; r<N; r++)
|
||||
{
|
||||
// initialize elements for row r
|
||||
|
||||
int rowr = row[r];
|
||||
row[r+1] = rowr + nr;
|
||||
int step = r/ nr;
|
||||
if (step < 1) step = 1; // take at least unit steps
|
||||
|
||||
|
||||
for (int i=0; i<nr; i++)
|
||||
col[rowr+i] = i*step;
|
||||
|
||||
}
|
||||
|
||||
Stopwatch Q = new Stopwatch();
|
||||
|
||||
int cycles=1;
|
||||
while(true)
|
||||
{
|
||||
Q.start();
|
||||
SparseCompRow.matmult(y, val, row, col, x, cycles);
|
||||
Q.stop();
|
||||
if (Q.read() >= min_time) break;
|
||||
|
||||
cycles *= 2;
|
||||
}
|
||||
// approx Mflops
|
||||
return SparseCompRow.num_flops(N, nz, cycles) / Q.read() * 1.0e-6;
|
||||
}
|
||||
|
||||
|
||||
public static double measureLU(int N, double min_time, Random R)
|
||||
{
|
||||
// compute approx Mlfops, or O if LU yields large errors
|
||||
|
||||
double A[][] = RandomMatrix(N, N, R);
|
||||
double lu[][] = new double[N][N];
|
||||
int pivot[] = new int[N];
|
||||
|
||||
Stopwatch Q = new Stopwatch();
|
||||
|
||||
int cycles=1;
|
||||
while(true)
|
||||
{
|
||||
Q.start();
|
||||
for (int i=0; i<cycles; i++)
|
||||
{
|
||||
CopyMatrix(lu, A);
|
||||
LU.factor(lu, pivot);
|
||||
}
|
||||
Q.stop();
|
||||
if (Q.read() >= min_time) break;
|
||||
|
||||
cycles *= 2;
|
||||
}
|
||||
|
||||
|
||||
// verify that LU is correct
|
||||
double b[] = RandomVector(N, R);
|
||||
double x[] = NewVectorCopy(b);
|
||||
|
||||
LU.solve(lu, pivot, x);
|
||||
|
||||
final double EPS = 1.0e-12;
|
||||
if ( normabs(b, matvec(A,x)) / N > EPS )
|
||||
return 0.0;
|
||||
|
||||
|
||||
// else return approx Mflops
|
||||
//
|
||||
return LU.num_flops(N) * cycles / Q.read() * 1.0e-6;
|
||||
}
|
||||
|
||||
|
||||
private static double[] NewVectorCopy(double x[])
|
||||
{
|
||||
int N = x.length;
|
||||
|
||||
double y[] = new double[N];
|
||||
for (int i=0; i<N; i++)
|
||||
y[i] = x[i];
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
private static void CopyVector(double B[], double A[])
|
||||
{
|
||||
int N = A.length;
|
||||
|
||||
for (int i=0; i<N; i++)
|
||||
B[i] = A[i];
|
||||
}
|
||||
|
||||
|
||||
private static double normabs(double x[], double y[])
|
||||
{
|
||||
int N = x.length;
|
||||
double sum = 0.0;
|
||||
|
||||
for (int i=0; i<N; i++)
|
||||
sum += Math.abs(x[i]-y[i]);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
private static void CopyMatrix(double B[][], double A[][])
|
||||
{
|
||||
int M = A.length;
|
||||
int N = A[0].length;
|
||||
|
||||
int remainder = N & 3; // N mod 4;
|
||||
|
||||
for (int i=0; i<M; i++)
|
||||
{
|
||||
double Bi[] = B[i];
|
||||
double Ai[] = A[i];
|
||||
for (int j=0; j<remainder; j++)
|
||||
Bi[j] = Ai[j];
|
||||
for (int j=remainder; j<N; j+=4)
|
||||
{
|
||||
Bi[j] = Ai[j];
|
||||
Bi[j+1] = Ai[j+1];
|
||||
Bi[j+2] = Ai[j+2];
|
||||
Bi[j+3] = Ai[j+3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double[][] RandomMatrix(int M, int N, Random R)
|
||||
{
|
||||
double A[][] = new double[M][N];
|
||||
|
||||
for (int i=0; i<N; i++)
|
||||
for (int j=0; j<N; j++)
|
||||
A[i][j] = R.nextDouble();
|
||||
return A;
|
||||
}
|
||||
|
||||
private static double[] RandomVector(int N, Random R)
|
||||
{
|
||||
double A[] = new double[N];
|
||||
|
||||
for (int i=0; i<N; i++)
|
||||
A[i] = R.nextDouble();
|
||||
return A;
|
||||
}
|
||||
|
||||
private static double[] matvec(double A[][], double x[])
|
||||
{
|
||||
int N = x.length;
|
||||
double y[] = new double[N];
|
||||
|
||||
matvec(A, x, y);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
private static void matvec(double A[][], double x[], double y[])
|
||||
{
|
||||
int M = A.length;
|
||||
int N = A[0].length;
|
||||
|
||||
for (int i=0; i<M; i++)
|
||||
{
|
||||
double sum = 0.0;
|
||||
double Ai[] = A[i];
|
||||
for (int j=0; j<N; j++)
|
||||
sum += Ai[j] * x[j];
|
||||
|
||||
y[i] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
module J2ME {
|
||||
export var Bindings = {
|
||||
"java/lang/Object": {
|
||||
native: {
|
||||
"hashCode.()I": function (): number {
|
||||
var self: J2ME.java.lang.Object = this;
|
||||
if (self._hashCode) {
|
||||
return self._hashCode;
|
||||
}
|
||||
return self._hashCode = $.nextHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* This script can be black-boxed in the debugger to disable breaking
|
||||
* at unwanted exception points.
|
||||
*/
|
||||
|
||||
function throwHelper(e) {
|
||||
J2ME.traceWriter && J2ME.traceWriter.writeLn("Throw " + e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
function throwPause() {
|
||||
throwHelper(VM.Pause);
|
||||
}
|
|
@ -0,0 +1,340 @@
|
|||
module J2ME {
|
||||
declare var ZipFile;
|
||||
declare var snarf;
|
||||
|
||||
export class ClassRegistry {
|
||||
/**
|
||||
* List of directories to look for source files in.
|
||||
*/
|
||||
sourceDirectories: string [];
|
||||
|
||||
/**
|
||||
* All source code, only ever used for debugging.
|
||||
*/
|
||||
sourceFiles: Map<string, string []>;
|
||||
|
||||
/**
|
||||
* List of classes whose sources files were not found. We keep track
|
||||
* of them so we don't have to search for them over and over.
|
||||
*/
|
||||
missingSourceFiles: Map<string, string []>;
|
||||
|
||||
jarFiles: Map<string, any>;
|
||||
classFiles: Map<string, any>;
|
||||
classes: Map<string, ClassInfo>;
|
||||
|
||||
preInitializedClasses: ClassInfo [];
|
||||
|
||||
java_lang_Object: ClassInfo;
|
||||
java_lang_Class: ClassInfo;
|
||||
java_lang_String: ClassInfo;
|
||||
java_lang_Thread: ClassInfo;
|
||||
|
||||
constructor() {
|
||||
this.sourceDirectories = [];
|
||||
this.sourceFiles = Object.create(null);
|
||||
this.missingSourceFiles = Object.create(null);
|
||||
|
||||
this.jarFiles = Object.create(null);
|
||||
this.classFiles = Object.create(null);
|
||||
this.classes = Object.create(null);
|
||||
this.preInitializedClasses = [];
|
||||
}
|
||||
|
||||
initializeBuiltinClasses() {
|
||||
// These classes are guaranteed to not have a static initializer.
|
||||
enterTimeline("initializeBuiltinClasses");
|
||||
this.java_lang_Object = this.loadAndLinkClass("java/lang/Object");
|
||||
this.java_lang_Class = this.loadAndLinkClass("java/lang/Class");
|
||||
this.java_lang_String = this.loadAndLinkClass("java/lang/String");
|
||||
this.java_lang_Thread = this.loadAndLinkClass("java/lang/Thread");
|
||||
|
||||
this.preInitializedClasses.push(this.java_lang_Object);
|
||||
this.preInitializedClasses.push(this.java_lang_Class);
|
||||
this.preInitializedClasses.push(this.java_lang_String);
|
||||
this.preInitializedClasses.push(this.java_lang_Thread);
|
||||
|
||||
/**
|
||||
* Force these frequently used classes to be initialized eagerly. We can
|
||||
* skip the class initialization check for them. This is only possible
|
||||
* because they don't have any static state.
|
||||
*/
|
||||
var classNames = [
|
||||
"java/lang/Integer",
|
||||
"java/lang/Character",
|
||||
"java/lang/Math",
|
||||
"java/util/HashtableEntry",
|
||||
"java/lang/StringBuffer",
|
||||
"java/util/Vector",
|
||||
"java/io/IOException",
|
||||
"java/lang/IllegalArgumentException"
|
||||
];
|
||||
|
||||
for (var i = 0; i < classNames.length; i++) {
|
||||
this.preInitializedClasses.push(this.loadAndLinkClass(classNames[i]));
|
||||
}
|
||||
|
||||
// Link primitive values and primitive arrays.
|
||||
for (var i = 0; i < "ZCFDBSIJ".length; i++) {
|
||||
var typeName = "ZCFDBSIJ"[i];
|
||||
linkKlass(PrimitiveClassInfo[typeName]);
|
||||
this.getClass("[" + typeName);
|
||||
}
|
||||
leaveTimeline("initializeBuiltinClasses");
|
||||
}
|
||||
|
||||
isPreInitializedClass(classInfo: ClassInfo) {
|
||||
return this.preInitializedClasses.indexOf(classInfo) >= 0;
|
||||
}
|
||||
|
||||
addPath(name: string, buffer: ArrayBuffer) {
|
||||
if (name.substr(-4) === ".jar") {
|
||||
this.jarFiles[name] = new ZipFile(buffer);
|
||||
} else {
|
||||
this.classFiles[name] = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
addSourceDirectory(name: string) {
|
||||
this.sourceDirectories.push(name);
|
||||
}
|
||||
|
||||
getSourceLine(sourceLocation: SourceLocation): string {
|
||||
if (typeof snarf === "undefined") {
|
||||
// Sorry, no snarf in the browser. Do async loading instead.
|
||||
return null;
|
||||
}
|
||||
var source = this.sourceFiles[sourceLocation.className];
|
||||
if (!source && !this.missingSourceFiles[sourceLocation.className]) {
|
||||
for (var i = 0; i < this.sourceDirectories.length; i++) {
|
||||
try {
|
||||
var path = this.sourceDirectories[i] + "/" + sourceLocation.className + ".java";
|
||||
var file = snarf(path);
|
||||
if (file) {
|
||||
source = this.sourceFiles[sourceLocation.className] = file.split("\n");
|
||||
}
|
||||
} catch (x) {
|
||||
// Keep looking.
|
||||
//stderrWriter.writeLn("" + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (source) {
|
||||
return source[sourceLocation.lineNumber - 1];
|
||||
}
|
||||
this.missingSourceFiles[sourceLocation.className] = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
loadFileFromJar(jarName: string, fileName: string): ArrayBuffer {
|
||||
var zip = this.jarFiles[jarName];
|
||||
if (!zip)
|
||||
return null;
|
||||
if (!(fileName in zip.directory))
|
||||
return null;
|
||||
var bytes = zip.read(fileName);
|
||||
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
||||
}
|
||||
|
||||
loadFile(fileName: string): ArrayBuffer {
|
||||
var classFiles = this.classFiles;
|
||||
var data = classFiles[fileName];
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
var jarFiles = this.jarFiles;
|
||||
for (var k in jarFiles) {
|
||||
var zip = jarFiles[k];
|
||||
if (fileName in zip.directory) {
|
||||
enterTimeline("ZIP", {file: fileName});
|
||||
var bytes = zip.read(fileName);
|
||||
data = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
||||
leaveTimeline("ZIP");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
classFiles[fileName] = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
loadClassBytes(bytes: ArrayBuffer): ClassInfo {
|
||||
enterTimeline("loadClassBytes");
|
||||
var classInfo = new ClassInfo(bytes);
|
||||
leaveTimeline("loadClassBytes", {className: classInfo.className});
|
||||
this.classes[classInfo.className] = classInfo;
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
loadClassFile(fileName: string): ClassInfo {
|
||||
loadWriter && loadWriter.enter("> Loading Class File: " + fileName);
|
||||
var bytes = this.loadFile(fileName);
|
||||
if (!bytes) {
|
||||
loadWriter && loadWriter.leave("< ClassNotFoundException");
|
||||
throw new (ClassNotFoundException)(fileName);
|
||||
}
|
||||
var self = this;
|
||||
var classInfo = this.loadClassBytes(bytes);
|
||||
if (classInfo.superClassName) {
|
||||
classInfo.superClass = this.loadClass(classInfo.superClassName);
|
||||
var superClass = classInfo.superClass;
|
||||
superClass.subClasses.push(classInfo);
|
||||
while (superClass) {
|
||||
superClass.allSubClasses.push(classInfo);
|
||||
superClass = superClass.superClass;
|
||||
}
|
||||
}
|
||||
var classes = classInfo.classes;
|
||||
classes.forEach(function (c, n) {
|
||||
classes[n] = self.loadClass(c);
|
||||
});
|
||||
classInfo.complete();
|
||||
loadWriter && loadWriter.leave("<");
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to test loading of all class files.
|
||||
*/
|
||||
loadAllClassFiles() {
|
||||
var jarFiles = this.jarFiles;
|
||||
Object.keys(jarFiles).every(function (path) {
|
||||
if (path.substr(-4) !== ".jar") {
|
||||
return true;
|
||||
}
|
||||
var zipFile = jarFiles[path];
|
||||
Object.keys(zipFile.directory).every(function (fileName) {
|
||||
if (fileName.substr(-6) !== '.class') {
|
||||
return true;
|
||||
}
|
||||
var className = fileName.substring(0, fileName.length - 6);
|
||||
CLASSES.getClass(className);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
loadClass(className: string): ClassInfo {
|
||||
var classInfo = this.classes[className];
|
||||
if (classInfo) {
|
||||
return classInfo;
|
||||
}
|
||||
return this.loadClassFile(className + ".class");
|
||||
}
|
||||
|
||||
loadAndLinkClass(className: string): ClassInfo {
|
||||
var classInfo = this.loadClass(className);
|
||||
linkKlass(classInfo);
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
getEntryPoint(classInfo: ClassInfo): MethodInfo {
|
||||
var methods = classInfo.methods;
|
||||
for (var i=0; i<methods.length; i++) {
|
||||
var method = methods[i];
|
||||
if (method.isPublic && method.isStatic && !method.isNative &&
|
||||
method.name === "main" &&
|
||||
method.signature === "([Ljava/lang/String;)V") {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getClass(className: string): ClassInfo {
|
||||
var classInfo = this.classes[className];
|
||||
if (!classInfo) {
|
||||
if (className[0] === "[") {
|
||||
classInfo = this.createArrayClass(className);
|
||||
} else {
|
||||
classInfo = this.loadClass(className);
|
||||
}
|
||||
if (!classInfo)
|
||||
return null;
|
||||
}
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
createArrayClass(typeName: string): ArrayClassInfo {
|
||||
var elementType = typeName.substr(1);
|
||||
var constructor = getArrayConstructor(elementType);
|
||||
var classInfo;
|
||||
if (constructor) {
|
||||
classInfo = PrimitiveArrayClassInfo[elementType];
|
||||
} else {
|
||||
if (elementType[0] === "L") {
|
||||
elementType = elementType.substr(1).replace(";", "");
|
||||
}
|
||||
classInfo = new ArrayClassInfo(typeName, this.getClass(elementType));
|
||||
}
|
||||
if (J2ME.phase === J2ME.ExecutionPhase.Runtime) {
|
||||
J2ME.linkKlass(classInfo);
|
||||
}
|
||||
return this.classes[typeName] = classInfo;
|
||||
}
|
||||
|
||||
|
||||
getField(classInfo, fieldKey) {
|
||||
if (classInfo.vfc[fieldKey]) {
|
||||
return classInfo.vfc[fieldKey];
|
||||
}
|
||||
|
||||
do {
|
||||
var fields = classInfo.fields;
|
||||
for (var i=0; i<fields.length; ++i) {
|
||||
var field = fields[i];
|
||||
if (!field.key) {
|
||||
field.key = (AccessFlags.isStatic(field.access_flags) ? "S" : "I") + "." + field.name + "." + field.signature;
|
||||
}
|
||||
if (field.key === fieldKey) {
|
||||
return classInfo.vfc[fieldKey] = field;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldKey[0] === 'S') {
|
||||
for (var n = 0; n < classInfo.interfaces.length; ++n) {
|
||||
var field = this.getField(classInfo.interfaces[n], fieldKey);
|
||||
if (field) {
|
||||
return classInfo.vfc[fieldKey] = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classInfo = classInfo.superClass;
|
||||
} while (classInfo);
|
||||
}
|
||||
|
||||
getMethod(classInfo, methodKey) {
|
||||
var c = classInfo;
|
||||
do {
|
||||
var methods = c.methods;
|
||||
for (var i=0; i<methods.length; ++i) {
|
||||
var method = methods[i];
|
||||
if (method.key === methodKey) {
|
||||
return classInfo.vmc[methodKey] = method;
|
||||
}
|
||||
}
|
||||
c = c.superClass;
|
||||
} while (c);
|
||||
|
||||
if (AccessFlags.isInterface(classInfo.access_flags)) {
|
||||
for (var n = 0; n < classInfo.interfaces.length; ++n) {
|
||||
var method = this.getMethod(classInfo.interfaces[n], methodKey);
|
||||
if (method) {
|
||||
return classInfo.vmc[methodKey] = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export var ClassNotFoundException = function(message) {
|
||||
this.message = message;
|
||||
};
|
||||
|
||||
ClassNotFoundException.prototype = Object.create(Error.prototype);
|
||||
ClassNotFoundException.prototype.name = "ClassNotFoundException";
|
||||
ClassNotFoundException.prototype.constructor = ClassNotFoundException;
|
||||
}
|
||||
|
192
classes.js
|
@ -1,192 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var Classes = function() {
|
||||
if (this instanceof Classes) {
|
||||
this.classfiles = [];
|
||||
this.mainclass = [];
|
||||
this.classes = {};
|
||||
} else {
|
||||
return new Classes();
|
||||
}
|
||||
}
|
||||
|
||||
Classes.ClassNotFoundException = function(message) {
|
||||
this.message = message;
|
||||
};
|
||||
Classes.ClassNotFoundException.prototype = Object.create(Error.prototype);
|
||||
Classes.ClassNotFoundException.prototype.name = "ClassNotFoundException";
|
||||
Classes.ClassNotFoundException.prototype.constructor = Classes.ClassNotFoundException;
|
||||
|
||||
Classes.prototype.addPath = function(name, data) {
|
||||
if (name.substr(-4) === ".jar") {
|
||||
data = new ZipFile(data);
|
||||
}
|
||||
this.classfiles[name] = data;
|
||||
}
|
||||
|
||||
Classes.prototype.loadFileFromJar = function(jar, fileName) {
|
||||
var classfiles = this.classfiles;
|
||||
var zip = classfiles[jar];
|
||||
if (!zip)
|
||||
return null;
|
||||
if (!(fileName in zip.directory))
|
||||
return null;
|
||||
var bytes = zip.read(fileName);
|
||||
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
||||
}
|
||||
|
||||
Classes.prototype.loadFile = function(fileName) {
|
||||
var classfiles = this.classfiles;
|
||||
var data = classfiles[fileName];
|
||||
if (data)
|
||||
return data;
|
||||
Object.keys(classfiles).every(function (name) {
|
||||
if (name.substr(-4) !== ".jar")
|
||||
return true;
|
||||
var zip = classfiles[name];
|
||||
if (fileName in zip.directory) {
|
||||
var bytes = zip.read(fileName);
|
||||
data = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
||||
}
|
||||
return !data;
|
||||
});
|
||||
if (data)
|
||||
classfiles[fileName] = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
Classes.prototype.loadClassBytes = function(bytes) {
|
||||
var classInfo = new ClassInfo(bytes);
|
||||
this.classes[classInfo.className] = classInfo;
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
Classes.prototype.loadClassFile = function(fileName) {
|
||||
var bytes = this.loadFile(fileName);
|
||||
if (!bytes)
|
||||
throw new (Classes.ClassNotFoundException)(fileName);
|
||||
var self = this;
|
||||
var classInfo = this.loadClassBytes(bytes);
|
||||
if (classInfo.superClassName)
|
||||
classInfo.superClass = this.loadClass(classInfo.superClassName);
|
||||
var classes = classInfo.classes;
|
||||
classes.forEach(function (c, n) {
|
||||
classes[n] = self.loadClass(c);
|
||||
});
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
Classes.prototype.loadClass = function(className) {
|
||||
var classInfo = this.classes[className];
|
||||
if (classInfo)
|
||||
return classInfo;
|
||||
return this.loadClassFile(className + ".class");
|
||||
}
|
||||
|
||||
Classes.prototype.getEntryPoint = function(classInfo) {
|
||||
var methods = classInfo.methods;
|
||||
for (var i=0; i<methods.length; i++) {
|
||||
var method = methods[i];
|
||||
if (method.isPublic && method.isStatic && !method.isNative &&
|
||||
method.name === "main" &&
|
||||
method.signature === "([Ljava/lang/String;)V") {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Classes.prototype.getClass = function(className) {
|
||||
var classInfo = this.classes[className];
|
||||
if (!classInfo) {
|
||||
if (className[0] === "[") {
|
||||
classInfo = this.initArrayClass(className);
|
||||
} else {
|
||||
classInfo = this.loadClass(className);
|
||||
}
|
||||
if (!classInfo)
|
||||
return null;
|
||||
}
|
||||
return classInfo;
|
||||
};
|
||||
|
||||
Classes.prototype.initArrayClass = function(typeName) {
|
||||
var elementType = typeName.substr(1);
|
||||
var constructor = ARRAYS[elementType];
|
||||
if (constructor)
|
||||
return this.classes[typeName] = this.initPrimitiveArrayType(typeName, constructor);
|
||||
if (elementType[0] === "L")
|
||||
elementType = elementType.substr(1).replace(";", "");
|
||||
var classInfo = new ArrayClass(typeName, this.getClass(elementType));
|
||||
classInfo.superClass = this.java_lang_Object;
|
||||
classInfo.constructor = function (size) {
|
||||
var array = new Array(size);
|
||||
array.class = classInfo;
|
||||
return array;
|
||||
}
|
||||
return this.classes[typeName] = classInfo;
|
||||
}
|
||||
|
||||
Classes.prototype.initPrimitiveArrayType = function(typeName, constructor) {
|
||||
var classInfo = new ArrayClass(typeName);
|
||||
classInfo.superClass = this.java_lang_Object;
|
||||
constructor.prototype.class = classInfo;
|
||||
classInfo.constructor = constructor;
|
||||
return classInfo;
|
||||
}
|
||||
|
||||
Classes.prototype.getField = function(classInfo, fieldKey) {
|
||||
if (classInfo.vfc[fieldKey]) {
|
||||
return classInfo.vfc[fieldKey];
|
||||
}
|
||||
|
||||
do {
|
||||
var fields = classInfo.fields;
|
||||
for (var i=0; i<fields.length; ++i) {
|
||||
var field = fields[i];
|
||||
if (!field.key) {
|
||||
field.key = (ACCESS_FLAGS.isStatic(field.access_flags) ? "S" : "I") + "." + field.name + "." + field.signature;
|
||||
}
|
||||
if (field.key === fieldKey) {
|
||||
return classInfo.vfc[fieldKey] = field;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldKey[0] === 'S') {
|
||||
for (var n = 0; n < classInfo.interfaces.length; ++n) {
|
||||
var field = this.getField(classInfo.interfaces[n], fieldKey);
|
||||
if (field) {
|
||||
return classInfo.vfc[fieldKey] = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classInfo = classInfo.superClass;
|
||||
} while (classInfo);
|
||||
};
|
||||
|
||||
Classes.prototype.getMethod = function(classInfo, methodKey) {
|
||||
var c = classInfo;
|
||||
|
||||
do {
|
||||
var methods = c.methods;
|
||||
for (var i=0; i<methods.length; ++i) {
|
||||
var method = methods[i];
|
||||
if (method.key === methodKey) {
|
||||
return classInfo.vmc[methodKey] = method;
|
||||
}
|
||||
}
|
||||
c = c.superClass;
|
||||
} while (c);
|
||||
|
||||
if (ACCESS_FLAGS.isInterface(classInfo.access_flags)) {
|
||||
for (var n = 0; n < classInfo.interfaces.length; ++n) {
|
||||
var method = this.getMethod(classInfo.interfaces[n], methodKey);
|
||||
if (method) {
|
||||
return classInfo.vmc[methodKey] = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,47 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var checkFlag = function(flag) {
|
||||
return function(flags) {
|
||||
return ((flags & flag) === flag);
|
||||
}
|
||||
};
|
||||
|
||||
var ACCESS_FLAGS = {
|
||||
ACC_PUBLIC: 0x0001,
|
||||
ACC_PRIVATE: 0x0002,
|
||||
ACC_PROTECTED: 0x0004,
|
||||
ACC_STATIC: 0x0008,
|
||||
ACC_FINAL: 0x0010,
|
||||
ACC_SYNCHRONIZED: 0x0020,
|
||||
ACC_VOLATILE: 0x0040,
|
||||
ACC_TRANSIENT: 0x0080,
|
||||
ACC_NATIVE: 0x0100,
|
||||
ACC_INTERFACE: 0x0200,
|
||||
ACC_ABSTRACT: 0x0400,
|
||||
toString: function(flags) {
|
||||
var flagNames = [];
|
||||
for(var flag in this) {
|
||||
if ((this[flag] & flags) === this[flag]) {
|
||||
flagNames.push(flag);
|
||||
}
|
||||
}
|
||||
return flagNames.toString();
|
||||
},
|
||||
isPublic: function(flags) { return checkFlag(this.ACC_PUBLIC)(flags) },
|
||||
isPrivate: function(flags) { return checkFlag(this.ACC_PRIVATE)(flags) },
|
||||
isProtected: function(flags) { return checkFlag(this.ACC_PROTECTED)(flags) },
|
||||
isStatic: function(flags) { return checkFlag(this.ACC_STATIC)(flags) },
|
||||
isFinal: function(flags) { return checkFlag(this.ACC_FINAL)(flags) },
|
||||
isSynchronized: function(flags) { return checkFlag(this.ACC_SYNCHRONIZED)(flags) },
|
||||
isVolatile: function(flags) { return checkFlag(this.ACC_VOLATILE)(flags) },
|
||||
isTransient: function(flags) { return checkFlag(this.ACC_TRANSIENT)(flags) },
|
||||
isNative: function(flags) { return checkFlag(this.ACC_NATIVE)(flags) },
|
||||
isInterface: function(flags) { return checkFlag(this.ACC_INTERFACE)(flags) },
|
||||
isAbstract: function(flags) { return checkFlag(this.ACC_ABSTRACT)(flags) }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var ATTRIBUTE_TYPES = {
|
||||
ConstantValue: "ConstantValue",
|
||||
Code: "Code",
|
||||
Exceptions: "Exceptions",
|
||||
InnerClasses: "InnerClasses",
|
||||
Synthetic: "Synthetic",
|
||||
SourceFile: "SourceFile",
|
||||
LineNumberTable: "LineNumberTable",
|
||||
LocalVariableTable: "LocalVariableTable",
|
||||
Deprecated: "Deprecated",
|
||||
};
|
|
@ -1,222 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var getClassImage = function(classBytes) {
|
||||
var classImage = {};
|
||||
|
||||
var getAttributes = function(attribute_name_index, bytes) {
|
||||
var reader = new Reader(bytes);
|
||||
var attribute = { attribute_name_index: attribute_name_index };
|
||||
|
||||
var item = classImage.constant_pool[attribute_name_index];
|
||||
|
||||
switch(item.tag) {
|
||||
case TAGS.CONSTANT_Long:
|
||||
case TAGS.CONSTANT_Float:
|
||||
case TAGS.CONSTANT_Double:
|
||||
case TAGS.CONSTANT_Integer:
|
||||
case TAGS.CONSTANT_String:
|
||||
attribute.type = ATTRIBUTE_TYPES.ConstantValue;
|
||||
attribute.info = reader.read16();
|
||||
return attribute;
|
||||
|
||||
case TAGS.CONSTANT_Utf8:
|
||||
switch(item.bytes) {
|
||||
case ATTRIBUTE_TYPES.Code:
|
||||
attribute.type = ATTRIBUTE_TYPES.Code;
|
||||
attribute.max_stack = reader.read16();
|
||||
attribute.max_locals = reader.read16();
|
||||
var code_length = reader.read32();
|
||||
attribute.code = reader.readBytes(code_length);
|
||||
|
||||
var exception_table_length = reader.read16();
|
||||
attribute.exception_table = [];
|
||||
for (var i=0; i<exception_table_length; i++) {
|
||||
attribute.exception_table.push({
|
||||
start_pc: reader.read16(),
|
||||
end_pc: reader.read16(),
|
||||
handler_pc: reader.read16(),
|
||||
catch_type: reader.read16()
|
||||
});
|
||||
}
|
||||
|
||||
var attributes_count = reader.read16();
|
||||
attribute.attributes = [];
|
||||
for(var i=0; i<attributes_count; i++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info = reader.readBytes(attribute_length);
|
||||
attribute.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.SourceFile:
|
||||
attribute.type = ATTRIBUTE_TYPES.SourceFile;
|
||||
attribute.sourcefile_index = reader.read16();
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.Exceptions:
|
||||
attribute.type = ATTRIBUTE_TYPES.Exceptions;
|
||||
var number_of_exceptions = reader.read16();
|
||||
attribute.exception_index_table = [];
|
||||
for(var i=0; i<number_of_exceptions; i++) {
|
||||
attribute.exception_index_table.push(reader.read16());
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.InnerClasses:
|
||||
attribute.type = ATTRIBUTE_TYPES.InnerClasses;
|
||||
var number_of_classes = reader.read16();
|
||||
attribute.classes = [];
|
||||
for(var i=0; i<number_of_classes; i++) {
|
||||
var inner = {};
|
||||
inner.inner_class_info_index = reader.read16();
|
||||
inner.outer_class_info_index = reader.read16();
|
||||
inner.inner_name_index = reader.read16();
|
||||
inner.inner_class_access_flags = reader.read16();
|
||||
attribute.classes.push(inner);
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.Synthetic:
|
||||
attribute.type = ATTRIBUTE_TYPES.Synthetic;
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.Deprecated:
|
||||
attribute.type = ATTRIBUTE_TYPES.Deprecated;
|
||||
return attribute;
|
||||
|
||||
default:
|
||||
throw new Error("This attribute type is not supported yet. [" + JSON.stringify(item) + "]");
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error("This attribute type is not supported yet. [" + JSON.stringify(item) + "]");
|
||||
}
|
||||
};
|
||||
|
||||
var reader = Reader(classBytes);
|
||||
classImage.magic = reader.read32().toString(16);
|
||||
|
||||
classImage.version = {
|
||||
minor_version: reader.read16(),
|
||||
major_version: reader.read16()
|
||||
};
|
||||
|
||||
classImage.constant_pool = [ null ];
|
||||
var constant_pool_count = reader.read16();
|
||||
for(var i=1; i<constant_pool_count; i++) {
|
||||
var tag = reader.read8();
|
||||
switch(tag) {
|
||||
case TAGS.CONSTANT_Class:
|
||||
var name_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, name_index: name_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_Utf8:
|
||||
var length = reader.read16();
|
||||
var bytes = reader.readString(length);
|
||||
classImage.constant_pool.push({ tag: tag, bytes: bytes });
|
||||
break;
|
||||
case TAGS.CONSTANT_Methodref:
|
||||
var class_index = reader.read16();
|
||||
var name_and_type_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, class_index: class_index, name_and_type_index: name_and_type_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_NameAndType:
|
||||
var name_index = reader.read16();
|
||||
var signature_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, name_index: name_index, signature_index: signature_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_Fieldref:
|
||||
var class_index = reader.read16();
|
||||
var name_and_type_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, class_index: class_index, name_and_type_index: name_and_type_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_String:
|
||||
var string_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, string_index: string_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_Integer:
|
||||
classImage.constant_pool.push({ tag: tag, integer: reader.readInteger() });
|
||||
break;
|
||||
case TAGS.CONSTANT_Float:
|
||||
classImage.constant_pool.push({ tag: tag, float: reader.readFloat() });
|
||||
break;
|
||||
case TAGS.CONSTANT_Double:
|
||||
classImage.constant_pool.push({ tag: tag, double: reader.readDouble() });
|
||||
classImage.constant_pool.push(null);
|
||||
++i;
|
||||
break;
|
||||
case TAGS.CONSTANT_Long:
|
||||
classImage.constant_pool.push({ tag: tag, highBits: reader.readInteger(), lowBits: reader.readInteger() });
|
||||
classImage.constant_pool.push(null);
|
||||
++i;
|
||||
break;
|
||||
case TAGS.CONSTANT_Fieldref:
|
||||
case TAGS.CONSTANT_Methodref:
|
||||
case TAGS.CONSTANT_InterfaceMethodref:
|
||||
var class_index = reader.read16();
|
||||
var name_and_type_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, class_index: class_index, name_and_type_index:name_and_type_index });
|
||||
break;
|
||||
default:
|
||||
throw new Error("tag " + tag + " not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
classImage.access_flags = reader.read16();
|
||||
|
||||
classImage.this_class = reader.read16();
|
||||
|
||||
classImage.super_class = reader.read16();
|
||||
|
||||
classImage.interfaces = [];
|
||||
var interfaces_count = reader.read16();
|
||||
for(var i=0; i<interfaces_count; i++) {
|
||||
var index = reader.read16();
|
||||
if (index != 0) {
|
||||
classImage.interfaces.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
classImage.fields = [];
|
||||
var fields_count = reader.read16();
|
||||
for(var i=0; i<fields_count; i++) {
|
||||
var field_info = { access_flags: reader.read16(), name_index: reader.read16(), descriptor_index: reader.read16(), attributes: [] };
|
||||
var attributes_count = reader.read16();
|
||||
for(var j=0; j <attributes_count; j++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info = reader.readBytes(attribute_length);
|
||||
field_info.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
classImage.fields.push(field_info);
|
||||
}
|
||||
|
||||
classImage.methods = [];
|
||||
var methods_count = reader.read16();
|
||||
for(var i=0; i<methods_count; i++) {
|
||||
var method_info = { access_flags: reader.read16(), name_index: reader.read16(), signature_index: reader.read16(), attributes: [] };
|
||||
var attributes_count = reader.read16();
|
||||
for(var j=0; j <attributes_count; j++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info = getAttributes(attribute_name_index, reader.readBytes(attribute_length));
|
||||
method_info.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
classImage.methods.push(method_info);
|
||||
}
|
||||
|
||||
classImage.attributes = [];
|
||||
var attributes_count = reader.read16();
|
||||
for(var i=0; i<attributes_count; i++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info = getAttributes(attribute_name_index, reader.readBytes(attribute_length));
|
||||
classImage.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
|
||||
return classImage;
|
||||
};
|
|
@ -0,0 +1,316 @@
|
|||
module J2ME {
|
||||
export var ATTRIBUTE_TYPES = {
|
||||
ConstantValue: "ConstantValue",
|
||||
Code: "Code",
|
||||
Exceptions: "Exceptions",
|
||||
InnerClasses: "InnerClasses",
|
||||
Synthetic: "Synthetic",
|
||||
SourceFile: "SourceFile",
|
||||
LineNumberTable: "LineNumberTable",
|
||||
LocalVariableTable: "LocalVariableTable",
|
||||
Deprecated: "Deprecated",
|
||||
StackMap: "StackMap"
|
||||
};
|
||||
|
||||
export enum ACCESS_FLAGS {
|
||||
ACC_PUBLIC = 0x0001,
|
||||
ACC_PRIVATE = 0x0002,
|
||||
ACC_PROTECTED = 0x0004,
|
||||
ACC_STATIC = 0x0008,
|
||||
ACC_FINAL = 0x0010,
|
||||
ACC_SYNCHRONIZED = 0x0020,
|
||||
ACC_VOLATILE = 0x0040,
|
||||
ACC_TRANSIENT = 0x0080,
|
||||
ACC_NATIVE = 0x0100,
|
||||
ACC_INTERFACE = 0x0200,
|
||||
ACC_ABSTRACT = 0x0400
|
||||
}
|
||||
|
||||
export enum TAGS {
|
||||
CONSTANT_Class = 7,
|
||||
CONSTANT_Fieldref = 9,
|
||||
CONSTANT_Methodref = 10,
|
||||
CONSTANT_InterfaceMethodref = 11,
|
||||
CONSTANT_String = 8,
|
||||
CONSTANT_Integer = 3,
|
||||
CONSTANT_Float = 4,
|
||||
CONSTANT_Long = 5,
|
||||
CONSTANT_Double = 6,
|
||||
CONSTANT_NameAndType = 12,
|
||||
CONSTANT_Utf8 = 1,
|
||||
CONSTANT_Unicode = 2
|
||||
}
|
||||
|
||||
export module AccessFlags {
|
||||
export function isPublic(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_PUBLIC) === ACCESS_FLAGS.ACC_PUBLIC;
|
||||
}
|
||||
export function isPrivate(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_PRIVATE) === ACCESS_FLAGS.ACC_PRIVATE;
|
||||
}
|
||||
export function isProtected(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_PROTECTED) === ACCESS_FLAGS.ACC_PROTECTED;
|
||||
}
|
||||
export function isStatic(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_STATIC) === ACCESS_FLAGS.ACC_STATIC;
|
||||
}
|
||||
export function isFinal(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_FINAL) === ACCESS_FLAGS.ACC_FINAL;
|
||||
}
|
||||
export function isSynchronized(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_SYNCHRONIZED) === ACCESS_FLAGS.ACC_SYNCHRONIZED;
|
||||
}
|
||||
export function isVolatile(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_VOLATILE) === ACCESS_FLAGS.ACC_VOLATILE;
|
||||
}
|
||||
export function isTransient(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_TRANSIENT) === ACCESS_FLAGS.ACC_TRANSIENT;
|
||||
}
|
||||
export function isNative(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_NATIVE) === ACCESS_FLAGS.ACC_NATIVE;
|
||||
}
|
||||
export function isInterface(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_INTERFACE) === ACCESS_FLAGS.ACC_INTERFACE;
|
||||
}
|
||||
export function isAbstract(flags) {
|
||||
return (flags & ACCESS_FLAGS.ACC_ABSTRACT) === ACCESS_FLAGS.ACC_ABSTRACT;
|
||||
}
|
||||
}
|
||||
|
||||
export function getClassImage(classBytes) {
|
||||
var classImage: any = {};
|
||||
|
||||
var getAttributes = function(attribute_name_index: number, bytes) {
|
||||
var reader = new Reader(bytes);
|
||||
var attribute: any = { attribute_name_index: attribute_name_index };
|
||||
|
||||
var item = classImage.constant_pool[attribute_name_index];
|
||||
|
||||
switch(item.tag) {
|
||||
case TAGS.CONSTANT_Long:
|
||||
case TAGS.CONSTANT_Float:
|
||||
case TAGS.CONSTANT_Double:
|
||||
case TAGS.CONSTANT_Integer:
|
||||
case TAGS.CONSTANT_String:
|
||||
attribute.type = ATTRIBUTE_TYPES.ConstantValue;
|
||||
attribute.info = reader.read16();
|
||||
return attribute;
|
||||
|
||||
case TAGS.CONSTANT_Utf8:
|
||||
switch(item.bytes) {
|
||||
case ATTRIBUTE_TYPES.Code:
|
||||
attribute.type = ATTRIBUTE_TYPES.Code;
|
||||
attribute.max_stack = reader.read16();
|
||||
attribute.max_locals = reader.read16();
|
||||
var code_length = reader.read32();
|
||||
attribute.code = reader.readBytes(code_length);
|
||||
|
||||
var exception_table_length = reader.read16();
|
||||
attribute.exception_table = [];
|
||||
for (var i=0; i<exception_table_length; i++) {
|
||||
attribute.exception_table.push({
|
||||
start_pc: reader.read16(),
|
||||
end_pc: reader.read16(),
|
||||
handler_pc: reader.read16(),
|
||||
catch_type: reader.read16()
|
||||
});
|
||||
}
|
||||
|
||||
var attributes_count = reader.read16();
|
||||
attribute.attributes = [];
|
||||
for(var i=0; i<attributes_count; i++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info = getAttributes(attribute_name_index, reader.readBytes(attribute_length));
|
||||
attribute.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.SourceFile:
|
||||
attribute.type = ATTRIBUTE_TYPES.SourceFile;
|
||||
attribute.sourcefile_index = reader.read16();
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.LineNumberTable:
|
||||
attribute.type = ATTRIBUTE_TYPES.LineNumberTable;
|
||||
if (!release) {
|
||||
var line_number_table_length = reader.read16();
|
||||
attribute.line_number_table = [];
|
||||
for (var i = 0; i < line_number_table_length; i++) {
|
||||
attribute.line_number_table.push({
|
||||
start_pc: reader.read16(),
|
||||
line_number: reader.read16()
|
||||
});
|
||||
}
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.Exceptions:
|
||||
attribute.type = ATTRIBUTE_TYPES.Exceptions;
|
||||
var number_of_exceptions = reader.read16();
|
||||
attribute.exception_index_table = [];
|
||||
for(var i=0; i<number_of_exceptions; i++) {
|
||||
attribute.exception_index_table.push(reader.read16());
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.InnerClasses:
|
||||
attribute.type = ATTRIBUTE_TYPES.InnerClasses;
|
||||
var number_of_classes = reader.read16();
|
||||
attribute.classes = [];
|
||||
for(var i=0; i<number_of_classes; i++) {
|
||||
var inner: any = {};
|
||||
inner.inner_class_info_index = reader.read16();
|
||||
inner.outer_class_info_index = reader.read16();
|
||||
inner.inner_name_index = reader.read16();
|
||||
inner.inner_class_access_flags = reader.read16();
|
||||
attribute.classes.push(inner);
|
||||
}
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.Synthetic:
|
||||
attribute.type = ATTRIBUTE_TYPES.Synthetic;
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.Deprecated:
|
||||
attribute.type = ATTRIBUTE_TYPES.Deprecated;
|
||||
return attribute;
|
||||
|
||||
case ATTRIBUTE_TYPES.StackMap:
|
||||
attribute.type = ATTRIBUTE_TYPES.StackMap;
|
||||
return attribute;
|
||||
|
||||
default:
|
||||
throw new Error("This attribute type is not supported yet. [" + JSON.stringify(item) + "]");
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error("This attribute type is not supported yet. [" + JSON.stringify(item) + "]");
|
||||
}
|
||||
};
|
||||
|
||||
var reader = new J2ME.Reader(classBytes);
|
||||
classImage.magic = reader.read32().toString(16);
|
||||
|
||||
classImage.version = {
|
||||
minor_version: reader.read16(),
|
||||
major_version: reader.read16()
|
||||
};
|
||||
|
||||
classImage.constant_pool = [ null ];
|
||||
var constant_pool_count = reader.read16();
|
||||
for(var i=1; i<constant_pool_count; i++) {
|
||||
var tag = reader.read8();
|
||||
switch(tag) {
|
||||
case TAGS.CONSTANT_Class:
|
||||
var name_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, name_index: name_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_Utf8:
|
||||
var length = reader.read16();
|
||||
var bytes = reader.readString(length);
|
||||
classImage.constant_pool.push({ tag: tag, bytes: bytes });
|
||||
break;
|
||||
case TAGS.CONSTANT_Methodref:
|
||||
var class_index = reader.read16();
|
||||
var name_and_type_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, class_index: class_index, name_and_type_index: name_and_type_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_NameAndType:
|
||||
var name_index = reader.read16();
|
||||
var signature_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, name_index: name_index, signature_index: signature_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_Fieldref:
|
||||
var class_index = reader.read16();
|
||||
var name_and_type_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, class_index: class_index, name_and_type_index: name_and_type_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_String:
|
||||
var string_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, string_index: string_index });
|
||||
break;
|
||||
case TAGS.CONSTANT_Integer:
|
||||
classImage.constant_pool.push({ tag: tag, integer: reader.readInteger() });
|
||||
break;
|
||||
case TAGS.CONSTANT_Float:
|
||||
classImage.constant_pool.push({ tag: tag, float: reader.readFloat() });
|
||||
break;
|
||||
case TAGS.CONSTANT_Double:
|
||||
classImage.constant_pool.push({ tag: tag, double: reader.readDouble() });
|
||||
classImage.constant_pool.push(null);
|
||||
++i;
|
||||
break;
|
||||
case TAGS.CONSTANT_Long:
|
||||
classImage.constant_pool.push({ tag: tag, highBits: reader.readInteger(), lowBits: reader.readInteger() });
|
||||
classImage.constant_pool.push(null);
|
||||
++i;
|
||||
break;
|
||||
case TAGS.CONSTANT_Fieldref:
|
||||
case TAGS.CONSTANT_Methodref:
|
||||
case TAGS.CONSTANT_InterfaceMethodref:
|
||||
var class_index = reader.read16();
|
||||
var name_and_type_index = reader.read16();
|
||||
classImage.constant_pool.push({ tag: tag, class_index: class_index, name_and_type_index:name_and_type_index });
|
||||
break;
|
||||
default:
|
||||
throw new Error("tag " + tag + " not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
classImage.access_flags = reader.read16();
|
||||
|
||||
classImage.this_class = reader.read16();
|
||||
|
||||
classImage.super_class = reader.read16();
|
||||
|
||||
classImage.interfaces = [];
|
||||
var interfaces_count = reader.read16();
|
||||
for(var i=0; i<interfaces_count; i++) {
|
||||
var index = reader.read16();
|
||||
if (index != 0) {
|
||||
classImage.interfaces.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
classImage.fields = [];
|
||||
var fields_count = reader.read16();
|
||||
for(var i=0; i<fields_count; i++) {
|
||||
var field_info = { access_flags: reader.read16(), name_index: reader.read16(), descriptor_index: reader.read16(), attributes: [] };
|
||||
var attributes_count = reader.read16();
|
||||
for(var j=0; j <attributes_count; j++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info: any = reader.readBytes(attribute_length);
|
||||
field_info.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
classImage.fields.push(field_info);
|
||||
}
|
||||
|
||||
classImage.methods = [];
|
||||
var methods_count = reader.read16();
|
||||
for(var i=0; i<methods_count; i++) {
|
||||
var method_info = { access_flags: reader.read16(), name_index: reader.read16(), signature_index: reader.read16(), attributes: [] };
|
||||
var attributes_count = reader.read16();
|
||||
for(var j=0; j <attributes_count; j++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info: any = getAttributes(attribute_name_index, reader.readBytes(attribute_length));
|
||||
method_info.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
classImage.methods.push(method_info);
|
||||
}
|
||||
|
||||
classImage.attributes = [];
|
||||
var attributes_count = reader.read16();
|
||||
for(var i=0; i<attributes_count; i++) {
|
||||
var attribute_name_index = reader.read16();
|
||||
var attribute_length = reader.read32();
|
||||
var info: any = getAttributes(attribute_name_index, reader.readBytes(attribute_length));
|
||||
classImage.attributes.push({ attribute_name_index: attribute_name_index, info: info });
|
||||
}
|
||||
|
||||
return classImage;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var Reader = function(bytes, offset) {
|
||||
if (this instanceof Reader) {
|
||||
this.bytes = new DataView(bytes);
|
||||
this.offset = offset || 0;
|
||||
} else {
|
||||
return new Reader(bytes, offset);
|
||||
}
|
||||
}
|
||||
|
||||
Reader.prototype.read8 = function() {
|
||||
var data = this.bytes.getUint8(this.offset);
|
||||
this.offset += 1;
|
||||
return data;
|
||||
}
|
||||
|
||||
Reader.prototype.read16 = function() {
|
||||
var data = this.bytes.getUint16(this.offset, false);
|
||||
this.offset += 2;
|
||||
return data;
|
||||
}
|
||||
|
||||
Reader.prototype.read32 = function() {
|
||||
var data = this.bytes.getUint32(this.offset, false);
|
||||
this.offset += 4;
|
||||
return data;
|
||||
}
|
||||
|
||||
Reader.prototype.readInteger = function() {
|
||||
var data = this.bytes.getInt32(this.offset, false);
|
||||
this.offset += 4;
|
||||
return data;
|
||||
}
|
||||
|
||||
Reader.prototype.readFloat = function() {
|
||||
var data = this.bytes.getFloat32(this.offset, false);
|
||||
this.offset += 4;
|
||||
return data;
|
||||
}
|
||||
|
||||
Reader.prototype.readDouble = function() {
|
||||
var data = this.bytes.getFloat64(this.offset, false);
|
||||
this.offset += 8;
|
||||
return data;
|
||||
}
|
||||
|
||||
Reader.prototype.readString = function(length) {
|
||||
// NB: no need to create a new slice.
|
||||
var data = new Uint8Array(this.bytes.buffer, this.offset, length);
|
||||
this.offset += length;
|
||||
|
||||
// First try w/ TextDecoder, fallback to manually parsing if there was an
|
||||
// error. This will handle parsing errors resulting from Java's modified
|
||||
// UTF-8 implementation.
|
||||
try {
|
||||
return util.decodeUtf8Array(data);
|
||||
} catch(e) {
|
||||
return util.javaUTF8Decode(data);
|
||||
}
|
||||
}
|
||||
|
||||
Reader.prototype.readBytes = function(length) {
|
||||
var data = this.bytes.buffer.slice(this.offset, this.offset + length);
|
||||
this.offset += length;
|
||||
return data;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
module J2ME {
|
||||
declare var util;
|
||||
export class Reader {
|
||||
view: DataView;
|
||||
// DataView is not optimized, use Uint8Array for the fast paths.
|
||||
u8: Uint8Array;
|
||||
offset: number;
|
||||
|
||||
static arrays: string [][] = ArrayUtilities.makeArrays(128);
|
||||
|
||||
static getArray(length: number) {
|
||||
return Reader.arrays[length];
|
||||
}
|
||||
|
||||
constructor(buffer: ArrayBuffer, offset: number = 0) {
|
||||
this.view = new DataView(buffer);
|
||||
this.u8 = new Uint8Array(buffer);
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
read8() {
|
||||
return this.u8[this.offset++];
|
||||
}
|
||||
|
||||
read16() {
|
||||
var u8 = this.u8;
|
||||
var o = this.offset;
|
||||
this.offset += 2;
|
||||
return u8[o] << 8 | u8[o + 1];
|
||||
}
|
||||
|
||||
read32() {
|
||||
return this.readInteger() >>> 0;
|
||||
}
|
||||
|
||||
readInteger() {
|
||||
var o = this.offset;
|
||||
var u8 = this.u8;
|
||||
var a = u8[o + 0];
|
||||
var b = u8[o + 1];
|
||||
var c = u8[o + 2];
|
||||
var d = u8[o + 3];
|
||||
this.offset = o + 4;
|
||||
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
}
|
||||
|
||||
readFloat() {
|
||||
var data = this.view.getFloat32(this.offset, false);
|
||||
this.offset += 4;
|
||||
return data;
|
||||
}
|
||||
|
||||
readDouble() {
|
||||
var data = this.view.getFloat64(this.offset, false);
|
||||
this.offset += 8;
|
||||
return data;
|
||||
}
|
||||
|
||||
readStringFast(length: number): string {
|
||||
var a = Reader.getArray(length);
|
||||
var i = 0, j = 0;
|
||||
var o = this.offset;
|
||||
var e = o + length;
|
||||
var u8 = this.u8;
|
||||
while (o < e) {
|
||||
var x = u8[o++];
|
||||
if (x <= 0x7f) {
|
||||
// Code points in the range '\u0001' to '\u007F' are represented by a
|
||||
// single byte.
|
||||
// The 7 bits of data in the byte give the value of the code point
|
||||
// represented.
|
||||
a[j++] = String.fromCharCode(x);
|
||||
} else if (x <= 0xdf) {
|
||||
// The null code point ('\u0000') and code points in the range '\u0080'
|
||||
// to '\u07FF' are represented by a pair of bytes x and y.
|
||||
var y = u8[o++]
|
||||
a[j++] = String.fromCharCode(((x & 0x1f) << 6) + (y & 0x3f));
|
||||
} else {
|
||||
// Code points in the range '\u0800' to '\uFFFF' are represented by 3
|
||||
// bytes x, y, and z.
|
||||
var y = u8[o++];
|
||||
var z = u8[o++];
|
||||
a[j++] = String.fromCharCode(((x & 0xf) << 12) + ((y & 0x3f) << 6) + (z & 0x3f));
|
||||
}
|
||||
}
|
||||
this.offset = o;
|
||||
if (j !== a.length) {
|
||||
var b = Reader.getArray(j);
|
||||
for (var i = 0; i < j; i++) {
|
||||
b[i] = a[i];
|
||||
}
|
||||
a = b;
|
||||
}
|
||||
return a.join("");
|
||||
}
|
||||
|
||||
readString(length) {
|
||||
if (length === 1) {
|
||||
var c = this.u8[this.offset];
|
||||
if (c <= 0x7f) {
|
||||
this.offset ++;
|
||||
return String.fromCharCode(c);
|
||||
}
|
||||
} else if (length < 128) {
|
||||
return this.readStringFast(length);
|
||||
}
|
||||
return this.readStringSlow(length);
|
||||
}
|
||||
|
||||
readStringSlow(length) {
|
||||
// NB: no need to create a new slice.
|
||||
var data = new Uint8Array(this.view.buffer, this.offset, length);
|
||||
this.offset += length;
|
||||
|
||||
// First try w/ TextDecoder, fallback to manually parsing if there was an
|
||||
// error. This will handle parsing errors resulting from Java's modified
|
||||
// UTF-8 implementation.
|
||||
try {
|
||||
var s = util.decodeUtf8Array(data);
|
||||
return s;
|
||||
} catch (e) {
|
||||
return util.javaUTF8Decode(data);
|
||||
}
|
||||
}
|
||||
|
||||
readBytes(length) {
|
||||
var data = this.u8.buffer.slice(this.offset, this.offset + length);
|
||||
this.offset += length;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var TAGS = {
|
||||
CONSTANT_Class: 7,
|
||||
CONSTANT_Fieldref: 9,
|
||||
CONSTANT_Methodref: 10,
|
||||
CONSTANT_InterfaceMethodref: 11,
|
||||
CONSTANT_String: 8,
|
||||
CONSTANT_Integer: 3,
|
||||
CONSTANT_Float: 4,
|
||||
CONSTANT_Long: 5,
|
||||
CONSTANT_Double: 6,
|
||||
CONSTANT_NameAndType: 12,
|
||||
CONSTANT_Utf8: 1,
|
||||
CONSTANT_Unicode: 2,
|
||||
};
|
227
classinfo.js
|
@ -1,227 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var FieldInfo = (function() {
|
||||
var idgen = 0;
|
||||
return function(classInfo, access_flags, name, signature) {
|
||||
this.classInfo = classInfo;
|
||||
this.access_flags = access_flags;
|
||||
this.name = name;
|
||||
this.signature = signature;
|
||||
this.id = idgen++;
|
||||
}
|
||||
})();
|
||||
|
||||
FieldInfo.prototype.get = function(obj) {
|
||||
var value = obj[this.id];
|
||||
if (typeof value === "undefined") {
|
||||
value = util.defaultValue(this.signature);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
FieldInfo.prototype.set = function(obj, value) {
|
||||
obj[this.id] = value;
|
||||
}
|
||||
|
||||
FieldInfo.prototype.toString = function() {
|
||||
return "[field " + this.name + "]";
|
||||
}
|
||||
|
||||
function missingNativeImpl(key, ctx, stack) {
|
||||
console.error("Attempted to invoke missing native:", key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required params:
|
||||
* - name
|
||||
* - signature
|
||||
* - classInfo
|
||||
*
|
||||
* Optional params:
|
||||
* - attributes (defaults to [])
|
||||
* - code (if not provided, pulls from attributes)
|
||||
* - isNative, isPublic, isStatic, isSynchronized
|
||||
*/
|
||||
function MethodInfo(opts) {
|
||||
this.name = opts.name;
|
||||
this.signature = opts.signature;
|
||||
this.classInfo = opts.classInfo;
|
||||
this.attributes = opts.attributes || [];
|
||||
|
||||
// Use code if provided, otherwise search for the code within attributes.
|
||||
if (opts.code) {
|
||||
this.code = opts.code;
|
||||
this.exception_table = [];
|
||||
this.max_locals = undefined; // Unused for now.
|
||||
} else {
|
||||
for (var i = 0; i < this.attributes.length; i++) {
|
||||
var a = this.attributes[i];
|
||||
if (a.info.type === ATTRIBUTE_TYPES.Code) {
|
||||
this.code = new Uint8Array(a.info.code);
|
||||
this.exception_table = a.info.exception_table;
|
||||
this.max_locals = a.info.max_locals;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.isNative = opts.isNative;
|
||||
this.isPublic = opts.isPublic;
|
||||
this.isStatic = opts.isStatic;
|
||||
this.isSynchronized = opts.isSynchronized;
|
||||
|
||||
this.key = (this.isStatic ? "S." : "I.") + this.name + "." + this.signature;
|
||||
this.implKey = this.classInfo.className + "." + this.name + "." + this.signature;
|
||||
|
||||
if (this.isNative) {
|
||||
if (this.implKey in Native) {
|
||||
this.alternateImpl = Native[this.implKey];
|
||||
} else {
|
||||
// Some Native MethodInfos are constructed but never called;
|
||||
// that's fine, unless we actually try to call them.
|
||||
this.alternateImpl = missingNativeImpl.bind(null, this.implKey);
|
||||
}
|
||||
} else if (this.implKey in Override) {
|
||||
this.alternateImpl = Override[this.implKey];
|
||||
} else {
|
||||
this.alternateImpl = null;
|
||||
}
|
||||
|
||||
this.consumes = Signature.getINSlots(this.signature);
|
||||
if (!this.isStatic) {
|
||||
this.consumes++;
|
||||
}
|
||||
|
||||
this.numCalled = urlParams.numCalled || 0;
|
||||
this.compiled = null;
|
||||
this.dontCompile = false;
|
||||
}
|
||||
|
||||
var ClassInfo = function(classBytes) {
|
||||
var classImage = getClassImage(classBytes, this);
|
||||
var cp = classImage.constant_pool;
|
||||
this.className = cp[cp[classImage.this_class].name_index].bytes;
|
||||
this.superClassName = classImage.super_class ? cp[cp[classImage.super_class].name_index].bytes : null;
|
||||
this.access_flags = classImage.access_flags;
|
||||
this.constant_pool = cp;
|
||||
this.constructor = function () {
|
||||
}
|
||||
this.constructor.prototype.class = this;
|
||||
this.constructor.prototype.toString = function() {
|
||||
return "[instance " + this.class.className + "]";
|
||||
}
|
||||
// Cache for virtual methods and fields
|
||||
this.vmc = {};
|
||||
this.vfc = {};
|
||||
|
||||
var self = this;
|
||||
|
||||
this.interfaces = [];
|
||||
classImage.interfaces.forEach(function(i) {
|
||||
var int = CLASSES.loadClass(cp[cp[i].name_index].bytes);
|
||||
self.interfaces.push(int);
|
||||
self.interfaces = self.interfaces.concat(int.interfaces);
|
||||
});
|
||||
|
||||
this.fields = [];
|
||||
classImage.fields.forEach(function(f) {
|
||||
var field = new FieldInfo(self, f.access_flags, cp[f.name_index].bytes, cp[f.descriptor_index].bytes);
|
||||
f.attributes.forEach(function(attribute) {
|
||||
if (cp[attribute.attribute_name_index].bytes === "ConstantValue")
|
||||
field.constantValue = new DataView(attribute.info).getUint16(0, false);
|
||||
});
|
||||
self.fields.push(field);
|
||||
});
|
||||
|
||||
this.methods = [];
|
||||
classImage.methods.forEach(function(m) {
|
||||
self.methods.push(new MethodInfo({
|
||||
name: cp[m.name_index].bytes,
|
||||
signature: cp[m.signature_index].bytes,
|
||||
classInfo: self,
|
||||
attributes: m.attributes,
|
||||
isNative: ACCESS_FLAGS.isNative(m.access_flags),
|
||||
isPublic: ACCESS_FLAGS.isPublic(m.access_flags),
|
||||
isStatic: ACCESS_FLAGS.isStatic(m.access_flags),
|
||||
isSynchronized: ACCESS_FLAGS.isSynchronized(m.access_flags)
|
||||
}));
|
||||
});
|
||||
|
||||
var classes = this.classes = [];
|
||||
classImage.attributes.forEach(function(a) {
|
||||
if (a.info.type === ATTRIBUTE_TYPES.InnerClasses) {
|
||||
a.info.classes.forEach(function(c) {
|
||||
classes.push(cp[cp[c.inner_class_info_index].name_index].bytes);
|
||||
if (c.outer_class_info_index)
|
||||
classes.push(cp[cp[c.outer_class_info_index].name_index].bytes);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ClassInfo.prototype.implementsInterface = function(iface) {
|
||||
var classInfo = this;
|
||||
do {
|
||||
var interfaces = classInfo.interfaces;
|
||||
for (var n = 0; n < interfaces.length; ++n) {
|
||||
if (interfaces[n] === iface)
|
||||
return true;
|
||||
}
|
||||
classInfo = classInfo.superClass;
|
||||
} while (classInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassInfo.prototype.isAssignableTo = function(toClass) {
|
||||
if (this === toClass || toClass === ClassInfo.java_lang_Object)
|
||||
return true;
|
||||
if (ACCESS_FLAGS.isInterface(toClass.access_flags) && this.implementsInterface(toClass))
|
||||
return true;
|
||||
if (this.elementClass && toClass.elementClass)
|
||||
return this.elementClass.isAssignableTo(toClass.elementClass);
|
||||
return this.superClass ? this.superClass.isAssignableTo(toClass) : false;
|
||||
}
|
||||
|
||||
ClassInfo.prototype.getClassObject = function(ctx) {
|
||||
var className = this.className;
|
||||
var classObjects = ctx.runtime.classObjects;
|
||||
var classObject = classObjects[className];
|
||||
if (!classObject) {
|
||||
classObject = util.newObject(CLASSES.java_lang_Class);
|
||||
classObject.vmClass = this;
|
||||
classObjects[className] = classObject;
|
||||
}
|
||||
return classObject;
|
||||
}
|
||||
|
||||
ClassInfo.prototype.getField = function(fieldKey) {
|
||||
return CLASSES.getField(this, fieldKey);
|
||||
}
|
||||
|
||||
ClassInfo.prototype.toString = function() {
|
||||
return "[class " + this.className + "]";
|
||||
}
|
||||
|
||||
var ArrayClass = function(className, elementClass) {
|
||||
this.className = className;
|
||||
this.superClassName = "java/lang/Object";
|
||||
this.access_flags = 0;
|
||||
this.elementClass = elementClass;
|
||||
this.vmc = {};
|
||||
this.vfc = {};
|
||||
}
|
||||
|
||||
ArrayClass.prototype.methods = [];
|
||||
|
||||
ArrayClass.prototype.isArrayClass = true;
|
||||
|
||||
ArrayClass.prototype.implementsInterface = function(iface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayClass.prototype.isAssignableTo = ClassInfo.prototype.isAssignableTo;
|
||||
|
||||
ArrayClass.prototype.getClassObject = ClassInfo.prototype.getClassObject;
|
268
context.js
|
@ -1,268 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
function Context(runtime) {
|
||||
this.frames = [];
|
||||
this.runtime = runtime;
|
||||
this.runtime.addContext(this);
|
||||
}
|
||||
|
||||
Context.prototype.kill = function() {
|
||||
this.runtime.removeContext(this);
|
||||
}
|
||||
|
||||
Context.prototype.current = function() {
|
||||
var frames = this.frames;
|
||||
return frames[frames.length - 1];
|
||||
}
|
||||
|
||||
Context.prototype.pushFrame = function(methodInfo) {
|
||||
var caller = this.current();
|
||||
var callee = new Frame(methodInfo, caller.stack, caller.stack.length - methodInfo.consumes);
|
||||
this.frames.push(callee);
|
||||
Instrument.callEnterHooks(methodInfo, caller, callee);
|
||||
return callee;
|
||||
}
|
||||
|
||||
Context.prototype.popFrame = function() {
|
||||
var callee = this.frames.pop();
|
||||
var caller = this.current();
|
||||
Instrument.callExitHooks(callee.methodInfo, caller, callee);
|
||||
caller.stack.length = callee.localsBase;
|
||||
return caller;
|
||||
}
|
||||
|
||||
Context.prototype.pushClassInitFrame = function(classInfo) {
|
||||
if (this.runtime.initialized[classInfo.className])
|
||||
return;
|
||||
classInfo.thread = this.thread;
|
||||
var syntheticMethod = new MethodInfo({
|
||||
name: "ClassInitSynthetic",
|
||||
signature: "()V",
|
||||
isStatic: false,
|
||||
classInfo: {
|
||||
className: classInfo.className,
|
||||
vmc: {},
|
||||
vfc: {},
|
||||
constant_pool: [
|
||||
null,
|
||||
{ tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 4 },
|
||||
{ tag: TAGS.CONSTANT_Class, name_index: 3 },
|
||||
{ bytes: "java/lang/Class" },
|
||||
{ name_index: 5, signature_index: 6 },
|
||||
{ bytes: "invoke_clinit" },
|
||||
{ bytes: "()V" },
|
||||
{ tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 8 },
|
||||
{ name_index: 9, signature_index: 10 },
|
||||
{ bytes: "init9" },
|
||||
{ bytes: "()V" },
|
||||
],
|
||||
},
|
||||
code: new Uint8Array([
|
||||
0x2a, // aload_0
|
||||
0x59, // dup
|
||||
0x59, // dup
|
||||
0x59, // dup
|
||||
0xc2, // monitorenter
|
||||
0xb7, 0x00, 0x01, // invokespecial <idx=1>
|
||||
0xb7, 0x00, 0x07, // invokespecial <idx=7>
|
||||
0xc3, // monitorexit
|
||||
0xb1, // return
|
||||
])
|
||||
});
|
||||
this.current().stack.push(classInfo.getClassObject(this));
|
||||
this.pushFrame(syntheticMethod);
|
||||
}
|
||||
|
||||
Context.prototype.raiseException = function(className, message) {
|
||||
if (!message)
|
||||
message = "";
|
||||
message = "" + message;
|
||||
var syntheticMethod = new MethodInfo({
|
||||
name: "RaiseExceptionSynthetic",
|
||||
signature: "()V",
|
||||
isStatic: true,
|
||||
classInfo: {
|
||||
className: className,
|
||||
vmc: {},
|
||||
vfc: {},
|
||||
constant_pool: [
|
||||
null,
|
||||
{ tag: TAGS.CONSTANT_Class, name_index: 2 },
|
||||
{ bytes: className },
|
||||
{ tag: TAGS.CONSTANT_String, string_index: 4 },
|
||||
{ bytes: message },
|
||||
{ tag: TAGS.CONSTANT_Methodref, class_index: 1, name_and_type_index: 6 },
|
||||
{ name_index: 7, signature_index: 8 },
|
||||
{ bytes: "<init>" },
|
||||
{ bytes: "(Ljava/lang/String;)V" },
|
||||
],
|
||||
},
|
||||
code: new Uint8Array([
|
||||
0xbb, 0x00, 0x01, // new <idx=1>
|
||||
0x59, // dup
|
||||
0x12, 0x03, // ldc <idx=2>
|
||||
0xb7, 0x00, 0x05, // invokespecial <idx=5>
|
||||
0xbf // athrow
|
||||
])
|
||||
});
|
||||
this.pushFrame(syntheticMethod);
|
||||
}
|
||||
|
||||
Context.prototype.raiseExceptionAndYield = function(className, message) {
|
||||
this.raiseException(className, message);
|
||||
throw VM.Yield;
|
||||
}
|
||||
|
||||
Context.prototype.execute = function() {
|
||||
Instrument.callResumeHooks(this.current());
|
||||
do {
|
||||
try {
|
||||
VM.execute(this);
|
||||
} catch (e) {
|
||||
switch (e) {
|
||||
case VM.Yield:
|
||||
// Ignore the yield and continue executing instructions on this thread.
|
||||
break;
|
||||
case VM.Pause:
|
||||
Instrument.callPauseHooks(this.current());
|
||||
return;
|
||||
default:
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} while (this.frames.length !== 1);
|
||||
|
||||
this.frames.pop();
|
||||
}
|
||||
|
||||
Context.prototype.start = function() {
|
||||
var ctx = this;
|
||||
|
||||
Instrument.callResumeHooks(ctx.current());
|
||||
try {
|
||||
VM.execute(ctx);
|
||||
} catch (e) {
|
||||
switch (e) {
|
||||
case VM.Yield:
|
||||
break;
|
||||
case VM.Pause:
|
||||
Instrument.callPauseHooks(ctx.current());
|
||||
return;
|
||||
default:
|
||||
console.info(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
Instrument.callPauseHooks(ctx.current());
|
||||
|
||||
// If there's one frame left, we're back to
|
||||
// the method that created the thread and
|
||||
// we're done.
|
||||
if (ctx.frames.length === 1) {
|
||||
ctx.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.resume();
|
||||
}
|
||||
|
||||
Context.prototype.resume = function() {
|
||||
window.setZeroTimeout(this.start.bind(this));
|
||||
}
|
||||
|
||||
Context.prototype.block = function(obj, queue, lockLevel) {
|
||||
if (!obj[queue])
|
||||
obj[queue] = [];
|
||||
obj[queue].push(this);
|
||||
this.lockLevel = lockLevel;
|
||||
throw VM.Pause;
|
||||
}
|
||||
|
||||
Context.prototype.unblock = function(obj, queue, notifyAll, callback) {
|
||||
while (obj[queue] && obj[queue].length) {
|
||||
var ctx = obj[queue].pop();
|
||||
if (!ctx)
|
||||
continue;
|
||||
callback(ctx);
|
||||
if (!notifyAll)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Context.prototype.wakeup = function(obj) {
|
||||
if (this.lockTimeout !== null) {
|
||||
window.clearTimeout(this.lockTimeout);
|
||||
this.lockTimeout = null;
|
||||
}
|
||||
if (obj.lock) {
|
||||
if (!obj.ready)
|
||||
obj.ready = [];
|
||||
obj.ready.push(this);
|
||||
} else {
|
||||
while (this.lockLevel-- > 0)
|
||||
this.monitorEnter(obj);
|
||||
this.resume();
|
||||
}
|
||||
}
|
||||
|
||||
Context.prototype.monitorEnter = function(obj) {
|
||||
var lock = obj.lock;
|
||||
if (!lock) {
|
||||
obj.lock = { thread: this.thread, level: 1 };
|
||||
return;
|
||||
}
|
||||
if (lock.thread === this.thread) {
|
||||
++lock.level;
|
||||
return;
|
||||
}
|
||||
this.block(obj, "ready", 1);
|
||||
}
|
||||
|
||||
Context.prototype.monitorExit = function(obj) {
|
||||
var lock = obj.lock;
|
||||
if (lock.thread !== this.thread)
|
||||
this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException");
|
||||
if (--lock.level > 0) {
|
||||
return;
|
||||
}
|
||||
obj.lock = null;
|
||||
this.unblock(obj, "ready", false, function(ctx) {
|
||||
ctx.wakeup(obj);
|
||||
});
|
||||
}
|
||||
|
||||
Context.prototype.wait = function(obj, timeout) {
|
||||
var lock = obj.lock;
|
||||
if (timeout < 0)
|
||||
this.raiseExceptionAndYield("java/lang/IllegalArgumentException");
|
||||
if (!lock || lock.thread !== this.thread)
|
||||
this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException");
|
||||
var lockLevel = lock.level;
|
||||
while (lock.level > 0)
|
||||
this.monitorExit(obj);
|
||||
if (timeout) {
|
||||
var self = this;
|
||||
this.lockTimeout = window.setTimeout(function() {
|
||||
obj.waiting.forEach(function(ctx, n) {
|
||||
if (ctx === self) {
|
||||
obj.waiting[n] = null;
|
||||
ctx.wakeup(obj);
|
||||
}
|
||||
});
|
||||
}, timeout);
|
||||
} else {
|
||||
this.lockTimeout = null;
|
||||
}
|
||||
this.block(obj, "waiting", lockLevel);
|
||||
}
|
||||
|
||||
Context.prototype.notify = function(obj, notifyAll) {
|
||||
if (!obj.lock || obj.lock.thread !== this.thread)
|
||||
this.raiseExceptionAndYield("java/lang/IllegalMonitorStateException");
|
||||
this.unblock(obj, "waiting", notifyAll, function(ctx) {
|
||||
ctx.wakeup(obj);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,670 @@
|
|||
interface Array<T> {
|
||||
push2: (value) => void;
|
||||
pop2: () => any;
|
||||
pushKind: (kind: J2ME.Kind, value) => void;
|
||||
popKind: (kind: J2ME.Kind) => any;
|
||||
read: (i) => any;
|
||||
}
|
||||
|
||||
module J2ME {
|
||||
import assert = Debug.assert;
|
||||
import Bytecodes = Bytecode.Bytecodes;
|
||||
declare var VM;
|
||||
declare var Instrument;
|
||||
declare var setZeroTimeout;
|
||||
|
||||
export enum WriterFlags {
|
||||
None = 0x00,
|
||||
Trace = 0x01,
|
||||
Link = 0x02,
|
||||
Init = 0x04,
|
||||
Perf = 0x08,
|
||||
Load = 0x10,
|
||||
JIT = 0x20,
|
||||
|
||||
All = Trace | Link | Init | Perf | Load | JIT
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle VM tracing here.
|
||||
*/
|
||||
export var writers = WriterFlags.None;
|
||||
|
||||
Array.prototype.push2 = function(value) {
|
||||
this.push(value);
|
||||
this.push(null);
|
||||
return value;
|
||||
}
|
||||
|
||||
Array.prototype.pop2 = function() {
|
||||
this.pop();
|
||||
return this.pop();
|
||||
}
|
||||
|
||||
Array.prototype.pushKind = function(kind: Kind, value) {
|
||||
if (isTwoSlot(kind)) {
|
||||
this.push2(value);
|
||||
return;
|
||||
}
|
||||
this.push(value);
|
||||
}
|
||||
|
||||
Array.prototype.popKind = function(kind: Kind) {
|
||||
if (isTwoSlot(kind)) {
|
||||
return this.pop2();
|
||||
}
|
||||
return this.pop();
|
||||
}
|
||||
|
||||
// A convenience function for retrieving values in reverse order
|
||||
// from the end of the stack. stack.read(1) returns the topmost item
|
||||
// on the stack, while stack.read(2) returns the one underneath it.
|
||||
Array.prototype.read = function(i) {
|
||||
return this[this.length - i];
|
||||
};
|
||||
|
||||
export var frameCount = 0;
|
||||
|
||||
export class Frame {
|
||||
methodInfo: MethodInfo;
|
||||
local: any [];
|
||||
stack: any [];
|
||||
code: Uint8Array;
|
||||
pc: number;
|
||||
opPC: number;
|
||||
cp: any;
|
||||
localBase: number;
|
||||
lockObject: java.lang.Object;
|
||||
|
||||
static dirtyStack: Frame [] = [];
|
||||
|
||||
/**
|
||||
* Denotes the start of the context frame stack.
|
||||
*/
|
||||
static Start: Frame = Frame.create(null, null, 0);
|
||||
|
||||
/**
|
||||
* Marks a frame set.
|
||||
*/
|
||||
static Marker: Frame = Frame.create(null, null, 0);
|
||||
|
||||
static isMarker(frame: Frame) {
|
||||
return frame.methodInfo === null;
|
||||
}
|
||||
|
||||
constructor(methodInfo: MethodInfo, local: any [], localBase: number) {
|
||||
frameCount ++;
|
||||
this.reset(methodInfo, local, localBase);
|
||||
}
|
||||
|
||||
reset(methodInfo: MethodInfo, local: any [], localBase: number) {
|
||||
this.methodInfo = methodInfo;
|
||||
this.cp = methodInfo ? methodInfo.classInfo.constant_pool : null;
|
||||
this.code = methodInfo ? methodInfo.code : null;
|
||||
this.pc = 0;
|
||||
this.opPC = 0;
|
||||
this.stack = [];
|
||||
this.local = local;
|
||||
this.localBase = localBase;
|
||||
this.lockObject = null;
|
||||
}
|
||||
|
||||
static create(methodInfo: MethodInfo, local: any [], localBase: number): Frame {
|
||||
var dirtyStack = Frame.dirtyStack;
|
||||
if (dirtyStack.length) {
|
||||
var frame = dirtyStack.pop();
|
||||
frame.reset(methodInfo, local, localBase);
|
||||
return frame;
|
||||
} else {
|
||||
return new Frame(methodInfo, local, localBase);
|
||||
}
|
||||
}
|
||||
|
||||
free() {
|
||||
release || assert(!Frame.isMarker(this));
|
||||
Frame.dirtyStack.push(this);
|
||||
}
|
||||
|
||||
getLocal(i: number): any {
|
||||
return this.local[this.localBase + i];
|
||||
}
|
||||
|
||||
setLocal(i: number, value: any) {
|
||||
this.local[this.localBase + i] = value;
|
||||
}
|
||||
|
||||
incLocal(i: number, value: any) {
|
||||
var j = this.localBase + i;
|
||||
this.local[j] = this.local[j] + value | 0;
|
||||
}
|
||||
|
||||
read8(): number {
|
||||
return this.code[this.pc++];
|
||||
}
|
||||
|
||||
peek8(): number {
|
||||
return this.code[this.pc];
|
||||
}
|
||||
|
||||
read16(): number {
|
||||
var code = this.code
|
||||
return code[this.pc++] << 8 | code[this.pc++];
|
||||
}
|
||||
|
||||
patch(offset: number, oldValue: Bytecodes, newValue: Bytecodes) {
|
||||
release || assert(this.code[this.pc - offset] === oldValue);
|
||||
this.code[this.pc - offset] = newValue;
|
||||
}
|
||||
|
||||
read32(): number {
|
||||
return this.read32Signed() >>> 0;
|
||||
}
|
||||
|
||||
read8Signed(): number {
|
||||
return this.code[this.pc++] << 24 >> 24;
|
||||
}
|
||||
|
||||
read16Signed(): number {
|
||||
var pc = this.pc;
|
||||
var code = this.code;
|
||||
this.pc = pc + 2
|
||||
return (code[pc] << 8 | code[pc + 1]) << 16 >> 16;
|
||||
}
|
||||
|
||||
readTargetPC(): number {
|
||||
var pc = this.pc;
|
||||
var code = this.code;
|
||||
this.pc = pc + 2
|
||||
var offset = (code[pc] << 8 | code[pc + 1]) << 16 >> 16;
|
||||
return pc - 1 + offset;
|
||||
}
|
||||
|
||||
read32Signed(): number {
|
||||
return this.read16() << 16 | this.read16();
|
||||
}
|
||||
|
||||
tableSwitch(): number {
|
||||
var start = this.pc;
|
||||
while ((this.pc & 3) != 0) {
|
||||
this.pc++;
|
||||
}
|
||||
var def = this.read32Signed();
|
||||
var low = this.read32Signed();
|
||||
var high = this.read32Signed();
|
||||
var value = this.stack.pop();
|
||||
var pc;
|
||||
if (value < low || value > high) {
|
||||
pc = def;
|
||||
} else {
|
||||
this.pc += (value - low) << 2;
|
||||
pc = this.read32Signed();
|
||||
}
|
||||
return start - 1 + pc;
|
||||
}
|
||||
|
||||
lookupSwitch(): number {
|
||||
var start = this.pc;
|
||||
while ((this.pc & 3) != 0) {
|
||||
this.pc++;
|
||||
}
|
||||
var pc = this.read32Signed();
|
||||
var size = this.read32();
|
||||
var value = this.stack.pop();
|
||||
lookup:
|
||||
for (var i = 0; i < size; i++) {
|
||||
var key = this.read32Signed();
|
||||
var offset = this.read32Signed();
|
||||
if (key === value) {
|
||||
pc = offset;
|
||||
}
|
||||
if (key >= value) {
|
||||
break lookup;
|
||||
}
|
||||
}
|
||||
return start - 1 + pc;
|
||||
}
|
||||
|
||||
wide() {
|
||||
var stack = this.stack;
|
||||
var op = this.read8();
|
||||
switch (op) {
|
||||
case Bytecodes.ILOAD:
|
||||
case Bytecodes.FLOAD:
|
||||
case Bytecodes.ALOAD:
|
||||
stack.push(this.getLocal(this.read16()));
|
||||
break;
|
||||
case Bytecodes.LLOAD:
|
||||
case Bytecodes.DLOAD:
|
||||
stack.push2(this.getLocal(this.read16()));
|
||||
break;
|
||||
case Bytecodes.ISTORE:
|
||||
case Bytecodes.FSTORE:
|
||||
case Bytecodes.ASTORE:
|
||||
this.setLocal(this.read16(), stack.pop());
|
||||
break;
|
||||
case Bytecodes.LSTORE:
|
||||
case Bytecodes.DSTORE:
|
||||
this.setLocal(this.read16(), stack.pop2());
|
||||
break;
|
||||
case Bytecodes.IINC:
|
||||
var index = this.read16();
|
||||
var value = this.read16Signed();
|
||||
this.setLocal(index, this.getLocal(index) + value);
|
||||
break;
|
||||
case Bytecodes.RET:
|
||||
this.pc = this.getLocal(this.read16());
|
||||
break;
|
||||
default:
|
||||
var opName = Bytecodes[op];
|
||||
throw new Error("Wide opcode " + opName + " [" + op + "] not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the |object| on which a call to the specified |methodInfo| would be
|
||||
* called.
|
||||
*/
|
||||
peekInvokeObject(methodInfo: MethodInfo): java.lang.Object {
|
||||
release || assert(!methodInfo.isStatic);
|
||||
var i = this.stack.length - methodInfo.argumentSlots - 1;
|
||||
release || assert (i >= 0);
|
||||
release || assert (this.stack[i] !== undefined);
|
||||
return this.stack[i];
|
||||
}
|
||||
|
||||
popArgumentsInto(signatureDescriptor: SignatureDescriptor, args): any [] {
|
||||
var stack = this.stack;
|
||||
var typeDescriptors = signatureDescriptor.typeDescriptors;
|
||||
var argumentSlotCount = signatureDescriptor.getArgumentSlotCount();
|
||||
for (var i = 1, j = stack.length - argumentSlotCount, k = 0; i < typeDescriptors.length; i++) {
|
||||
var typeDescriptor = typeDescriptors[i];
|
||||
args[k++] = stack[j++];
|
||||
if (isTwoSlot(typeDescriptor.kind)) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
release || assert(j === stack.length && k === signatureDescriptor.getArgumentCount());
|
||||
stack.length -= argumentSlotCount;
|
||||
args.length = k;
|
||||
return args;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.methodInfo.implKey + " " + this.pc;
|
||||
}
|
||||
|
||||
trace(writer: IndentingWriter) {
|
||||
var localStr = this.local.map(function (x) {
|
||||
return toDebugString(x);
|
||||
}).join(", ");
|
||||
|
||||
var stackStr = this.stack.map(function (x) {
|
||||
return toDebugString(x);
|
||||
}).join(", ");
|
||||
|
||||
writer.writeLn(("" + this.pc).padLeft(" ", 4) + " " + localStr + " | " + stackStr);
|
||||
}
|
||||
}
|
||||
|
||||
export class Context {
|
||||
private static _nextId: number = 0;
|
||||
private static _colors = [
|
||||
IndentingWriter.PURPLE,
|
||||
IndentingWriter.YELLOW,
|
||||
IndentingWriter.GREEN,
|
||||
IndentingWriter.RED,
|
||||
IndentingWriter.BOLD_RED
|
||||
];
|
||||
private static writer: IndentingWriter = new IndentingWriter(false, function (s) {
|
||||
console.log(s);
|
||||
});
|
||||
|
||||
id: number
|
||||
|
||||
/*
|
||||
* Contains method frames separated by special frame instances called marker frames. These
|
||||
* mark the position in the frame stack where the interpreter starts execution.
|
||||
*
|
||||
* During normal execution, a marker frame is inserted on every call to |executeFrames|, so
|
||||
* the stack looks something like:
|
||||
*
|
||||
* frame stack: [start, f0, m, f1, m, f2]
|
||||
* ^ ^ ^
|
||||
* | | |
|
||||
* js call stack: I ........ I .... I ...
|
||||
*
|
||||
* After unwinding, the frame stack is compacted:
|
||||
*
|
||||
* frame stack: [start, f0, f1, f2]
|
||||
* ^ ^
|
||||
* | |
|
||||
* js call stack: I ..... I .......
|
||||
*
|
||||
*/
|
||||
frames: Frame [];
|
||||
bailoutFrames: Frame [];
|
||||
lockTimeout: number;
|
||||
lockLevel: number;
|
||||
thread: java.lang.Thread;
|
||||
writer: IndentingWriter;
|
||||
constructor(public runtime: Runtime) {
|
||||
var id = this.id = Context._nextId ++;
|
||||
this.frames = [];
|
||||
this.bailoutFrames = [];
|
||||
this.runtime = runtime;
|
||||
this.runtime.addContext(this);
|
||||
this.writer = new IndentingWriter(false, function (s) {
|
||||
console.log(s);
|
||||
});
|
||||
}
|
||||
|
||||
public static color(id) {
|
||||
if (inBrowser) {
|
||||
return id;
|
||||
}
|
||||
return Context._colors[id % Context._colors.length] + id + IndentingWriter.ENDC;
|
||||
}
|
||||
public static currentContextPrefix() {
|
||||
if ($) {
|
||||
return Context.color($.id) + ":" + Context.color($.ctx.id);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets global writers. Uncomment these if you want to see trace output.
|
||||
*/
|
||||
static setWriters(writer: IndentingWriter) {
|
||||
traceWriter = writers & WriterFlags.Trace ? writer : null;
|
||||
perfWriter = writers & WriterFlags.Perf ? writer : null;
|
||||
linkWriter = writers & WriterFlags.Link ? writer : null;
|
||||
jitWriter = writers & WriterFlags.JIT ? writer : null;
|
||||
initWriter = writers & WriterFlags.Init ? writer : null;
|
||||
loadWriter = writers & WriterFlags.Load ? writer : null;
|
||||
}
|
||||
|
||||
kill() {
|
||||
if (this.thread) {
|
||||
this.thread.alive = false;
|
||||
}
|
||||
this.runtime.removeContext(this);
|
||||
}
|
||||
|
||||
current(): Frame {
|
||||
var frames = this.frames;
|
||||
return frames[frames.length - 1];
|
||||
}
|
||||
|
||||
private popMarkerFrame() {
|
||||
var marker = this.frames.pop();
|
||||
release || assert (Frame.isMarker(marker));
|
||||
}
|
||||
|
||||
executeFrames(group: Frame []) {
|
||||
var frames = this.frames;
|
||||
frames.push(Frame.Marker);
|
||||
|
||||
for (var i = 0; i < group.length; i++) {
|
||||
frames.push(group[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
var returnValue = VM.execute();
|
||||
if (U) {
|
||||
// Prepend all frames up until the first marker to the bailout frames.
|
||||
while (true) {
|
||||
var frame = frames.pop();
|
||||
if (Frame.isMarker(frame)) {
|
||||
break;
|
||||
}
|
||||
this.bailoutFrames.unshift(frame);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
this.popMarkerFrame();
|
||||
throwHelper(e);
|
||||
}
|
||||
this.popMarkerFrame();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
getClassInitFrame(classInfo: ClassInfo) {
|
||||
if (this.runtime.initialized[classInfo.className]) {
|
||||
return;
|
||||
}
|
||||
classInfo.thread = this.thread;
|
||||
var syntheticMethod = new MethodInfo({
|
||||
name: "ClassInitSynthetic",
|
||||
signature: "()V",
|
||||
isStatic: false,
|
||||
classInfo: ClassInfo.createFromObject({
|
||||
className: {value: classInfo.className},
|
||||
vmc: {value: {}},
|
||||
vfc: {value: {}},
|
||||
constant_pool: {value: [
|
||||
null,
|
||||
{tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 4},
|
||||
{tag: TAGS.CONSTANT_Class, name_index: 3},
|
||||
{bytes: "java/lang/Class"},
|
||||
{name_index: 5, signature_index: 6},
|
||||
{bytes: "invoke_clinit"},
|
||||
{bytes: "()V"},
|
||||
{tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 8},
|
||||
{name_index: 9, signature_index: 10},
|
||||
{bytes: "init9"},
|
||||
{bytes: "()V"},
|
||||
]},
|
||||
}),
|
||||
code: new Uint8Array([
|
||||
0x2a, // aload_0
|
||||
0x59, // dup
|
||||
0x59, // dup
|
||||
0x59, // dup
|
||||
0xc2, // monitorenter
|
||||
0xb7, 0x00, 0x01, // invokespecial <idx=1>
|
||||
0xb7, 0x00, 0x07, // invokespecial <idx=7>
|
||||
0xc3, // monitorexit
|
||||
0xb1, // return
|
||||
])
|
||||
});
|
||||
return Frame.create(syntheticMethod, [classInfo.getClassInitLockObject(this)], 0);
|
||||
}
|
||||
|
||||
pushClassInitFrame(classInfo: ClassInfo) {
|
||||
if (this.runtime.initialized[classInfo.className]) {
|
||||
return;
|
||||
}
|
||||
linkKlass(classInfo);
|
||||
var classInitFrame = this.getClassInitFrame(classInfo);
|
||||
this.executeFrames([classInitFrame]);
|
||||
}
|
||||
|
||||
createException(className: string, message?: string) {
|
||||
if (!message) {
|
||||
message = "";
|
||||
}
|
||||
message = "" + message;
|
||||
var classInfo = CLASSES.loadAndLinkClass(className);
|
||||
runtimeCounter && runtimeCounter.count("createException " + className);
|
||||
var exception = new classInfo.klass();
|
||||
var methodInfo = CLASSES.getMethod(classInfo, "I.<init>.(Ljava/lang/String;)V");
|
||||
jsGlobal[methodInfo.mangledClassAndMethodName].call(exception, message ? newString(message) : null);
|
||||
|
||||
return exception;
|
||||
}
|
||||
|
||||
setAsCurrentContext() {
|
||||
$ = this.runtime;
|
||||
if ($.ctx === this) {
|
||||
return;
|
||||
}
|
||||
$.ctx = this;
|
||||
Context.setWriters(this.writer);
|
||||
}
|
||||
|
||||
clearCurrentContext() {
|
||||
$ = null;
|
||||
Context.setWriters(Context.writer);
|
||||
}
|
||||
|
||||
start(frame: Frame) {
|
||||
this.frames = [Frame.Start, frame];
|
||||
this.resume();
|
||||
}
|
||||
|
||||
private execute() {
|
||||
var start = performance.now();
|
||||
this.setAsCurrentContext();
|
||||
do {
|
||||
VM.execute();
|
||||
if (U) {
|
||||
if (this.bailoutFrames.length) {
|
||||
Array.prototype.push.apply(this.frames, this.bailoutFrames);
|
||||
this.bailoutFrames = [];
|
||||
}
|
||||
var frames = this.frames;
|
||||
if (windingWriter) {
|
||||
windingWriter.enter("Unwound");
|
||||
frames.map(function (f) {
|
||||
if (Frame.isMarker(f)) {
|
||||
windingWriter.writeLn("- marker -");
|
||||
} else {
|
||||
windingWriter.writeLn((f.methodInfo.state === MethodState.Compiled ? "C" : "I") + " " + f.toString());
|
||||
}
|
||||
});
|
||||
windingWriter.leave("");
|
||||
}
|
||||
switch (U) {
|
||||
case VMState.Yielding:
|
||||
this.resume();
|
||||
break;
|
||||
case VMState.Pausing:
|
||||
break;
|
||||
}
|
||||
U = VMState.Running;
|
||||
this.clearCurrentContext();
|
||||
return;
|
||||
}
|
||||
} while (this.current() !== Frame.Start);
|
||||
this.kill();
|
||||
}
|
||||
|
||||
resume() {
|
||||
(<any>window).setZeroTimeout(this.execute.bind(this));
|
||||
}
|
||||
|
||||
block(obj, queue, lockLevel) {
|
||||
if (!obj[queue])
|
||||
obj[queue] = [];
|
||||
obj[queue].push(this);
|
||||
this.lockLevel = lockLevel;
|
||||
$.pause("block");
|
||||
}
|
||||
|
||||
unblock(obj, queue, notifyAll, callback) {
|
||||
while (obj[queue] && obj[queue].length) {
|
||||
var ctx = obj[queue].pop();
|
||||
if (!ctx)
|
||||
continue;
|
||||
// Wait until next tick, so that we are sure to notify all waiting.
|
||||
(<any>window).setZeroTimeout(callback.bind(null, ctx));
|
||||
if (!notifyAll)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wakeup(obj) {
|
||||
if (this.lockTimeout !== null) {
|
||||
window.clearTimeout(this.lockTimeout);
|
||||
this.lockTimeout = null;
|
||||
}
|
||||
if (obj._lock) {
|
||||
if (!obj.ready)
|
||||
obj.ready = [];
|
||||
obj.ready.push(this);
|
||||
} else {
|
||||
while (this.lockLevel-- > 0) {
|
||||
this.monitorEnter(obj);
|
||||
if (U === VMState.Pausing) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.resume();
|
||||
}
|
||||
}
|
||||
|
||||
monitorEnter(object: java.lang.Object) {
|
||||
var lock = object._lock;
|
||||
if (!lock) {
|
||||
object._lock = new Lock(this.thread, 1);
|
||||
return;
|
||||
}
|
||||
if (lock.thread === this.thread) {
|
||||
++lock.level;
|
||||
return;
|
||||
}
|
||||
this.block(object, "ready", 1);
|
||||
}
|
||||
|
||||
monitorExit(object: java.lang.Object) {
|
||||
var lock = object._lock;
|
||||
if (lock.thread !== this.thread)
|
||||
throw $.newIllegalMonitorStateException();
|
||||
if (--lock.level > 0) {
|
||||
return;
|
||||
}
|
||||
object._lock = null;
|
||||
this.unblock(object, "ready", false, function (ctx) {
|
||||
ctx.wakeup(object);
|
||||
});
|
||||
}
|
||||
|
||||
wait(object: java.lang.Object, timeout) {
|
||||
var lock = object._lock;
|
||||
if (timeout < 0)
|
||||
throw $.newIllegalArgumentException();
|
||||
if (!lock || lock.thread !== this.thread)
|
||||
throw $.newIllegalMonitorStateException();
|
||||
var lockLevel = lock.level;
|
||||
while (lock.level > 0)
|
||||
this.monitorExit(object);
|
||||
if (timeout) {
|
||||
var self = this;
|
||||
this.lockTimeout = window.setTimeout(function () {
|
||||
object.waiting.forEach(function (ctx, n) {
|
||||
if (ctx === self) {
|
||||
object.waiting[n] = null;
|
||||
ctx.wakeup(object);
|
||||
}
|
||||
});
|
||||
}, timeout);
|
||||
} else {
|
||||
this.lockTimeout = null;
|
||||
}
|
||||
this.block(object, "waiting", lockLevel);
|
||||
}
|
||||
|
||||
notify(obj, notifyAll) {
|
||||
if (!obj._lock || obj._lock.thread !== this.thread)
|
||||
throw $.newIllegalMonitorStateException();
|
||||
|
||||
this.unblock(obj, "waiting", notifyAll, function (ctx) {
|
||||
ctx.wakeup(obj);
|
||||
});
|
||||
}
|
||||
|
||||
bailout(methodInfo: MethodInfo, pc: number, nextPC: number, local: any [], stack: any [], lockObject: java.lang.Object) {
|
||||
// perfWriter && perfWriter.writeLn("C Unwind: " + methodInfo.implKey);
|
||||
var frame = Frame.create(methodInfo, local, 0);
|
||||
frame.stack = stack;
|
||||
frame.pc = nextPC;
|
||||
frame.opPC = pc;
|
||||
frame.lockObject = lockObject;
|
||||
this.bailoutFrames.unshift(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Context = J2ME.Context;
|
||||
var Frame = J2ME.Frame;
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
var xy = document.getElementById("xy");
|
||||
|
||||
document.getElementById("canvas").onmousemove = function(ev) {
|
||||
xy.textContent = "" + ev.layerX + "," + ev.layerY;
|
||||
}
|
||||
|
85
frame.js
|
@ -1,85 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
Array.prototype.push2 = function(value) {
|
||||
this.push(value);
|
||||
this.push(null);
|
||||
}
|
||||
|
||||
Array.prototype.pop2 = function() {
|
||||
this.pop();
|
||||
return this.pop();
|
||||
}
|
||||
|
||||
Array.prototype.pushType = function(signature, value) {
|
||||
if (signature === "J" || signature === "D") {
|
||||
this.push2(value);
|
||||
return;
|
||||
}
|
||||
this.push(value);
|
||||
}
|
||||
|
||||
Array.prototype.popType = function(signature) {
|
||||
return (signature === "J" || signature === "D") ? this.pop2() : this.pop();
|
||||
}
|
||||
|
||||
// A convenience function for retrieving values in reverse order
|
||||
// from the end of the stack. stack.read(1) returns the topmost item
|
||||
// on the stack, while stack.read(2) returns the one underneath it.
|
||||
Array.prototype.read = function(i) {
|
||||
return this[this.length - i];
|
||||
};
|
||||
|
||||
|
||||
var Frame = function(methodInfo, locals, localsBase) {
|
||||
this.methodInfo = methodInfo;
|
||||
this.cp = methodInfo.classInfo.constant_pool;
|
||||
this.code = methodInfo.code;
|
||||
this.ip = 0;
|
||||
|
||||
this.stack = [];
|
||||
|
||||
this.locals = locals;
|
||||
this.localsBase = localsBase;
|
||||
|
||||
this.lockObject = null;
|
||||
|
||||
this.profileData = null;
|
||||
}
|
||||
|
||||
Frame.prototype.getLocal = function(idx) {
|
||||
return this.locals[this.localsBase + idx];
|
||||
}
|
||||
|
||||
Frame.prototype.setLocal = function(idx, value) {
|
||||
this.locals[this.localsBase + idx] = value;
|
||||
}
|
||||
|
||||
Frame.prototype.read8 = function() {
|
||||
return this.code[this.ip++];
|
||||
};
|
||||
|
||||
Frame.prototype.read16 = function() {
|
||||
return this.read8()<<8 | this.read8();
|
||||
};
|
||||
|
||||
Frame.prototype.read32 = function() {
|
||||
return this.read16()<<16 | this.read16();
|
||||
};
|
||||
|
||||
Frame.prototype.read8signed = function() {
|
||||
var x = this.read8();
|
||||
return (x > 0x7f) ? (x - 0x100) : x;
|
||||
}
|
||||
|
||||
Frame.prototype.read16signed = function() {
|
||||
var x = this.read16();
|
||||
return (x > 0x7fff) ? (x - 0x10000) : x;
|
||||
}
|
||||
|
||||
Frame.prototype.read32signed = function() {
|
||||
var x = this.read32();
|
||||
return (x > 0x7fffffff) ? (x - 0x100000000) : x;
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="style/index.css">
|
||||
<script type="text/javascript" src="libs/load.js" defer></script>
|
||||
<script type="text/javascript" src="libs/promise-6.0.0.js" defer></script>
|
||||
<script type="text/javascript" src="midlet.js" defer></script>
|
||||
<script type="text/javascript" src="libs/urlparams.js" defer></script>
|
||||
<script type="text/javascript" src="timer.js" defer></script>
|
||||
<script type="text/javascript" src="index.js" defer></script>
|
||||
|
|
24
index.js
|
@ -7,7 +7,7 @@
|
|||
* Pre-load dependencies and then load the main page.
|
||||
*/
|
||||
(function() {
|
||||
var midletClassName = urlParams.midletClassName ? urlParams.midletClassName.replace(/\//g, '.') : "RunTests";
|
||||
var midletClassName = config.midletClassName ? config.midletClassName.replace(/\//g, '.') : "RunTests";
|
||||
var loadingPromises = [];
|
||||
if (midletClassName == "RunTests") {
|
||||
loadingPromises.push(loadScript("tests/contacts.js"),
|
||||
|
@ -128,13 +128,13 @@ DumbPipe.registerOpener("mobileInfo", function(message, sender) {
|
|||
// for testing/debugging on a desktop.
|
||||
var mobileInfo = {
|
||||
network: {
|
||||
mcc: urlParams.network_mcc || "310", // United States
|
||||
mnc: urlParams.network_mnc || "001",
|
||||
mcc: config.network_mcc || "310", // United States
|
||||
mnc: config.network_mnc || "001",
|
||||
},
|
||||
icc: {
|
||||
mcc: urlParams.icc_mcc || "310", // United States
|
||||
mnc: urlParams.icc_mnc || "001",
|
||||
msisdn: urlParams.icc_msisdn || "10005551212",
|
||||
mcc: config.icc_mcc || "310", // United States
|
||||
mnc: config.icc_mnc || "001",
|
||||
msisdn: config.icc_msisdn || "10005551212",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -334,6 +334,7 @@ DumbPipe.registerOpener("audiorecorder", function(message, sender) {
|
|||
|
||||
DumbPipe.registerOpener("camera", function(message, sender) {
|
||||
var mediaStream = null;
|
||||
var url = null;
|
||||
|
||||
var video = document.createElement("video");
|
||||
document.body.appendChild(video);
|
||||
|
@ -359,8 +360,13 @@ DumbPipe.registerOpener("camera", function(message, sender) {
|
|||
audio: false,
|
||||
}, function(localMediaStream) {
|
||||
mediaStream = localMediaStream;
|
||||
url = URL.createObjectURL(localMediaStream);
|
||||
|
||||
video.src = URL.createObjectURL(localMediaStream);
|
||||
video.onerror = video.onloadeddata = function() {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
video.src = url;
|
||||
video.play();
|
||||
}, function(err) {
|
||||
console.log("Error: " + err);
|
||||
|
@ -529,6 +535,10 @@ DumbPipe.registerOpener("reload", function(message, sender) {
|
|||
window.location.reload();
|
||||
});
|
||||
|
||||
DumbPipe.registerOpener("exit", function(message, sender) {
|
||||
window.close();
|
||||
});
|
||||
|
||||
navigator.mozAlarms.add(new Date(Date.now()+10000), 'ignoreTimezone', {});
|
||||
|
||||
navigator.mozSetMessageHandler('alarm', function() {
|
||||
|
|
|
@ -11,7 +11,7 @@ var Instrument = {
|
|||
profile: null,
|
||||
asyncProfile: null,
|
||||
|
||||
enabled: "instrument" in urlParams && !/no|0/.test(urlParams.instrument),
|
||||
enabled: "instrument" in config && !/no|0/.test(config.instrument),
|
||||
|
||||
callEnterHooks: function(methodInfo, caller, callee) {
|
||||
if (this.enabled) {
|
||||
|
@ -141,19 +141,19 @@ var Instrument = {
|
|||
};
|
||||
|
||||
Instrument.enter["com/sun/midp/ssl/SSLStreamConnection.<init>.(Ljava/lang/String;ILjava/io/InputStream;Ljava/io/OutputStream;Lcom/sun/midp/pki/CertStore;)V"] = function(caller, callee) {
|
||||
var _this = caller.stack.read(6), port = caller.stack.read(4), host = util.fromJavaString(caller.stack.read(5));
|
||||
var _this = callee.locals.read(6), port = callee.locals.read(4), host = util.fromJavaString(callee.locals.read(5));
|
||||
_this.logBuffer = "SSLStreamConnection to " + host + ":" + port + ":\n";
|
||||
};
|
||||
|
||||
Instrument.enter["com/sun/midp/ssl/Out.write.(I)V"] = function(caller, callee) {
|
||||
var _this = caller.stack.read(3);
|
||||
var connection = _this.class.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
var _this = callee.locals.read(3);
|
||||
var connection = _this.klass.classInfo.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
connection.logBuffer += String.fromCharCode(callee.stack.read(1));
|
||||
};
|
||||
|
||||
Instrument.enter["com/sun/midp/ssl/Out.write.([BII)V"] = function(caller, callee) {
|
||||
var len = caller.stack.read(1), off = caller.stack.read(2), b = caller.stack.read(3), _this = caller.stack.read(4);
|
||||
var connection = _this.class.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
var len = callee.locals.read(1), off = callee.locals.read(2), b = callee.locals.read(3), _this = callee.locals.read(4);
|
||||
var connection = _this.klass.classInfo.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
var range = b.subarray(off, off + len);
|
||||
for (var i = 0; i < range.length; i++) {
|
||||
if (range[i] == 0) {
|
||||
|
@ -168,13 +168,13 @@ Instrument.exit["com/sun/midp/ssl/In.read.()I"] = function(caller, callee) {
|
|||
// stack differs depending on whether or not In.read threw an exception.
|
||||
var _this = caller.stack[2];
|
||||
|
||||
var connection = _this.class.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
var connection = _this.klass.classInfo.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
connection.logBuffer += String.fromCharCode(callee.stack.read(1));
|
||||
};
|
||||
|
||||
Instrument.exit["com/sun/midp/ssl/In.read.([BII)I"] = function(caller, callee) {
|
||||
var len = caller.stack.read(4), off = caller.stack.read(5), b = caller.stack.read(6), _this = caller.stack.read(7);
|
||||
var connection = _this.class.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
var len = callee.locals.read(4), off = callee.locals.read(5), b = callee.locals.read(6), _this = callee.locals.read(7);
|
||||
var connection = _this.klass.classInfo.getField("I.ssc.Lcom/sun/midp/ssl/SSLStreamConnection;").get(_this);
|
||||
var range = b.subarray(off, off + len);
|
||||
for (var i = 0; i < range.length; i++) {
|
||||
if (range[i] == 0) {
|
||||
|
@ -185,7 +185,7 @@ Instrument.exit["com/sun/midp/ssl/In.read.([BII)I"] = function(caller, callee) {
|
|||
};
|
||||
|
||||
Instrument.enter["com/sun/midp/ssl/SSLStreamConnection.close.()V"] = function(caller, callee) {
|
||||
var _this = caller.stack.read(1);
|
||||
var _this = callee.locals.read(1);
|
||||
if ("logBuffer" in _this) {
|
||||
console.log(_this.logBuffer);
|
||||
delete _this.logBuffer;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SRCS=$(shell find ./cldc1.1.1 -name *.java) $(shell find ./vm -name *.java) $(shell find ./midp -name *.java) $(shell find ./jsr-075 -name *.java) $(shell find ./custom -name *.java)
|
||||
JPP_DEFS=-DENABLE_JSR_205 -DENABLE_CHAMELEON -DENABLE_SSL -DENABLE_PUBLICKEYSTORE -DENABLE_JSR_211 -DENABLE_MULTIPLE_ISOLATES -DRECORD -DUSE_FILE_CONNECTION -DENABLE_JSR_234
|
||||
JPP_DEFS=-DENABLE_JSR_205 -DENABLE_SSL -DENABLE_PUBLICKEYSTORE -DENABLE_JSR_211 -DENABLE_MULTIPLE_ISOLATES -DRECORD -DUSE_FILE_CONNECTION -DENABLE_JSR_234
|
||||
JPP_SRCS=$(shell find . -name *.jpp)
|
||||
JPP_DESTS=$(JPP_SRCS:.jpp=.java)
|
||||
EXTRA=$(shell find . -name *.png) $(shell find . -name *.bin) $(shell find . -name *.xml)
|
||||
|
|
Двоичные данные
java/assets/0/alert.image_bg0.png
До Ширина: | Высота: | Размер: 187 B |
Двоичные данные
java/assets/0/alert.image_bg1.png
До Ширина: | Высота: | Размер: 165 B |
Двоичные данные
java/assets/0/alert.image_bg2.png
До Ширина: | Высота: | Размер: 187 B |
Двоичные данные
java/assets/0/alert.image_bg3.png
До Ширина: | Высота: | Размер: 170 B |
Двоичные данные
java/assets/0/alert.image_bg4.png
До Ширина: | Высота: | Размер: 186 B |
Двоичные данные
java/assets/0/alert.image_bg5.png
До Ширина: | Высота: | Размер: 177 B |
Двоичные данные
java/assets/0/alert.image_bg6.png
До Ширина: | Высота: | Размер: 170 B |
Двоичные данные
java/assets/0/alert.image_bg7.png
До Ширина: | Высота: | Размер: 186 B |
Двоичные данные
java/assets/0/alert.image_bg8.png
До Ширина: | Высота: | Размер: 177 B |
Двоичные данные
java/assets/0/alert.image_icon_alrm.png
До Ширина: | Высота: | Размер: 1.9 KiB |
Двоичные данные
java/assets/0/alert.image_icon_cnfm.png
До Ширина: | Высота: | Размер: 1.9 KiB |
Двоичные данные
java/assets/0/alert.image_icon_errr.png
До Ширина: | Высота: | Размер: 1.5 KiB |
Двоичные данные
java/assets/0/alert.image_icon_info.png
До Ширина: | Высота: | Размер: 1.9 KiB |
Двоичные данные
java/assets/0/alert.image_icon_warn.png
До Ширина: | Высота: | Размер: 1.3 KiB |
Двоичные данные
java/assets/0/busycrsr.image_bg.png
До Ширина: | Высота: | Размер: 2.5 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame0.png
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame1.png
До Ширина: | Высота: | Размер: 753 B |
Двоичные данные
java/assets/0/busycrsr.image_frame10.png
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame11.png
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame12.png
До Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame13.png
До Ширина: | Высота: | Размер: 1.9 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame14.png
До Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame15.png
До Ширина: | Высота: | Размер: 1.4 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame16.png
До Ширина: | Высота: | Размер: 1.2 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame2.png
До Ширина: | Высота: | Размер: 996 B |
Двоичные данные
java/assets/0/busycrsr.image_frame3.png
До Ширина: | Высота: | Размер: 1.4 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame4.png
До Ширина: | Высота: | Размер: 1.5 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame5.png
До Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame6.png
До Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame7.png
До Ширина: | Высота: | Размер: 1.9 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame8.png
До Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
java/assets/0/busycrsr.image_frame9.png
До Ширина: | Высота: | Размер: 2.2 KiB |
Двоичные данные
java/assets/0/choice.image_btn_bg0.png
До Ширина: | Высота: | Размер: 255 B |
Двоичные данные
java/assets/0/choice.image_btn_bg1.png
До Ширина: | Высота: | Размер: 171 B |
Двоичные данные
java/assets/0/choice.image_btn_bg2.png
До Ширина: | Высота: | Размер: 219 B |
Двоичные данные
java/assets/0/choice.image_btn_bg3.png
До Ширина: | Высота: | Размер: 161 B |
Двоичные данные
java/assets/0/choice.image_btn_bg4.png
До Ширина: | Высота: | Размер: 150 B |
Двоичные данные
java/assets/0/choice.image_btn_bg5.png
До Ширина: | Высота: | Размер: 160 B |
Двоичные данные
java/assets/0/choice.image_btn_bg6.png
До Ширина: | Высота: | Размер: 254 B |
Двоичные данные
java/assets/0/choice.image_btn_bg7.png
До Ширина: | Высота: | Размер: 173 B |
Двоичные данные
java/assets/0/choice.image_btn_bg8.png
До Ширина: | Высота: | Размер: 219 B |
Двоичные данные
java/assets/0/choice.image_btn_icon.png
До Ширина: | Высота: | Размер: 310 B |
Двоичные данные
java/assets/0/choice.image_chkbx0.png
До Ширина: | Высота: | Размер: 839 B |
Двоичные данные
java/assets/0/choice.image_chkbx1.png
До Ширина: | Высота: | Размер: 913 B |
Двоичные данные
java/assets/0/choice.image_popup_bg0.png
До Ширина: | Высота: | Размер: 167 B |
Двоичные данные
java/assets/0/choice.image_popup_bg1.png
До Ширина: | Высота: | Размер: 160 B |
Двоичные данные
java/assets/0/choice.image_popup_bg2.png
До Ширина: | Высота: | Размер: 211 B |
Двоичные данные
java/assets/0/choice.image_popup_bg3.png
До Ширина: | Высота: | Размер: 160 B |
Двоичные данные
java/assets/0/choice.image_popup_bg4.png
До Ширина: | Высота: | Размер: 156 B |
Двоичные данные
java/assets/0/choice.image_popup_bg5.png
До Ширина: | Высота: | Размер: 174 B |
Двоичные данные
java/assets/0/choice.image_popup_bg6.png
До Ширина: | Высота: | Размер: 169 B |
Двоичные данные
java/assets/0/choice.image_popup_bg7.png
До Ширина: | Высота: | Размер: 160 B |
Двоичные данные
java/assets/0/choice.image_popup_bg8.png
До Ширина: | Высота: | Размер: 203 B |
Двоичные данные
java/assets/0/choice.image_radio0.png
До Ширина: | Высота: | Размер: 925 B |
Двоичные данные
java/assets/0/choice.image_radio1.png
До Ширина: | Высота: | Размер: 897 B |
Двоичные данные
java/assets/0/dateeditor.image_ampm.png
До Ширина: | Высота: | Размер: 667 B |
Двоичные данные
java/assets/0/dateeditor.image_cal_bg.png
До Ширина: | Высота: | Размер: 4.8 KiB |
Двоичные данные
java/assets/0/dateeditor.image_clock_bg.png
До Ширина: | Высота: | Размер: 2.6 KiB |
Двоичные данные
java/assets/0/dateeditor.image_dates.png
До Ширина: | Высота: | Размер: 3.6 KiB |