Clean up name mangling and use a better string hashing function.

This commit is contained in:
Michael Bebenita 2015-01-22 01:43:49 -08:00
Родитель bd748126d7
Коммит d0d6c9e472
5 изменённых файлов: 111 добавлений и 73 удалений

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

@ -287,6 +287,7 @@ module J2ME {
static createFromObject(object) {
var classInfo = Object.create(ClassInfo.prototype, object);
classInfo.resolved_constant_pool = new Array(classInfo.constant_pool.length);
classInfo.mangledName = mangleClass(classInfo);
return classInfo;
}
@ -389,16 +390,6 @@ module J2ME {
}
private _mangleFields() {
if (false) {
// Safe mangling that includes className, fieldName and signature.
var fields = this.fields;
for (var j = 0; j < fields.length; j++) {
var fieldInfo = fields[j];
fieldInfo.mangledName = "$" + escapeString(fieldInfo.classInfo.className + "_" + fieldInfo.name + "_" + fieldInfo.signature);
}
return;
}
// Keep track of how many times a field name was used and resolve conflicts by
// prefixing filed names with numbers.
var classInfo: ClassInfo;
@ -546,11 +537,11 @@ module J2ME {
}
export class ArrayClassInfo extends ClassInfo {
constructor(className: string, elementClass?) {
constructor(className: string, elementClass: ClassInfo, mangledName?: string) {
false && super(null);
this.className = className;
// TODO this may need to change for compiled code.
this.mangledName = className;
this.mangledName = mangledName;
this.superClass = CLASSES.java_lang_Object;
this.superClassName = "java/lang/Object";
this.access_flags = 0;
@ -589,22 +580,22 @@ module J2ME {
PrimitiveClassInfo.prototype.interfaces = [];
export class PrimitiveArrayClassInfo extends ArrayClassInfo {
constructor(className: string, elementClass?) {
super(className, elementClass);
constructor(className: string, elementClass: ClassInfo, mangledName: string) {
super(className, elementClass, mangledName);
}
get superClass() {
return CLASSES.java_lang_Object;
}
static Z = new PrimitiveArrayClassInfo("[Z", PrimitiveClassInfo.Z);
static C = new PrimitiveArrayClassInfo("[C", PrimitiveClassInfo.C);
static F = new PrimitiveArrayClassInfo("[F", PrimitiveClassInfo.F);
static D = new PrimitiveArrayClassInfo("[D", PrimitiveClassInfo.D);
static B = new PrimitiveArrayClassInfo("[B", PrimitiveClassInfo.B);
static S = new PrimitiveArrayClassInfo("[S", PrimitiveClassInfo.S);
static I = new PrimitiveArrayClassInfo("[I", PrimitiveClassInfo.I);
static J = new PrimitiveArrayClassInfo("[J", PrimitiveClassInfo.J);
static Z = new PrimitiveArrayClassInfo("[Z", PrimitiveClassInfo.Z, "Uint8Array");
static C = new PrimitiveArrayClassInfo("[C", PrimitiveClassInfo.C, "Uint16Array");
static F = new PrimitiveArrayClassInfo("[F", PrimitiveClassInfo.F, "Float32Array");
static D = new PrimitiveArrayClassInfo("[D", PrimitiveClassInfo.D, "Float64Array");
static B = new PrimitiveArrayClassInfo("[B", PrimitiveClassInfo.B, "Int8Array");
static S = new PrimitiveArrayClassInfo("[S", PrimitiveClassInfo.S, "Int16Array");
static I = new PrimitiveArrayClassInfo("[I", PrimitiveClassInfo.I, "Int32Array");
static J = new PrimitiveArrayClassInfo("[J", PrimitiveClassInfo.J, "Int64Array");
}
PrimitiveClassInfo.prototype.fields = [];

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

@ -169,6 +169,17 @@ module J2ME {
return "Long.fromInt(" + v + ")";
}
function classConstant(classInfo: ClassInfo): string {
if (classInfo.mangledName) {
return classInfo.mangledName;
}
if (classInfo.isArrayClass) {
return "$AK(" + classConstant(classInfo.elementClass) + ")";
}
release || assert(classInfo.mangledName);
return classInfo.mangledName;
}
export class BaselineCompiler {
sp: number;
pc: number;
@ -308,7 +319,7 @@ module J2ME {
if (classInfo.isInterface) {
check = "$IOI";
}
check += "(" + this.peek(Kind.Reference) + ", " + mangleClass(classInfo) + ")";
check += "(" + this.peek(Kind.Reference) + ", " + classConstant(classInfo) + ")";
check = " && " + check;
}
this.emitter.enter("if (pc >= " + handler.start_pc + " && pc < " + handler.end_pc + check + ") {");
@ -591,11 +602,11 @@ module J2ME {
}
runtimeClass(classInfo: ClassInfo) {
return "$." + mangleClass(classInfo);
return "$." + classConstant(classInfo);
}
runtimeClassObject(classInfo: ClassInfo) {
return "$." + mangleClass(classInfo) + ".classObject";
return "$." + classConstant(classInfo) + ".classObject";
}
emitClassInitializationCheck(classInfo: ClassInfo) {
@ -650,12 +661,12 @@ module J2ME {
object = this.pop(Kind.Reference);
if (opcode === Bytecodes.INVOKESPECIAL) {
args.unshift(object);
call = mangleClassAndMethod(methodInfo) + ".call(" + args.join(", ") + ")";
call = methodInfo.mangledClassAndMethodName + ".call(" + args.join(", ") + ")";
} else {
call = object + "." + mangleMethod(methodInfo) + "(" + args.join(", ") + ")";
call = object + "." + methodInfo.mangledName + "(" + args.join(", ") + ")";
}
} else {
call = mangleClassAndMethod(methodInfo) + "(" + args.join(", ") + ")";
call = methodInfo.mangledClassAndMethodName + "(" + args.join(", ") + ")";
}
if (methodInfo.implKey in inlineMethods) {
emitDebugInfoComments && this.emitter.writeLn("// Inlining: " + methodInfo.implKey);
@ -733,7 +744,7 @@ module J2ME {
emitNewInstance(cpi: number) {
var classInfo = this.lookupClass(cpi);
this.emitClassInitializationCheck(classInfo);
this.emitPush(Kind.Reference, "new " + mangleClass(classInfo)+ "()");
this.emitPush(Kind.Reference, "new " + classConstant(classInfo)+ "()");
}
emitNewTypeArray(typeCode: number) {
@ -749,7 +760,7 @@ module J2ME {
if (classInfo.isInterface) {
call = "$CCI";
}
this.emitter.writeLn(call + "(" + object + ", " + mangleClass(classInfo) + ");");
this.emitter.writeLn(call + "(" + object + ", " + classConstant(classInfo) + ");");
}
emitInstanceOf(cpi: number) {
@ -759,7 +770,7 @@ module J2ME {
if (classInfo.isInterface) {
call = "$IOI";
}
this.emitPush(Kind.Int, call + "(" + object + ", " + mangleClass(classInfo) + ") | 0");
this.emitPush(Kind.Int, call + "(" + object + ", " + classConstant(classInfo) + ") | 0");
}
emitArrayLength() {
@ -770,7 +781,7 @@ module J2ME {
var classInfo = this.lookupClass(cpi);
this.emitClassInitializationCheck(classInfo);
var length = this.pop(Kind.Int);
this.emitPush(Kind.Reference, "$NA(" + mangleClass(classInfo) + ", " + length + ")");
this.emitPush(Kind.Reference, "$NA(" + classConstant(classInfo) + ", " + length + ")");
}
emitUnwind(pc: number, nextPC: number) {

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

@ -142,7 +142,7 @@ module J2ME {
export function emitKlass(emitter: Emitter, classInfo: ClassInfo) {
var writer = emitter.writer;
var mangledClassName = mangleClass(classInfo);
var mangledClassName = classInfo.mangledName;
if (emitter.closure) {
writer.writeLn("/** @constructor */");
}
@ -227,7 +227,7 @@ module J2ME {
});
}
var mangledClassName = mangleClass(classInfo);
var mangledClassName = classInfo.mangledName;
emitter.writer.writeLn(mangledClassName + ".classSymbols = [" + referencedClasses.map(classInfo => {
return quote(classInfo.className);
@ -240,7 +240,7 @@ module J2ME {
methodFilter: (methodInfo: MethodInfo) => boolean,
ctx: Context): CompiledMethodInfo [] {
var writer = emitter.writer;
var mangledClassName = mangleClass(classInfo);
var mangledClassName = classInfo.mangledName;
if (!isIdentifierName(mangledClassName)) {
mangledClassName = quote(mangledClassName);
}
@ -276,7 +276,7 @@ module J2ME {
if (!methodFilter(method)) {
continue;
}
var mangledMethodName = mangleMethod(method);
var mangledMethodName = method.mangledName;
if (!isIdentifierName(mangledMethodName)) {
mangledMethodName = quote(mangledMethodName);
}
@ -285,7 +285,7 @@ module J2ME {
continue;
}
try {
var mangledClassAndMethodName = mangleClassAndMethod(method);
var mangledClassAndMethodName = method.mangledClassAndMethodName;
if (emitter.debugInfo) {
writer.writeLn("// " + method.implKey + " (" + mangledClassAndMethodName + ") " + method.getSourceLocationForPC(0));
}

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

@ -226,6 +226,8 @@ module J2ME {
declare var util;
import assert = J2ME.Debug.assert;
import concat3 = StringUtilities.concat3;
import concat5 = StringUtilities.concat5;
export enum RuntimeStatus {
New = 1,
@ -240,7 +242,10 @@ module J2ME {
Compiled
}
var hashMap = Object.create(null);
var hashArray = new Int32Array(1024);
function hashString(s: string) {
if (hashArray.length < s.length) {
hashArray = new Int32Array((hashArray.length * 2 / 3) | 0);
@ -249,10 +254,18 @@ module J2ME {
for (var i = 0; i < s.length; i++) {
data[i] = s.charCodeAt(i);
}
return HashUtilities.hashBytesTo32BitsAdler(data, 0, s.length);
var hash = HashUtilities.hashBytesTo32BitsMurmur(data, 0, s.length);
if (!release) { // Check to see that no collisions have ever happened.
if (hashMap[hash] && hashMap[hash] !== s) {
assert(false, "This is very bad.")
}
hashMap[hash] = s;
}
var friendlyMangledNames = true;
return hash;
}
function isIdentifierChar(c: number): boolean {
@ -318,58 +331,55 @@ module J2ME {
var stringHashes = Object.create(null);
var stringHashCount = 0;
function hashStringStrong(s): string {
// Hash with Murmur hash.
var result = StringUtilities.variableLengthEncodeInt32(hashString(s));
// Also use the length for some more precision.
result += StringUtilities.toEncoding(s.length & 0x3f);
return result;
}
export function hashStringToString(s: string) {
if (stringHashCount > 1024) {
return StringUtilities.variableLengthEncodeInt32(hashString(s));
return hashStringStrong(s);
}
var c = stringHashes[s];
if (c) {
return c;
}
c = stringHashes[s] = StringUtilities.variableLengthEncodeInt32(hashString(s));
c = stringHashes[s] = hashStringStrong(s);
stringHashCount ++;
return c;
}
export function mangleClassAndMethod(methodInfo: MethodInfo) {
var name = methodInfo.classInfo.className + "_" + methodInfo.name + "_" + hashStringToString(methodInfo.signature);
var name = concat5(methodInfo.classInfo.className, "_", methodInfo.name, "_", hashStringToString(methodInfo.signature));
if (friendlyMangledNames) {
return escapeString(name);
}
var hash = hashString(name);
return StringUtilities.variableLengthEncodeInt32(hash);
return hashStringToString(name);
}
export function mangleMethod(methodInfo: MethodInfo) {
var name = methodInfo.name + "_" + hashStringToString(methodInfo.signature);
var name = concat3(methodInfo.name, "_", hashStringToString(methodInfo.signature));
if (friendlyMangledNames) {
return escapeString(name);
}
var hash = hashString(name);
return StringUtilities.variableLengthEncodeInt32(hash);
return "$" + hashStringToString(name);
}
export function mangleClassName(name: string): string {
if (friendlyMangledNames) {
return "$" + escapeString(name);
}
return "$" + hashStringToString(name);
}
export function mangleClass(classInfo: ClassInfo) {
if (classInfo instanceof PrimitiveArrayClassInfo) {
switch (classInfo) {
case PrimitiveArrayClassInfo.Z: return "Uint8Array";
case PrimitiveArrayClassInfo.C: return "Uint16Array";
case PrimitiveArrayClassInfo.F: return "Float32Array";
case PrimitiveArrayClassInfo.D: return "Float64Array";
case PrimitiveArrayClassInfo.B: return "Int8Array";
case PrimitiveArrayClassInfo.S: return "Int16Array";
case PrimitiveArrayClassInfo.I: return "Int32Array";
case PrimitiveArrayClassInfo.J: return "Int64Array";
}
} else if (classInfo.isArrayClass) {
return "$AK(" + mangleClass(classInfo.elementClass) + ")";
} else {
if (friendlyMangledNames) {
return "$" + escapeString(classInfo.className);
}
var hash = hashString(classInfo.className);
return "$" + StringUtilities.variableLengthEncodeInt32(hash);
if (classInfo.mangledName) {
return classInfo.mangledName;
}
return mangleClassName(classInfo.className);
}
/**
@ -892,7 +902,7 @@ module J2ME {
export function registerKlassSymbol(className: string) {
// TODO: This needs to be kept in sync to how mangleClass works.
var mangledName = "$" + escapeString(className);
var mangledName = mangleClassName(className);
if (RuntimeTemplate.prototype.hasOwnProperty(mangledName)) {
return;
}
@ -1025,7 +1035,7 @@ module J2ME {
function makeKlassConstructor(classInfo: ClassInfo): Klass {
var klass: Klass;
var mangledName = mangleClass(classInfo);
var mangledName = classInfo.mangledName;
if (classInfo.isInterface) {
klass = <Klass><any>function () {
Debug.unexpected("Should never be instantiated.")
@ -1085,7 +1095,7 @@ module J2ME {
return;
}
enterTimeline("linkKlass", {classInfo: classInfo});
var mangledName = mangleClass(classInfo);
var mangledName = classInfo.mangledName;
var klass;
classInfo.klass = klass = getKlass(classInfo);
classInfo.klass.classInfo = classInfo;
@ -1235,9 +1245,7 @@ module J2ME {
}
function findCompiledMethod(klass: Klass, methodInfo: MethodInfo): Function {
var name = methodInfo.mangledClassAndMethodName;
var method = jsGlobal[name];
return method;
return jsGlobal[methodInfo.mangledClassAndMethodName];
}
/**
@ -1446,7 +1454,7 @@ module J2ME {
return;
}
var mangledClassAndMethodName = mangleClassAndMethod(methodInfo);
var mangledClassAndMethodName = methodInfo.mangledClassAndMethodName;
compiledCount ++;

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

@ -965,6 +965,34 @@ module J2ME {
}
export module HashUtilities {
// https://github.com/garycourt/murmurhash-js
export function hashBytesTo32BitsMurmur(data: Uint8Array, offset: number, length: number) {
var l = length, h = 0x12345678 ^ l, i = offset, k;
while (l >= 4) {
k =
(data[i]) |
(data[++i] << 8) |
(data[++i] << 16) |
(data[++i] << 24);
k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
k ^= k >>> 24;
k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
l -= 4;
++i;
}
switch (l) {
case 3: h ^= data[i + 2] << 16;
case 2: h ^= data[i + 1] << 8;
case 1: h ^= data[i];
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
}
h ^= h >>> 13;
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
h ^= h >>> 15;
return h >>> 0;
}
export function hashBytesTo32BitsAdler(data: Uint8Array, offset: number, length: number): number {
var a = 1;
var b = 0;