зеркало из https://github.com/mozilla/pluotsorbet.git
Snapshot.
This commit is contained in:
Родитель
8619727920
Коммит
d61ee78b38
1244
actors.ts
1244
actors.ts
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -201,7 +201,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;
|
||||
|
||||
|
||||
|
@ -287,7 +287,7 @@ module J2ME {
|
|||
}
|
||||
mi = frame.methodInfo;
|
||||
ci = mi.classInfo;
|
||||
rp = ci.resolved_constant_pool;
|
||||
rp = ci.constantPool.resolved;
|
||||
stack = frame.stack;
|
||||
lastPC = -1;
|
||||
|
||||
|
@ -1074,7 +1074,7 @@ module J2ME {
|
|||
mi = frame.methodInfo;
|
||||
mi.interpreterCallCount ++;
|
||||
ci = mi.classInfo;
|
||||
rp = ci.resolved_constant_pool;
|
||||
rp = ci.constantPool.resolved;
|
||||
stack = frame.stack;
|
||||
lastPC = -1;
|
||||
continue;
|
||||
|
@ -1179,7 +1179,7 @@ module J2ME {
|
|||
mi = frame.methodInfo;
|
||||
mi.interpreterCallCount ++;
|
||||
ci = mi.classInfo;
|
||||
rp = ci.resolved_constant_pool;
|
||||
rp = ci.constantPool.resolved;
|
||||
stack = frame.stack;
|
||||
lastPC = -1;
|
||||
if (calleeTargetMethodInfo.isSynchronized) {
|
||||
|
@ -1270,7 +1270,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) {
|
||||
|
@ -1302,7 +1302,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;
|
||||
|
|
|
@ -74,7 +74,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;
|
||||
|
@ -97,7 +97,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 &&
|
||||
|
@ -112,7 +112,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];
|
||||
|
@ -237,7 +237,7 @@ module J2ME {
|
|||
case Bytecodes.INVOKESPECIAL:
|
||||
case Bytecodes.INVOKESTATIC:
|
||||
var cpi = stream.readCPI();
|
||||
var callee = methodInfo.classInfo.resolve(cpi, op === Bytecodes.INVOKESTATIC);
|
||||
var callee = methodInfo.classInfo.resolveMethod(cpi, op === Bytecodes.INVOKESTATIC);
|
||||
|
||||
if (op !== Bytecodes.INVOKESTATIC) {
|
||||
if (yieldVirtualMap[methodInfo.implKey] === YieldReason.None) {
|
||||
|
|
|
@ -243,7 +243,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) {
|
||||
|
@ -570,19 +570,19 @@ module J2ME {
|
|||
}
|
||||
|
||||
lookupClass(cpi: number): ClassInfo {
|
||||
var classInfo = this.methodInfo.classInfo.resolve(cpi, false);
|
||||
var classInfo = this.methodInfo.classInfo.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.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.resolveField(cpi);
|
||||
ArrayUtilities.pushUnique(this.referencedClasses, fieldInfo.classInfo);
|
||||
return fieldInfo;
|
||||
}
|
||||
|
@ -725,8 +725,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]) {
|
||||
|
|
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,7 +268,7 @@ 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];
|
||||
|
@ -447,7 +447,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) {
|
||||
|
|
29
jsshell.js
29
jsshell.js
|
@ -13,6 +13,14 @@ console.print = function (c) {
|
|||
putstr(String.fromCharCode(c));
|
||||
};
|
||||
|
||||
console.info = function (c) {
|
||||
putstr(String.fromCharCode(c));
|
||||
};
|
||||
|
||||
console.error = function (c) {
|
||||
putstr(String.fromCharCode(c));
|
||||
};
|
||||
|
||||
function check() {
|
||||
|
||||
}
|
||||
|
@ -91,9 +99,9 @@ var config = {
|
|||
};
|
||||
|
||||
try {
|
||||
load("libs/relooper.js", "build/j2me.js","libs/zipfile.js", "blackBox.js",
|
||||
load("build/shumway.js", "libs/relooper.js", "build/j2me.js","libs/zipfile.js", "blackBox.js",
|
||||
"libs/encoding.js", "util.js",
|
||||
"override.js", "vm/tags.js", "native.js", "tests/override.js",
|
||||
"override.js", "vm/tags.js", "native.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");
|
||||
|
@ -111,21 +119,26 @@ try {
|
|||
CLASSES.addPath("java/classes.jar", snarf("java/classes.jar", "binary").buffer);
|
||||
CLASSES.addPath("tests/tests.jar", snarf("tests/tests.jar", "binary").buffer);
|
||||
CLASSES.addPath("bench/benchmark.jar", snarf("bench/benchmark.jar", "binary").buffer);
|
||||
//CLASSES.addPath("program.jar", snarf("program.jar", "binary").buffer);
|
||||
CLASSES.addPath("program.jar", snarf("program.jar", "binary").buffer);
|
||||
|
||||
CLASSES.initializeBuiltinClasses();
|
||||
|
||||
var start = dateNow();
|
||||
var jvm = new JVM();
|
||||
|
||||
J2ME.writers = J2ME.WriterFlags.None;
|
||||
|
||||
start = dateNow();
|
||||
var runtime = jvm.startIsolate0(scriptArgs[0], config.args);
|
||||
|
||||
while (callbacks.length) {
|
||||
(callbacks.shift())();
|
||||
}
|
||||
//J2ME.writers = J2ME.WriterFlags.All;
|
||||
//J2ME.loadWriter = new J2ME.IndentingWriter();
|
||||
//J2ME.linkWriter = new J2ME.IndentingWriter();
|
||||
//J2ME.classCounter.clear();
|
||||
//CLASSES.loadAllClassFilesInJARFile("program.jar");
|
||||
//J2ME.classCounter.trace(J2ME.loadWriter);
|
||||
//
|
||||
////while (callbacks.length) {
|
||||
//// (callbacks.shift())();
|
||||
////}
|
||||
|
||||
// J2ME.interpreterCounter.traceSorted(new J2ME.IndentingWriter());
|
||||
|
||||
|
|
796
parser.ts
796
parser.ts
|
@ -1,8 +1,30 @@
|
|||
module J2ME.Parser {
|
||||
module J2ME {
|
||||
declare var util;
|
||||
import assert = J2ME.Debug.assert;
|
||||
export class ByteStream {
|
||||
u8: Uint8Array;
|
||||
var utf8ToString = util.decodeUtf8Array;
|
||||
|
||||
module UTF8 {
|
||||
export var Code = new Uint8Array([67, 111, 100, 101]);
|
||||
export var InnerClasses = new Uint8Array([67, 111, 100, 101]);
|
||||
}
|
||||
|
||||
function strcmp(a: Uint8Array, b: Uint8Array): boolean {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export class Bytes {
|
||||
u1: Uint8Array;
|
||||
offset: number;
|
||||
|
||||
static arrays: string [][] = ArrayUtilities.makeArrays(128);
|
||||
|
@ -11,39 +33,47 @@ module J2ME.Parser {
|
|||
return Reader.arrays[length];
|
||||
}
|
||||
|
||||
constructor(buffer: ArrayBuffer, offset: number = 0) {
|
||||
this.u8 = new Uint8Array(buffer);
|
||||
constructor(buffer: Uint8Array, offset: number) {
|
||||
this.u1 = buffer;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
readU8() {
|
||||
return this.u8[this.offset++];
|
||||
clone() {
|
||||
return new Bytes(this.u1, this.offset);
|
||||
}
|
||||
|
||||
readU16() {
|
||||
var u8 = this.u8;
|
||||
readU1() {
|
||||
return this.u1[this.offset++];
|
||||
}
|
||||
|
||||
peekU1() {
|
||||
return this.u1[this.offset];
|
||||
}
|
||||
|
||||
readU2() {
|
||||
var u1 = this.u1;
|
||||
var o = this.offset;
|
||||
this.offset += 2;
|
||||
return u8[o] << 8 | u8[o + 1];
|
||||
return u1[o] << 8 | u1[o + 1];
|
||||
}
|
||||
|
||||
peekU16() {
|
||||
var u8 = this.u8;
|
||||
var u1 = this.u1;
|
||||
var o = this.offset;
|
||||
return u8[o] << 8 | u8[o + 1];
|
||||
return u1[o] << 8 | u1[o + 1];
|
||||
}
|
||||
|
||||
readU32() {
|
||||
readU4() {
|
||||
return this.readI32() >>> 0;
|
||||
}
|
||||
|
||||
readI32() {
|
||||
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];
|
||||
var u1 = this.u1;
|
||||
var a = u1[o + 0];
|
||||
var b = u1[o + 1];
|
||||
var c = u1[o + 2];
|
||||
var d = u1[o + 3];
|
||||
this.offset = o + 4;
|
||||
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
}
|
||||
|
@ -60,8 +90,14 @@ module J2ME.Parser {
|
|||
// return data;
|
||||
//}
|
||||
|
||||
skip(length: number) {
|
||||
seek(offset: number): Bytes {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
skip(length: number): Bytes {
|
||||
this.offset += length;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Decode Java's modified UTF-8 (JVM specs, $ 4.4.7)
|
||||
|
@ -71,9 +107,9 @@ module J2ME.Parser {
|
|||
var i = 0, j = 0;
|
||||
var o = this.offset;
|
||||
var e = o + length;
|
||||
var u8 = this.u8;
|
||||
var u1 = this.u1;
|
||||
while (o < e) {
|
||||
var x = u8[o++];
|
||||
var x = u1[o++];
|
||||
if (x <= 0x7f) {
|
||||
// Code points in the range '\u0001' to '\u007F' are represented by a
|
||||
// single byte.
|
||||
|
@ -83,13 +119,13 @@ module J2ME.Parser {
|
|||
} 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++]
|
||||
var y = u1[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++];
|
||||
var y = u1[o++];
|
||||
var z = u1[o++];
|
||||
a[j++] = String.fromCharCode(((x & 0xf) << 12) + ((y & 0x3f) << 6) + (z & 0x3f));
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +142,7 @@ module J2ME.Parser {
|
|||
|
||||
readString(length) {
|
||||
if (length === 1) {
|
||||
var c = this.u8[this.offset];
|
||||
var c = this.u1[this.offset];
|
||||
if (c <= 0x7f) {
|
||||
this.offset++;
|
||||
return String.fromCharCode(c);
|
||||
|
@ -123,7 +159,7 @@ module J2ME.Parser {
|
|||
// UTF-8 implementation.
|
||||
try {
|
||||
// NB: no need to create a new slice.
|
||||
var data = new Uint8Array(this.u8.buffer, this.offset, length);
|
||||
var data = new Uint8Array(this.u1.buffer, this.offset, length);
|
||||
var s = util.decodeUtf8Array(data);
|
||||
this.offset += length;
|
||||
return s;
|
||||
|
@ -132,34 +168,76 @@ module J2ME.Parser {
|
|||
}
|
||||
}
|
||||
|
||||
readBytes(length) {
|
||||
var data = this.u8.buffer.slice(this.offset, this.offset + length);
|
||||
readBytes(length): Uint8Array {
|
||||
var data = this.u1.subarray(this.offset, this.offset + length);
|
||||
this.offset += length;
|
||||
return data;
|
||||
}
|
||||
|
||||
//static readU32(u8: Uint8Array, o: number): number {
|
||||
// return Bytes.readI32(u8, o) >>> 0;
|
||||
//static readU4(u1: Uint8Array, o: number): number {
|
||||
// return Bytes.readI32(u1, o) >>> 0;
|
||||
//}
|
||||
//
|
||||
//static readI32(u8: Uint8Array, o: number): number {
|
||||
// var a = u8[o + 0];
|
||||
// var b = u8[o + 1];
|
||||
// var c = u8[o + 2];
|
||||
// var d = u8[o + 3];
|
||||
//static readI32(u1: Uint8Array, o: number): number {
|
||||
// var a = u1[o + 0];
|
||||
// var b = u1[o + 1];
|
||||
// var c = u1[o + 2];
|
||||
// var d = u1[o + 3];
|
||||
// return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
//}
|
||||
//
|
||||
static readU16(u8: Uint8Array, o: number): number {
|
||||
return u8[o] << 8 | u8[o + 1];
|
||||
static readU16(u1: Uint8Array, o: number): number {
|
||||
return u1[o] << 8 | u1[o + 1];
|
||||
}
|
||||
}
|
||||
|
||||
export class ExceptionHandler {
|
||||
start_pc: number;
|
||||
end_pc: number;
|
||||
handler_pc: number;
|
||||
catch_type: number;
|
||||
}
|
||||
|
||||
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 enum CONSTANT_Class_info {
|
||||
tag = 0, // u1
|
||||
name_index = 1 // u2 CONSTANT_Utf8_info
|
||||
}
|
||||
|
||||
export class ConstantPool {
|
||||
stream: ByteStream;
|
||||
bytes: Bytes;
|
||||
offset: number;
|
||||
count: number;
|
||||
entries: Uint32Array;
|
||||
resolved: any [];
|
||||
|
||||
private static tagSize = new Int8Array([
|
||||
-1, // ?
|
||||
|
@ -177,9 +255,9 @@ module J2ME.Parser {
|
|||
4 // CONSTANT_NameAndType
|
||||
]);
|
||||
|
||||
constructor(stream: ByteStream) {
|
||||
this.stream = stream;
|
||||
this.offset = stream.offset;
|
||||
constructor(bytes: Bytes) {
|
||||
this.bytes = bytes.clone();
|
||||
this.offset = bytes.offset;
|
||||
this.scanEntries();
|
||||
}
|
||||
|
||||
|
@ -187,18 +265,19 @@ module J2ME.Parser {
|
|||
* Quickly scan over the constant pool and record the position of each constant pool entry.
|
||||
*/
|
||||
private scanEntries() {
|
||||
var s = this.stream;
|
||||
var c = this.count = s.readU16();
|
||||
var s = this.bytes;
|
||||
var c = this.count = s.readU2();
|
||||
this.entries = new Uint32Array(this.count);
|
||||
this.resolved = new Array(this.count);
|
||||
var S = ConstantPool.tagSize;
|
||||
var o = s.offset;
|
||||
var u8 = s.u8;
|
||||
var u1 = s.u1;
|
||||
var e = this.entries;
|
||||
for (var i = 1; i < c; i++) {
|
||||
e[i] = o;
|
||||
var t = u8[o++];
|
||||
var t = u1[o++];
|
||||
if (t === TAGS.CONSTANT_Utf8) {
|
||||
o += 2 + ByteStream.readU16(u8, o);
|
||||
o += 2 + Bytes.readU16(u1, o);
|
||||
} else {
|
||||
o += S[t];
|
||||
}
|
||||
|
@ -208,100 +287,627 @@ module J2ME.Parser {
|
|||
}
|
||||
s.offset = o;
|
||||
}
|
||||
|
||||
utf8(i: number): Uint8Array {
|
||||
return <Uint8Array>this.resolve(i, TAGS.CONSTANT_Utf8);
|
||||
}
|
||||
|
||||
u2(i: number, tag: TAGS, offset: number) {
|
||||
var s = this.bytes.seek(this.entries[i]);
|
||||
release || assert (s.peekU1() === tag);
|
||||
return s.skip(offset).readU2();
|
||||
}
|
||||
|
||||
seek(i: number, tag: TAGS) {
|
||||
this.bytes.seek(this.entries[i]);
|
||||
release || assert(this.bytes.peekU1() === tag);
|
||||
}
|
||||
|
||||
resolve(i: number, tag: TAGS): any {
|
||||
var b = this.bytes, r = this.resolved[i];
|
||||
if (r === undefined) {
|
||||
this.seek(i, tag);
|
||||
switch (b.readU1()) {
|
||||
case TAGS.CONSTANT_Utf8:
|
||||
r = this.resolved[i] = b.readBytes(b.readU2());
|
||||
break;
|
||||
case TAGS.CONSTANT_Class:
|
||||
r = this.resolved[i] = CLASSES.loadClass(utf8ToString(this.resolve(b.readU2(), TAGS.CONSTANT_Utf8)));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
resolveClass(index: number): ClassInfo {
|
||||
return <ClassInfo>this.resolve(index, TAGS.CONSTANT_Class);
|
||||
}
|
||||
}
|
||||
|
||||
export class FieldInfo {
|
||||
offset: number;
|
||||
classInfo: ClassInfo;
|
||||
kind: Kind;
|
||||
name: string;
|
||||
mangledName: string;
|
||||
signature: string;
|
||||
access_flags: ACCESS_FLAGS;
|
||||
|
||||
constructor(classInfo: ClassInfo, offset: number) {
|
||||
this.offset = offset;
|
||||
this.classInfo = classInfo;
|
||||
}
|
||||
|
||||
get isStatic(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_STATIC);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 MethodInfo {
|
||||
access_flags: number;
|
||||
name_index: number;
|
||||
descriptor_index: number;
|
||||
|
||||
fn: any;
|
||||
|
||||
|
||||
classInfo: ClassInfo;
|
||||
offset: number;
|
||||
name: Uint16Array;
|
||||
code: Uint8Array;
|
||||
codeAttribute: CodeAttribute;
|
||||
|
||||
name: string;
|
||||
state: MethodState;
|
||||
signature: string;
|
||||
mangledName: string;
|
||||
mangledClassAndMethodName: string;
|
||||
|
||||
onStackReplacementEntryPoints: number [];
|
||||
|
||||
callCount: number;
|
||||
bytecodeCount: number;
|
||||
backwardsBranchCount: number;
|
||||
interpreterCallCount: number;
|
||||
|
||||
argumentSlots: number;
|
||||
/**
|
||||
* The number of arguments to pop of the stack when calling this function.
|
||||
*/
|
||||
consumeArgumentSlots: number;
|
||||
|
||||
hasTwoSlotArguments: boolean;
|
||||
|
||||
// Remove these
|
||||
max_locals: number;
|
||||
max_stack: number;
|
||||
|
||||
exception_table: any [];
|
||||
implKey: string;
|
||||
isOptimized: boolean;
|
||||
signatureDescriptor: SignatureDescriptor;
|
||||
|
||||
constructor(classInfo: ClassInfo, offset: number) {
|
||||
this.classInfo = classInfo;
|
||||
this.offset = offset;
|
||||
|
||||
var b = classInfo.bytes.seek(offset);
|
||||
this.access_flags = b.readU2();
|
||||
this.name_index = b.readU2();
|
||||
this.descriptor_index = b.readU2();
|
||||
this.scanMethodInfoAttributes(b);
|
||||
}
|
||||
|
||||
scanMethodInfoAttributes(s: Bytes) {
|
||||
var count = s.readU2();
|
||||
for (var i = 0; i < count; i++) {
|
||||
var attribute_name_index = s.readU2();
|
||||
var attribute_length = s.readU4();
|
||||
var o = s.offset;
|
||||
var attribute_name = this.classInfo.constantPool.utf8(attribute_name_index);
|
||||
if (strcmp(attribute_name, UTF8.Code)) {
|
||||
this.codeAttribute = new CodeAttribute(this.classInfo, o);
|
||||
}
|
||||
s.seek(o + attribute_length);
|
||||
}
|
||||
}
|
||||
|
||||
public getReturnKind(): Kind {
|
||||
return this.signatureDescriptor.typeDescriptors[0].kind;
|
||||
}
|
||||
|
||||
get isNative(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_NATIVE);
|
||||
}
|
||||
|
||||
get isFinal(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_FINAL);
|
||||
}
|
||||
|
||||
get isPublic(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_PUBLIC);
|
||||
}
|
||||
|
||||
get isStatic(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_STATIC);
|
||||
}
|
||||
|
||||
get isSynchronized(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_SYNCHRONIZED);
|
||||
}
|
||||
|
||||
get isAbstract(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_ABSTRACT);
|
||||
}
|
||||
|
||||
getSourceLocationForPC(pc: number): SourceLocation {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
enum ResolvedFlags {
|
||||
None = 0,
|
||||
Fields = 1,
|
||||
Methods = 2,
|
||||
Classes = 4,
|
||||
Interfaces = 8
|
||||
}
|
||||
|
||||
export class CodeAttribute {
|
||||
max_stack: number;
|
||||
max_locals: number;
|
||||
code: Uint8Array;
|
||||
constructor(classInfo: ClassInfo, offset: number) {
|
||||
var s = classInfo.bytes;
|
||||
this.max_stack = s.readU2();
|
||||
this.max_locals = s.readU2();
|
||||
var code_length = s.readU4();
|
||||
this.code = s.readBytes(code_length);
|
||||
var exception_table_length = s.readU2();
|
||||
}
|
||||
}
|
||||
|
||||
export class ClassInfo {
|
||||
stream: ByteStream;
|
||||
magic: number;
|
||||
minor_version: number;
|
||||
major_version: number;
|
||||
constantPool: ConstantPool;
|
||||
bytes: Bytes = null;
|
||||
constantPool: ConstantPool = null;
|
||||
|
||||
access_flags: number;
|
||||
this_class: number;
|
||||
super_class: number;
|
||||
|
||||
fields: number | FieldInfo [];
|
||||
methods: number | MethodInfo [];
|
||||
interfaces: number | ClassInfo [];
|
||||
access_flags: number = 0;
|
||||
this_class: number = 0;
|
||||
super_class: number= 0;
|
||||
|
||||
constructor(stream: ByteStream) {
|
||||
var s = this.stream = stream;
|
||||
name: string = null;
|
||||
superClassName: string = null;
|
||||
superClass: ClassInfo = null;
|
||||
subClasses: ClassInfo [] = null;
|
||||
allSubClasses: ClassInfo [] = null;
|
||||
|
||||
this.magic = s.readU32();
|
||||
this.minor_version = s.readU16();
|
||||
this.major_version = s.readU16();
|
||||
this.constantPool = new ConstantPool(s);
|
||||
this.access_flags = s.readU16();
|
||||
this.this_class = s.readU16();
|
||||
this.super_class = s.readU16();
|
||||
staticInitializer: MethodInfo = null;
|
||||
|
||||
klass: Klass = null;
|
||||
private resolvedFlags: ResolvedFlags = ResolvedFlags.None;
|
||||
private fields: (number | FieldInfo) [] = null;
|
||||
private methods: (number | MethodInfo) [] = null;
|
||||
private classes: (number | ClassInfo) [] = null;
|
||||
private interfaces: (number | ClassInfo) [] = null;
|
||||
|
||||
sourceFile: string = null;
|
||||
mangledName: string = null;
|
||||
|
||||
private _className: Uint16Array = null;
|
||||
|
||||
// Delete me:
|
||||
constant_pool: any = null;
|
||||
thread: any = null;
|
||||
|
||||
constructor(buffer: Uint8Array) {
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
var b = this.bytes = new Bytes(buffer, 0);
|
||||
b.readU4(); // magic
|
||||
b.readU2(); // minor_version
|
||||
b.readU2(); // major_version
|
||||
this.constantPool = new ConstantPool(b);
|
||||
b.seek(this.constantPool.bytes.offset);
|
||||
this.access_flags = b.readU2();
|
||||
this.this_class = b.readU2();
|
||||
this.super_class = b.readU2();
|
||||
|
||||
this.scanInterfaces();
|
||||
this.scanFields();
|
||||
this.scanMethods();
|
||||
this.skipAttributes();
|
||||
this.scanClassInfoAttributes();
|
||||
|
||||
this.mangledName = mangleClass(this);
|
||||
this.getMethods();
|
||||
}
|
||||
|
||||
private scanInterfaces() {
|
||||
var s = this.stream;
|
||||
var count = s.readU16();
|
||||
this.interfaces = new Array(count);
|
||||
for (var i = 0; i < count; i++) {
|
||||
this.interfaces[i] = s.offset;
|
||||
s.readU16();
|
||||
var b = this.bytes;
|
||||
var interfaces_count = b.readU2();
|
||||
this.interfaces = new Array(interfaces_count);
|
||||
for (var i = 0; i < interfaces_count; i++) {
|
||||
this.interfaces[i] = b.readU2();
|
||||
}
|
||||
}
|
||||
|
||||
private scanFields() {
|
||||
var s = this.stream;
|
||||
var count = s.readU16();
|
||||
var f = this.fields = new Array(count);
|
||||
for (var i = 0; i < count; i++) {
|
||||
f[i] = s.offset;
|
||||
s.skip(6);
|
||||
var b = this.bytes;
|
||||
var fields_count = b.readU2();
|
||||
var f = this.fields = new Array(fields_count);
|
||||
for (var i = 0; i < fields_count; i++) {
|
||||
f[i] = b.offset;
|
||||
b.skip(6);
|
||||
this.skipAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
private scanMethods() {
|
||||
var s = this.stream;
|
||||
var count = s.readU16();
|
||||
var m = this.methods = new Array(count);
|
||||
for (var i = 0; i < count; i++) {
|
||||
m[i] = s.offset;
|
||||
s.skip(6);
|
||||
var b = this.bytes;
|
||||
var methods_count = b.readU2();
|
||||
var m = this.methods = new Array(methods_count);
|
||||
for (var i = 0; i < methods_count; i++) {
|
||||
m[i] = b.offset;
|
||||
b.skip(6);
|
||||
this.skipAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
private skipAttributes() {
|
||||
var s = this.stream;
|
||||
var count = s.readU16();
|
||||
for (var i = 0; i < count; i++) {
|
||||
s.readU16();
|
||||
s.skip(s.readU32());
|
||||
var b = this.bytes;
|
||||
var attributes_count = b.readU2();
|
||||
for (var i = 0; i < attributes_count; i++) {
|
||||
b.readU2();
|
||||
b.skip(b.readU4());
|
||||
}
|
||||
}
|
||||
|
||||
getMethodInfo(i: number): MethodInfo {
|
||||
if (typeof this.methods[i] === "number") {
|
||||
this.methods[i] = new MethodInfo(this, this.methods[i]);
|
||||
scanClassInfoAttributes() {
|
||||
var b = this.bytes;
|
||||
var attributes_count = b.readU2();
|
||||
for (var i = 0; i < attributes_count; i++) {
|
||||
var attribute_name_index = b.readU2();
|
||||
var attribute_length = b.readU4();
|
||||
var o = b.offset;
|
||||
var attribute_name = this.constantPool.utf8(attribute_name_index);
|
||||
if (strcmp(attribute_name, UTF8.InnerClasses)) {
|
||||
var number_of_classes = b.readU2();
|
||||
assert (!this.classes);
|
||||
this.classes = new Array(number_of_classes);
|
||||
for(var i = 0; i < number_of_classes; i++) {
|
||||
this.classes[i] = b.offset;
|
||||
b.skip(8);
|
||||
}
|
||||
}
|
||||
b.seek(o + attribute_length);
|
||||
}
|
||||
return this.methods[i];
|
||||
}
|
||||
|
||||
getMethod(i: number): MethodInfo {
|
||||
if (typeof this.methods[i] === "number") {
|
||||
this.methods[i] = new MethodInfo(this, <number>this.methods[i]);
|
||||
}
|
||||
return <MethodInfo>this.methods[i];
|
||||
}
|
||||
|
||||
getMethods(): MethodInfo [] {
|
||||
if (!this.methods) {
|
||||
return null;
|
||||
}
|
||||
if (this.resolvedFlags & ResolvedFlags.Methods) {
|
||||
return <MethodInfo []>this.methods;
|
||||
}
|
||||
for (var i = 0; i < this.methods.length; i++) {
|
||||
this.getMethod(i);
|
||||
}
|
||||
this.resolvedFlags |= ResolvedFlags.Methods;
|
||||
return <MethodInfo []>this.methods;
|
||||
}
|
||||
|
||||
getField(i: number): FieldInfo {
|
||||
if (typeof this.fields[i] === "number") {
|
||||
this.fields[i] = new FieldInfo(this, <number>this.fields[i]);
|
||||
}
|
||||
return <FieldInfo>this.fields[i];
|
||||
}
|
||||
|
||||
getFields(): FieldInfo [] {
|
||||
if (!this.fields) {
|
||||
return null;
|
||||
}
|
||||
if (this.resolvedFlags & ResolvedFlags.Fields) {
|
||||
return <FieldInfo []>this.fields;
|
||||
}
|
||||
for (var i = 0; i < this.fields.length; i++) {
|
||||
this.getField(i);
|
||||
}
|
||||
this.resolvedFlags |= ResolvedFlags.Fields;
|
||||
return <FieldInfo []>this.fields;
|
||||
}
|
||||
|
||||
getClass(i: number): ClassInfo {
|
||||
if (typeof this.classes[i] === "number") {
|
||||
this.classes[i] = new ClassInfo(null);
|
||||
}
|
||||
return <ClassInfo>this.classes[i];
|
||||
}
|
||||
|
||||
getClasses(): ClassInfo [] {
|
||||
if (!this.classes) {
|
||||
return null;
|
||||
}
|
||||
if (this.resolvedFlags & ResolvedFlags.Classes) {
|
||||
return <ClassInfo []>this.classes;
|
||||
}
|
||||
for (var i = 0; i < this.classes.length; i++) {
|
||||
this.getClass(i);
|
||||
}
|
||||
this.resolvedFlags |= ResolvedFlags.Classes;
|
||||
return <ClassInfo []>this.classes;
|
||||
}
|
||||
|
||||
getInterface(i: number): ClassInfo {
|
||||
if (typeof this.interfaces[i] === "number") {
|
||||
this.interfaces[i] = this.constantPool.resolveClass(<number>this.interfaces[i]);
|
||||
}
|
||||
return <ClassInfo>this.interfaces[i];
|
||||
}
|
||||
|
||||
getInterfaces(): ClassInfo [] {
|
||||
if (!this.interfaces) {
|
||||
return null;
|
||||
}
|
||||
if (this.resolvedFlags & ResolvedFlags.Interfaces) {
|
||||
return <ClassInfo []>this.interfaces;
|
||||
}
|
||||
for (var i = 0; i < this.interfaces.length; i++) {
|
||||
this.getInterface(i);
|
||||
}
|
||||
this.resolvedFlags |= ResolvedFlags.Interfaces;
|
||||
return <ClassInfo []>this.interfaces;
|
||||
}
|
||||
|
||||
getFieldByName(fieldKey: string): FieldInfo {
|
||||
// return CLASSES.getField(this, fieldKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object that holds static properties for this class.
|
||||
*/
|
||||
getStaticObject(ctx: Context): java.lang.Object {
|
||||
return <java.lang.Object><any>getRuntimeKlass(ctx.runtime, this.klass);
|
||||
}
|
||||
|
||||
getClassNameIndex(): number {
|
||||
return this.constantPool.u2(this.this_class, TAGS.CONSTANT_Class, CONSTANT_Class_info.name_index);
|
||||
}
|
||||
|
||||
getClassName(): Uint8Array {
|
||||
return this.constantPool.utf8(this.getClassNameIndex());
|
||||
}
|
||||
|
||||
getClassNameString(): string {
|
||||
return util.decodeUtf8Array(this.getClassName());
|
||||
}
|
||||
|
||||
// TODO: Remove
|
||||
get className(): string {
|
||||
return this.getClassNameString();
|
||||
}
|
||||
|
||||
get isInterface(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_INTERFACE);
|
||||
}
|
||||
|
||||
get isFinal(): boolean {
|
||||
return !!(this.access_flags & ACCESS_FLAGS.ACC_FINAL);
|
||||
}
|
||||
|
||||
implementsInterface(i: ClassInfo): boolean {
|
||||
var classInfo = this;
|
||||
do {
|
||||
var interfaces = classInfo.interfaces;
|
||||
for (var n = 0; n < interfaces.length; ++n) {
|
||||
if (interfaces[n] === i)
|
||||
return true;
|
||||
}
|
||||
classInfo = classInfo.superClass;
|
||||
} while (classInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
isAssignableTo(toClass: ClassInfo): boolean {
|
||||
if (this === toClass || toClass === CLASSES.java_lang_Object)
|
||||
return true;
|
||||
if (toClass.isInterface && this.implementsInterface(toClass))
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
|
||||
resolveClass(i: number): ClassInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
resolveMethod(i: number, isStatic: boolean): MethodInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
resolveField(i: number): FieldInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a constant pool reference.
|
||||
*/
|
||||
resolve(index: number, isStatic: boolean) {
|
||||
// return this.constantPool.resolve(index);
|
||||
|
||||
//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 PrimitiveClassInfo extends ClassInfo {
|
||||
private primitiveClassName: string;
|
||||
|
||||
constructor(className, mangledName) {
|
||||
super(null);
|
||||
this.primitiveClassName = className;
|
||||
this.mangledName = mangledName;
|
||||
}
|
||||
|
||||
getClassNameString(): string {
|
||||
return this.primitiveClassName;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
export class ArrayClassInfo extends ClassInfo {
|
||||
elementClass: ClassInfo;
|
||||
|
||||
constructor(elementClass: ClassInfo) {
|
||||
super(null);
|
||||
this.elementClass = elementClass;
|
||||
}
|
||||
|
||||
getClassNameString(): string {
|
||||
return "[" + this.elementClass.getClassNameString();
|
||||
}
|
||||
|
||||
isAssignableTo(toClass: ClassInfo): boolean {
|
||||
if (this === toClass || toClass === CLASSES.java_lang_Object)
|
||||
return true;
|
||||
if (toClass.isInterface && this.implementsInterface(toClass))
|
||||
return true;
|
||||
if (toClass instanceof ArrayClassInfo) {
|
||||
if (this.elementClass && toClass.elementClass)
|
||||
return this.elementClass.isAssignableTo(toClass.elementClass);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return this.superClass ? this.superClass.isAssignableTo(toClass) : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class PrimitiveArrayClassInfo extends ArrayClassInfo {
|
||||
constructor(elementClass: ClassInfo, mangledName: string) {
|
||||
super(elementClass);
|
||||
this.mangledName = mangledName;
|
||||
}
|
||||
static Z = new PrimitiveArrayClassInfo(PrimitiveClassInfo.Z, "Uint8Array");
|
||||
static C = new PrimitiveArrayClassInfo(PrimitiveClassInfo.C, "Uint16Array");
|
||||
static F = new PrimitiveArrayClassInfo(PrimitiveClassInfo.F, "Float32Array");
|
||||
static D = new PrimitiveArrayClassInfo(PrimitiveClassInfo.D, "Float64Array");
|
||||
static B = new PrimitiveArrayClassInfo(PrimitiveClassInfo.B, "Int8Array");
|
||||
static S = new PrimitiveArrayClassInfo(PrimitiveClassInfo.S, "Int16Array");
|
||||
static I = new PrimitiveArrayClassInfo(PrimitiveClassInfo.I, "Int32Array");
|
||||
static J = new PrimitiveArrayClassInfo(PrimitiveClassInfo.J, "Int64Array");
|
||||
}
|
||||
}
|
|
@ -22,13 +22,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' />
|
|
@ -1,6 +1,7 @@
|
|||
module J2ME {
|
||||
declare var ZipFile;
|
||||
declare var snarf;
|
||||
export var classCounter = new Metrics.Counter(true);
|
||||
|
||||
export class ClassRegistry {
|
||||
/**
|
||||
|
@ -153,8 +154,9 @@ module J2ME {
|
|||
|
||||
loadClassBytes(bytes: ArrayBuffer): ClassInfo {
|
||||
enterTimeline("loadClassBytes");
|
||||
var classInfo = new ClassInfo(bytes);
|
||||
var classInfo = new ClassInfo(new Uint8Array(bytes));
|
||||
leaveTimeline("loadClassBytes", {className: classInfo.className});
|
||||
loadWriter && loadWriter.writeLn("XXX: " + classInfo.className + " -> " + classInfo.superClassName + ";");
|
||||
this.classes[classInfo.className] = classInfo;
|
||||
return classInfo;
|
||||
}
|
||||
|
@ -177,11 +179,12 @@ module J2ME {
|
|||
superClass = superClass.superClass;
|
||||
}
|
||||
}
|
||||
var classes = classInfo.classes;
|
||||
classes.forEach(function (c, n) {
|
||||
classes[n] = self.loadClass(c);
|
||||
});
|
||||
classInfo.complete();
|
||||
var classes = classInfo.getClasses();
|
||||
// FIXME
|
||||
//classes.forEach(function (c, n) {
|
||||
// classes[n] = self.loadClass(c);
|
||||
//});
|
||||
// classInfo.complete();
|
||||
loadWriter && loadWriter.leave("<");
|
||||
return classInfo;
|
||||
}
|
||||
|
@ -191,19 +194,27 @@ module J2ME {
|
|||
*/
|
||||
loadAllClassFiles() {
|
||||
var jarFiles = this.jarFiles;
|
||||
var self = this;
|
||||
Object.keys(jarFiles).every(function (path) {
|
||||
if (path.substr(-4) !== ".jar") {
|
||||
return true;
|
||||
}
|
||||
var zipFile = jarFiles[path];
|
||||
Object.keys(zipFile.directory).every(function (fileName) {
|
||||
if (fileName.substr(-6) !== '.class') {
|
||||
return true;
|
||||
}
|
||||
var className = fileName.substring(0, fileName.length - 6);
|
||||
CLASSES.getClass(className);
|
||||
self.loadAllClassFilesInJARFile(path);
|
||||
});
|
||||
}
|
||||
|
||||
loadAllClassFilesInJARFile(path: string) {
|
||||
var jarFiles = this.jarFiles;
|
||||
var zipFile = jarFiles[path];
|
||||
var self = this;
|
||||
Object.keys(zipFile.directory).every(function (fileName) {
|
||||
if (fileName.substr(-6) !== '.class') {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
var className = fileName.substring(0, fileName.length - 6);
|
||||
var bytes = self.loadFile(className + ".class");
|
||||
var classInfo2 = new ClassInfo(new Uint8Array(bytes));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -222,8 +233,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" &&
|
||||
|
@ -257,7 +268,8 @@ module J2ME {
|
|||
if (elementType[0] === "L") {
|
||||
elementType = elementType.substr(1).replace(";", "");
|
||||
}
|
||||
classInfo = new ArrayClassInfo(typeName, this.getClass(elementType));
|
||||
// FIXME
|
||||
// classInfo = new ArrayClassInfo(typeName, this.getClass(elementType));
|
||||
}
|
||||
if (J2ME.phase === J2ME.ExecutionPhase.Runtime) {
|
||||
J2ME.linkKlass(classInfo);
|
||||
|
|
|
@ -12,35 +12,6 @@ module J2ME {
|
|||
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;
|
||||
|
@ -86,6 +57,7 @@ module J2ME {
|
|||
|
||||
var item = classImage.constant_pool[attribute_name_index];
|
||||
|
||||
classCounter.count("Attr: " + TAGS[item.tag]);
|
||||
switch(item.tag) {
|
||||
case TAGS.CONSTANT_Long:
|
||||
case TAGS.CONSTANT_Float:
|
||||
|
@ -190,6 +162,7 @@ module J2ME {
|
|||
};
|
||||
|
||||
var reader = new J2ME.Reader(classBytes);
|
||||
classCounter.count("Bytes: ", classBytes.byteLength);
|
||||
classImage.magic = reader.read32().toString(16);
|
||||
|
||||
classImage.version = {
|
||||
|
@ -201,6 +174,7 @@ module J2ME {
|
|||
var constant_pool_count = reader.read16();
|
||||
for(var i=1; i<constant_pool_count; i++) {
|
||||
var tag = reader.read8();
|
||||
classCounter.count(TAGS[tag]);
|
||||
switch(tag) {
|
||||
case TAGS.CONSTANT_Class:
|
||||
var name_index = reader.read16();
|
||||
|
@ -209,6 +183,7 @@ module J2ME {
|
|||
case TAGS.CONSTANT_Utf8:
|
||||
var length = reader.read16();
|
||||
var bytes = reader.readString(length);
|
||||
classCounter.count("String Size", bytes.length);
|
||||
classImage.constant_pool.push({ tag: tag, bytes: bytes });
|
||||
break;
|
||||
case TAGS.CONSTANT_Methodref:
|
||||
|
|
|
@ -439,7 +439,9 @@ module J2ME {
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
getClassInitFrame(classInfo: ClassInfo) {
|
||||
getClassInitFrame(classInfo: ClassInfo): Frame {
|
||||
return null;
|
||||
/*
|
||||
if (this.runtime.initialized[classInfo.className]) {
|
||||
return;
|
||||
}
|
||||
|
@ -479,6 +481,7 @@ module J2ME {
|
|||
])
|
||||
});
|
||||
return Frame.create(syntheticMethod, [classInfo.getClassInitLockObject(this)], 0);
|
||||
*/
|
||||
}
|
||||
|
||||
pushClassInitFrame(classInfo: ClassInfo) {
|
||||
|
|
|
@ -34,8 +34,8 @@ module J2ME {
|
|||
}
|
||||
|
||||
startIsolate(isolate: Isolate) {
|
||||
var mainClass = util.fromJavaString(isolate.klass.classInfo.getField("I._mainClass.Ljava/lang/String;").get(isolate)).replace(/\./g, "/");
|
||||
var mainArgs = isolate.klass.classInfo.getField("I._mainArgs.[Ljava/lang/String;").get(isolate);
|
||||
var mainClass = util.fromJavaString(isolate.klass.classInfo.getFieldByName("I._mainClass.Ljava/lang/String;").get(isolate)).replace(/\./g, "/");
|
||||
var mainArgs = isolate.klass.classInfo.getFieldByName("I._mainArgs.[Ljava/lang/String;").get(isolate);
|
||||
var runtime = new J2ME.Runtime(this);
|
||||
var ctx = new Context(runtime);
|
||||
|
||||
|
|
|
@ -424,7 +424,7 @@ module J2ME {
|
|||
if (classInfo.mangledName) {
|
||||
return classInfo.mangledName;
|
||||
}
|
||||
return mangleClassName(classInfo.className);
|
||||
return mangleClassName(classInfo.getClassNameString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -854,7 +854,10 @@ module J2ME {
|
|||
release || assert(!runtimeKlass.classObject);
|
||||
runtimeKlass.classObject = <java.lang.Class><any>new Klasses.java.lang.Class();
|
||||
runtimeKlass.classObject.runtimeKlass = runtimeKlass;
|
||||
var fields = runtimeKlass.templateKlass.classInfo.fields;
|
||||
var fields = runtimeKlass.templateKlass.classInfo.getFields();
|
||||
if (!fields) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var field = fields[i];
|
||||
if (field.isStatic) {
|
||||
|
@ -1031,7 +1034,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;
|
||||
|
@ -1059,7 +1062,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) {
|
||||
|
@ -1306,7 +1309,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++) {
|
||||
|
@ -1338,8 +1341,11 @@ 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;
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
var methodInfo = methods[i];
|
||||
if (methodInfo.isAbstract) {
|
||||
|
@ -1468,9 +1474,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.getInterfaces();
|
||||
if (interfaceClassInfos) {
|
||||
for (var j = 0; j < interfaceClassInfos.length; j++) {
|
||||
ArrayUtilities.pushUnique(interfaces, getKlass(interfaceClassInfos[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1844,7 +1852,7 @@ module J2ME {
|
|||
}
|
||||
|
||||
export function classInitCheck(classInfo: ClassInfo, pc: number) {
|
||||
if (classInfo.isArrayClass) {
|
||||
if (classInfo instanceof ArrayClassInfo) {
|
||||
return;
|
||||
}
|
||||
$.ctx.pushClassInitFrame(classInfo);
|
||||
|
|
Загрузка…
Ссылка в новой задаче