Merge branch 'master' of github.com:mozilla/j2me.js into fix_asyncImpl

This commit is contained in:
Marco Castelluccio 2015-03-10 02:06:13 +01:00
Родитель da0e835198 19aa2266cd
Коммит aea7991ac8
34 изменённых файлов: 1320 добавлений и 7104 удалений

597
actors.ts
Просмотреть файл

@ -1,597 +0,0 @@
module J2ME {
declare var Native, Override;
declare var missingNativeImpl;
declare var CC;
declare var Signature;
declare var classObjects;
declare var util;
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;
onStackReplacementEntryPoints: number [];
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.isFinal;
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.onStackReplacementEntryPoints = 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);
classInfo.mangledName = mangleClass(classInfo);
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() {
// 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>ctx.runtime.getRuntimeKlass(this.klass);
}
getField(fieldKey: string) : FieldInfo {
return CLASSES.getField(this, fieldKey);
}
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: ClassInfo, mangledName?: string) {
false && super(null);
this.className = className;
// TODO this may need to change for compiled code.
this.mangledName = mangledName || mangleClassName(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: ClassInfo, mangledName: string) {
super(className, elementClass, mangledName);
}
get superClass() {
return CLASSES.java_lang_Object;
}
static Z = new PrimitiveArrayClassInfo("[Z", PrimitiveClassInfo.Z, "Uint8Array");
static C = new PrimitiveArrayClassInfo("[C", PrimitiveClassInfo.C, "Uint16Array");
static F = new PrimitiveArrayClassInfo("[F", PrimitiveClassInfo.F, "Float32Array");
static D = new PrimitiveArrayClassInfo("[D", PrimitiveClassInfo.D, "Float64Array");
static B = new PrimitiveArrayClassInfo("[B", PrimitiveClassInfo.B, "Int8Array");
static S = new PrimitiveArrayClassInfo("[S", PrimitiveClassInfo.S, "Int16Array");
static I = new PrimitiveArrayClassInfo("[I", PrimitiveClassInfo.I, "Int32Array");
static J = new PrimitiveArrayClassInfo("[J", PrimitiveClassInfo.J, "Int64Array");
}
PrimitiveClassInfo.prototype.fields = [];
PrimitiveClassInfo.prototype.methods = [];
PrimitiveClassInfo.prototype.interfaces = [];
}
var FieldInfo = J2ME.FieldInfo;
var MethodInfo = J2ME.MethodInfo;
var ClassInfo = J2ME.ClassInfo;

Просмотреть файл

