зеркало из https://github.com/mozilla/pluotsorbet.git
Clean up name mangling and use a better string hashing function.
This commit is contained in:
Родитель
bd748126d7
Коммит
d0d6c9e472
35
actors.ts
35
actors.ts
|
@ -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));
|
||||
}
|
||||
|
|
78
runtime.ts
78
runtime.ts
|
@ -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 ++;
|
||||
|
||||
|
|
28
utilities.ts
28
utilities.ts
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче