pluotsorbet/frame.js

163 строки
4.4 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';
2014-07-13 10:05:35 +04:00
Array.prototype.push2 = function (value) {
this.push(value);
this.push(null);
}
Array.prototype.pop2 = function () {
this.pop();
return this.pop();
}
Array.prototype.top = function () {
return this[this.length - 1];
}
var Frame = function(methodInfo) {
2014-07-13 11:00:11 +04:00
if (methodInfo) {
this.methodInfo = methodInfo;
this.cp = methodInfo.classInfo.constant_pool;
2014-07-13 11:00:11 +04:00
this.code = methodInfo.code;
this.ip = 0;
}
2014-07-13 10:13:53 +04:00
this.stack = [];
2014-07-06 12:29:36 +04:00
}
2014-07-16 05:11:59 +04:00
Frame.prototype.pushFrame = function(methodInfo, consumes) {
2014-07-16 04:18:34 +04:00
var callee = new Frame(methodInfo);
callee.locals = this.stack;
callee.localsBase = this.stack.length - consumes;
callee.caller = this;
THREADS.current.frame = callee;
return callee;
}
Frame.prototype.popFrame = function() {
var caller = this.caller;
caller.stack.length = this.localsBase;
THREADS.current.frame = caller;
return caller;
}
2014-07-13 10:05:35 +04:00
Frame.prototype.getLocal = function(idx) {
return this.locals[this.localsBase + idx];
}
Frame.prototype.setLocal = function(idx, value) {
this.locals[this.localsBase + idx] = value;
}
2014-07-12 22:54:04 +04:00
Frame.prototype.isWide = function() {
2014-07-14 05:36:06 +04:00
return this.code[this.ip - 2] === OPCODES.wide;
2014-07-12 22:54:04 +04:00
}
Frame.prototype.getOp = function() {
return this.code[this.ip - 1];
}
2014-07-12 10:20:45 +04:00
Frame.prototype.read8 = function() {
return this.code[this.ip++];
2014-07-06 12:29:36 +04:00
};
2014-07-12 10:20:45 +04:00
Frame.prototype.read16 = function() {
return this.read8()<<8 | this.read8();
2014-07-06 12:29:36 +04:00
};
2014-07-12 10:20:45 +04:00
Frame.prototype.read32 = function() {
return this.read16()<<16 | this.read16();
2014-07-06 12:29:36 +04:00
};
2014-07-15 09:30:30 +04:00
Frame.prototype.read8signed = function() {
var x = this.read8();
return (x > 0x7f) ? (x - 0x100) : x;
}
2014-07-12 10:20:45 +04:00
Frame.prototype.read16signed = function() {
2014-07-15 09:30:30 +04:00
var x = this.read16();
return (x > 0x7fff) ? (x - 0x10000) : x;
2014-07-06 13:03:36 +04:00
}
2014-07-12 10:20:45 +04:00
Frame.prototype.read32signed = function() {
2014-07-15 09:30:30 +04:00
var x = this.read32();
return (x > 0x7fffffff) ? (x - 0x100000000) : x;
2014-07-06 13:03:36 +04:00
}
2014-07-12 20:48:05 +04:00
Frame.prototype.throw = function(ex) {
2014-07-06 12:29:36 +04:00
var handler_pc = null;
2014-07-13 04:51:35 +04:00
for (var i=0; i<this.exception_table.length; i++) {
2014-07-12 10:20:45 +04:00
if (this.ip >= this.exception_table[i].start_pc && this.ip <= this.exception_table[i].end_pc) {
if (this.exception_table[i].catch_type === 0) {
2014-07-12 20:48:05 +04:00
handler_pc = this.exception_table[i].handler_pc;
2014-07-06 12:29:36 +04:00
} else {
2014-07-12 10:20:45 +04:00
var name = this.cp[this.cp[this.exception_table[i].catch_type].name_index].bytes;
if (name === ex.className) {
2014-07-12 10:20:45 +04:00
handler_pc = this.exception_table[i].handler_pc;
2014-07-06 12:29:36 +04:00
break;
}
}
}
}
2014-07-12 20:48:05 +04:00
2014-07-06 12:29:36 +04:00
if (handler_pc != null) {
2014-07-13 01:07:11 +04:00
stack.push(ex);
2014-07-12 20:48:05 +04:00
this.ip = handler_pc;
2014-07-06 12:29:36 +04:00
} else {
throw ex;
}
}
Frame.prototype.raiseException = function(className, message) {
var ex = CLASSES.newObject(this, className);
var ctor = CLASSES.getMethod(this, ex.class, "<init>", "(Ljava/lang/String;)V", false, false);
2014-07-13 10:24:10 +04:00
this.stack.push(ex);
this.stack.push(message);
this.invoke(OPCODES.invokespecial, ctor);
2014-07-12 10:20:45 +04:00
this.throw(ex);
}
2014-07-16 17:23:23 +04:00
Frame.prototype.checkArrayAccess = function(refArray, idx) {
if (!refArray) {
this.raiseException("java/lang/NullPointerException");
return false;
}
if (idx < 0 || idx >= refArray.length) {
this.raiseException("java/lang/ArrayIndexOutOfBoundsException", idx);
return false;
}
return true;
}
Frame.prototype.invoke = function(op, methodInfo) {
2014-07-14 06:53:24 +04:00
var consumes = Signature.parse(methodInfo.signature).IN.slots;
if (op !== OPCODES.invokestatic) {
2014-07-14 06:53:24 +04:00
++consumes;
var obj = this.stack[this.stack.length - consumes];
if (!obj) {
this.raiseException("java/lang/NullPointerException");
return;
}
2014-07-14 22:21:25 +04:00
switch (op) {
case OPCODES.invokevirtual:
2014-07-15 09:13:01 +04:00
// console.log("virtual dispatch", methodInfo.classInfo.className, obj.class.className, methodInfo.name, methodInfo.signature);
2014-07-14 22:21:25 +04:00
if (methodInfo.classInfo != obj.class)
methodInfo = CLASSES.getMethod(this, obj.class, methodInfo.name, methodInfo.signature, op === OPCODES.invokestatic);
2014-07-14 22:21:25 +04:00
break;
}
}
2014-07-13 02:03:46 +04:00
if (ACCESS_FLAGS.isNative(methodInfo.access_flags)) {
NATIVE.invokeNative(this, methodInfo);
return;
}
2014-07-16 05:11:59 +04:00
var callee = this.pushFrame(methodInfo, consumes);
2014-07-13 10:05:35 +04:00
2014-07-16 23:15:48 +04:00
VM.execute(callee);
2014-07-06 12:29:36 +04:00
}