@ -151,14 +151,40 @@ var Benchmark = (function() {
startup.startTimer();
}
var numRoundsEl;
var roundDelayEl;
var deleteFsEl;
var deleteJitCacheEl;
var startButton;
var baselineButton;
function getSettings() {
return {
numRounds: numRoundsEl.value | 0,
roundDelay: roundDelayEl.value | 0,
deleteFs: !!deleteFsEl.checked,
deleteJitCache: !!deleteJitCacheEl.checked,
};
}
function start() {
startup.run(getSettings());
};
function buildBaseline() {
var settings = getSettings();
settings["buildBaseline"] = true;
startup.run(settings);
}
return {
initUI: function() {
var numRoundsEl = document.getElementById("benchmark-num-rounds");
var roundDelayEl = document.getElementById("benchmark-round-delay");
var deleteFsEl = document.getElementById("benchmark-delete-fs");
var deleteJitCacheEl = document.getElementById("benchmark-delete-jit-cache");
var startButton = document.getElementById("benchmark-startup-run");
var baselineButton = document.getElementById("benchmark-startup-baseline");
numRoundsEl = document.getElementById("benchmark-num-rounds");
roundDelayEl = document.getElementById("benchmark-round-delay");
deleteFsEl = document.getElementById("benchmark-delete-fs");
deleteJitCacheEl = document.getElementById("benchmark-delete-jit-cache");
startButton = document.getElementById("benchmark-startup-run");
baselineButton = document.getElementById("benchmark-startup-baseline");
numRoundsEl.value = storage.numRounds;
roundDelayEl.value = storage.roundDelay;
@ -169,25 +195,11 @@ var Benchmark = (function() {
startButton.disabled = true;
}
function getSettings() {
return {
numRounds: numRoundsEl.value | 0,
roundDelay: roundDelayEl.value | 0,
deleteFs: !!deleteFsEl.checked,
deleteJitCache: !!deleteJitCacheEl.checked,
};
}
startButton.onclick = function() {
startup.run(getSettings());
};
baselineButton.onclick = function() {
var settings = getSettings();
settings["buildBaseline"] = true;
startup.run(settings);
};
startButton.onclick = start;
baselineButton.onclick = buildBaseline;
},
start: start,
buildBaseline: buildBaseline,
startup: {
init: function() {
if (!storage.running) {

Просмотреть файл

@ -39,7 +39,7 @@ module J2ME {
*/
function optimizeMethodBytecode(methodInfo: MethodInfo) {
interpreterCounter && interpreterCounter.count("optimize: " + methodInfo.implKey);
var stream = new BytecodeStream(methodInfo.code);
var stream = new BytecodeStream(methodInfo.codeAttribute.code);
while (stream.currentBC() !== Bytecodes.END) {
if (stream.rawCurrentBC() === Bytecodes.WIDE) {
stream.next();
@ -67,24 +67,12 @@ module J2ME {
methodInfo.isOptimized = true;
}
function resolve(index: number, classInfo: ClassInfo, isStatic: boolean = false): any {
return classInfo.resolve(index, isStatic);
}
function resolveField(index: number, classInfo: ClassInfo, isStatic: boolean): FieldInfo {
return <FieldInfo><any>classInfo.resolve(index, isStatic);
}
function resolveClass(index: number, classInfo: ClassInfo, isStatic: boolean): ClassInfo {
var classInfo: ClassInfo = <any>classInfo.resolve(index, isStatic);
function resolveClass(index: number, classInfo: ClassInfo): ClassInfo {
var classInfo = classInfo.constantPool.resolveClass(index);
linkKlass(classInfo);
return classInfo;
}
function resolveMethod(index: number, classInfo: ClassInfo, isStatic: boolean): MethodInfo {
return <MethodInfo><any>classInfo.resolve(index, isStatic);
}
/**
* Debugging helper to make sure native methods were implemented correctly.
*/
@ -119,7 +107,7 @@ module J2ME {
function buildExceptionLog(ex, stackTrace) {
var className = ex.klass.classInfo.className;
var detailMessage = util.fromJavaString(CLASSES.getField(ex.klass.classInfo, "I.detailMessage.Ljava/lang/String;").get(ex));
var detailMessage = util.fromJavaString(ex.klass.classInfo.getFieldByName("detailMessage", "Ljava/lang/String;", false).get(ex));
return className + ": " + (detailMessage || "") + "\n" + stackTrace.map(function(entry) {
return " - " + entry.className + "." + entry.methodName + entry.methodSignature + ", pc=" + entry.offset;
}).join("\n") + "\n\n";
@ -139,17 +127,18 @@ module J2ME {
var stackTrace = e.stackTrace;
do {
var exception_table = frame.methodInfo.exception_table;
var handler_pc = null;
for (var i = 0; exception_table && i < exception_table.length; i++) {
if (frame.opPC >= exception_table[i].start_pc && frame.opPC < exception_table[i].end_pc) {
if (exception_table[i].catch_type === 0) {
handler_pc = exception_table[i].handler_pc;
for (var i = 0; i < frame.methodInfo.exception_table_length; i++) {
var exceptionEntryView = frame.methodInfo.getExceptionEntryViewByIndex(i);
if (frame.opPC >= exceptionEntryView.start_pc && frame.opPC < exceptionEntryView.end_pc) {
if (exceptionEntryView.catch_type === 0) {
handler_pc = exceptionEntryView.handler_pc;
break;
} else {
classInfo = resolveClass(exception_table[i].catch_type, frame.methodInfo.classInfo, false);
classInfo = resolveClass(exceptionEntryView.catch_type, frame.methodInfo.classInfo);
if (isAssignableTo(e.klass, classInfo.klass)) {
handler_pc = exception_table[i].handler_pc;
handler_pc = exceptionEntryView.handler_pc;
break;
}
}
@ -210,7 +199,7 @@ module J2ME {
var frames = ctx.frames;
var mi = frame.methodInfo;
var ci = mi.classInfo;
var rp = ci.resolved_constant_pool;
var rp = ci.constantPool.resolved;
var stack = frame.stack;
@ -239,17 +228,17 @@ module J2ME {
// We don't want to optimize methods for interpretation if we're going to be using the JIT until
// we teach the Baseline JIT about the new bytecodes.
if (!enableRuntimeCompilation && !frame.methodInfo.isOptimized && frame.methodInfo.bytecodeCount > 100) {
if (!enableRuntimeCompilation && !frame.methodInfo.isOptimized && frame.methodInfo.stats.bytecodeCount > 100) {
optimizeMethodBytecode(frame.methodInfo);
}
mi.interpreterCallCount ++;
mi.stats.interpreterCallCount ++;
interpreterCount ++;
while (true) {
bytecodeCount ++;
mi.bytecodeCount ++;
mi.stats.bytecodeCount ++;
// TODO: Make sure this works even if we JIT everything. At the moment it fails
// for synthetic method frames which have bad max_local counts.
@ -257,13 +246,13 @@ module J2ME {
// Inline heuristics that trigger JIT compilation here.
if (enableRuntimeCompilation &&
mi.state < MethodState.Compiled && // Give up if we're at this state.
mi.backwardsBranchCount + mi.interpreterCallCount > 10) {
mi.stats.backwardsBranchCount + mi.stats.interpreterCallCount > 10) {
compileAndLinkMethod(mi);
}
try {
if (frame.pc < lastPC) {
mi.backwardsBranchCount ++;
mi.stats.backwardsBranchCount ++;
if (enableOnStackReplacement && mi.state === MethodState.Compiled) {
// Just because we've jumped backwards doesn't mean we are at a loop header but it does mean that we are
// at the beggining of a basic block. This is a really cheap test and a convenient place to perform an
@ -296,7 +285,7 @@ module J2ME {
}
mi = frame.methodInfo;
ci = mi.classInfo;
rp = ci.resolved_constant_pool;
rp = ci.constantPool.resolved;
stack = frame.stack;
lastPC = -1;
@ -351,12 +340,12 @@ module J2ME {
case Bytecodes.LDC:
case Bytecodes.LDC_W:
index = (op === Bytecodes.LDC) ? frame.read8() : frame.read16();
constant = resolve(index, ci, false);
constant = ci.constantPool.resolve(index, TAGS.CONSTANT_Any, false);
stack.push(constant);
break;
case Bytecodes.LDC2_W:
index = frame.read16();
constant = resolve(index, ci, false);
constant = ci.constantPool.resolve(index, TAGS.CONSTANT_Any, false);
stack.push2(constant);
break;
case Bytecodes.ILOAD:
@ -945,14 +934,14 @@ module J2ME {
break;
case Bytecodes.ANEWARRAY:
index = frame.read16();
classInfo = resolveClass(index, mi.classInfo, false);
classInfo = resolveClass(index, mi.classInfo);
classInitAndUnwindCheck(classInfo, frame.pc - 3);
size = stack.pop();
stack.push(newArray(classInfo.klass, size));
break;
case Bytecodes.MULTIANEWARRAY:
index = frame.read16();
classInfo = resolveClass(index, mi.classInfo, false);
classInfo = resolveClass(index, mi.classInfo);
var dimensions = frame.read8();
var lengths = new Array(dimensions);
for (var i = 0; i < dimensions; i++)
@ -974,7 +963,7 @@ module J2ME {
break;
case Bytecodes.GETFIELD:
index = frame.read16();
fieldInfo = resolveField(index, mi.classInfo, false);
fieldInfo = mi.classInfo.constantPool.resolveField(index, false);
object = stack.pop();
stack.pushKind(fieldInfo.kind, fieldInfo.get(object));
frame.patch(3, Bytecodes.GETFIELD, Bytecodes.RESOLVED_GETFIELD);
@ -986,7 +975,7 @@ module J2ME {
break;
case Bytecodes.PUTFIELD:
index = frame.read16();
fieldInfo = resolveField(index, mi.classInfo, false);
fieldInfo = mi.classInfo.constantPool.resolveField(index, false);
value = stack.popKind(fieldInfo.kind);
object = stack.pop();
fieldInfo.set(object, value);
@ -1000,7 +989,7 @@ module J2ME {
break;
case Bytecodes.GETSTATIC:
index = frame.read16();
fieldInfo = resolveField(index, mi.classInfo, true);
fieldInfo = mi.classInfo.constantPool.resolveField(index, true);
classInitAndUnwindCheck(fieldInfo.classInfo, frame.pc - 3);
if (U) {
return;
@ -1010,7 +999,7 @@ module J2ME {
break;
case Bytecodes.PUTSTATIC:
index = frame.read16();
fieldInfo = resolveField(index, mi.classInfo, true);
fieldInfo = mi.classInfo.constantPool.resolveField(index, true);
classInitAndUnwindCheck(fieldInfo.classInfo, frame.pc - 3);
if (U) {
return;
@ -1019,7 +1008,7 @@ module J2ME {
break;
case Bytecodes.NEW:
index = frame.read16();
classInfo = resolveClass(index, mi.classInfo, false);
classInfo = resolveClass(index, mi.classInfo);
classInitAndUnwindCheck(classInfo, frame.pc - 3);
if (U) {
return;
@ -1028,7 +1017,7 @@ module J2ME {
break;
case Bytecodes.CHECKCAST:
index = frame.read16();
classInfo = resolveClass(index, mi.classInfo, false);
classInfo = resolveClass(index, mi.classInfo);
object = stack[stack.length - 1];
if (object && !isAssignableTo(object.klass, classInfo.klass)) {
throw $.newClassCastException(
@ -1038,7 +1027,7 @@ module J2ME {
break;
case Bytecodes.INSTANCEOF:
index = frame.read16();
classInfo = resolveClass(index, mi.classInfo, false);
classInfo = resolveClass(index, mi.classInfo);
object = stack.pop();
var result = !object ? false : isAssignableTo(object.klass, classInfo.klass);
stack.push(result ? 1 : 0);
@ -1081,9 +1070,9 @@ module J2ME {
frames.push(calleeFrame);
frame = calleeFrame;
mi = frame.methodInfo;
mi.interpreterCallCount ++;
mi.stats.interpreterCallCount ++;
ci = mi.classInfo;
rp = ci.resolved_constant_pool;
rp = ci.constantPool.resolved;
stack = frame.stack;
lastPC = -1;
continue;
@ -1141,7 +1130,7 @@ module J2ME {
var isStatic = (op === Bytecodes.INVOKESTATIC);
// Resolve method and do the class init check if necessary.
var calleeMethodInfo = resolveMethod(index, mi.classInfo, isStatic);
var calleeMethodInfo = mi.classInfo.constantPool.resolveMethod(index, isStatic);
// Fast path for some of the most common interpreter call targets.
if (calleeMethodInfo.implKey === "java/lang/Object.<init>.()V") {
@ -1187,9 +1176,9 @@ module J2ME {
frames.push(calleeFrame);
frame = calleeFrame;
mi = frame.methodInfo;
mi.interpreterCallCount ++;
mi.stats.interpreterCallCount ++;
ci = mi.classInfo;
rp = ci.resolved_constant_pool;
rp = ci.constantPool.resolved;
stack = frame.stack;
lastPC = -1;
if (calleeTargetMethodInfo.isSynchronized) {
@ -1280,7 +1269,7 @@ module J2ME {
}
mi = frame.methodInfo;
ci = mi.classInfo;
rp = ci.resolved_constant_pool;
rp = ci.constantPool.resolved;
stack = frame.stack;
lastPC = -1;
if (op === Bytecodes.RETURN) {
@ -1312,7 +1301,7 @@ module J2ME {
assert (!Frame.isMarker(frame));
mi = frame.methodInfo;
ci = mi.classInfo;
rp = ci.resolved_constant_pool;
rp = ci.constantPool.resolved;
stack = frame.stack;
lastPC = -1;
continue;

Просмотреть файл

@ -115,8 +115,18 @@ class Class {
* instantiation fails for some other reason.
* @since JDK1.0
*/
public native Object newInstance()
throws InstantiationException, IllegalAccessException;
public Object newInstance() throws InstantiationException, IllegalAccessException {
Object o = newInstance0();
// newInstance1 can potentially unwind.
newInstance1(o);
return o;
}
// Creates the object without running the constructor.
private native Object newInstance0();
// Runs o's constructor.
private native void newInstance1(Object o);
/**
* Determines if the specified <code>Object</code> is assignment-compatible

Просмотреть файл

@ -76,4 +76,15 @@ public final class Sys {
* escape hatch for the purpose of testing and profiling.
*/
public native static void eval(String src);
public static void throwException(Exception e) throws Exception {
throw e;
}
public static void runThread(Thread t) {
t.run();
synchronized (t) {
t.notifyAll();
}
}
}

Просмотреть файл

@ -62,10 +62,10 @@ module J2ME {
"com/sun/j2me/pim/PIMProxy.getNextItemDescription0.(I[I)Z": YieldReason.Root,
"java/lang/Object.wait.(J)V": YieldReason.Root,
"java/lang/Class.invoke_clinit.()V": YieldReason.Root,
"java/lang/Class.newInstance.()Ljava/lang/Object;": YieldReason.Root,
"java/lang/Thread.yield.()V": YieldReason.Root,
"java/lang/Thread.start0.()V": YieldReason.Root,
"java/lang/Class.forName0.(Ljava/lang/String;)V": YieldReason.Root,
"java/lang/Class.newInstance1.(Ljava/lang/Object;)V": YieldReason.Root,
// Test Files:
"gnu/testlet/vm/NativeTest.throwExceptionAfterPause.()V": YieldReason.Root,
"gnu/testlet/vm/NativeTest.returnAfterPause.()I": YieldReason.Root,
@ -77,7 +77,7 @@ module J2ME {
// These can technically yield but are worth the risk.
// XXX Determine the current status of this item.
// "java/lang/Object.equals.(Ljava/lang/Object;)Z": YieldReason.None
}
};
export function isFinalClass(classInfo: ClassInfo): boolean {
var result = classInfo.isFinal;
@ -98,7 +98,7 @@ module J2ME {
var allSubClasses = classInfo.allSubClasses;
result = true;
for (var i = 0; i < allSubClasses.length; i++) {
var subClassMethods = allSubClasses[i].methods;
var subClassMethods = allSubClasses[i].getMethods();
for (var j = 0; j < subClassMethods.length; j++) {
var subClassMethodInfo = subClassMethods[j];
if (methodInfo.name === subClassMethodInfo.name &&
@ -114,7 +114,7 @@ module J2ME {
}
export function gatherCallees(callees: MethodInfo [], classInfo: ClassInfo, methodInfo: MethodInfo) {
var methods = classInfo.methods;
var methods = classInfo.getMethods();
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
@ -225,25 +225,28 @@ module J2ME {
yieldWriter && yieldWriter.leave("< " + methodInfo.implKey + " " + YieldReason[YieldReason.Cycle]);
return YieldReason.Cycle;
}
if (!methodInfo.code) {
if (!methodInfo.codeAttribute) {
assert (methodInfo.isNative || methodInfo.isAbstract);
yieldWriter && yieldWriter.leave("< " + methodInfo.implKey + " Abstract");
return yieldMap[methodInfo.implKey] = YieldReason.None;
}
checkingForCanYield[methodInfo.implKey] = true;
var constantPool = methodInfo.classInfo.constantPool;
try {
var result = YieldReason.None;
var stream = new BytecodeStream(methodInfo.code);
var stream = new BytecodeStream(methodInfo.codeAttribute.code);
stream.setBCI(0);
while (stream.currentBCI < methodInfo.code.length) {
while (stream.currentBCI < methodInfo.codeAttribute.code.length) {
var op: Bytecodes = stream.currentBC();
switch (op) {
case Bytecodes.NEW:
var classInfo = constantPool.resolveClass(stream.readCPI());
result = canStaticInitializerYield(classInfo);
break;
case Bytecodes.GETSTATIC:
case Bytecodes.PUTSTATIC:
var cpi = stream.readCPI();
var fieldInfo = methodInfo.classInfo.resolve(cpi, true);
var fieldInfo = constantPool.resolveField(stream.readCPI(), true);
var classInfo = fieldInfo.classInfo;
result = canStaticInitializerYield(classInfo);
break;
@ -262,8 +265,8 @@ module J2ME {
case Bytecodes.RESOLVED_INVOKEVIRTUAL:
case Bytecodes.INVOKESPECIAL:
case Bytecodes.INVOKESTATIC:
var cpi = stream.readCPI()
var callee = methodInfo.classInfo.resolve(cpi, op === Bytecodes.INVOKESTATIC);
var cpi = stream.readCPI();
var callee = constantPool.resolveMethod(cpi, op === Bytecodes.INVOKESTATIC);
if (op !== Bytecodes.INVOKESTATIC) {
if (yieldVirtualMap[methodInfo.implKey] === YieldReason.None) {

Просмотреть файл

@ -88,7 +88,7 @@ module J2ME {
var compileExceptions = true;
var compileSynchronized = true;
if (!compileExceptions && methodInfo.exception_table && methodInfo.exception_table.length) {
if (!compileExceptions && methodInfo.exception_table_length) {
throw new Error("Method: " + methodInfo.implKey + " has exception handlers.");
}
if (!compileSynchronized && methodInfo.isSynchronized) {
@ -217,7 +217,7 @@ module J2ME {
if (classInfo instanceof PrimitiveArrayClassInfo) {
return classInfo.mangledName;
}
if (classInfo.isArrayClass) {
if (classInfo instanceof ArrayClassInfo) {
return "AK(" + classConstant(classInfo.elementClass) + ")";
}
if (classInfo.mangledName) {
@ -329,7 +329,7 @@ module J2ME {
this.parameters = [];
this.referencedClasses = [];
this.initializedClasses = null;
this.hasHandlers = !!methodInfo.exception_table.length;
this.hasHandlers = methodInfo.exception_table_length > 0;
this.hasMonitorEnter = false;
this.blockStackHeightMap = [0];
this.bodyEmitter = new Emitter(!release);
@ -383,7 +383,7 @@ module J2ME {
emitBody() {
var blockMap = this.blockMap;
writer && blockMap.trace(writer);
var stream = new BytecodeStream(this.methodInfo.code);
var stream = new BytecodeStream(this.methodInfo.codeAttribute.code);
var needsTry = this.hasHandlers || this.methodInfo.isSynchronized;
@ -430,9 +430,8 @@ module J2ME {
this.blockStack = [this.getStackName(0)];
this.sp = 1;
if (this.hasHandlers) {
var handlers = this.methodInfo.exception_table;
for (var i = 0; i < handlers.length; i++) {
this.emitExceptionHandler(this.bodyEmitter, handlers[i]);
for (var i = 0; i < this.methodInfo.exception_table_length; i++) {
this.emitExceptionHandler(this.bodyEmitter, this.methodInfo.getExceptionEntryViewByIndex(i));
}
}
if (this.methodInfo.isSynchronized) {
@ -446,7 +445,7 @@ module J2ME {
}
}
private emitExceptionHandler(emitter: Emitter, handler: ExceptionHandler) {
private emitExceptionHandler(emitter: Emitter, handler: ExceptionEntryView) {
var check = "";
if (handler.catch_type > 0) {
var classInfo = this.lookupClass(handler.catch_type);
@ -516,7 +515,7 @@ module J2ME {
parameterLocalIndex += isTwoSlot(kind) ? 2 : 1;
}
var maxLocals = this.methodInfo.max_locals;
var maxLocals = this.methodInfo.codeAttribute.max_locals;
for (var i = 0; i < maxLocals; i++) {
local.push(this.getLocalName(i));
}
@ -527,7 +526,7 @@ module J2ME {
this.bodyEmitter.writeLn(this.getLocal(0) + "=this;");
}
var stack = this.stack;
for (var i = 0; i < this.methodInfo.max_stack; i++) {
for (var i = 0; i < this.methodInfo.codeAttribute.max_stack; i++) {
stack.push(this.getStackName(i));
}
if (stack.length) {
@ -572,7 +571,7 @@ module J2ME {
// Restore locals.
var restoreLocals = [];
for (var i = 0; i < this.methodInfo.max_locals; i++) {
for (var i = 0; i < this.methodInfo.codeAttribute.max_locals; i++) {
restoreLocals.push(this.getLocal(i) + "=_[" + i + "]");
}
this.bodyEmitter.writeLn(restoreLocals.join(",") + ";");
@ -621,19 +620,19 @@ module J2ME {
}
lookupClass(cpi: number): ClassInfo {
var classInfo = this.methodInfo.classInfo.resolve(cpi, false);
var classInfo = this.methodInfo.classInfo.constantPool.resolveClass(cpi);
ArrayUtilities.pushUnique(this.referencedClasses, classInfo);
return classInfo;
}
lookupMethod(cpi: number, opcode: Bytecodes, isStatic: boolean): MethodInfo {
var methodInfo = this.methodInfo.classInfo.resolve(cpi, isStatic);
var methodInfo = this.methodInfo.classInfo.constantPool.resolveMethod(cpi, isStatic);
ArrayUtilities.pushUnique(this.referencedClasses, methodInfo.classInfo);
return methodInfo;
}
lookupField(cpi: number, opcode: Bytecodes, isStatic: boolean): FieldInfo {
var fieldInfo = this.methodInfo.classInfo.resolve(cpi, isStatic);
var fieldInfo = this.methodInfo.classInfo.constantPool.resolveField(cpi, isStatic);
ArrayUtilities.pushUnique(this.referencedClasses, fieldInfo.classInfo);
return fieldInfo;
}
@ -803,8 +802,8 @@ module J2ME {
}
emitClassInitializationCheck(classInfo: ClassInfo) {
while (classInfo.isArrayClass) {
classInfo = classInfo.elementClass;
while (classInfo instanceof ArrayClassInfo) {
classInfo = (<ArrayClassInfo>classInfo).elementClass;
}
if (!CLASSES.isPreInitializedClass(classInfo)) {
if (this.target === CompilationTarget.Runtime && $.initialized[classInfo.className]) {
@ -908,27 +907,28 @@ module J2ME {
}
emitLoadConstant(cpi: number) {
var cp = this.methodInfo.classInfo.constant_pool;
var entry = cp[cpi];
switch (entry.tag) {
var cp = this.methodInfo.classInfo.constantPool;
var tag = cp.getConstantTag(cpi);
switch (tag) {
case TAGS.CONSTANT_Integer:
this.emitPush(Kind.Int, entry.integer, Precedence.Primary);
this.emitPush(Kind.Int, cp.resolve(cpi, tag), Precedence.Primary);
return;
case TAGS.CONSTANT_Float:
this.emitPush(Kind.Float, doubleConstant(entry.float), Precedence.Primary);
this.emitPush(Kind.Float, doubleConstant(cp.resolve(cpi, tag)), Precedence.Primary);
return;
case TAGS.CONSTANT_Double:
this.emitPush(Kind.Double, doubleConstant(entry.double), Precedence.Primary);
this.emitPush(Kind.Double, doubleConstant(cp.resolve(cpi, tag)), Precedence.Primary);
return;
case TAGS.CONSTANT_Long:
this.emitPush(Kind.Long, "Long.fromBits(" + entry.lowBits + "," + entry.highBits + ")", Precedence.Primary);
var long = cp.resolve(cpi, tag);
this.emitPush(Kind.Long, "Long.fromBits(" + long.getLowBits() + "," + long.getHighBits() + ")", Precedence.Primary);
return;
case TAGS.CONSTANT_String:
entry = cp[entry.string_index];
this.emitPush(Kind.Reference, "SC(" + StringUtilities.escapeStringLiteral(entry.bytes) + ")", Precedence.Primary);
this.emitPush(Kind.Reference, "SC(" + StringUtilities.escapeStringLiteral(cp.resolveString(cpi)) + ")", Precedence.Primary);
return;
default:
throw "Not done for: " + entry.tag;
throw "Not done for: " + TAGS[tag];
}
}

Просмотреть файл

@ -79,7 +79,7 @@ module J2ME.Bytecode {
}
export class ExceptionBlock extends Block {
public handler: ExceptionHandler ;
public handler: ExceptionEntryView;
public deoptBci: number;
}
@ -91,16 +91,14 @@ module J2ME.Bytecode {
private blockMap: Block [];
private startBlock: Block;
private canTrap: Uint32ArrayBitSet;
exceptionHandlers: ExceptionHandler [];
constructor(method: MethodInfo) {
this.blocks = [];
this.method = method;
this.hasBackwardBranches = false;
this.invokeCount = 0;
this.blockMap = new Array<Block>(method.code.length);
this.blockMap = new Array<Block>(method.codeAttribute.code.length);
this.canTrap = new Uint32ArrayBitSet(this.blockMap.length);
this.exceptionHandlers = this.method.exception_table;
}
build() {
@ -115,8 +113,8 @@ module J2ME.Bytecode {
private makeExceptionEntries() {
// start basic blocks at all exception handler blocks and mark them as exception entries
for (var i = 0; i < this.exceptionHandlers.length; i++) {
var handler = this.exceptionHandlers[i];
for (var i = 0; i < this.method.exception_table_length; i++) {
var handler = this.method.getExceptionEntryViewByIndex(i);
var block = this.makeBlock(handler.handler_pc);
block.isExceptionEntry = true;
}
@ -209,7 +207,7 @@ module J2ME.Bytecode {
// iterate over the bytecodes top to bottom.
// mark the entrypoints of basic blocks and build lists of successors for
// all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret)
var code = this.method.code;
var code = this.method.codeAttribute.code;
var current: Block = null;
var bci = 0;
while (bci < code.length) {
@ -336,13 +334,13 @@ module J2ME.Bytecode {
// catch_type
private handlerIsCatchAll(handler: ExceptionHandler) {
private handlerIsCatchAll(handler: ExceptionEntryView) {
return handler.catch_type === 0;
}
private exceptionDispatch: Map<ExceptionHandler, ExceptionBlock> = new Map<ExceptionHandler, ExceptionBlock>();
private exceptionDispatch: Map<ExceptionEntryView, ExceptionBlock> = new Map<ExceptionEntryView, ExceptionBlock>();
private makeExceptionDispatch(handlers: ExceptionHandler [], index: number, bci: number): Block {
private makeExceptionDispatch(handlers: ExceptionEntryView [], index: number, bci: number): Block {
var handler = handlers[index];
if (this.handlerIsCatchAll(handler)) {
return this.blockMap[handler.handler_pc];
@ -367,9 +365,9 @@ module J2ME.Bytecode {
var length = this.canTrap.length;
for (var bci = this.canTrap.nextSetBit(0, length); bci >= 0; bci = this.canTrap.nextSetBit(bci + 1, length)) {
var block = this.blockMap[bci];
var handlers: ExceptionHandler [] = null;
for (var i = 0; i < this.exceptionHandlers.length; i++) {
var handler = this.exceptionHandlers[i];
var handlers: ExceptionEntryView [] = null;
for (var i = 0; i < this.method.exception_table_length; i++) {
var handler = this.method.getExceptionEntryViewByIndex(i);
if (handler.start_pc <= bci && bci < handler.end_pc) {
if (!handlers) {
handlers = [];
@ -512,7 +510,7 @@ module J2ME.Bytecode {
}
public trace(writer: IndentingWriter, traceBytecode: boolean = false) {
var code = this.method.code;
var code = this.method.codeAttribute.code;
var stream = new BytecodeStream(code);
writer.enter("Block Map: " + this.blocks.map(b => b.blockID).join(", "));

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,616 +0,0 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Like most JITs we don't need all the fancy AST serialization, this
* is a quick and dirty AST writer.
*/
module J2ME.C4.AST {
import notImplemented = Debug.notImplemented;
// The top part of this file is copied from escodegen.
var json = false;
var escapeless = false;
var hexadecimal = false;
var renumber = false;
var quotes = "double";
var generateNumberCacheCount = 0;
var generateNumberCache = Object.create(null);
function generateNumber(value) {
var result, point, temp, exponent, pos;
if (value !== value) {
throw new Error('Numeric literal whose value is NaN');
}
if (value < 0 || (value === 0 && 1 / value < 0)) {
throw new Error('Numeric literal whose value is negative');
}
if (value === 1 / 0) {
return json ? 'null' : renumber ? '1e400' : '1e+400';
}
result = generateNumberCache[value];
if (result) {
return result;
}
if (generateNumberCacheCount === 1024) {
generateNumberCache = Object.create(null);
generateNumberCacheCount = 0;
}
result = '' + value;
if (!renumber || result.length < 3) {
generateNumberCache[value] = result;
generateNumberCacheCount ++;
return result;
}
point = result.indexOf('.');
if (!json && result.charAt(0) === '0' && point === 1) {
point = 0;
result = result.slice(1);
}
temp = result;
result = result.replace('e+', 'e');
exponent = 0;
if ((pos = temp.indexOf('e')) > 0) {
exponent = +temp.slice(pos + 1);
temp = temp.slice(0, pos);
}
if (point >= 0) {
exponent -= temp.length - point - 1;
temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
}
pos = 0;
while (temp.charAt(temp.length + pos - 1) === '0') {
--pos;
}
if (pos !== 0) {
exponent -= pos;
temp = temp.slice(0, pos);
}
if (exponent !== 0) {
temp += 'e' + exponent;
}
if ((temp.length < result.length ||
(hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) &&
+temp === value) {
result = temp;
}
generateNumberCache[value] = result;
generateNumberCacheCount ++;
return result;
}
var Precedence = {
Default: 0,
Sequence: 0,
Assignment: 1,
Conditional: 2,
ArrowFunction: 2,
LogicalOR: 3,
LogicalAND: 4,
BitwiseOR: 5,
BitwiseXOR: 6,
BitwiseAND: 7,
Equality: 8,
Relational: 9,
BitwiseSHIFT: 10,
Additive: 11,
Multiplicative: 12,
Unary: 13,
Postfix: 14,
Call: 15,
New: 16,
Member: 17,
Primary: 18
};
var BinaryPrecedence = {
'||': Precedence.LogicalOR,
'&&': Precedence.LogicalAND,
'|': Precedence.BitwiseOR,
'^': Precedence.BitwiseXOR,
'&': Precedence.BitwiseAND,
'==': Precedence.Equality,
'!=': Precedence.Equality,
'===': Precedence.Equality,
'!==': Precedence.Equality,
'is': Precedence.Equality,
'isnt': Precedence.Equality,
'<': Precedence.Relational,
'>': Precedence.Relational,
'<=': Precedence.Relational,
'>=': Precedence.Relational,
'in': Precedence.Relational,
'instanceof': Precedence.Relational,
'<<': Precedence.BitwiseSHIFT,
'>>': Precedence.BitwiseSHIFT,
'>>>': Precedence.BitwiseSHIFT,
'+': Precedence.Additive,
'-': Precedence.Additive,
'*': Precedence.Multiplicative,
'%': Precedence.Multiplicative,
'/': Precedence.Multiplicative
};
function toLiteralSource(value) {
if (value === null) {
return 'null';
}
if (value === undefined) {
return 'undefined';
}
if (typeof value === 'string') {
return escapeString(value);
}
if (typeof value === 'number') {
return generateNumber(value);
}
if (typeof value === 'boolean') {
return value ? 'true' : 'false';
}
notImplemented(value);
}
function nodesToSource(nodes: Node [], precedence: number, separator?: string) {
var result = "";
for (var i = 0; i < nodes.length; i++) {
result += nodes[i].toSource(precedence);
if (separator && (i < nodes.length - 1)) {
result += separator;
}
}
return result;
}
function alwaysParenthesize(text: string) {
return '(' + text + ')';
}
function parenthesize(text: string, current: number, should: number) {
if (current < should) {
return '(' + text + ')';
}
return text;
}
export class Node {
type: string;
toSource(precedence: number) : string {
notImplemented(this.type);
return "";
}
}
export class Statement extends Node {
}
export class Expression extends Node {
}
export class Program extends Node {
constructor (public body: Node []) {
super();
}
}
export class EmptyStatement extends Statement {
}
export class BlockStatement extends Statement {
end: IR.Node;
constructor (public body: Statement []) {
super();
}
toSource(precedence: number) : string {
return "{" + nodesToSource(this.body, precedence, "\n") + "}";
}
}
export class ExpressionStatement extends Statement {
constructor (public expression: Expression) {
super();
}
toSource(precedence: number) : string {
return this.expression.toSource(Precedence.Sequence) + ";";
}
}
export class IfStatement extends Statement {
constructor (public test: Expression, public consequent: Statement, public alternate?: Statement) {
super();
}
toSource(precedence: number) : string {
var result = "if(" + this.test.toSource(Precedence.Sequence) + "){" + this.consequent.toSource(Precedence.Sequence) + "}";
if (this.alternate) {
result += "else{" + this.alternate.toSource(Precedence.Sequence) + "}";
}
return result;
}
}
export class LabeledStatement extends Statement {
constructor (public label: Identifier, public body: Statement) {
super();
}
}
export class BreakStatement extends Statement {
constructor (public label: Identifier) {
super();
}
toSource(precedence: number) : string {
var result = "break";
if (this.label) {
result += " " + this.label.toSource(Precedence.Default);
}
return result + ";";
}
}
export class ContinueStatement extends Statement {
constructor (public label: Identifier) {
super();
}
toSource(precedence: number) : string {
var result = "continue";
if (this.label) {
result += " " + this.label.toSource(Precedence.Default);
}
return result + ";";
}
}
export class WithStatement extends Statement {
constructor (public object: Expression, public body: Statement) {
super();
}
}
export class SwitchStatement extends Statement {
constructor (public discriminant: Expression, public cases: SwitchCase [], public lexical: boolean) {
super();
}
toSource(precedence: number) : string {
return "switch(" + this.discriminant.toSource(Precedence.Sequence) + "){" + nodesToSource(this.cases, Precedence.Default, ";") + "};";
}
}
export class ReturnStatement extends Statement {
constructor (public argument: Expression) {
super();
}
toSource(precedence: number) : string {
var result = "return";
if (this.argument) {
result += " " + this.argument.toSource(Precedence.Sequence);
}
return result + ";";
}
}
export class ThrowStatement extends Statement {
constructor (public argument: Expression) {
super();
}
toSource(precedence: number) : string {
return "throw " + this.argument.toSource(Precedence.Sequence) + ";\n";
}
}
export class TryStatement extends Statement {
constructor (public block: BlockStatement, public handlers: CatchClause, public guardedHandlers: CatchClause [], public finalizer: BlockStatement) {
super();
}
toSource(precedence: number) : string {
if (this.guardedHandlers.length !== 0 || this.finalizer !== null) {
throw "TODO";
}
return "try " + this.block.toSource(Precedence.Sequence) + " catch(" + this.handlers.param.toSource(Precedence.Sequence) + ") " + this.handlers.body.toSource(Precedence.Sequence);
}
}
export class WhileStatement extends Statement {
constructor (public test: Expression, public body: Statement) {
super();
}
toSource(precedence: number) : string {
return "while(" + this.test.toSource(Precedence.Sequence) + "){" + this.body.toSource(Precedence.Sequence) + "}";
}
}
export class DoWhileStatement extends Statement {
constructor (public body: Statement, public test: Expression) {
super();
}
}
export class ForStatement extends Statement {
constructor (public init: Node, public test: Expression, public update: Expression, public body: Statement) {
super();
}
}
export class ForInStatement extends Statement {
constructor (public left: Node, public right: Expression, public body: Statement, public each: boolean) {
super();
}
}
export class DebuggerStatement extends Statement {
}
export class Declaration extends Statement {
}
export class FunctionDeclaration extends Declaration {
constructor (public id: Identifier, public params: Node[], public defaults: Expression[], public rest: Identifier, public body: BlockStatement, public generator: boolean, public expression: boolean) {
super();
}
}
export class VariableDeclaration extends Declaration {
constructor (public declarations: VariableDeclarator[], public kind: string) {
super();
}
toSource(precedence: number) : string {
return this.kind + " " + nodesToSource(this.declarations, precedence, ",") + ";\n";
}
}
export class VariableDeclarator extends Node {
constructor (public id: Node, public init?: Node) {
super();
}
toSource(precedence: number) : string {
var result = this.id.toSource(Precedence.Assignment);
if (this.init) {
result += "=" + this.init.toSource(Precedence.Assignment);
}
return result;
}
}
export class Identifier extends Expression {
constructor (public name: string) {
super();
}
toSource(precedence: number) : string {
return this.name;
}
}
export class Literal extends Expression {
constructor (public value: any) {
super();
}
toSource(precedence: number) : string {
return toLiteralSource(this.value);
}
}
export class ThisExpression extends Expression {
toSource(precedence: number) : string {
return "this";
}
}
export class ArrayExpression extends Expression {
constructor (public elements: Expression []) {
super();
}
toSource(precedence: number) : string {
return "[" + nodesToSource(this.elements, Precedence.Assignment, ",") + "]";
}
}
export class ObjectExpression extends Expression {
constructor (public properties: Property []) {
super();
}
toSource(precedence: number) : string {
return "{" + nodesToSource(this.properties, Precedence.Sequence, ",") + "}";
}
}
export class FunctionExpression extends Expression {
constructor (public id: Identifier, public params: Node[], public defaults: Expression [], public rest: Identifier, public body: BlockStatement, public generator: boolean, public expression: boolean) {
super();
}
}
export class SequenceExpression extends Expression {
constructor (public expressions: Expression []) {
super();
}
toSource(precedence: number) : string {
return "(" + this.expressions.map(x => x.toSource(precedence)).join(", ") + ")";
}
}
export class UnaryExpression extends Expression {
constructor (public operator: string, public prefix: boolean, public argument: Expression) {
super();
}
toSource(precedence: number) : string {
var argument = this.argument.toSource(Precedence.Unary);
var result = this.prefix ? this.operator + argument : argument + this.operator;
result = " " + result;
result = parenthesize(result, Precedence.Unary, precedence);
return result;
}
}
export class BinaryExpression extends Expression {
constructor (public operator: string, public left: Expression, public right: Expression) {
super();
}
toSource(precedence: number) : string {
var currentPrecedence = BinaryPrecedence[this.operator];
var result = this.left.toSource(currentPrecedence) + " " + this.operator + " " + this.right.toSource(currentPrecedence + 1);
return parenthesize(result, currentPrecedence, precedence);
}
}
export class AssignmentExpression extends Expression {
constructor (public operator: string, public left: Expression, public right: Expression) {
super();
}
toSource(precedence: number) : string {
var result = this.left.toSource(Precedence.Assignment) + this.operator + this.right.toSource(Precedence.Assignment);
return parenthesize(result, Precedence.Assignment, precedence);
}
}
export class UpdateExpression extends Expression {
constructor (public operator: string, public argument: Expression, public prefix: boolean) {
super();
}
}
export class LogicalExpression extends BinaryExpression {
constructor (operator: string, left: Expression, right: Expression) {
super(operator, left, right);
}
}
export class ConditionalExpression extends Expression {
constructor (public test: Expression, public consequent: Expression, public alternate: Expression) {
super();
}
toSource(precedence: number) : string {
return this.test.toSource(Precedence.LogicalOR) + "?" + this.consequent.toSource(Precedence.Assignment) + ":" + this.alternate.toSource(Precedence.Assignment);
}
}
export class NewExpression extends Expression {
arguments: Expression [];
constructor (public callee: Expression, _arguments: Expression []) {
super();
this.arguments = _arguments;
}
toSource(precedence: number) : string {
return "new " + this.callee.toSource(precedence) + "(" + nodesToSource(this.arguments, precedence, ",") + ")";
}
}
export class CallExpression extends Expression {
arguments: Expression [];
constructor (public callee: Expression, _arguments: Expression []) {
super();
this.arguments = _arguments;
}
toSource(precedence: number) : string {
return this.callee.toSource(precedence) + "(" + nodesToSource(this.arguments, precedence, ",") + ")";
}
}
export class MemberExpression extends Expression {
constructor (public object: Expression, public property: Node, public computed: boolean) {
super();
}
toSource(precedence: number) : string {
var result = this.object.toSource(Precedence.Call);
if (this.object instanceof Literal) {
result = alwaysParenthesize(result);
}
var property = this.property.toSource(Precedence.Sequence);
if (this.computed) {
result += "[" + property + "]";
} else {
result += "." + property;
}
return parenthesize(result, Precedence.Member, precedence);
}
}
export class Property extends Node {
constructor (public key: Node, public value: Expression, public kind: string) {
super();
}
toSource(precedence: number) : string {
return this.key.toSource(precedence) + ":" + this.value.toSource(precedence);
}
}
export class SwitchCase extends Node {
constructor (public test: Expression, public consequent: Statement []) {
super();
}
toSource(precedence: number) : string {
var result = this.test ? "case " + this.test.toSource(precedence) : "default";
return result + ": " + nodesToSource(this.consequent, precedence, ";");
}
}
export class CatchClause extends Node {
constructor (public param: Node, public guard: Expression, public body: BlockStatement) {
super();
}
}
Node.prototype.type = "Node";
Program.prototype.type = "Program";
Statement.prototype.type = "Statement";
EmptyStatement.prototype.type = "EmptyStatement";
BlockStatement.prototype.type = "BlockStatement";
ExpressionStatement.prototype.type = "ExpressionStatement";
IfStatement.prototype.type = "IfStatement";
LabeledStatement.prototype.type = "LabeledStatement";
BreakStatement.prototype.type = "BreakStatement";
ContinueStatement.prototype.type = "ContinueStatement";
WithStatement.prototype.type = "WithStatement";
SwitchStatement.prototype.type = "SwitchStatement";
ReturnStatement.prototype.type = "ReturnStatement";
ThrowStatement.prototype.type = "ThrowStatement";
TryStatement.prototype.type = "TryStatement";
WhileStatement.prototype.type = "WhileStatement";
DoWhileStatement.prototype.type = "DoWhileStatement";
ForStatement.prototype.type = "ForStatement";
ForInStatement.prototype.type = "ForInStatement";
DebuggerStatement.prototype.type = "DebuggerStatement";
Declaration.prototype.type = "Declaration";
FunctionDeclaration.prototype.type = "FunctionDeclaration";
VariableDeclaration.prototype.type = "VariableDeclaration";
VariableDeclarator.prototype.type = "VariableDeclarator";
Expression.prototype.type = "Expression";
Identifier.prototype.type = "Identifier";
Literal.prototype.type = "Literal";
ThisExpression.prototype.type = "ThisExpression";
ArrayExpression.prototype.type = "ArrayExpression";
ObjectExpression.prototype.type = "ObjectExpression";
FunctionExpression.prototype.type = "FunctionExpression";
SequenceExpression.prototype.type = "SequenceExpression";
UnaryExpression.prototype.type = "UnaryExpression";
BinaryExpression.prototype.type = "BinaryExpression";
AssignmentExpression.prototype.type = "AssignmentExpression";
UpdateExpression.prototype.type = "UpdateExpression";
LogicalExpression.prototype.type = "LogicalExpression";
ConditionalExpression.prototype.type = "ConditionalExpression";
NewExpression.prototype.type = "NewExpression";
CallExpression.prototype.type = "CallExpression";
MemberExpression.prototype.type = "MemberExpression";
Property.prototype.type = "Property";
SwitchCase.prototype.type = "SwitchCase";
CatchClause.prototype.type = "CatchClause";
}

Просмотреть файл

@ -1,628 +0,0 @@
/*
* Copyright 2013 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module J2ME.C4.Backend {
import assert = Debug.assert;
import unexpected = Debug.unexpected;
import notImplemented = Debug.notImplemented;
import pushUnique = ArrayUtilities.pushUnique;
import Literal = AST.Literal;
import Identifier = AST.Identifier;
import VariableDeclaration = AST.VariableDeclaration;
import VariableDeclarator = AST.VariableDeclarator;
import MemberExpression = AST.MemberExpression;
import BinaryExpression = AST.BinaryExpression;
import CallExpression = AST.CallExpression;
import AssignmentExpression = AST.AssignmentExpression;
import ExpressionStatement = AST.ExpressionStatement;
import ReturnStatement = AST.ReturnStatement;
import FunctionDeclaration = AST.FunctionDeclaration;
import ConditionalExpression = AST.ConditionalExpression;
import ObjectExpression = AST.ObjectExpression;
import ArrayExpression = AST.ArrayExpression;
import UnaryExpression = AST.UnaryExpression;
import NewExpression = AST.NewExpression;
import Property = AST.Property;
import BlockStatement = AST.BlockStatement;
import ThisExpression = AST.ThisExpression;
import ThrowStatement = AST.ThrowStatement;
import IfStatement = AST.IfStatement;
import WhileStatement = AST.WhileStatement;
import BreakStatement = AST.BreakStatement;
import ContinueStatement = AST.ContinueStatement;
import SwitchStatement = AST.SwitchStatement;
import SwitchCase = AST.SwitchCase;
import Start = IR.Start;
import Block = IR.Block;
import Variable = IR.Variable;
import Constant = IR.Constant;
import Operator = IR.Operator;
import Projection = IR.Projection;
var Control = Looper.Control;
import ControlNode = Looper.Control.ControlNode;
import last = ArrayUtilities.last;
Control.Break.prototype.compile = function (cx: Context): AST.Node {
return cx.compileBreak(this);
};
Control.Continue.prototype.compile = function (cx: Context): AST.Node {
return cx.compileContinue(this);
};
Control.Exit.prototype.compile = function (cx: Context): AST.Node {
return cx.compileExit(this);
};
Control.LabelSwitch.prototype.compile = function (cx: Context): AST.Node {
return cx.compileLabelSwitch(this);
};
Control.Seq.prototype.compile = function (cx: Context): AST.Node {
return cx.compileSequence(this);
};
Control.Loop.prototype.compile = function (cx: Context): AST.Node {
return cx.compileLoop(this);
};
Control.Switch.prototype.compile = function (cx: Context): AST.Node {
return cx.compileSwitch(this);
};
Control.If.prototype.compile = function (cx: Context): AST.Node {
return cx.compileIf(this);
};
Control.Try.prototype.compile = function (cx: Context): AST.Node {
notImplemented("try");
return null;
};
var F = new Identifier("$F");
var C = new Identifier("$C");
function isLazyConstant(value) {
return false;
}
export function constant(value, cx?: Context): AST.Node {
if (typeof value === "string" || value === null || value === true || value === false) {
return new Literal(value);
} else if (value === undefined) {
return new Identifier("undefined");
} else if (typeof value === "object" || typeof value === "function") {
if (isLazyConstant(value)) {
return call(property(F, "C"), [new Literal(cx.useConstant(value))]);
} else {
return new MemberExpression(C, new Literal(cx.useConstant(value)), true);
}
} else if (typeof value === "number" && isNaN(value)) {
return new Identifier("NaN");
} else if (value === Infinity) {
return new Identifier("Infinity");
} else if (value === -Infinity) {
return new UnaryExpression("-", true, new Identifier("Infinity"));
} else if (typeof value === "number" && (1 / value) < 0) {
return new UnaryExpression("-", true, new Literal(Math.abs(value)));
} else if (typeof value === "number") {
return new Literal(value);
} else {
unexpected("Cannot emit constant for value: " + value);
}
}
export function id(name) {
release || assert (typeof name === "string");
return new Identifier(name);
}
export function property(obj, ...args) {
for (var i = 0; i < args.length; i++) {
var x = args[i];
if (typeof x === "string") {
if (isIdentifierName(x)) {
obj = new MemberExpression(obj, new Identifier(x), false);
} else {
obj = new MemberExpression(obj, new Literal(x), true);
}
} else if (x instanceof Literal && isIdentifierName(x.value)) {
obj = new MemberExpression(obj, new Identifier(x.value), false);
} else {
obj = new MemberExpression(obj, x, true);
}
}
return obj;
}
export function call(callee, args): CallExpression {
release || assert(args instanceof Array);
release || args.forEach(function (x) {
release || assert(!(x instanceof Array));
release || assert(x !== undefined);
});
return new CallExpression(callee, args);
}
function callAsCall(callee, object, args) {
return call(property(callee, "asCall"), [object].concat(args));
}
export function callCall(callee, object, args) {
return call(property(callee, "call"), [object].concat(args));
}
export function assignment(left, right) {
release || assert(left && right);
return new AssignmentExpression("=", left, right);
}
function variableDeclaration(declarations) {
return new VariableDeclaration(declarations, "var");
}
function negate(node) {
if (node instanceof Constant) {
if (node.value === true || node.value === false) {
return constant(!node.value);
}
} else if (node instanceof Identifier) {
return new UnaryExpression(Operator.FALSE.name, true, node);
}
release || assert(node instanceof BinaryExpression || node instanceof UnaryExpression, node);
var left = node instanceof BinaryExpression ? node.left : node.argument;
var right = node.right;
var operator = Operator.fromName(node.operator);
if (operator === Operator.EQ && right instanceof Literal && right.value === false) {
return left;
}
if (operator === Operator.FALSE) {
return left;
}
if (operator.not) {
if (node instanceof BinaryExpression) {
return new BinaryExpression(operator.not.name, left, right);
} else {
return new UnaryExpression(operator.not.name, true, left);
}
}
return new UnaryExpression(Operator.FALSE.name, true, node);
}
export class Context {
label = new Variable("$L");
variables = [];
constants = [];
parameters = [];
useConstant(constant: IR.Constant): number {
return pushUnique(this.constants, constant);
}
useVariable(variable: IR.Variable) {
release || assert (variable);
return pushUnique(this.variables, variable);
}
useParameter(parameter: IR.Parameter) {
return this.parameters[parameter.index] = parameter;
}
compileLabelBody(node) {
var body = [];
if (node.label !== undefined) {
this.useVariable(this.label);
body.push(new ExpressionStatement(assignment(id(this.label.name), new Literal(node.label))));
}
return body;
}
compileBreak(node) {
var body = this.compileLabelBody(node);
body.push(new BreakStatement(null));
return new BlockStatement(body);
}
compileContinue(node) {
var body = this.compileLabelBody(node);
body.push(new ContinueStatement(null));
return new BlockStatement(body);
}
compileExit(node) {
return new BlockStatement(this.compileLabelBody(node));
}
compileIf(node) {
var cr = node.cond.compile(this);
var tr = null, er = null;
if (node.then) {
tr = node.then.compile(this);
}
if (node.else) {
er = node.else.compile(this);
}
var condition = compileValue(cr.end.predicate, this);
condition = node.negated ? negate(condition) : condition;
cr.body.push(new IfStatement(condition, tr || new BlockStatement([]), er || null));
return cr;
}
compileSwitch(node) {
var dr = node.determinant.compile(this);
var cases = [];
node.cases.forEach(function (x) {
var br;
if (x.body) {
br = x.body.compile(this);
}
var test = typeof x.index === "number" ? new Literal(x.index) : undefined;
cases.push(new SwitchCase(test, br ? [br] : []));
}, this);
var determinant = compileValue(dr.end.determinant, this);
dr.body.push(new SwitchStatement(determinant, cases, false))
return dr;
}
compileLabelSwitch(node) {
var statement = null;
var labelName = id(this.label.name);
function compileLabelTest(labelID) {
release || assert(typeof labelID === "number");
return new BinaryExpression("===", labelName, new Literal(labelID));
}
for (var i = node.cases.length - 1; i >= 0; i--) {
var c = node.cases[i];
var labels = c.labels;
var labelTest = compileLabelTest(labels[0]);
for (var j = 1; j < labels.length; j++) {
labelTest = new BinaryExpression("||", labelTest, compileLabelTest(labels[j]));
}
statement = new IfStatement(
labelTest,
c.body ? c.body.compile(this) : new BlockStatement([]),
statement);
}
return statement;
}
compileLoop(node) {
var br = node.body.compile(this);
return new WhileStatement(constant(true), br);
}
compileSequence(node) {
var cx = this;
var body = [];
node.body.forEach(function (x) {
var result = x.compile(cx);
if (result instanceof BlockStatement) {
body = body.concat(result.body);
} else {
body.push(result);
}
});
return new BlockStatement(body);
}
compileBlock(block) {
var body = [];
/*
for (var i = 1; i < block.nodes.length - 1; i++) {
print("Block[" + i + "]: " + block.nodes[i]);
}
*/
for (var i = 1; i < block.nodes.length - 1; i++) {
var node = block.nodes[i];
var statement;
var to;
var from;
if (node instanceof IR.Throw) {
statement = compileValue(node, this, true);
} else {
if (node instanceof IR.Move) {
to = id(node.to.name);
this.useVariable(node.to);
from = compileValue(node.from, this);
} else {
from = compileValue(node, this, true);
if (from instanceof AST.Statement) {
body.push(from);
continue;
} else {
if (node.variable) {
to = id(node.variable.name);
this.useVariable(node.variable);
} else {
to = null;
}
}
}
if (to) {
statement = new ExpressionStatement(assignment(to, from));
} else {
statement = new ExpressionStatement(from);
}
}
body.push(statement);
}
var end = last(block.nodes);
if (end instanceof IR.Stop) {
body.push(new ReturnStatement(compileValue(end.argument, this)));
}
var result = new BlockStatement(body);
result.end = last(block.nodes);
release || assert (result.end instanceof IR.End);
// print("Block: " + block + " -> " + generateSource(result));
return result;
}
}
export function compileValue(value, cx: Context, noVariable?) {
release || assert (value);
release || assert (value.compile, "Implement |compile| for " + value + " (" + value.nodeName + ")");
release || assert (cx instanceof Context);
release || assert (!isArray(value));
if (noVariable || !value.variable) {
var node = value.compile(cx);
return node;
}
release || assert (value.variable, "Value has no variable: " + value);
return id(value.variable.name);
}
function isArray(array) {
return array instanceof Array;
}
export function compileValues(values, cx: Context) {
release || assert (isArray(values));
return values.map(function (value) {
return compileValue(value, cx);
});
}
IR.Parameter.prototype.compile = function (cx: Context): AST.Node {
cx.useParameter(this);
return id(this.name);
};
IR.Constant.prototype.compile = function (cx: Context): AST.Node {
return constant(this.value, cx);
};
IR.Variable.prototype.compile = function (cx: Context): AST.Node {
return id(this.name);
};
IR.Phi.prototype.compile = function (cx: Context): AST.Node {
release || assert (this.variable);
return compileValue(this.variable, cx);
};
IR.Latch.prototype.compile = function (cx: Context): AST.Node {
return new ConditionalExpression (
compileValue(this.condition, cx),
compileValue(this.left, cx),
compileValue(this.right, cx)
);
};
IR.Unary.prototype.compile = function (cx: Context): AST.Node {
var result = new UnaryExpression (
this.operator.name,
true,
compileValue(this.argument, cx)
);
if (this.operator === Operator.INEG) {
return new BinaryExpression("|", result, constant(0));
}
// Float and double don't need conversion.
return result;
};
IR.Copy.prototype.compile = function (cx: Context): AST.Node {
return compileValue(this.argument, cx);
};
IR.Binary.prototype.compile = function (cx: Context): AST.Expression {
var left = compileValue(this.left, cx);
var right = compileValue(this.right, cx);
var result = new BinaryExpression (this.operator.name, left, right);
if (this.operator === Operator.IADD ||
this.operator === Operator.ISUB ||
this.operator === Operator.IMUL ||
this.operator === Operator.IDIV ||
this.operator === Operator.IREM) {
return new BinaryExpression("|", result, constant(0));
} else if (this.operator === Operator.FADD ||
this.operator === Operator.FSUB ||
this.operator === Operator.FMUL ||
this.operator === Operator.FDIV ||
this.operator === Operator.FREM) {
return call(id("Math.fround"), [result]);
} else if (this.operator === Operator.DADD ||
this.operator === Operator.DSUB ||
this.operator === Operator.DMUL ||
this.operator === Operator.DDIV ||
this.operator === Operator.DREM) {
return new UnaryExpression("+", true, result);
}
return result;
};
IR.CallProperty.prototype.compile = function (cx: Context): AST.Node {
var object = compileValue(this.object, cx);
var name = compileValue(this.name, cx);
var callee = property(object, name);
var args = this.args.map(function (arg) {
return compileValue(arg, cx);
});
return call(callee, args);
};
IR.Call.prototype.compile = function (cx: Context): AST.Node {
var args = this.args.map(function (arg) {
return compileValue(arg, cx);
});
var callee = compileValue(this.callee, cx);
var object;
if (this.object) {
object = compileValue(this.object, cx);
} else {
object = new Literal(null);
}
return callCall(callee, object, args);
};
IR.This.prototype.compile = function (cx: Context): AST.Node {
return new ThisExpression();
};
IR.Throw.prototype.compile = function (cx: Context): AST.Node {
var argument = compileValue(this.argument, cx);
return new ThrowStatement(argument);
};
IR.Arguments.prototype.compile = function (cx: Context): AST.Node {
return id("arguments");
};
IR.GlobalProperty.prototype.compile = function (cx: Context): AST.Node {
return id(this.name);
};
IR.GetProperty.prototype.compile = function (cx: Context): AST.Node {
var object = compileValue(this.object, cx);
var name = compileValue(this.name, cx);
return property(object, name);
};
IR.SetProperty.prototype.compile = function (cx: Context): AST.Node {
var object = compileValue(this.object, cx);
var name = compileValue(this.name, cx);
var value = compileValue(this.value, cx);
return assignment(property(object, name), value);
};
IR.Projection.prototype.compile = function (cx: Context): AST.Node {
release || assert (this.type === IR.ProjectionType.CONTEXT);
release || assert (this.argument instanceof Start);
return compileValue(this.argument.scope, cx);
};
IR.NewArray.prototype.compile = function (cx: Context): AST.Node {
return new ArrayExpression(compileValues(this.elements, cx));
};
IR.NewObject.prototype.compile = function (cx: Context): AST.Node {
var properties = this.properties.map(function (property) {
var key = compileValue(property.key, cx);
var value = compileValue(property.value, cx);
return new Property(key, value, "init");
});
return new ObjectExpression(properties);
};
IR.Block.prototype.compile = function (cx: Context): AST.Node {
return cx.compileBlock(this);
};
function generateSource(node) {
return node.toSource();
}
export class Compilation {
static id: number = 0;
constructor(public parameters: string [],
public body: string,
public constants: any []) {
// ...
}
/**
* Object references are stored on the compilation object in a property called |constants|. Some of
* these constants are |LazyInitializer|s and the backend makes sure to emit a call to a function
* named |C| that resolves them.
*/
public C(index: number) {
var value = this.constants[index];
// TODO: Avoid using |instanceof| here since this can be called quite frequently.
if (value._isLazyInitializer) {
this.constants[index] = value.resolve();
}
return this.constants[index];
}
}
export function generate(cfg): Compilation {
enterTimeline("Looper");
var root = Looper.analyze(cfg);
leaveTimeline();
var writer = new IndentingWriter();
var cx = new Context();
enterTimeline("Construct AST");
var code = <BlockStatement>root.compile(cx);
leaveTimeline();
var parameters = [];
for (var i = 0; i < cx.parameters.length; i++) {
// Closure Compiler complains if the parameter names are the same even if they are not used,
// so we differentiate them here.
var name = cx.parameters[i] ? cx.parameters[i].name : "_" + i;
parameters.push(id(name));
}
var compilationId = Compilation.id ++;
var compilationGlobalPropertyName = "$$F" + compilationId;
if (cx.constants.length) {
var compilation = new Identifier(compilationGlobalPropertyName);
var constants = new MemberExpression(compilation, new Identifier("constants"), false);
code.body.unshift(variableDeclaration([
new VariableDeclarator(id("$F"), compilation),
new VariableDeclarator(id("$C"), constants)
]));
}
if (cx.variables.length) {
countTimeline("Backend: Locals", cx.variables.length);
var variables = variableDeclaration(cx.variables.map(function (variable) {
return new VariableDeclarator(id(variable.name));
}));
code.body.unshift(variables);
}
enterTimeline("Serialize AST");
var source = generateSource(code);
leaveTimeline();
// Save compilation as a globa property name.
return jsGlobal[compilationGlobalPropertyName] = new Compilation (
parameters.map(function (p) { return p.name; }),
source,
cx.constants
);
}
}

Просмотреть файл

@ -1,691 +0,0 @@
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* SSA-based Sea-of-Nodes IR based on Cliff Click's Work: A simple graph-based intermediate
* representation (http://doi.acm.org/10.1145/202530.202534)
*
* Node Hierarchy:
*
* Node
* - Control
* - Region
* - Start
* - End
* - Stop
* - If
* - Jump
* - Value
* - Constant, Parameter, Phi, Binary, GetProperty ...
*
* Control flow is modeled with control edges rather than with CFGs. Each basic block is represented
* as a region node which has control dependencies on predecessor regions. Nodes that are dependent
* on the execution of a region, have a |control| property assigned to the region they belong to.
*
* Memory (and the external world) is modeled as an SSA value called the Store. Nodes that mutate the
* Store produce a new Store.
*
* Nodes that produce multiple values, such as Ifs which produce two values (a True and False control
* value) can have their values projected (extracted) using Projection nodes.
*
* A node scheduler is responsible for serializing nodes back into a CFG such that all dependencies
* are satisfied.
*
* Compiler Pipeline:
*
* Graph Builder -> IR (DFG) -> Optimizations -> CFG -> Restructuring -> Backend
*
*/
module J2ME.C4.IR {
import assert = Debug.assert;
import unexpected = Debug.unexpected;
import createEmptyObject = ObjectUtilities.createEmptyObject;
// TODO is there a better way to deal with Math.fround
declare var Math: any;
export interface NodeVisitor {
(node: Node): void;
}
export interface BlockVisitor {
(block: Block): void;
}
export function visitArrayInputs(array: Node [], visitor: NodeVisitor, ignoreNull: boolean = false) {
for (var i = 0; i < array.length; i++) {
if (ignoreNull && array[i] === null) {
continue;
}
visitor(array[i]);
}
}
export enum NodeFlags {
None
}
export class Node {
abstract: boolean; // TODO: No idea what this is for.
kind: Kind;
isDeleted: boolean;
private static _nextID: number [] = [];
static getNextID(): number {
return Node._nextID[Node._nextID.length - 1] += 1
}
id: number;
control: Control;
nodeName: string;
variable: Variable;
// TODO: Remove all these.
mustFloat: boolean;
mustNotFloat: boolean;
shouldFloat: boolean;
shouldNotFloat: boolean;
handlesAssignment: boolean;
constructor() {
this.id = Node.getNextID();
}
compile: (cx) => void;
visitInputs(visitor: NodeVisitor) {
}
static startNumbering() {
Node._nextID.push(0);
}
static stopNumbering() {
Node._nextID.pop();
}
toString(brief?: boolean) {
if (brief) {
return nameOf(this);
}
var inputs = [];
this.visitInputs(function (input) {
inputs.push(nameOf(input));
});
var result = nameOf(this) + " = " + this.nodeName.toUpperCase();
if (inputs.length) {
result += " " + inputs.join(", ");
}
return result;
}
visitInputsNoConstants(visitor: NodeVisitor) {
this.visitInputs(function (node) {
if (isConstant(node)) {
return;
}
visitor(node);
});
}
replaceInput(oldInput: Node, newInput: Node) {
var count = 0;
for (var k in this) {
var v = this[k];
if (v instanceof Node) {
if (v === oldInput) {
this[k] = newInput;
count ++;
}
}
if (v instanceof Array) {
count += (<any>v).replace(oldInput, newInput);
}
}
return count;
}
}
Node.prototype.nodeName = "Node";
export class Control extends Node {
block: Block;
constructor() {
super();
}
}
Control.prototype.nodeName = "Control";
export class Region extends Control {
entryState: any;
predecessors: Control [];
constructor(control: Control) {
super();
this.predecessors = control ? [control] : [];
}
visitInputs(visitor: NodeVisitor) {
visitArrayInputs(this.predecessors, visitor);
}
}
Region.prototype.nodeName = "Region";
export class Start extends Region {
constructor() {
super(null);
this.control = this;
}
visitInputs(visitor: NodeVisitor) {
visitArrayInputs(this.predecessors, visitor);
}
}
Start.prototype.nodeName = "Start";
export class End extends Control {
constructor(public control: Control) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
}
}
End.prototype.nodeName = "End";
export class Stop extends End {
constructor(control: Control, public store: Store, public argument: Value) {
super(control);
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
visitor(this.store);
visitor(this.argument);
}
}
Stop.prototype.nodeName = "Stop";
export class If extends End {
constructor(control: Control, public predicate: Value) {
super(control);
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
visitor(this.predicate);
}
}
If.prototype.nodeName = "If";
export class Switch extends End {
constructor(control, public determinant: Value) {
super(control);
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
visitor(this.determinant);
}
}
Switch.prototype.nodeName = "Switch";
export class Jump extends End {
constructor(control) {
super(control);
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
}
}
Jump.prototype.nodeName = "Jump";
export class Value extends Node {
constructor() {
super();
}
}
Value.prototype.nodeName = "Value";
export class Store extends Value {
constructor() {
super();
}
}
Store.prototype.nodeName = "Store";
export class StoreDependent extends Value {
public loads: Node [];
constructor(public control: Control, public store: Store) {
super();
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
}
}
StoreDependent.prototype.nodeName = "StoreDependent";
export class Call extends StoreDependent {
constructor(control: Control, store: Store, public callee: Value, public object: Value, public args: Value []) {
super(control, store);
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
visitor(this.callee);
this.object && visitor(this.object);
visitArrayInputs(this.args, visitor);
}
}
Call.prototype.nodeName = "Call";
export class New extends StoreDependent {
constructor(control: Control, store: Store, public callee: Value, public args: Value []) {
super(control, store);
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
visitor(this.callee);
visitArrayInputs(this.args, visitor);
}
}
New.prototype.nodeName = "New";
export class GetProperty extends StoreDependent {
constructor(control: Control, store: Store, public object: Value, public name: Value) {
super(control, store);
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
visitor(this.object);
visitor(this.name);
}
}
GetProperty.prototype.nodeName = "GetProperty";
export class SetProperty extends StoreDependent {
constructor(control: Control, store: Store, public object: Value, public name: Value, public value: Value) {
super(control, store);
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
visitor(this.object);
visitor(this.name);
visitor(this.value);
}
}
SetProperty.prototype.nodeName = "SetProperty";
export class DeleteProperty extends StoreDependent {
constructor(control, store, public object: Value, public name: Value) {
super(control, store);
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
visitor(this.object);
visitor(this.name);
}
}
DeleteProperty.prototype.nodeName = "DeleteProperty";
export class CallProperty extends StoreDependent {
constructor(control: Control, store: Store, public object: Value, public name: Value, public args: Value []) {
super(control, store);
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
this.store && visitor(this.store);
this.loads && visitArrayInputs(this.loads, visitor);
visitor(this.object);
visitor(this.name);
visitArrayInputs(this.args, visitor);
}
}
CallProperty.prototype.nodeName = "CallProperty";
export class Phi extends Value {
isLoop: boolean;
sealed: boolean;
args: Value [];
constructor(public control: Control, value: Value) {
super();
this.control = control;
this.args = value ? [value] : [];
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
visitArrayInputs(this.args, visitor);
}
seal() {
this.sealed = true;
}
pushValue(x: Value) {
release || assert (!this.sealed);
this.args.push(x);
}
}
Phi.prototype.nodeName = "Phi";
export class Variable extends Value {
constructor(public name: string) {
super();
}
}
Variable.prototype.nodeName = "Variable";
export class Copy extends Value {
constructor(public argument: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.argument);
}
}
Copy.prototype.nodeName = "Copy";
export class Move extends Value {
constructor(public to: Variable, public from: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.to);
visitor(this.from);
}
}
Move.prototype.nodeName = "Move";
export enum ProjectionType {
CASE,
TRUE,
FALSE,
STORE,
CONTEXT
}
export class Projection extends Value {
constructor(public argument: Node, public type: ProjectionType, public selector?: Constant) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.argument);
}
project(): Node {
return this.argument;
}
}
Projection.prototype.nodeName = "Projection";
export class Latch extends Value {
constructor(public control: Control, public condition: Value, public left: Value, public right: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
this.control && visitor(this.control);
visitor(this.condition);
visitor(this.left);
visitor(this.right);
}
}
Latch.prototype.nodeName = "Latch";
export class Operator {
not: Operator;
static byName: Map<string, Operator> = createEmptyObject();
constructor(public name: string, public evaluate: Function, public isBinary: boolean) {
Operator.byName[name] = this;
}
static IADD = new Operator("+", (l, r) => (l + r) | 0, true);
static LADD = new Operator("+", (l, r) => l.add(r), true);
static FADD = new Operator("+", (l, r) => Math.fround(l + r), true);
static DADD = new Operator("+", (l, r) => +(l + r), true);
static ISUB = new Operator("-", (l, r) => (l - r) | 0, true);
static LSUB = new Operator("-", (l, r) => l.subtract(r), true);
static FSUB = new Operator("-", (l, r) => Math.fround(l - r), true);
static DSUB = new Operator("-", (l, r) => +(l - r), true);
static IMUL = new Operator("*", (l, r) => (l * r) | 0, true);
static LMUL = new Operator("*", (l, r) => l.multiply(r), true);
static FMUL = new Operator("*", (l, r) => Math.fround(l * r), true);
static DMUL = new Operator("*", (l, r) => +(l * r), true);
static IDIV = new Operator("/", (l, r) => (l / r) | 0, true);
static LDIV = new Operator("/", (l, r) => l.div(r), true);
static FDIV = new Operator("/", (l, r) => Math.fround(l / r), true);
static DDIV = new Operator("/", (l, r) => +(l / r), true);
static IREM = new Operator("%", (l, r) => (l % r) | 0, true);
static LREM = new Operator("%", (l, r) => l.modulo(r), true);
static FREM = new Operator("%", (l, r) => Math.fround(l % r), true);
static DREM = new Operator("%", (l, r) => +(l % r), true);
static INEG = new Operator("-", (a) => (-a) | 0, false);
static LNEG = new Operator("-", (a) => a.negate(), false);
static FNEG = new Operator("-", (a) => -a, false);
static DNEG = new Operator("-", (a) => -a, false);
// static ADD = new Operator("+", (l, r) => l + r, true);
// static SUB = new Operator("-", (l, r) => l - r, true);
// static MUL = new Operator("*", (l, r) => l * r, true);
// static DIV = new Operator("/", (l, r) => l / r, true);
// static MOD = new Operator("%", (l, r) => l % r, true);
static AND = new Operator("&", (l, r) => l & r, true);
static OR = new Operator("|", (l, r) => l | r, true);
static XOR = new Operator("^", (l, r) => l ^ r, true);
static LSH = new Operator("<<", (l, r) => l << r, true);
static RSH = new Operator(">>", (l, r) => l >> r, true);
static URSH = new Operator(">>>", (l, r) => l >>> r, true);
static SEQ = new Operator("===", (l, r) => l === r, true);
static SNE = new Operator("!==", (l, r) => l !== r, true);
static EQ = new Operator("==", (l, r) => l == r, true);
static NE = new Operator("!=", (l, r) => l != r, true);
static LE = new Operator("<=", (l, r) => l <= r, true);
static GT = new Operator(">", (l, r) => l > r, true);
static LT = new Operator("<", (l, r) => l < r, true);
static GE = new Operator(">=", (l, r) => l >= r, true);
static PLUS = new Operator("+", (a) => +a, false);
static NEG = new Operator("-", (a) => -a, false);
static TRUE = new Operator("!!", (a) => !!a, false);
static FALSE = new Operator("!", (a) => !a, false);
static TYPE_OF = new Operator("typeof", (a) => typeof a, false);
static BITWISE_NOT = new Operator("~", (a) => ~a, false);
static linkOpposites(a: Operator, b: Operator) {
a.not = b;
b.not = a;
}
static fromName(name: string) {
return Operator.byName[name];
}
}
Operator.linkOpposites(Operator.SEQ, Operator.SNE);
Operator.linkOpposites(Operator.EQ, Operator.NE);
Operator.linkOpposites(Operator.TRUE, Operator.FALSE);
export class Binary extends Value {
constructor(public operator: Operator, public left: Value, public right: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.left);
visitor(this.right);
}
}
Binary.prototype.nodeName = "Binary";
export class Unary extends Value {
constructor(public operator: Operator, public argument: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.argument);
}
}
Unary.prototype.nodeName = "Unary";
export class Constant extends Value {
constructor(public value: any) {
super();
}
}
Constant.prototype.nodeName = "Constant";
export class GlobalProperty extends Value {
constructor(public name: string) {
super();
}
}
GlobalProperty.prototype.nodeName = "GlobalProperty";
export class This extends Value {
constructor(public control: Control) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
}
}
This.prototype.nodeName = "This";
export class Throw extends Value {
constructor(public control: Control, public argument: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
visitor(this.argument);
}
}
Throw.prototype.nodeName = "Throw";
export class Arguments extends Value {
constructor(public control: Control) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
}
}
Arguments.prototype.nodeName = "Arguments";
export class Parameter extends Value {
constructor(public control: Control, public index: number, public name: string) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
}
}
Parameter.prototype.nodeName = "Parameter";
export class NewArray extends Value {
constructor(public control: Control, public elements: Value []) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
visitArrayInputs(this.elements, visitor);
}
}
NewArray.prototype.nodeName = "NewArray";
export class NewObject extends Value {
constructor(public control: Control, public properties: KeyValuePair []) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.control);
visitArrayInputs(this.properties, visitor);
}
}
NewObject.prototype.nodeName = "NewObject";
export class KeyValuePair extends Value {
constructor(public key: Value, public value: Value) {
super();
}
visitInputs(visitor: NodeVisitor) {
visitor(this.key);
visitor(this.value);
}
}
KeyValuePair.prototype.mustFloat = true;
KeyValuePair.prototype.nodeName = "KeyValuePair";
export function nameOf(node: any) {
var useColors = false;
var result;
var m = StringUtilities;
if (node instanceof Constant) {
return kindCharacter(node.kind) + node.value;
} else if (node instanceof Variable) {
return node.name;
} else if (node instanceof Parameter) {
return node.name;
} else if (node instanceof Phi) {
return result = m.concat3("|", node.id, "|"), useColors ? m.concat3(IndentingWriter.PURPLE, result, IndentingWriter.ENDC) : result;
} else if (node instanceof Control) {
return result = m.concat3("{", node.id, "}"), useColors ? m.concat3(IndentingWriter.RED, result, IndentingWriter.ENDC) : result;
} else if (node instanceof Projection) {
if (node.type === ProjectionType.STORE) {
return result = m.concat5("[", node.id, "->", node.argument.id, "]"), useColors ? m.concat3(IndentingWriter.YELLOW, result, IndentingWriter.ENDC) : result;
}
return result = m.concat3("(", node.id, ")"), useColors ? m.concat3(IndentingWriter.GREEN, result, IndentingWriter.ENDC) : result;
} else if (node instanceof Value) {
return result = m.concat3("(", node.id, ")"), useColors ? m.concat3(IndentingWriter.GREEN, result, IndentingWriter.ENDC) : result;
} else if (node instanceof Node) {
return node.id;
}
unexpected(node + " " + typeof node);
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -179,8 +179,8 @@ module J2ME {
}
if (emitter.definitions) {
emitFields(classInfo.fields, false);
emitFields(classInfo.fields, true);
emitFields(classInfo.getFields(), false);
emitFields(classInfo.getFields(), true);
return;
}
@ -192,15 +192,15 @@ module J2ME {
// writer.writeLn("this._hashCode = $.nextHashCode(this);");
writer.writeLn("this._hashCode = 0;");
getClassInheritanceChain(classInfo).forEach(function (ci) {
emitFields(ci.fields, false);
emitFields(ci.getFields(), false);
});
writer.leave("}");
// Emit class static initializer if it has any static fields. We don't emit this for now
// since it probably doesn't pay off to emit code that only gets executed once.
if (false && classInfo.fields.some(f => f.isStatic)) {
if (false && classInfo.getFields().some(f => f.isStatic)) {
writer.enter(mangledClassName + ".staticInitializer = function() {");
emitFields(classInfo.fields, true);
emitFields(classInfo.getFields(), true);
writer.leave("}");
}
@ -268,14 +268,14 @@ module J2ME {
emitKlass(emitter, classInfo);
var methods = classInfo.methods;
var methods = classInfo.getMethods();
var compiledMethods: CompiledMethodInfo [] = [];
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (method.isNative) {
continue;
}
if (!method.code) {
if (!method.codeAttribute) {
continue;
}
if (methodFilterList !== null && methodFilterList.indexOf(method.implKey) < 0) {
@ -292,7 +292,7 @@ module J2ME {
try {
var mangledClassAndMethodName = method.mangledClassAndMethodName;
if (emitter.debugInfo) {
writer.writeLn("// " + method.implKey + " (" + mangledClassAndMethodName + ") " + method.getSourceLocationForPC(0));
writer.writeLn("// " + method.implKey + " (" + mangledClassAndMethodName + ")");
}
var compiledMethod = undefined;
try {
@ -412,7 +412,8 @@ module J2ME {
function hasDependencies(list, classInfo) {
var superClass = classInfo.superClass;
if (!superClass && classInfo.interfaces.length === 0) {
var interfaces = classInfo.getAllInterfaces();
if (!superClass && interfaces.length === 0) {
return false;
}
for (var i = 0; i < list.length; i++) {
@ -421,9 +422,9 @@ module J2ME {
}
}
for (var j = 0; j < classInfo.interfaces; j++) {
for (var j = 0; j < interfaces; j++) {
for (var i = 0; i < list.length; i++) {
if (list[i].className === classInfo.interfaces[j].className) {
if (list[i].className === interfaces[j].className) {
return true;
}
}
@ -445,7 +446,7 @@ module J2ME {
var filteredClassInfoList: ClassInfo [] = [];
for (var i = 0; i < orderedClassInfoList.length; i++) {
var classInfo = orderedClassInfoList[i];
var methods = classInfo.methods;
var methods = classInfo.getMethods();
for (var j = 0; j < methods.length; j++) {
var method = methods[j];
if (methodFilterList === null || methodFilterList.indexOf(method.implKey) >= 0) {

2
jsc.ts
Просмотреть файл

@ -84,7 +84,7 @@ module J2ME {
}
}
loadFiles("blackBox.js", "build/j2me-jsc.js", "libs/zipfile.js", "libs/jarstore.js", "libs/encoding.js", "util.js");
loadFiles("libs/long.js", "blackBox.js", "build/j2me-jsc.js", "libs/zipfile.js", "libs/jarstore.js", "libs/encoding.js", "util.js");
phase = ExecutionPhase.Compiler;

Просмотреть файл

@ -95,11 +95,11 @@ var config = {
try {
load("libs/relooper.js", "build/j2me.js","libs/zipfile.js", "blackBox.js",
"libs/encoding.js", "util.js", "libs/jarstore.js",
"override.js", "vm/tags.js", "native.js", "string.js", "tests/override.js",
"midp/midp.js", "midp/gestures.js",
"libs/long.js", "midp/crypto.js", "libs/forge/md5.js", "libs/forge/util.js",
"build/classes.jar.js");
"libs/encoding.js", "util.js", "libs/jarstore.js",
"override.js", "native.js", "string.js", "tests/override.js",
"midp/midp.js", "midp/gestures.js",
"libs/long.js", "midp/crypto.js", "libs/forge/md5.js", "libs/forge/util.js",
"build/classes.jar.js");
// load("build/classes.jar.js");
// load("build/program.jar.js");

Просмотреть файл

@ -137,15 +137,12 @@ var JARStore = (function() {
return null;
}
if (jar.isBuiltIn) {
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
} else {
if (fileName.endsWith(".class")) {
// Classes are loaded just once and then are cached in ClassRegistry::classes
delete jar.directory[fileName];
}
return bytes.buffer;
if (!jar.isBuiltIn && fileName.endsWith(".class")) {
// Classes are loaded just once and then are cached in ClassRegistry::classes
delete jar.directory[fileName];
}
return bytes;
}
function loadFile(fileName) {

Просмотреть файл

@ -38,7 +38,6 @@
<script type="text/javascript" src="libs/relooper.js" defer></script>
<script type="text/javascript" src="build/j2me.js" defer></script>
<script type="text/javascript" src="override.js" defer></script>
<script type="text/javascript" src="vm/tags.js" defer></script>
<script type="text/javascript" src="native.js" defer></script>
<script type="text/javascript" src="string.js" defer></script>
<script type="text/javascript" src="libs/load.js" defer></script>

Просмотреть файл

@ -383,7 +383,7 @@ var currentlyFocusedTextEditor;
if (!defaultFont) {
var classInfo = CLASSES.loadAndLinkClass("javax/microedition/lcdui/Font");
defaultFont = new classInfo.klass();
var methodInfo = CLASSES.getMethod(classInfo, "I.<init>.(III)V");
var methodInfo = classInfo.getMethodByName("<init>", "(III)V", false);
jsGlobal[methodInfo.mangledClassAndMethodName].call(defaultFont, 0, 0, 0);
}
return defaultFont;

Просмотреть файл

@ -58,10 +58,9 @@ var MIDP = (function() {
throw $.newIOException();
}
var length = bytes.byteLength;
var data = new Int8Array(bytes);
var array = J2ME.newByteArray(length);
for (var n = 0; n < length; ++n) {
array[n] = data[n];
array[n] = bytes[n];
}
return array;
};
@ -501,9 +500,8 @@ var MIDP = (function() {
}
var len = data.byteLength;
var bytes = J2ME.newByteArray(len);
var src = new Int8Array(data);
for (var n = 0; n < bytes.byteLength; ++n) {
bytes[n] = src[n];
for (var n = 0; n < len; ++n) {
bytes[n] = data[n];
}
return bytes;
};
@ -1149,15 +1147,16 @@ var MIDP = (function() {
// First build up a mapping of field names to field IDs
var classInfo = CLASSES.getClass("com/sun/midp/i18n/ResourceConstants");
var constantsMap = new Map();
classInfo.fields.forEach(function(field) {
constantsMap.set(field.name, classInfo.constant_pool[field.constantValue].integer);
var fields = classInfo.getFields();
fields.forEach(function(field) {
constantsMap.set(field.name, field.constantValue);
});
var data = JARStore.loadFileFromJAR("java/classes.jar", "assets/0/en-US.xml");
if (!data)
throw $.newIOException();
var text = util.decodeUtf8(data);
var text = util.decodeUtf8Array(data);
var xml = new window.DOMParser().parseFromString(text, "text/xml");
var entries = xml.getElementsByTagName("localized_string");

100
native.js
Просмотреть файл

@ -286,7 +286,7 @@ Native["java/lang/Class.getSuperclass.()Ljava/lang/Class;"] = function() {
Native["java/lang/Class.invoke_clinit.()V"] = function() {
var classInfo = this.runtimeKlass.templateKlass.classInfo;
var className = classInfo.className;
var clinit = CLASSES.getMethod(classInfo, "S.<clinit>.()V");
var clinit = classInfo.getMethodByName("<clinit>", "()V", true);
if (clinit && clinit.classInfo.className === className) {
$.ctx.executeFrames([Frame.create(clinit, [], 0)]);
}
@ -327,42 +327,21 @@ Native["java/lang/Class.forName1.(Ljava/lang/String;)Ljava/lang/Class;"] = funct
return classObject;
};
Native["java/lang/Class.newInstance.()Ljava/lang/Object;"] = function() {
var className = this.runtimeKlass.templateKlass.classInfo.className;
var syntheticMethod = new MethodInfo({
name: "ClassNewInstanceSynthetic",
signature: "()Ljava/lang/Object;",
isStatic: true,
classInfo: J2ME.ClassInfo.createFromObject({
className: {value: className},
vmc: {value: {}},
vfc: {value: {}},
constant_pool: {value: [
null,
{ tag: TAGS.CONSTANT_Class, name_index: 2 },
{ bytes: className },
{ tag: TAGS.CONSTANT_Methodref, class_index: 1, name_and_type_index: 4 },
{ name_index: 5, signature_index: 6 },
{ bytes: "<init>" },
{ bytes: "()V" },
]}
}),
code: new Uint8Array([
0xbb, 0x00, 0x01, // new <idx=1>
0x59, // dup
0xb7, 0x00, 0x03, // invokespecial <idx=3>
0xb0 // areturn
]),
});
return $.ctx.executeFrames([new Frame(syntheticMethod, [], 0)]);
Native["java/lang/Class.newInstance0.()Ljava/lang/Object;"] = function() {
return new this.runtimeKlass.templateKlass;
};
Native["java/lang/Class.newInstance1.(Ljava/lang/Object;)V"] = function(o) {
// The following can trigger an unwind.
o.klass.classInfo.getMethodByName("<init>", "()V", false).fn.call(o);
};
Native["java/lang/Class.isInterface.()Z"] = function() {
return J2ME.AccessFlags.isInterface(this.runtimeKlass.templateKlass.classInfo.access_flags) ? 1 : 0;
return this.runtimeKlass.templateKlass.classInfo.isInterface ? 1 : 0;
};
Native["java/lang/Class.isArray.()Z"] = function() {
return this.runtimeKlass.templateKlass.classInfo.isArrayClass ? 1 : 0;
return this.runtimeKlass.templateKlass.classInfo instanceof J2ME.ArrayClassInfo ? 1 : 0;
};
Native["java/lang/Class.isAssignableFrom.(Ljava/lang/Class;)Z"] = function(fromClass) {
@ -516,63 +495,14 @@ Native["java/lang/Thread.start0.()V"] = function() {
throw $.newIllegalThreadStateException();
this.alive = true;
this.pid = util.id();
var run = CLASSES.getMethod(this.klass.classInfo, "I.run.()V");
// Create a context for the thread and start it.
var newCtx = new Context($.ctx.runtime);
newCtx.thread = this;
var syntheticMethod = new MethodInfo({
name: "ThreadStart0Synthetic",
signature: "()V",
classInfo: J2ME.ClassInfo.createFromObject({
className: {value: this.klass.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/Thread" },
{ tag: TAGS.CONSTANT_Methodref, name_index: 5, signature_index: 6 },
{ bytes: "run" },
{ bytes: "()V" },
{ tag: TAGS.CONSTANT_Methodref, class_index: 2, name_and_type_index: 8 },
{ name_index: 9, signature_index: 10 },
{ bytes: "internalExit" },
{ bytes: "()V" },
{ tag: TAGS.CONSTANT_Methodref, class_index: 12, name_and_type_index: 14 },
{ tag: TAGS.CONSTANT_Class, name_index: 13 },
{ bytes: "java/lang/Object" },
{ name_index: 15, signature_index: 16 },
{ bytes: "notifyAll" },
{ bytes: "()V" },
]},
}),
code: new Uint8Array([
0x2a, // aload_0
0x59, // dup
0xb6, 0x00, 0x01, // invokevitual <idx=1> Thread.run
0xb7, 0x00, 0x07, // invokespecial <idx=7> Thread.internalExit
0x2a, // aload_0
0x59, // dup
0x4c, // astore_1
0xc2, // monitorenter
0x2a, // aload_0
// Signal waiters waiting on thread
0xb7, 0x00, 0x0b, // invokespecial <idx=11> Object.notifyAll
0x2b, // aload_1
0xc3, // monitorexit
0xb1, // return
])
});
newCtx.start([new Frame(syntheticMethod, [ this ], 0)]);
};
Native["java/lang/Thread.internalExit.()V"] = function() {
this.alive = false;
};
var classInfo = CLASSES.getClass("org/mozilla/internal/Sys");
var run = classInfo.getMethodByName("runThread", "(Ljava/lang/Thread;)V", true);
newCtx.start([new Frame(run, [ this ], 0)]);
}
Native["java/lang/Thread.isAlive.()Z"] = function() {
return this.alive ? 1 : 0;
@ -602,7 +532,7 @@ Native["com/sun/cldc/io/ResourceInputStream.open.(Ljava/lang/String;)Ljava/lang/
var obj = null;
if (data) {
obj = J2ME.newObject(CLASSES.java_lang_Object.klass);
obj.data = new Uint8Array(data);
obj.data = data;
obj.pos = 0;
}
return obj;

Просмотреть файл

@ -18,25 +18,9 @@ function asyncImpl(returnKind, promise) {
}
ctx.execute();
}, function(exception) {
var syntheticMethod = new MethodInfo({
name: "RaiseExceptionSynthetic",
signature: "()V",
isStatic: true,
classInfo: J2ME.ClassInfo.createFromObject({
className: {value: "java/lang/Object"},
vmc: {value: {}},
vfc: {value: {}},
constant_pool: {value: [
null
]}
}),
code: new Uint8Array([
0x2a, // aload_0
0xbf // athrow
])
});
var callee = Frame.create(syntheticMethod, [exception], 0);
ctx.frames.push(callee);
var classInfo = CLASSES.getClass("org/mozilla/internal/Sys");
var methodInfo = classInfo.getMethodByName("throwException", "(Ljava/lang/Exception;)V", true);
ctx.frames.push(Frame.create(methodInfo, [exception], 0));
ctx.execute();
});
$.pause("Async");

Просмотреть файл

@ -1,9 +1,7 @@
// Basics
///<reference path='config.ts' />
///<reference path='utilities.ts' />
///<reference path='vm/classfile.ts' />
///<reference path='vm/reader.ts' />
///<reference path='vm/parser.ts' />
///<reference path='options.ts' />
///<reference path='metrics.ts' />
@ -12,7 +10,6 @@
///<reference path='types.ts' />
///<reference path='vm/classRegistry.ts' />
///<reference path='vm/jvm.ts' />
///<reference path='actors.ts' />
///<reference path='bindings.ts' />
///<reference path='vm/runtime.ts' />
///<reference path='interpreter.ts' />
@ -21,13 +18,6 @@
// JIT
///<reference path='jit/jit.ts' />
///<reference path='jit/c4/ir.ts' />
///<reference path='jit/c4/optimizer.ts' />
///<reference path='jit/c4/ast.ts' />
///<reference path='jit/c4/looper.ts' />
///<reference path='jit/c4/backend.ts' />
///<reference path='jit/jvm.ir.ts' />
///<reference path='jit/analyze.ts' />
///<reference path='jit/builder.ts' />
///<reference path='jit/baseline.ts' />
///<reference path='jit/compiler.ts' />

Просмотреть файл

@ -2,16 +2,14 @@
///<reference path='config.ts' />
///<reference path='utilities.ts' />
///<reference path='vm/parser.ts' />
///<reference path='vm/classfile.ts' />
///<reference path='vm/reader.ts' />
///<reference path='metrics.ts' />
///<reference path='bytecodes.ts' />
///<reference path='jit/blockMap.ts' />
///<reference path='types.ts' />
///<reference path='vm/classRegistry.ts' />
///<reference path='vm/jvm.ts' />
///<reference path='actors.ts' />
///<reference path='bindings.ts' />
///<reference path='vm/runtime.ts' />
///<reference path='interpreter.ts' />

Просмотреть файл

@ -335,6 +335,8 @@ module J2ME {
export module ArrayUtilities {
import assert = Debug.assert;
export var EMPTY_ARRAY = [];
export function makeArrays(length: number): any [][] {
var arrays = [];
@ -1119,6 +1121,10 @@ module J2ME {
i32[0] = i; return f32[0];
}
export function int64ToDouble(high: number, low: number) {
i32[0] = low; i32[1] = high; return f64[0];
}
/**
* Swap the bytes of a 16 bit number.
*/

Просмотреть файл

@ -6,6 +6,7 @@
module J2ME {
declare var ZipFile;
declare var snarf;
export var classCounter = new Metrics.Counter(true);
declare var JARStore;
export class ClassRegistry {
@ -79,10 +80,15 @@ module J2ME {
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];
// Link primitive values.
var primitiveTypes = "ZCFDBSIJ";
for (var i = 0; i < primitiveTypes.length; i++) {
var typeName = primitiveTypes[i];
linkKlass(PrimitiveClassInfo[typeName]);
}
// Link primitive arrays.
PrimitiveArrayClassInfo.initialize();
for (var i = 0; i < primitiveTypes.length; i++) {
this.getClass("[" + typeName);
}
leaveTimeline("initializeBuiltinClasses");
@ -123,10 +129,11 @@ module J2ME {
return null;
}
loadClassBytes(bytes: ArrayBuffer): ClassInfo {
loadClassBytes(bytes: Uint8Array): ClassInfo {
enterTimeline("loadClassBytes");
var classInfo = new ClassInfo(bytes);
leaveTimeline("loadClassBytes", {className: classInfo.className});
loadWriter && loadWriter.writeLn("XXX: " + classInfo.className + " -> " + classInfo.superClassName + ";");
this.classes[classInfo.className] = classInfo;
return classInfo;
}
@ -149,10 +156,6 @@ module J2ME {
superClass = superClass.superClass;
}
}
var classes = classInfo.classes;
classes.forEach(function (c, n) {
classes[n] = self.loadClass(c);
});
classInfo.complete();
loadWriter && loadWriter.leave("<");
return classInfo;
@ -173,8 +176,8 @@ module J2ME {
}
getEntryPoint(classInfo: ClassInfo): MethodInfo {
var methods = classInfo.methods;
for (var i=0; i<methods.length; i++) {
var methods = classInfo.getMethods();
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (method.isPublic && method.isStatic && !method.isNative &&
method.name === "main" &&
@ -208,7 +211,7 @@ module J2ME {
if (elementType[0] === "L") {
elementType = elementType.substr(1).replace(";", "");
}
classInfo = new ArrayClassInfo(typeName, this.getClass(elementType));
classInfo = new ObjectArrayClassInfo(this.getClass(elementType));
}
if (J2ME.phase === J2ME.ExecutionPhase.Runtime) {
J2ME.linkKlass(classInfo);
@ -216,60 +219,6 @@ module J2ME {
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) {

Просмотреть файл

@ -1,321 +0,0 @@
/*
node-jvm
Copyright (c) 2013 Yaroslav Gaponov <yaroslav.gaponov@gmail.com>
*/
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;
};
}

Просмотреть файл

@ -105,8 +105,8 @@ module J2ME {
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.cp = methodInfo ? methodInfo.classInfo.constantPool : null;
this.code = methodInfo ? methodInfo.codeAttribute.code : null;
this.pc = 0;
this.opPC = 0;
this.stack = [];
@ -454,7 +454,7 @@ module J2ME {
release || Debug.assert(!U, "Unexpected unwind during createException.");
runtimeCounter && runtimeCounter.count("createException " + className);
var exception = new classInfo.klass();
var methodInfo = CLASSES.getMethod(classInfo, "I.<init>.(Ljava/lang/String;)V");
var methodInfo = classInfo.getMethodByName("<init>", "(Ljava/lang/String;)V", false);
jsGlobal[methodInfo.mangledClassAndMethodName].call(exception, message ? newString(message) : null);
return exception;

Просмотреть файл

@ -38,8 +38,8 @@ module J2ME {
// The <init> frames go at the end of the array so they are executed first to initialize the thread and isolate.
ctx.start([
Frame.create(CLASSES.getMethod(isolateClassInfo, "I.start.()V"), [ isolate ], 0),
Frame.create(CLASSES.getMethod(isolateClassInfo, "I.<init>.(Ljava/lang/String;[Ljava/lang/String;)V"),
Frame.create(isolateClassInfo.getMethodByName("start", "()V", false), [ isolate ], 0),
Frame.create(isolateClassInfo.getMethodByName("<init>", "(Ljava/lang/String;[Ljava/lang/String;)V", false),
[ isolate, J2ME.newString(className.replace(/\./g, "/")), array ], 0)
]);
release || Debug.assert(!U, "Unexpected unwind during isolate initialization.");
@ -71,7 +71,7 @@ module J2ME {
ctx.start([
Frame.create(entryPoint, [ args ], 0),
Frame.create(CLASSES.getMethod(CLASSES.java_lang_Thread, "I.<init>.(Ljava/lang/String;)V"),
Frame.create(CLASSES.java_lang_Thread.getMethodByName("<init>", "(Ljava/lang/String;)V", false),
[ runtime.mainThread, J2ME.newString("main") ], 0)
]);
release || Debug.assert(!U, "Unexpected unwind during isolate initialization.");

1073
vm/parser.ts Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,138 +0,0 @@
/*
node-jvm
Copyright (c) 2013 Yaroslav Gaponov <yaroslav.gaponov@gmail.com>
*/
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;
}
// Decode Java's modified UTF-8 (JVM specs, $ 4.4.7)
// http://docs.oracle.com/javase/specs/jvms/se5.0/html/ClassFile.doc.html#7963
readStringFast(length: number): string {
var a = (length < 128) ? Reader.getArray(length) : new Array(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 = (j < 128) ? Reader.getArray(j) : new Array(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) {
// 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 {
// NB: no need to create a new slice.
var data = new Uint8Array(this.view.buffer, this.offset, length);
var s = util.decodeUtf8Array(data);
this.offset += length;
return s;
} catch (e) {
return this.readStringFast(length);
}
}
readBytes(length) {
var data = this.u8.buffer.slice(this.offset, this.offset + length);
this.offset += length;
return data;
}
}
}

Просмотреть файл

@ -907,7 +907,7 @@ module J2ME {
$.setClassInitialized(runtimeKlass);
return;
}
var fields = runtimeKlass.templateKlass.classInfo.fields;
var fields = runtimeKlass.templateKlass.classInfo.getFields();
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
if (field.isStatic) {
@ -1072,7 +1072,7 @@ module J2ME {
registerKlass(klass, classInfo);
leaveTimeline("registerKlass");
if (classInfo.isArrayClass) {
if (classInfo instanceof ArrayClassInfo) {
klass.isArrayKlass = true;
var elementKlass = getKlass(classInfo.elementClass);
elementKlass.arrayKlass = klass;
@ -1100,7 +1100,7 @@ module J2ME {
return "[Interface Klass " + classInfo.className + "]";
};
setKlassSymbol(mangledName, klass);
} else if (classInfo.isArrayClass) {
} else if (classInfo instanceof ArrayClassInfo) {
var elementKlass = getKlass(classInfo.elementClass);
// Have we already created one? We need to maintain pointer identity.
if (elementKlass.arrayKlass) {
@ -1341,7 +1341,7 @@ module J2ME {
*/
function linkKlassFields(klass: Klass) {
var classInfo = klass.classInfo;
var fields = classInfo.fields;
var fields = classInfo.getFields();
var classBindings = Bindings[klass.classInfo.className];
if (classBindings && classBindings.fields) {
for (var i = 0; i < fields.length; i++) {
@ -1373,8 +1373,12 @@ module J2ME {
}
function linkKlassMethods(klass: Klass) {
var methods = klass.classInfo.getMethods();
if (!methods) {
return;
}
linkWriter && linkWriter.enter("Link Klass Methods: " + klass);
var methods = klass.classInfo.methods;
var methods = klass.classInfo.getMethods();
var classBindings = Bindings[klass.classInfo.className];
for (var i = 0; i < methods.length; i++) {
var methodInfo = methods[i];
@ -1442,7 +1446,7 @@ module J2ME {
if (methodType === MethodType.Interpreted) {
nativeCounter.count(MethodType[MethodType.Interpreted]);
key += methodInfo.isSynchronized ? " Synchronized" : "";
key += methodInfo.exception_table.length ? " Has Exceptions" : "";
key += methodInfo.exception_table_length ? " Has Exceptions" : "";
// key += " " + methodInfo.implKey;
}
// var key = methodType !== MethodType.Interpreted ? MethodType[methodType] : methodInfo.implKey;
@ -1480,7 +1484,7 @@ module J2ME {
function tracingWrapper(fn: Function, methodInfo: MethodInfo, methodType: MethodType) {
return function() {
var args = Array.prototype.slice.apply(arguments);
traceWriter.enter("> " + MethodType[methodType][0] + " " + methodInfo.implKey + " " + (methodInfo.callCount ++));
traceWriter.enter("> " + MethodType[methodType][0] + " " + methodInfo.implKey + " " + (methodInfo.stats.callCount ++));
var s = performance.now();
var value = fn.apply(this, args);
traceWriter.outdent();
@ -1510,9 +1514,11 @@ module J2ME {
release || assert (!klass.interfaces);
var interfaces = klass.interfaces = klass.superKlass ? klass.superKlass.interfaces.slice() : [];
var interfaceClassInfos = classInfo.interfaces;
for (var j = 0; j < interfaceClassInfos.length; j++) {
ArrayUtilities.pushUnique(interfaces, getKlass(interfaceClassInfos[j]));
var interfaceClassInfos = classInfo.getAllInterfaces();
if (interfaceClassInfos) {
for (var j = 0; j < interfaceClassInfos.length; j++) {
ArrayUtilities.pushUnique(interfaces, getKlass(interfaceClassInfos[j]));
}
}
}
@ -1565,8 +1571,8 @@ module J2ME {
}
// Don't compile methods that are too large.
if (methodInfo.code.length > 2000) {
jitWriter && jitWriter.writeLn("Not compiling: " + methodInfo.implKey + " because it's too large. " + methodInfo.code.length);
if (methodInfo.codeAttribute.code.length > 2000) {
jitWriter && jitWriter.writeLn("Not compiling: " + methodInfo.implKey + " because it's too large. " + methodInfo.codeAttribute.code.length);
methodInfo.state = MethodState.NotCompiled;
return;
}
@ -1582,7 +1588,7 @@ module J2ME {
var mangledClassAndMethodName = methodInfo.mangledClassAndMethodName;
jitWriter && jitWriter.enter("Compiling: " + methodInfo.implKey + ", currentBytecodeCount: " + methodInfo.bytecodeCount);
jitWriter && jitWriter.enter("Compiling: " + methodInfo.implKey + ", currentBytecodeCount: " + methodInfo.stats.bytecodeCount);
var s = performance.now();
var compiledMethod;
@ -1622,7 +1628,7 @@ module J2ME {
if (jitWriter) {
jitWriter.leave(
"Compilation Done: " + methodJITTime.toFixed(2) + " ms, " +
"codeSize: " + methodInfo.code.length + ", " +
"codeSize: " + methodInfo.codeAttribute.code.length + ", " +
"sourceSize: " + compiledMethod.body.length);
jitWriter.writeLn("Total: " + totalJITTime.toFixed(2) + " ms");
}
@ -1866,7 +1872,7 @@ module J2ME {
}
export function classInitCheck(classInfo: ClassInfo) {
if (classInfo.isArrayClass || $.initialized[classInfo.className]) {
if (classInfo instanceof ArrayClassInfo || $.initialized[classInfo.className]) {
return;
}
linkKlass(classInfo);

Просмотреть файл

@ -1,24 +0,0 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
/*
node-jvm
Copyright (c) 2013 Yaroslav Gaponov <yaroslav.gaponov@gmail.com>
*/
'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,
};