Native Interface, Static invocation, several bug fixes, 40% opcode coverage

This commit is contained in:
Artur Ventura 2011-08-09 00:39:43 +01:00
parent 7dec232268
commit 8630cf0e59
8 changed files with 173 additions and 49 deletions

View File

@ -22,7 +22,7 @@ function slurpFile (filename, fa) {
} else if ('responseType' in xmlHttpRequest) { } else if ('responseType' in xmlHttpRequest) {
xmlHttpRequest.responseType = 'arraybuffer'; xmlHttpRequest.responseType = 'arraybuffer';
} else { } else {
xmlHttpRequest.overrideMimeType('text/plain; charset=x-user-defined'); //xmlHttpRequest.overrideMimeType('text/plain; charset=x-user-defined');
} }
xmlHttpRequest.send(null); xmlHttpRequest.send(null);
if (xmlHttpRequest.status != 200 && xmlHttpRequest.status != 0) { if (xmlHttpRequest.status != 200 && xmlHttpRequest.status != 0) {
@ -42,6 +42,11 @@ function slurpFile (filename, fa) {
if (bf) { if (bf) {
result = [response.byteLength, response]; result = [response.byteLength, response];
} else { } else {
var a = "";
for(var k in xmlHttpRequest){
a+=k+",";
}
alert(a)
throw "No typed arrays"; throw "No typed arrays";
} }
return result; return result;

View File

@ -16,7 +16,9 @@
/** @constructor */ /** @constructor */
var JVM = function(params,args){ var JVM = function(params,args){
this.nativeMappingTable = {} this.JNITable = params.JNITable || {}
this.internalJNITable =
#include "internalJNI.jsh"
this.params = params; this.params = params;
this.args = args; this.args = args;
this.method_area = {}; this.method_area = {};
@ -40,7 +42,10 @@ var JVM = function(params,args){
this.makeInstanceOfStringFromJSSTring = function(string){ this.makeInstanceOfStringFromJSSTring = function(string){
var inst = this.java_lang_string.makeInstance(); var inst = this.java_lang_string.makeInstance();
inst["java/lang/String value"] = string; inst["java/lang/String count"] = string.length;
var x = make1DNativeArray(string.length,true,T_CHAR);
x.value = string.toArray();
inst["java/lang/String value"] = x;
inst["java/lang/String hash"] = this.stringHashCode(string) inst["java/lang/String hash"] = this.stringHashCode(string)
return inst; return inst;
} }
@ -56,7 +61,7 @@ var JVM = function(params,args){
LOG("[Loaded " + name + "]"); LOG("[Loaded " + name + "]");
} }
loaded_class.initializeClass();
return loaded_class; return loaded_class;
} }

View File

@ -11,11 +11,48 @@
#include "constantPool.jsh" #include "constantPool.jsh"
function parseArgs(description){ #define DSCRPT_DEFAULT 0
// "([Ljava/lang/String;)V" #define DSCRPT_ARRAY 1
var length = description.length #define DSCRPT_OBJ 2
var sides = description.substr(1,length).split(")")
return {args:sides[0].split(","),ret:sides[1]}; function parseArgs(descriptor){
var sides = descriptor.substr(1,descriptor.length).split(")")
var result = sides[1];
var args = sides[0];
var argsA = []
var state = DSCRPT_DEFAULT;
var temp = "";
for (var i=0; i<args.length; i++){
switch(args[i]){
case "[":
state = DSCRPT_ARRAY;
temp += args[i];
break;
case "L":
state = DSCRPT_OBJ;
temp += args[i]
break;
case ";":
if (state != DSCRPT_OBJ){
PANIC("DESCRIPTOR ERROR");
}
temp += args[i]
argsA.push(args[i]);
temp ="";
state = DSCRPT_DEFAULT;
break;
default:
if (state == DSCRPT_ARRAY){
temp += args[i];
argsA.push(temp);
temp = "";
state = DSCRPT_DEFAULT;
}else{
argsA.push(args[i]);
}
}
}
return {args:argsA,ret:result};
} }
/** @constructor */ /** @constructor */
@ -45,7 +82,7 @@ var MethodInfo = function(dStream, constantPool){
} }
this.invoke = function (local_var,xl){ this.invoke = function (local_var,xl){
#ifdef DEBUG_INTRP #ifdef DEBUG_INTRP
LOG("Calling " + this.name_ref.str + this.descriptor_ref.str) LOG("Calling " + xl.className+ " " + this.name_ref.str + this.descriptor_ref.str)
#endif #endif
local_var = local_var||[]; local_var = local_var||[];
var frame = { operand_stack: [], local_variables:local_var }; var frame = { operand_stack: [], local_variables:local_var };
@ -54,7 +91,7 @@ var MethodInfo = function(dStream, constantPool){
if (attr.id == ATTR_CODE){ if (attr.id == ATTR_CODE){
var result = interpret(frame,attr.code,this,xl); var result = interpret(frame,attr.code,this,xl);
#ifdef DEBUG_INTRP #ifdef DEBUG_INTRP
LOG("Returing from " + this.name_ref.str + this.descriptor_ref.str) LOG("Returing from " + xl.className+ " " + this.name_ref.str + this.descriptor_ref.str)
#endif #endif
return result; return result;
} }

16
src/internalJNI.jsh Normal file
View File

@ -0,0 +1,16 @@
/* -*- Mode: Javascript -*-
* -*- coding: UTF-8 -*-
* Copyright (C) 2011 by Artur Ventura
*
* File: types.js
* Time-stamp: Fri Jul 15 02:46:27 2011
*
* Author: Artur Ventura
*
*/
{
'java.lang.System' : {
'method arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V' : java_lang_System_arraycopy
}
}

View File

@ -73,6 +73,9 @@ ENDDEF
DEFOP(ARRAYLENGTH) DEFOP(ARRAYLENGTH)
var arrayref = OPPOP(); var arrayref = OPPOP();
if (!(arrayref.primitive == true || arrayref.primitive == false)){
PANIC("NOT AN ARRAY");
}
OPPUSH(arrayref.length); OPPUSH(arrayref.length);
ENDDEF ENDDEF
@ -516,9 +519,10 @@ DEFOP(GETFIELD)
var objectref = OPPOP(); var objectref = OPPOP();
CHECK_NULL(objectref) CHECK_NULL(objectref)
var field = objectref["class"].constantPool.get((indexbyte1 << 8) | indexbyte2); var field = xl.constantPool.get((indexbyte1 << 8) | indexbyte2);
//check if static //check if static
OPPUSH(objectref[canonicalName(field.class_ref.name_ref) + " " + field.name_and_type_ref.name_ref.str]); OPPUSH(objectref[field.class_ref.name_ref.str + " " + field.name_and_type_ref.name_ref.str]);
LOG(field.class_ref.name_ref.str + " " + field.name_and_type_ref.name_ref.str);
ENDDEF ENDDEF
DEFOP(GETSTATIC) DEFOP(GETSTATIC)
@ -538,7 +542,7 @@ DEFOP(GOTO)
var branchbyte2 = READ_NEXT(); var branchbyte2 = READ_NEXT();
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
ENDDEF ENDDEF
DEFOP(GOTO_W) DEFOP(GOTO_W)
@ -548,7 +552,7 @@ DEFOP(GOTO_W)
var branchbyte4 = READ_NEXT(); var branchbyte4 = READ_NEXT();
var branchoffset = (branchbyte1 << 24) | (branchbyte2 << 16) | (branchbyte3 << 8) | branchbyte4; var branchoffset = (branchbyte1 << 24) | (branchbyte2 << 16) | (branchbyte3 << 8) | branchbyte4;
PC = PC + branchoffset; PC = PC + branchoffset - 5;
ENDDEF ENDDEF
DEFOP(I2B) DEFOP(I2B)
@ -651,7 +655,7 @@ DEFOP(IF_ACMPEQ)
var value2 = OPPOP(); var value2 = OPPOP();
if (value1 == value2){ if (value1 == value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -662,7 +666,7 @@ DEFOP(IF_ACMPNE)
var value2 = OPPOP(); var value2 = OPPOP();
if (value1 != value2){ if (value1 != value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -673,7 +677,7 @@ DEFOP(IF_ICMPEQ)
var value2 = OPPOP(); var value2 = OPPOP();
if (value1 == value2){ if (value1 == value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -684,51 +688,51 @@ DEFOP(IF_ICMPNE)
var value2 = OPPOP(); var value2 = OPPOP();
if (value1 != value2){ if (value1 != value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
DEFOP(IF_ICMPLT) DEFOP(IF_ICMPLT)
var branchbyte1 = READ_NEXT(); var branchbyte1 = READ_NEXT();
var branchbyte2 = READ_NEXT(); var branchbyte2 = READ_NEXT();
var value1 = OPPOP();
var value2 = OPPOP(); var value2 = OPPOP();
var value1 = OPPOP();
if (value1 < value2){ if (value1 < value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
DEFOP(IF_ICMPLE) DEFOP(IF_ICMPLE)
var branchbyte1 = READ_NEXT(); var branchbyte1 = READ_NEXT();
var branchbyte2 = READ_NEXT(); var branchbyte2 = READ_NEXT();
var value1 = OPPOP();
var value2 = OPPOP(); var value2 = OPPOP();
var value1 = OPPOP();
if (value1 <= value2){ if (value1 <= value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
DEFOP(IF_ICMPGT) DEFOP(IF_ICMPGT)
var branchbyte1 = READ_NEXT(); var branchbyte1 = READ_NEXT();
var branchbyte2 = READ_NEXT(); var branchbyte2 = READ_NEXT();
var value1 = OPPOP();
var value2 = OPPOP(); var value2 = OPPOP();
var value1 = OPPOP();
if (value1 > value2){ if (value1 > value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
DEFOP(IF_ICMPGE) DEFOP(IF_ICMPGE)
var branchbyte1 = READ_NEXT(); var branchbyte1 = READ_NEXT();
var branchbyte2 = READ_NEXT(); var branchbyte2 = READ_NEXT();
var value1 = OPPOP();
var value2 = OPPOP(); var value2 = OPPOP();
var value1 = OPPOP();
if (value1 >= value2){ if (value1 >= value2){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -739,7 +743,7 @@ DEFOP(IFEQ)
if (value == 0){ if (value == 0){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -750,7 +754,7 @@ DEFOP(IFNE)
if (value != 0){ if (value != 0){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -761,7 +765,7 @@ DEFOP(IFLT)
if (value < 0){ if (value < 0){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -772,7 +776,7 @@ DEFOP(IFLE)
if (value <= 0){ if (value <= 0){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -783,7 +787,7 @@ DEFOP(IFGT)
if (value > 0){ if (value > 0){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -794,7 +798,7 @@ DEFOP(IFGE)
if (value >= 0){ if (value >= 0){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -805,7 +809,7 @@ DEFOP(IFNONNULL)
if (value != NULL){ if (value != NULL){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -816,7 +820,7 @@ DEFOP(IFNULL)
if (value != NULL){ if (value != NULL){
var branchoffset = (branchbyte1 << 8) | branchbyte2; var branchoffset = (branchbyte1 << 8) | branchbyte2;
PC = PC + branchoffset; PC = PC + branchoffset - 3;
} }
ENDDEF ENDDEF
@ -836,7 +840,7 @@ DEFALIAS(ILOAD_1)
DEFALIAS(ILOAD_2) DEFALIAS(ILOAD_2)
DEFALIAS(ILOAD_3) DEFALIAS(ILOAD_3)
DEFNOP() DEFNOP()
OPPUSH(OPCODE - ILOAD_0); OPPUSH(LOCAL_VAR(OPCODE - ILOAD_0));
ENDDEF ENDDEF
DEFOP(IMUL) DEFOP(IMUL)
@ -923,12 +927,31 @@ DEFOP(INVOKESTATIC)
var indexbyte2 = READ_NEXT(); var indexbyte2 = READ_NEXT();
var args = []; var args = [];
var method = xl.constantPool.get((indexbyte1 << 8) | indexbyte2); var methodDesrc = xl.constantPool.get((indexbyte1 << 8) | indexbyte2);
for(var i=0; i<method.descriptor.args.length; i++){ var cl = xl.jvm.classForName(methodDesrc.class_ref.jvmClassName);
args.push(OPPOP()); var methodId = "method " + methodDesrc.name_and_type_ref.name_ref.str + methodDesrc.name_and_type_ref.descriptor_ref.str
var method = cl[methodId];
var args = OPSTACK_MULTIPOP(OPSTACK_LENGTH() - method.descriptor.args.length);
var result;
if(method.access_flags & ACC_NATIVE){
LOG("Calling " + xl.className+ " " + method.name_ref.str + method.descriptor_ref.str)
LOG("!! NATIVE !!")
if (methodId in xl.jvm.internalJNITable[canonicalName(cl.this_class.name_ref)]){
result = xl.jvm.internalJNITable[canonicalName(cl.this_class.name_ref)][methodId].apply(cl,args);
LOG("Returing from " + xl.className+ " " + method.name_ref.str + method.descriptor_ref.str)
}else if (methodId in xl.jvm.JNITable[canonicalName(cl.this_class.name_ref)][methodId]){
result = xl.jvm.JNITable[canonicalName(cl.this_class.name_ref)][methodId].apply(cl,args)
}else{
PANIC(methodId + " declared as native but not mapped");
}
LOG("Returing from " + xl.className+ " " + method.name_ref.str + method.descriptor_ref.str)
}else{
result = method.invoke(args,cl);
}
if (result != undefined){
OPPUSH(result.return_object);
} }
PANIC("NOT IMPLEMENTED YET");
ENDDEF ENDDEF
DEFOP(INVOKEVIRTUAL) DEFOP(INVOKEVIRTUAL)
@ -940,7 +963,7 @@ DEFOP(INVOKEVIRTUAL)
var cl = xl.jvm.classForName(methodDesrc.class_ref.jvmClassName); var cl = xl.jvm.classForName(methodDesrc.class_ref.jvmClassName);
var methodId = "method " + methodDesrc.name_and_type_ref.name_ref.str + methodDesrc.name_and_type_ref.descriptor_ref.str var methodId = "method " + methodDesrc.name_and_type_ref.name_ref.str + methodDesrc.name_and_type_ref.descriptor_ref.str
var method = cl[methodId]; var method = cl[methodId];
var args = OPSTACK_MULTIPOP(OPSTACK_LENGTH() - method.descriptor.args.length); var args = OPSTACK_MULTIPOP(OPSTACK_LENGTH() - method.descriptor.args.length - 1);
var result; var result;
if(method.access_flags & ACC_NATIVE){ if(method.access_flags & ACC_NATIVE){
PANIC("INVOKEVIRTUAL NATIVE CALL") PANIC("INVOKEVIRTUAL NATIVE CALL")
@ -1017,10 +1040,10 @@ DEFNOP()
ENDDEF ENDDEF
DEFOP(ISUB) DEFOP(ISUB)
var value1 = OPPOP();
var value2 = OPPOP(); var value2 = OPPOP();
var value1 = OPPOP();
var result = value1 - value2; var result = value1 - value2;
if (IS_UNDERFLOW(result,INT_MAX_VALUE)){ if (IS_UNDERFLOW(result,INT_MIN_VALUE)){
OPPUSH(INT_OVERFLOW(result)); OPPUSH(INT_OVERFLOW(result));
}else{ }else{
OPPUSH(result); OPPUSH(result);
@ -1417,9 +1440,9 @@ DEFOP(PUTFIELD)
var objectref = OPPOP(); var objectref = OPPOP();
CHECK_NULL(objectref) CHECK_NULL(objectref)
var field = objectref["class"].constantPool.get((indexbyte1 << 8) | indexbyte2); var field = xl.constantPool.get((indexbyte1 << 8) | indexbyte2);
//check if static //check if static
objectref[canonicalName(field.class_ref.name_ref) + " " + field.name_and_type_ref.name_ref.str] = value; objectref[field.class_ref.name_ref.str + " " + field.name_and_type_ref.name_ref.str] = value;
ENDDEF ENDDEF
DEFOP(GETSTATIC) DEFOP(GETSTATIC)

View File

@ -0,0 +1,18 @@
/* -*- Mode: Javascript -*-
* -*- coding: UTF-8 -*-
* Copyright (C) 2011 by Artur Ventura
*
* File: javaNativeInterface.js
* Time-stamp: Fri Jul 15 02:46:27 2011
*
* Author: Artur Ventura
*
*/
//arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V
function java_lang_System_arraycopy(src,srcPos,dest,destPos,length){
var temp = src.value.slice(srcPos,length);
for (var i = 0; i < temp.length; i++){
dest.value[destPos + i] = temp[i];
}
}

View File

@ -10,7 +10,15 @@
*/ */
#include "cpu.jsh" #include "cpu.jsh"
String.prototype.toArray = function(){
var result =[];
for(i =0; i < this.length; i++){
result.push(this.charCodeAt(i));
}
return result;
}
function printNativeArray(){ function printNativeArray(){
var result = "["; var result = "[";
if(this.primitive){ if(this.primitive){
@ -49,4 +57,4 @@ function printNativeArray(){
function make1DNativeArray(count,primitive,type){ function make1DNativeArray(count,primitive,type){
var inst = {toString: printNativeArray,length:count, dimensions:1, value:[], primitive:primitive, 'class':type}; var inst = {toString: printNativeArray,length:count, dimensions:1, value:[], primitive:primitive, 'class':type};
return inst; return inst;
} }

View File

@ -2,9 +2,13 @@
<head> <head>
<title>JS JVM</title> <title>JS JVM</title>
<script> <script>
var lident = -1;
write = function(msg){ write = function(msg){
var l = document.getElementById("log"); var l = document.getElementById("log");
var match; var match;
if (msg.match(/Calling/)){
lident++;
}
if ((match = msg.match(/(\d+): (\w+) (op:\[[^\]]*]) (.*)/))){ if ((match = msg.match(/(\d+): (\w+) (op:\[[^\]]*]) (.*)/))){
var space3 = ""; var space3 = "";
for(var i=0; i<3-(match[1].length); i++){space3 += " " } for(var i=0; i<3-(match[1].length); i++){space3 += " " }
@ -16,7 +20,15 @@
}else{ }else{
msg=htmlentities(msg); msg=htmlentities(msg);
} }
l.innerHTML = l.innerHTML + msg + "\n"; if (msg.match(/!! NATIVE !!/)){
msg = "<span style='color:green'>" + msg + "</span>"
}
var spac = ""
for (var i =0; i<lident; i++){ spac += " ";}
if (msg.match(/Returing/)){
lident--;
}
l.innerHTML = l.innerHTML + spac + msg + "\n";
} }
</script> </script>