primordial memory structure and bytecode execution

This commit is contained in:
Artur Ventura 2011-07-06 16:30:18 +01:00
parent 4bba81c3f0
commit edb0b77a61
3 changed files with 182 additions and 23 deletions

View File

@ -52,7 +52,7 @@ var log = function (msg){
}
}
var ClassDefinition = function (file){
var ClassDefinition = function (file,jvm){
var dataStream = new DataStream(slurpFile(file)[1]);
this.magic = dataStream.getU4();
if (this.magic != 0xCAFEBABE){
@ -75,7 +75,6 @@ var ClassDefinition = function (file){
}
this.interface_count = dataStream.getU2();
// VER: interfaces refs must be classes
this.interfaces = [];
for(var i=0; i<this.interface_count; i++){
this.interfaces[i] = ConstantPoolRef(dataStream.getU2(), this.constantPool,CONSTANT_Class);
@ -93,8 +92,72 @@ var ClassDefinition = function (file){
for(var i=0; i<this.methods_count; i++){
this.methods[i] = new MethodInfo(dataStream, this.constantPool);
}
// Post added info;
this.jvm = jvm;
this className = this.this_class.name_ref.str.replace(/\//g,".");
}
function LoadClassFile (x){
return new ClassDefinition(x);
}
ClassDefinition.prototype.isInterface = function () {
return ACC_INTERFACE & this.access_flags;
}
ClassDefinition.prototype.isArrayClass = function (){
return false;
}
ClassDefinition.prototype.isAssignable = function (T) {
// 2.6.7 Assignment Conversion
if (this.isInterface()){
if (T.isInterface()){
return this.isInterfaceOrSuperInterface(T);
}else{
return T == this.jvm.java_lang_object;
}
}else if(this.isArrayClass()){
if (T.isInterface()){
return (T == this.jvm.java_lang_cloneable || T == this.jvm.java_io_serializable);
}else if (T.isArrayClass()){
}else{
return T == this.jvm.java_lang_object;
}
}else{
if (T.isInterface()){
return this.isInterfaceOrSuperInterface(T);
}else{
return this.isClassOrSuperClass(T);
}
}
}
ClassDefinition.prototype.isClassOrSuperClass = function(C){
if (this == C){
return true;
}else{
if (this.jvm.java_lang_object == this){
return false;
}else{
this.jvm.classForName(this.super_class.name_ref).isClassOrSuperClass(C);
}
}
}
ClassDefinition.prototype.isInterfaceOrSuperInterface = function(I){
if (this == I){
return true;
}else{
for(var i; i<this.interface_count; i++){
if (this.interfaces[i].isInterfaceOrSuperInterface(I)){
return true;
}
}
return false;
}
}
function LoadClassFile (x,jvm){
return new ClassDefinition(x,jvm);
}

93
cpu.js
View File

@ -9,37 +9,52 @@ var JVM = function(params,args){
this.method_area = {};
this.level = 0;
this.classpath = params.classes_to_load;
this.verifyAndLoadClass = function(classFile){
if (!this.method_area[classFile]){
// log(">>>>>> " + classFile);
var loaded_class = LoadClassFile(classFile);
var className = loaded_class.this_class.name_ref.str.replace(/\//g,".");
this.classForName = function (name){
var superClass, loaded_class = this.method_area[name];
if (!loaded_class){
loaded_class = LoadClassFile(name, this);
this.method_area[className] = loaded_class;
var superClass;
if(loaded_class.super_class){
superClass = canonicalName(loaded_class.super_class.name_ref);
}else{
superClass = "java.lang.Object";
}
this.verifyAndLoadClass(superClass);
this.verifyAndLoadClass(loaded_class);
log("[Loaded " + className + " from runtime/" + classFile + "]");
}
return loaded_class;
}
this.verifyAndLoadClass = function(classFile){
var superClass;
if(loaded_class.super_class){
superClass = canonicalName(loaded_class.super_class.name_ref);
}else{
superClass = "java.lang.Object";
}
this.classForName(superClass);
// this doesn't seem right. doing this will cause the entire JRE to be loaded
// as soon as you start JVM.
/*
var that = this;
loaded_class.constantPool.each(function(constant){
if (constant.name_ref.str.charAt(0) == "[") {
return;
}
that.verifyAndLoadClass(canonicalName(constant.name_ref));
}, CONSTANT_Class);
log("[Loaded " + className + " from runtime/" + classFile + "]");
}
}, CONSTANT_Class);*/
};
this.run = function (){
this.java_lang_object = this.classForName("java.lang.Object");
this.java_lang_cloneable = this.classForName("java.lang.Cloneable");
this.java_io_serializable = this.classForName("java.io.Serializable");
var mainClass = this.args[0];
this.verifyAndLoadClass(mainClass);
this.classForName(mainClass);
};
};
@ -52,4 +67,46 @@ var JVMFrame = function(){
this.local_variables = [];
this.operand_stack = [];
}
function JVM_THROWS_NEW(exception){
throw "VER: throws new " + exception;
}
function (frame){
var operand_stack = frame.operand_stack;
switch(opcode){
case 0x32: // aaload
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");
}
operand_stack.push(arrayref.value[index.value]);
break;
case 0x53: // aastore
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");
}
if (value.ref_of == REF_TYPE_class){
if (isSubClass(value.ref_of,arrayref.of));
}
}
}

39
types.js Normal file
View File

@ -0,0 +1,39 @@
// Local Variables Types
var LOC_VAR_boolean = 0x001;
var LOC_VAR_byte = 0x002;
var LOC_VAR_char = 0x004;
var LOC_VAR_short = 0x008;
var LOC_VAR_int = 0x010;
var LOC_VAR_float = 0x020;
var LOC_VAR_reference = 0x040;
var LOC_VAR_returnAddress = 0x080;
var LOC_VAR_long = 0x100;
var LOC_VAR_double = 0x200;
// Reference Types
var REF_TYPE_class = 0x1;
var REF_TYPE_interface = 0x2;
var REF_TYPE_array = 0x4
function makeLocalVar(kind){
return {id:kind};
}
function getRefClass(ref){
if (ref.type == REF_TYPE_array){
return getArrayClass();
}else{
return ref.classRef;
}
}
var NULL = makeLocalVar(LOC_VAR_reference);
function isSubClass(refS,refT){
}
function implements(refS,refT){
}