pluotsorbet/classinfo.js

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

2014-07-13 20:12:57 +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';
2014-08-02 09:47:26 +04:00
var FieldInfo = (function() {
var idgen = 0;
return function(classInfo, access_flags, name, signature) {
this.classInfo = classInfo;
this.access_flags = access_flags;
this.name = name;
this.signature = signature;
this.id = idgen++;
}
})();
FieldInfo.prototype.get = function(obj) {
var value = obj[this.id];
if (typeof value === "undefined") {
value = util.defaultValue(this.signature);
}
return value;
}
FieldInfo.prototype.set = function(obj, value) {
obj[this.id] = value;
}
FieldInfo.prototype.toString = function() {
return "[field " + this.name + "]";
}
function MethodInfo(m, classInfo, constantPool) {
this.classInfo = classInfo;
this.access_flags = m.access_flags;
this.name = constantPool[m.name_index].bytes;
this.signature = constantPool[m.signature_index].bytes;
this.attributes = m.attributes;
this.attributes.forEach(function(a) {
if (a.info.type === ATTRIBUTE_TYPES.Code) {
this.code = new Uint8Array(a.info.code);
this.exception_table = a.info.exception_table;
this.max_locals = a.info.max_locals;
}
}, this);
this.isNative = ACCESS_FLAGS.isNative(this.access_flags);
this.isPublic = ACCESS_FLAGS.isPublic(this.access_flags);
this.isStatic = ACCESS_FLAGS.isStatic(this.access_flags);
this.isSynchronized = ACCESS_FLAGS.isSynchronized(this.access_flags);
this.alternateImpl = (this.isNative ? Native :
Override.hasMethod(this) ? Override :
null);
}
2014-07-13 20:12:57 +04:00
var ClassInfo = function(classBytes) {
2014-07-14 02:32:58 +04:00
var classImage = getClassImage(classBytes, this);
var cp = classImage.constant_pool;
this.className = cp[cp[classImage.this_class].name_index].bytes;
this.superClassName = classImage.super_class ? cp[cp[classImage.super_class].name_index].bytes : null;
this.access_flags = classImage.access_flags;
this.constant_pool = cp;
this.constructor = function () {
}
this.constructor.prototype.class = this;
this.constructor.prototype.toString = function() {
return "[instance " + this.class.className + "]";
}
2014-09-25 23:52:38 +04:00
// Cache for virtual methods and fields
this.vmc = {};
2014-09-25 23:52:38 +04:00
this.vfc = {};
2014-07-13 21:37:28 +04:00
2014-07-14 02:32:58 +04:00
var self = this;
2014-07-13 21:37:28 +04:00
2014-07-18 10:26:34 +04:00
this.interfaces = [];
classImage.interfaces.forEach(function(i) {
var int = CLASSES.loadClass(cp[cp[i].name_index].bytes);
self.interfaces.push(int);
self.interfaces = self.interfaces.concat(int.interfaces);
2014-07-18 10:26:34 +04:00
});
2014-07-14 02:32:58 +04:00
this.fields = [];
classImage.fields.forEach(function(f) {
2014-08-02 09:47:26 +04:00
var field = new FieldInfo(self, f.access_flags, cp[f.name_index].bytes, cp[f.descriptor_index].bytes);
f.attributes.forEach(function(attribute) {
if (cp[attribute.attribute_name_index].bytes === "ConstantValue")
field.constantValue = new DataView(attribute.info).getUint16(0, false);
});
self.fields.push(field);
2014-07-14 02:32:58 +04:00
});
2014-07-13 21:37:28 +04:00
2014-07-14 02:32:58 +04:00
this.methods = [];
classImage.methods.forEach(function(m) {
self.methods.push(new MethodInfo(m, self, cp));
2014-07-14 02:32:58 +04:00
});
2014-07-16 03:49:00 +04:00
var classes = this.classes = [];
2014-07-14 02:32:58 +04:00
classImage.attributes.forEach(function(a) {
if (a.info.type === ATTRIBUTE_TYPES.InnerClasses) {
a.info.classes.forEach(function(c) {
classes.push(cp[cp[c.inner_class_info_index].name_index].bytes);
2014-07-31 04:40:39 +04:00
if (c.outer_class_info_index)
classes.push(cp[cp[c.outer_class_info_index].name_index].bytes);
2014-07-14 02:32:58 +04:00
});
}
});
2014-07-13 20:12:57 +04:00
}
2014-07-14 04:02:57 +04:00
2014-07-18 10:44:06 +04:00
ClassInfo.prototype.implementsInterface = function(iface) {
2014-07-18 10:02:28 +04:00
var classInfo = this;
do {
2014-07-18 10:44:06 +04:00
var interfaces = classInfo.interfaces;
for (var n = 0; n < interfaces.length; ++n) {
if (interfaces[n] === iface)
return true;
}
2014-07-18 10:02:28 +04:00
classInfo = classInfo.superClass;
} while (classInfo);
return false;
}
ClassInfo.prototype.isAssignableTo = function(toClass) {
2014-07-21 04:10:12 +04:00
if (this === toClass || toClass === ClassInfo.java_lang_Object)
2014-07-18 10:44:06 +04:00
return true;
if (ACCESS_FLAGS.isInterface(toClass.access_flags) && this.implementsInterface(toClass))
return true;
if (this.elementClass && toClass.elementClass)
return this.elementClass.isAssignableTo(toClass.elementClass);
return this.superClass ? this.superClass.isAssignableTo(toClass) : false;
2014-07-18 10:44:06 +04:00
}
ClassInfo.prototype.getClassObject = function(ctx) {
var className = this.className;
var classObjects = ctx.runtime.classObjects;
var classObject = classObjects[className];
if (!classObject) {
classObject = ctx.newObject(CLASSES.java_lang_Class);
classObject.vmClass = this;
classObjects[className] = classObject;
}
return classObject;
2014-07-18 10:02:28 +04:00
}
ClassInfo.prototype.getField = function(fieldKey) {
return CLASSES.getField(this, fieldKey);
2014-08-02 09:47:26 +04:00
}
ClassInfo.prototype.toString = function() {
return "[class " + this.className + "]";
}
var ArrayClass = function(className, elementClass) {
2014-07-18 12:25:12 +04:00
this.className = className;
2014-07-14 04:02:57 +04:00
this.superClassName = "java/lang/Object";
this.access_flags = 0;
this.elementClass = elementClass;
2014-09-26 06:20:41 +04:00
this.vmc = {};
this.vfc = {};
2014-07-14 04:02:57 +04:00
}
2014-07-18 10:11:45 +04:00
2014-07-27 05:20:54 +04:00
ArrayClass.prototype.methods = [];
2014-07-18 10:11:45 +04:00
ArrayClass.prototype.isArrayClass = true;
ArrayClass.prototype.implementsInterface = function(iface) {
return false;
}
ArrayClass.prototype.isAssignableTo = ClassInfo.prototype.isAssignableTo;
ArrayClass.prototype.getClassObject = ClassInfo.prototype.getClassObject;