pluotsorbet/classes.js

187 строки
5.8 KiB
JavaScript
Исходник Обычный вид История

2014-07-06 12:29:36 +04:00
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
'use strict';
var Classes = function() {
if (this instanceof Classes) {
this.classfiles = [];
this.mainclass = [];
this.classes = {};
} else {
return new Classes();
}
}
Classes.prototype.addPath = function(name, data) {
if (name.substr(-4) === ".jar") {
data = new ZipFile(data);
}
this.classfiles[name] = data;
}
Classes.prototype.loadFile = function(fileName) {
2014-07-06 13:03:36 +04:00
var classfiles = this.classfiles;
var data = classfiles[fileName];
2014-07-06 12:29:36 +04:00
if (data)
return data;
2014-07-06 13:03:36 +04:00
Object.keys(classfiles).every(function (name) {
2014-07-06 12:29:36 +04:00
if (name.substr(-4) !== ".jar")
return true;
2014-07-06 13:03:36 +04:00
var zip = classfiles[name];
if (fileName in zip.directory) {
var bytes = zip.read(fileName);
data = bytes.buffer.slice(0, bytes.length);
}
return !data;
2014-07-06 12:29:36 +04:00
});
2014-07-06 13:03:36 +04:00
classfiles[fileName] = data;
2014-07-06 12:29:36 +04:00
return data;
}
Classes.prototype.loadClassBytes = function(bytes) {
2014-07-13 03:42:01 +04:00
var classInfo = new ClassInfo(bytes);
this.classes[classInfo.className] = classInfo;
2014-07-13 03:42:01 +04:00
return classInfo;
2014-07-06 12:29:36 +04:00
}
Classes.prototype.loadClassFile = function(fileName) {
2014-07-15 11:30:45 +04:00
console.info("loading " + fileName + " ...");
2014-07-06 12:29:36 +04:00
var bytes = this.loadFile(fileName);
if (!bytes)
return null;
2014-07-13 03:42:01 +04:00
var classInfo = this.loadClassBytes(bytes);
var classes = classInfo.classes;
if (classInfo.superClassName)
classInfo.superClass = this.getClass(classInfo.superClassName);
classInfo.classes.map(function (c) {
return this.getClass(fileName.replace(/[^/]*\.class$/, "") + "/" + c);
});
2014-07-13 03:42:01 +04:00
return classInfo;
2014-07-06 12:29:36 +04:00
}
2014-07-17 12:14:18 +04:00
Classes.prototype.getEntryPoint = function(classInfo) {
if (ACCESS_FLAGS.isPublic(classInfo.access_flags)) {
var methods = classInfo.methods;
for (var i=0; i<methods.length; i++) {
if (ACCESS_FLAGS.isPublic(methods[i].access_flags) &&
ACCESS_FLAGS.isStatic(methods[i].access_flags) &&
!ACCESS_FLAGS.isNative(methods[i].access_flags) &&
methods[i].name === "main" &&
methods[i].signature === "([Ljava/lang/String;)V") {
return methods[i];
2014-07-06 12:29:36 +04:00
}
}
2014-07-12 20:48:05 +04:00
}
2014-07-06 12:29:36 +04:00
}
Classes.prototype.initClass = function(classInfo) {
2014-07-17 12:37:35 +04:00
if (classInfo.staticFields)
return;
if (classInfo.superClassName)
this.getClass(classInfo.superClassName, true);
2014-07-17 12:37:35 +04:00
classInfo.staticFields = {};
var clinit = this.getMethod(classInfo, "<clinit>", "()V", true, false);
if (clinit) {
2014-07-18 04:39:25 +04:00
VM.invoke(clinit);
}
2014-07-17 09:45:10 +04:00
classInfo.constructor = function () {
}
classInfo.constructor.prototype.class = classInfo;
}
Classes.prototype.getClass = function(className, init) {
2014-07-13 03:42:01 +04:00
var classInfo = this.classes[className];
2014-07-17 12:37:35 +04:00
if (!classInfo) {
if (className[0] === "[") {
2014-07-17 22:21:00 +04:00
return this.classes[className] = this.getArrayClass(className);
2014-07-17 12:37:35 +04:00
}
classInfo = this.loadClassFile(className + ".class");
if (!classInfo)
return null;
2014-07-09 11:12:58 +04:00
}
2014-07-17 12:37:35 +04:00
if (init)
this.initClass(classInfo);
2014-07-17 12:37:35 +04:00
return classInfo;
2014-07-06 12:29:36 +04:00
};
2014-07-17 22:21:00 +04:00
Classes.prototype.getArrayClass = function(typeName) {
2014-07-14 03:31:36 +04:00
var elementType = typeName.substr(1);
2014-07-14 04:36:47 +04:00
if (elementType in ARRAY_TYPE)
return this.initPrimitiveArrayType(elementType, ARRAY_TYPE[elementType]);
2014-07-14 04:02:57 +04:00
var classInfo = new ArrayClass(elementType);
classInfo.constructor = function (size) {
var array = new Array(size);
array.class = classInfo;
return array;
}
return classInfo;
2014-07-14 03:31:36 +04:00
}
2014-07-14 04:02:57 +04:00
Classes.prototype.initPrimitiveArrayType = function(elementType, constructor) {
var classInfo = new ArrayClass(elementType);
constructor.prototype.class = classInfo;
classInfo.constructor = constructor;
return classInfo;
2014-07-14 03:31:36 +04:00
}
Classes.prototype.getStaticField = function(className, fieldName) {
return this.getClass(className, true).staticFields[fieldName];
2014-07-06 12:29:36 +04:00
}
Classes.prototype.setStaticField = function(className, fieldName, value) {
this.getClass(className, true).staticFields[fieldName] = value;
2014-07-06 12:29:36 +04:00
}
Classes.prototype.getMethod = function(classInfo, methodName, signature, staticFlag, inheritFlag) {
while (true) {
var methods = classInfo.methods;
for (var i=0; i<methods.length; i++) {
if (ACCESS_FLAGS.isStatic(methods[i].access_flags) === !!staticFlag) {
if (methods[i].name === methodName && methods[i].signature === signature) {
return methods[i];
}
2014-07-10 09:23:17 +04:00
}
2014-07-06 12:29:36 +04:00
}
var superClassName = classInfo.superClassName;
if (!superClassName)
return null;
classInfo = this.getClass(superClassName);
2014-07-06 12:29:36 +04:00
}
};
Classes.prototype.newObject = function(className) {
return new (this.getClass(className, true).constructor)();
2014-07-09 12:28:03 +04:00
}
2014-07-16 18:59:37 +04:00
Classes.prototype.newPrimitiveArray = function(constructor, size) {
2014-07-14 04:36:47 +04:00
return constructor.call(null, size);
2014-07-06 12:29:36 +04:00
}
2014-07-09 12:28:03 +04:00
Classes.prototype.newArray = function(typeName, size) {
2014-07-17 22:21:00 +04:00
return this.getArrayClass(typeName).constructor.call(null, size);
2014-07-16 18:59:37 +04:00
}
Classes.prototype.newMultiArray = function(typeName, lengths) {
2014-07-16 19:25:57 +04:00
var length = lengths[0];
var array = this.newArray(caller, typeName, length);
if (lengths.length > 0) {
lengths = lengths.slice(1);
for (var i=0; i<length; i++)
array[i] = this.newMultiArray(typeName.substr(1), lengths);
2014-07-16 19:25:57 +04:00
}
return array;
}
Classes.prototype.newString = function(s) {
var obj = this.newObject("java/lang/String");
2014-07-09 12:28:03 +04:00
var length = s.length;
2014-07-16 18:59:37 +04:00
var chars = this.newPrimitiveArray(Uint16Array, length);
2014-07-09 12:28:03 +04:00
for (var n = 0; n < length; ++n)
chars[n] = s.charCodeAt(n);
obj.value = chars;
obj.offset = 0;
obj.count = length;
return obj;
2014-07-12 20:48:05 +04:00
}