This commit is contained in:
Michael Bebenita 2015-02-27 17:37:08 -08:00
Родитель 8619727920
Коммит d61ee78b38
19 изменённых файлов: 1424 добавлений и 6473 удалений

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]) {

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

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

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

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

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

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

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

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

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

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

@ -179,8 +179,8 @@ module J2ME {
}
if (emitter.definitions) {
emitFields(classInfo.fields, false);
emitFields(classInfo.fields, true);
emitFields(classInfo.getFields(), false);
emitFields(classInfo.getFields(), true);
return;
}
@ -192,15 +192,15 @@ module J2ME {
// writer.writeLn("this._hashCode = $.nextHashCode(this);");
writer.writeLn("this._hashCode = 0;");
getClassInheritanceChain(classInfo).forEach(function (ci) {
emitFields(ci.fields, false);
emitFields(ci.getFields(), false);
});
writer.leave("}");
// Emit class static initializer if it has any static fields. We don't emit this for now
// since it probably doesn't pay off to emit code that only gets executed once.
if (false && classInfo.fields.some(f => f.isStatic)) {
if (false && classInfo.getFields().some(f => f.isStatic)) {
writer.enter(mangledClassName + ".staticInitializer = function() {");
emitFields(classInfo.fields, true);
emitFields(classInfo.getFields(), true);
writer.leave("}");
}
@ -268,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) {

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

@ -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,7 +99,7 @@ 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",
"midp/midp.js", "midp/gestures.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
Просмотреть файл

@ -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);