primary support for arrays and bytecode interpret is at letter D
This commit is contained in:
parent
edb0b77a61
commit
2d6305c1bc
86
class.js
86
class.js
@ -52,7 +52,58 @@ var log = function (msg){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ClassDefinition = function (file,jvm){
|
var ClassDefinition = function(jvm) {
|
||||||
|
this.jvm = jvm;
|
||||||
|
};
|
||||||
|
|
||||||
|
// bad bad code! This shouldn't be done this way!
|
||||||
|
ClassDefinition.prototype.makeForArray = function(arrayDef){
|
||||||
|
this.magic = 0xCAFEBABE;
|
||||||
|
this.minorVersion = 0;
|
||||||
|
this.majorVersion = 50;
|
||||||
|
this.constantPool = [];
|
||||||
|
this.access_flags = 0;
|
||||||
|
this.this_class = {id:CONSTANT_Class, name_ref:{str:arrayDef}};
|
||||||
|
this.super_class = null;
|
||||||
|
this.interface_count = 0;
|
||||||
|
this.interfaces = [];
|
||||||
|
this.fields_count = 0;
|
||||||
|
this.fields = [];
|
||||||
|
this.methods_count = 1;
|
||||||
|
this.methods = [
|
||||||
|
{
|
||||||
|
access_flags:0,
|
||||||
|
name_ref: {str:"clone"},
|
||||||
|
descriptor_ref: {str: "()Ljava.lang.Object;"},
|
||||||
|
attributes_count:0,
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ClassDefinition.prototype.isArrayClass = function (){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extra info:
|
||||||
|
this.dimensions = 0;
|
||||||
|
var i=0;
|
||||||
|
for (i=0; i<arrayDef.length; i++){
|
||||||
|
if (arrayDef.charAt(i) == "["){
|
||||||
|
this.dimensions += 1;
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.arrayType = arrayDef.substr(1,arrayDef.length);
|
||||||
|
if (this.arrayType.charAt(0) == "L"){
|
||||||
|
this.arrayTypeClass = arrayDef.substr(i+1,arrayDef.length-1);
|
||||||
|
this.jvm.classForName(this.arrayTypeDef);
|
||||||
|
}else{
|
||||||
|
this.arrayTypeClass = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassDefinition.prototype.loadFromFile = function (file){
|
||||||
var dataStream = new DataStream(slurpFile(file)[1]);
|
var dataStream = new DataStream(slurpFile(file)[1]);
|
||||||
this.magic = dataStream.getU4();
|
this.magic = dataStream.getU4();
|
||||||
if (this.magic != 0xCAFEBABE){
|
if (this.magic != 0xCAFEBABE){
|
||||||
@ -63,7 +114,8 @@ var ClassDefinition = function (file,jvm){
|
|||||||
if (this.majorVersion > 50 || this.majorVersion < 45){
|
if (this.majorVersion > 50 || this.majorVersion < 45){
|
||||||
throw "Unsuported java class file format version";
|
throw "Unsuported java class file format version";
|
||||||
}
|
}
|
||||||
this.constantPool = new ConstantPool(dataStream);
|
this.constantPool = new ConstantPool();
|
||||||
|
this.constantPool.loadFromStream(dataStream);
|
||||||
this.access_flags = dataStream.getU2();
|
this.access_flags = dataStream.getU2();
|
||||||
|
|
||||||
this.this_class = ConstantPoolRef(dataStream.getU2(), this.constantPool, CONSTANT_Class);
|
this.this_class = ConstantPoolRef(dataStream.getU2(), this.constantPool, CONSTANT_Class);
|
||||||
@ -93,9 +145,14 @@ var ClassDefinition = function (file,jvm){
|
|||||||
this.methods[i] = new MethodInfo(dataStream, this.constantPool);
|
this.methods[i] = new MethodInfo(dataStream, this.constantPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.attributes_count = dataStream.getU2();
|
||||||
|
this.attributes = [];
|
||||||
|
for (var i=0; i<this.attributes_count; i++){
|
||||||
|
this.attributes[i] = Attribute(dataStream,this.constantPool);
|
||||||
|
}
|
||||||
|
|
||||||
// Post added info;
|
// Post added info;
|
||||||
this.jvm = jvm;
|
this.className = this.this_class.name_ref.str.replace(/\//g,".");
|
||||||
this className = this.this_class.name_ref.str.replace(/\//g,".");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassDefinition.prototype.isInterface = function () {
|
ClassDefinition.prototype.isInterface = function () {
|
||||||
@ -118,7 +175,16 @@ ClassDefinition.prototype.isAssignable = function (T) {
|
|||||||
if (T.isInterface()){
|
if (T.isInterface()){
|
||||||
return (T == this.jvm.java_lang_cloneable || T == this.jvm.java_io_serializable);
|
return (T == this.jvm.java_lang_cloneable || T == this.jvm.java_io_serializable);
|
||||||
}else if (T.isArrayClass()){
|
}else if (T.isArrayClass()){
|
||||||
|
if (T.arrayType.charAt(i) == this.arrayType.charAt(i) && (this.arrayType.charAt(i) == "L" || this.arrayType.charAt(i) == "[")){
|
||||||
|
return this.jvm.classForName(this.arrayType).isAssignable(T.arrayType);
|
||||||
|
}else{
|
||||||
|
// VER: check if elements are primitive.
|
||||||
|
if (T.arrayType.charAt(i) == this.arrayType.charAt(i)){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
return T == this.jvm.java_lang_object;
|
return T == this.jvm.java_lang_object;
|
||||||
}
|
}
|
||||||
@ -157,7 +223,15 @@ ClassDefinition.prototype.isInterfaceOrSuperInterface = function(I){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LoadClassFile (x,jvm){
|
function LoadClassFile (x,jvm){
|
||||||
return new ClassDefinition(x,jvm);
|
var def = new ClassDefinition(jvm);
|
||||||
|
if (x.charAt(0) != "[" ){
|
||||||
|
def.loadFromFile(x);
|
||||||
|
}else{
|
||||||
|
def.makeForArray(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,34 +40,7 @@ var constUtf8 = function(){
|
|||||||
}else{
|
}else{
|
||||||
result = byte_x
|
result = byte_x
|
||||||
}
|
}
|
||||||
strBuf += String.fromCharCode(byte_x);
|
strBuf += String.fromCharCode(byte_x);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
if ((one_byte >> 7) == 1) {
|
|
||||||
var tmp;
|
|
||||||
|
|
||||||
// its a multi-byte character
|
|
||||||
tmp = (one_byte & 0x3f); // Bits 5..0 (six bits)
|
|
||||||
// read the next byte
|
|
||||||
one_byte = dStream.getU1();
|
|
||||||
charCnt++;
|
|
||||||
tmp = (tmp | ((one_byte & 0x3f) << 6));
|
|
||||||
if ((one_byte >> 6) == 0x2) {
|
|
||||||
// We have 12 bits so far, get bits 15..12
|
|
||||||
one_byte = dStream .getU1();
|
|
||||||
charCnt++;
|
|
||||||
one_byte = (one_byte & 0xf);
|
|
||||||
tmp = (tmp | (one_byte << 12));
|
|
||||||
}
|
|
||||||
one_char = tmp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
one_char = one_byte;
|
|
||||||
}
|
|
||||||
strBuf += String.fromCharCode(one_char);
|
|
||||||
*/
|
|
||||||
} // while
|
} // while
|
||||||
this.str = strBuf.toString();
|
this.str = strBuf.toString();
|
||||||
} // read
|
} // read
|
||||||
@ -300,7 +273,10 @@ var ConstantPoolRef = function(index, constantPool, expected){
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConstantPool = function(dStream){
|
var ConstantPool = function(){
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantPool.prototype.loadFromStream = function(dStream){
|
||||||
this.constantPoolCount = dStream.getU2();
|
this.constantPoolCount = dStream.getU2();
|
||||||
this.constantPool = [];
|
this.constantPool = [];
|
||||||
for(var i = 1; i < this.constantPoolCount; i++){
|
for(var i = 1; i < this.constantPoolCount; i++){
|
||||||
@ -328,4 +304,8 @@ var ConstantPool = function(dStream){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantPool.prototype.get = function (i){
|
||||||
|
return this.constantPoll[i];
|
||||||
}
|
}
|
117
cpu.js
117
cpu.js
@ -12,27 +12,26 @@ var JVM = function(params,args){
|
|||||||
|
|
||||||
this.classForName = function (name){
|
this.classForName = function (name){
|
||||||
var superClass, loaded_class = this.method_area[name];
|
var superClass, loaded_class = this.method_area[name];
|
||||||
|
|
||||||
if (!loaded_class){
|
if (!loaded_class){
|
||||||
loaded_class = LoadClassFile(name, this);
|
loaded_class = LoadClassFile(name, this);
|
||||||
this.method_area[className] = loaded_class;
|
this.method_area[name] = loaded_class;
|
||||||
this.verifyAndLoadClass(loaded_class);
|
this.verifyAndLoadClass(loaded_class);
|
||||||
|
|
||||||
log("[Loaded " + className + " from runtime/" + classFile + "]");
|
log("[Loaded " + name + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
return loaded_class;
|
return loaded_class;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.verifyAndLoadClass = function(classFile){
|
this.verifyAndLoadClass = function(loaded_class){
|
||||||
var superClass;
|
var superClass;
|
||||||
if(loaded_class.super_class){
|
if(loaded_class.super_class){
|
||||||
|
// if super_class not java.lang.Object
|
||||||
superClass = canonicalName(loaded_class.super_class.name_ref);
|
superClass = canonicalName(loaded_class.super_class.name_ref);
|
||||||
}else{
|
this.classForName(superClass);
|
||||||
superClass = "java.lang.Object";
|
|
||||||
}
|
}
|
||||||
this.classForName(superClass);
|
|
||||||
|
|
||||||
// this doesn't seem right. doing this will cause the entire JRE to be loaded
|
// this doesn't seem right. doing this will cause the entire JRE to be loaded
|
||||||
// as soon as you start JVM.
|
// as soon as you start JVM.
|
||||||
@ -52,7 +51,6 @@ var JVM = function(params,args){
|
|||||||
this.java_lang_object = this.classForName("java.lang.Object");
|
this.java_lang_object = this.classForName("java.lang.Object");
|
||||||
this.java_lang_cloneable = this.classForName("java.lang.Cloneable");
|
this.java_lang_cloneable = this.classForName("java.lang.Cloneable");
|
||||||
this.java_io_serializable = this.classForName("java.io.Serializable");
|
this.java_io_serializable = this.classForName("java.io.Serializable");
|
||||||
|
|
||||||
var mainClass = this.args[0];
|
var mainClass = this.args[0];
|
||||||
this.classForName(mainClass);
|
this.classForName(mainClass);
|
||||||
};
|
};
|
||||||
@ -73,8 +71,10 @@ function JVM_THROWS_NEW(exception){
|
|||||||
throw "VER: throws new " + exception;
|
throw "VER: throws new " + exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
function (frame){
|
function interpret(frame){
|
||||||
var operand_stack = frame.operand_stack;
|
var operand_stack = frame.operand_stack;
|
||||||
|
var local_variables = frame.local_variables;
|
||||||
|
var code = 0; //resolve code from method;
|
||||||
|
|
||||||
switch(opcode){
|
switch(opcode){
|
||||||
case 0x32: // aaload
|
case 0x32: // aaload
|
||||||
@ -101,12 +101,105 @@ function (frame){
|
|||||||
if (index >= arrayref.length){
|
if (index >= arrayref.length){
|
||||||
JVM_THROWS_NEW("java.lang.ArrayIndexOutOfBoundsException");
|
JVM_THROWS_NEW("java.lang.ArrayIndexOutOfBoundsException");
|
||||||
}
|
}
|
||||||
|
if (!arrayref.classRef.isAssignable(value.cl)){
|
||||||
if (value.ref_of == REF_TYPE_class){
|
JVM_THROWS_NEW("java.lang.ArrayStoreException");
|
||||||
if (isSubClass(value.ref_of,arrayref.of));
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1: //aconst_null
|
||||||
|
operand_stack.push(null);
|
||||||
|
break;
|
||||||
|
case 0x19: //aload
|
||||||
|
var i = operand_stack.pop();
|
||||||
|
operand_stack.push(local_variables[i])
|
||||||
|
break;
|
||||||
|
case 0x2a:
|
||||||
|
case 0x2b:
|
||||||
|
case 0x2c:
|
||||||
|
case 0x2d: // aload_<n>
|
||||||
|
operand_stack.push(local_variables[opcode - 0x2a]);
|
||||||
|
break;
|
||||||
|
case 0xbd: // anewarray
|
||||||
|
var indexbyte1 = code.pop();
|
||||||
|
var indexbyte2 = code.pop();
|
||||||
|
var count = operand_stack.pop();
|
||||||
|
if (count < 0){
|
||||||
|
JVM_THROWS_NEW("java.lang.NegativeArraySizeException");
|
||||||
|
}
|
||||||
|
var clRef = frame.classRef.constantPool.get((indexbyte1 << 8) | indexbyte2);
|
||||||
|
var instance = {length:count, value:[], classRef:this.jvm.classForName(clRef)};
|
||||||
|
operand_stack.push(instance);
|
||||||
|
break;
|
||||||
|
case 0xb0: // areturn
|
||||||
|
var objectref = operand_stack.pop();
|
||||||
|
return {return_object: objectref}
|
||||||
|
case 0xbe: // arraylength
|
||||||
|
var arrayref = operand_stack.pop();
|
||||||
|
operand_stack.push(arrayref.length);
|
||||||
|
break;
|
||||||
|
case 0x3a: // astore
|
||||||
|
var objectref = operand_stack.pop();
|
||||||
|
local_variables[code.pop()] = objectref;
|
||||||
|
break;
|
||||||
|
case 0x4b:
|
||||||
|
case 0x4c:
|
||||||
|
case 0x4d:
|
||||||
|
case 0x4e: // astore_<n>
|
||||||
|
var objectref = operand_stack.pop();
|
||||||
|
local_variables[opcode-0x4b] = objectref;
|
||||||
|
break;
|
||||||
|
case 0xbf: // athrow
|
||||||
|
var objectref = operand_stack.pop();
|
||||||
|
if (objectref == null){
|
||||||
|
JVM_THROWS_NEW("java.lang.NullPointerException");
|
||||||
|
}
|
||||||
|
throw [objectref.classRef.name_ref.str,objectref];
|
||||||
|
case 0x33: // baload
|
||||||
|
var value = operand_stack.pop();
|
||||||
|
var index = operand_stack.pop();
|
||||||
|
var arrayref = operand_stack.pop();
|
||||||
|
|
||||||
|
|
||||||
|
if (arrayref == NULL){
|
||||||
|
JVM_THROWS_NEW("java.lang.NullPointerException");
|
||||||
|
}
|
||||||
|
if (index >= arrayref.length){
|
||||||
|
JVM_THROWS_NEW("java.lang.ArrayIndexOutOfBoundsException");
|
||||||
|
}
|
||||||
|
arrayref.value[index] = value;
|
||||||
|
break;
|
||||||
|
case 0x10: // bipush
|
||||||
|
operand_stack.push(code.pop());
|
||||||
|
break;
|
||||||
|
case 0x34: // caload
|
||||||
|
var index = operand_stack.pop();
|
||||||
|
var arrayref = operand_stack.pop();
|
||||||
|
|
||||||
|
operand_stack.push(arrayref.value[index]);
|
||||||
|
break;
|
||||||
|
case 0x55: // castore
|
||||||
|
var value = operand_stack.pop();
|
||||||
|
var index = operand_stack.pop();
|
||||||
|
var arrayref = operand_stack.pop();
|
||||||
|
|
||||||
|
|
||||||
|
if (arrayref == NULL){
|
||||||
|
JVM_THROWS_NEW("java.lang.NullPointerException");
|
||||||
|
}
|
||||||
|
if (index >= arrayref.length){
|
||||||
|
JVM_THROWS_NEW("java.lang.ArrayIndexOutOfBoundsException");
|
||||||
|
}
|
||||||
|
arrayref.value[index] = value;
|
||||||
|
break;
|
||||||
|
case 0xc0: // checkcast
|
||||||
|
var objectref = operand_stack.pop();
|
||||||
|
var indexbyte1 = code.pop();
|
||||||
|
var indexbyte2 = code.pop();
|
||||||
|
var clRef = frame.classRef.constantPool.get((indexbyte1 << 8) | indexbyte2);
|
||||||
|
if (objectref.classRef.isAssignable(clRef)){
|
||||||
|
operand_stack.push(objectref);
|
||||||
|
}else{
|
||||||
|
JVM_THROWS_NEW("java.lang.ClassCastException");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
5
main.js
5
main.js
@ -5,7 +5,8 @@ include("attributes.js");
|
|||||||
include("infos.js");
|
include("infos.js");
|
||||||
include("class.js");
|
include("class.js");
|
||||||
include("cpu.js");
|
include("cpu.js");
|
||||||
|
var test_jvm;
|
||||||
function main (args){
|
function main (args){
|
||||||
new JVM({},["java.text.DecimalFormat"]).run();
|
test_jvm = new JVM({},["[I"])
|
||||||
|
test_jvm.run();
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user