зеркало из https://github.com/mozilla/pluotsorbet.git
Merge branch 'master' of github.com:mozilla/j2me.js into fix_asyncImpl
This commit is contained in:
Коммит
aea7991ac8
597
actors.ts
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;
|
60
benchmark.js
60
benchmark.js
|
@ -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(", "));
|
||||
|
|
1405
jit/builder.ts
1405
jit/builder.ts
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
616
jit/c4/ast.ts
616
jit/c4/ast.ts
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
691
jit/c4/ir.ts
691
jit/c4/ir.ts
|
@ -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);
|
||||
}
|
||||
}
|
1065
jit/c4/looper.ts
1065
jit/c4/looper.ts
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
1254
jit/c4/optimizer.ts
1254
jit/c4/optimizer.ts
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
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;
|
||||
|
||||
|
|
10
jsshell.js
10
jsshell.js
|
@ -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;
|
||||
|
|
15
midp/midp.js
15
midp/midp.js
|
@ -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
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;
|
||||
|
|
22
override.js
22
override.js
|
@ -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) {
|
||||
|
|
321
vm/classfile.ts
321
vm/classfile.ts
|
@ -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.");
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
138
vm/reader.ts
138
vm/reader.ts
|
@ -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);
|
||||
|
|
24
vm/tags.js
24
vm/tags.js
|
@ -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,
|
||||
};
|
Загрузка…
Ссылка в новой задаче