├── jar-reader.js ├── jvm-lib.js ├── jvm-loader.js ├── jvm.js ├── license.txt ├── longvalue.js ├── run.html └── sandbox ├── generics ├── Gen1.class ├── Gen1.java └── gen1 │ ├── ClassGen1.class │ └── ClassGen1.java ├── jar ├── TestJar.class ├── TestJar.java ├── testjar.jar └── testjar │ ├── ClassA.class │ └── ClassA.java └── simple ├── Bottles.class ├── Bottles.java ├── Class1.class ├── Class1.java ├── Hello.class ├── Hello.java ├── ZeroDiv.class ├── ZeroDiv.java ├── ZeroDivCatch.class ├── ZeroDivCatch.java └── class1 ├── ClassA.class ├── ClassA.java ├── ClassB.class └── ClassB.java /jar-reader.js: -------------------------------------------------------------------------------- 1 | var readJarContent = ((function() { 2 | function BitReader(reader) 3 | { 4 | this.bitsLength = 0; 5 | this.bits = 0; 6 | this.reader = reader; 7 | this.readBit = function() { 8 | if(this.bitsLength == 0) { 9 | var nextByte = this.reader.readByte(); 10 | if(nextByte < 0) throw new "Unexpected end of stream"; 11 | this.bits = nextByte; 12 | this.bitsLength = 8; 13 | } 14 | 15 | var bit = (this.bits & 1) != 0; 16 | this.bits >>= 1; 17 | --this.bitsLength; 18 | return bit; 19 | }; 20 | this.align = function() { this.bitsLength = 0; } 21 | this.readLSB = function(length) { 22 | var data = 0; 23 | for(var i=0;i 0) 140 | { 141 | var code = new Object(); 142 | code.bits = codes[i]; 143 | code.length = lengths[i]; 144 | code.index = i; 145 | nonEmptyCodes.push(code); 146 | } 147 | } 148 | return buildTreeBranch(nonEmptyCodes, 0, 0); 149 | } 150 | 151 | function buildTreeBranch(codes, prefix, prefixLength) 152 | { 153 | if(codes.length == 0) return null; 154 | 155 | var zeros = new Array(0); 156 | var ones = new Array(0); 157 | var branch = new Object(); 158 | branch.isLeaf = false; 159 | for(var i=0; i> (codes[i].length - prefixLength - 1)) & 1) > 0; 170 | if(nextBit) 171 | { 172 | ones.push(codes[i]); 173 | } 174 | else 175 | { 176 | zeros.push(codes[i]); 177 | } 178 | } 179 | } 180 | if(!branch.isLeaf) 181 | { 182 | branch.zero = buildTreeBranch(zeros, (prefix << 1), prefixLength + 1); 183 | branch.one = buildTreeBranch(ones, (prefix << 1) | 1, prefixLength + 1); 184 | } 185 | return branch; 186 | } 187 | 188 | function readDynamicTrees(bitReader) 189 | { 190 | var hlit = bitReader.readLSB(5) + 257; 191 | var hdist = bitReader.readLSB(5) + 1; 192 | var hclen = bitReader.readLSB(4) + 4; 193 | 194 | var clen = new Array(19); 195 | for(var i=0; i= this.buffer.length) 254 | { 255 | var item = this.decodeItem(); 256 | if(item == null) return -1; 257 | switch(item.itemType) 258 | { 259 | case 0: 260 | this.buffer = this.buffer.concat(item.array); 261 | break; 262 | case 2: 263 | this.buffer.push(item.symbol); 264 | break; 265 | case 3: 266 | var j = this.buffer.length - item.distance; 267 | for(var i=0;i 0xC000) 276 | { 277 | var shift = this.buffer.length - 0x8000; 278 | if(shift > this.bufferPosition) shift = this.bufferPosition; 279 | this.buffer.splice(0, shift); 280 | this.bufferPosition -= shift; 281 | } 282 | return symbol; 283 | } 284 | 285 | this.decodeItem = function() { 286 | if(this.state == 2) return null; 287 | 288 | var item; 289 | if(this.state == 0) 290 | { 291 | this.blockFinal = this.bitReader.readBit(); 292 | var blockType = this.bitReader.readLSB(2); 293 | switch(blockType) 294 | { 295 | case 0: 296 | this.bitReader.align(); 297 | var len = this.bitReader.readLSB(16); 298 | var nlen = this.bitReader.readLSB(16); 299 | if((len & ~nlen) != len) throw "Invalid block type 0 length"; 300 | 301 | item = new Object(); 302 | item.itemType = 0; 303 | item.array = new Array(len); 304 | for(var i=0;i 256) 340 | { 341 | var lengthCode = p.index; 342 | if(lengthCode > 285) throw new "Invalid length code"; 343 | 344 | var length = encodedLengthStart[lengthCode - 257]; 345 | if(encodedLengthAdditionalBits[lengthCode - 257] > 0) 346 | { 347 | length += this.bitReader.readLSB(encodedLengthAdditionalBits[lengthCode - 257]); 348 | } 349 | 350 | p = this.distancesTree; 351 | while(!p.isLeaf) 352 | { 353 | p = this.bitReader.readBit() ? p.one : p.zero; 354 | } 355 | 356 | var distanceCode = p.index; 357 | var distance = encodedDistanceStart[distanceCode]; 358 | if(encodedDistanceAdditionalBits[distanceCode] > 0) 359 | { 360 | distance += this.bitReader.readLSB(encodedDistanceAdditionalBits[distanceCode]); 361 | } 362 | 363 | item.itemType = 3; 364 | item.distance = distance; 365 | item.length = length; 366 | } 367 | else 368 | { 369 | item.itemType = 1; 370 | this.state = this.blockFinal ? 2 : 0; 371 | } 372 | return item; 373 | }; 374 | } 375 | 376 | /* initialization */ 377 | initializeStaticTrees(); 378 | 379 | function DataReader(data) { 380 | var dataLength = data.length; 381 | var position = 0; 382 | this.readByte = function() { 383 | if (position >= dataLength) { 384 | return -1; 385 | } 386 | return data[position++]; 387 | }; 388 | this.readU16 = function() { 389 | var number = data[position] | (data[position + 1] << 8); 390 | position += 2; 391 | return number; 392 | }; 393 | this.readU32 = function() { 394 | var number = (data[position] | (data[position + 1] << 8) | (data[position + 2] << 16) ) + 395 | 2 * (data[position + 3] << 23); 396 | position += 4; 397 | return number; 398 | }; 399 | this.readBlock = function(size) { 400 | var result = []; 401 | result.length = size; 402 | for(var i = 0; i < size; ++i) { 403 | result[i] = data[position++]; 404 | } 405 | return result; 406 | }; 407 | this.seek = function(offset) { 408 | return (position += offset); 409 | }; 410 | this.setPosition = function(newPosition) { 411 | position = newPosition; 412 | }; 413 | } 414 | 415 | function readContent(data) { 416 | var reader = new DataReader(data); 417 | var entries = {}; 418 | reader.setPosition(data.length - 22); 419 | if (reader.readU32() !== 0x06054b50) { 420 | throw new "Invalid jar file"; 421 | } 422 | reader.seek(12); 423 | reader.setPosition(reader.readU32()); // set to directory 424 | var offsets = []; 425 | while (reader.readU32() === 0x02014b50) { 426 | reader.seek(16); 427 | var compressedSize = reader.readU32(); 428 | var size = reader.readU32(); 429 | var extraLength = reader.readU16() +reader.readU16() + reader.readU16(); 430 | reader.seek(8); 431 | var offset = reader.readU32(); 432 | reader.seek(extraLength); 433 | if (size > 0) { 434 | // interested only in non-empty files 435 | offsets.push({offset:offset, size: size, compressedSize: compressedSize}); 436 | } 437 | } 438 | // processing the local zip files 439 | while (offsets.length > 0) { 440 | reader.setPosition(offsets[0].offset); 441 | if (reader.readU32() !== 0x04034b50) { 442 | throw "Invalid jar file entry"; 443 | } 444 | reader.seek(22); 445 | var compressedSize = offsets[0].compressedSize; 446 | var size = offsets[0].size; 447 | var filenameLength = reader.readU16(); 448 | var extraLength = reader.readU16(); 449 | var filename = ""; 450 | for (var i = 0; i < filenameLength; ++i) { 451 | filename += String.fromCharCode(reader.readByte()); 452 | } 453 | reader.seek(extraLength); 454 | 455 | var uncompressedData = [], inflator = new Inflator(reader); 456 | uncompressedData.length = size; 457 | for (var i = 0; i < size; ++i) { 458 | uncompressedData[i] = inflator.readByte(); 459 | } 460 | entries[filename] = uncompressedData; 461 | 462 | offsets.shift(); 463 | } 464 | return entries; 465 | } 466 | 467 | return readContent; 468 | })()); 469 | 470 | -------------------------------------------------------------------------------- /jvm-lib.js: -------------------------------------------------------------------------------- 1 | var nextLockId = 0; 2 | 3 | function addFactory(description) { 4 | factories[description.className] = description; 5 | } 6 | 7 | addFactory({ 8 | className: "java/lang/Object", 9 | create: function() { 10 | return new JavaObject(); 11 | }, 12 | instanceMethods: ["toString", "hashCode", "equals"] 13 | }); 14 | 15 | function JavaObject() { 16 | this.$lockId = nextLockId++ | 0; 17 | } 18 | JavaObject.prototype.$factory = factories["java/lang/Object"]; 19 | JavaObject.prototype.toString = function() { return "[object: " + this.$lockId + "]"; }; 20 | JavaObject.prototype.hashCode = function() { return this.$lockId; }; 21 | JavaObject.prototype.equals = function(other) { return this == normalizeObject(other, "java/lang/Object"); }; 22 | JavaObject.prototype[""] = function() {}; 23 | 24 | var systemOut = { 25 | print: function(s) { log(s); }, 26 | println : function(s) { log((s||"") + "\n"); } 27 | }; 28 | 29 | addFactory({ 30 | className: "java/lang/System", 31 | statics: { 32 | "out": systemOut, 33 | "err": systemOut, 34 | "exit": function() { 35 | throw "Exit was called"; 36 | } 37 | } 38 | }); 39 | 40 | addFactory({ 41 | className: "java/lang/StringBuilder", 42 | superFactory: factories["java/lang/Object"], 43 | create: function() { 44 | var buffer; 45 | return { 46 | "": function() { 47 | buffer = ""; 48 | }, 49 | append: function(value) { 50 | if (typeof value === "object" && "value" in value) { 51 | buffer += value.value; 52 | } else if (value != null) { 53 | buffer += value.toString(); 54 | } 55 | return this; 56 | }, 57 | toString: function() { 58 | return buffer; 59 | } 60 | }; 61 | }, 62 | instanceMethods: ["toString", "append"] 63 | }); 64 | 65 | addFactory({ 66 | className: "java/lang/String", 67 | superFactory: factories["java/lang/Object"], 68 | create: function () { 69 | return new JavaString(); 70 | }, 71 | instanceMethods: ["toString", "hashCode", "equals"] 72 | }); 73 | 74 | function JavaString(s) { 75 | if (typeof s === "string") { 76 | this.s = s; 77 | this.$self = this; 78 | var super_= new JavaObject(); 79 | this.$super = super_; 80 | super_.$self = this; 81 | super_.$upcast = this; 82 | } 83 | }; 84 | JavaString.prototype.$factory = factories["java/lang/String"]; 85 | JavaString.prototype.toString = function() { return this.s; }; 86 | JavaString.prototype.hashCode = function() { return this.s.length; }; 87 | JavaString.prototype.equals = function(other) { return this.s == normalizeObject(other, "java/lang/String").s; }; 88 | JavaString.prototype[""] = function(s) { this.s = s; }; 89 | 90 | addFactory({ 91 | className: "java/lang/Throwable", 92 | superFactory: factories["java/lang/Object"], 93 | create: function () { 94 | return { 95 | "" : function(message, cause) { 96 | this.$super[""](); 97 | this.message = message || null; 98 | this.cause = cause || null; 99 | }, 100 | getMessage: function() { return this.message; }, 101 | getCause: function() { return this.cause; }, 102 | toString: function() { 103 | return this.$self.$factory.className.replace(/\//g, ".") + ": " + this.$self.getMessage(); 104 | } 105 | }; 106 | }, 107 | instanceMethods: ["getMessage", "getCause", "toString"] 108 | }); 109 | 110 | addFactory({ 111 | className: "java/lang/Exception", 112 | superFactory: factories["java/lang/Throwable"], 113 | create: function() { 114 | return { "" : function(message, cause) { this.$super[""](message, cause); } }; 115 | }, 116 | instanceMethods: [] 117 | }); 118 | 119 | addFactory({ 120 | className: "java/lang/RuntimeException", 121 | superFactory: factories["java/lang/Exception"], 122 | create: function() { 123 | return { "" : function(message, cause) { this.$super[""](message, cause); } }; 124 | }, 125 | instanceMethods: [] 126 | }); 127 | 128 | addFactory({ 129 | className: "java/lang/ArithmeticException", 130 | superFactory: factories["java/lang/RuntimeException"], 131 | create: function() { 132 | return { "" : function(message) { this.$super[""](message); } }; 133 | }, 134 | instanceMethods: [] 135 | }); 136 | -------------------------------------------------------------------------------- /jvm-loader.js: -------------------------------------------------------------------------------- 1 | function parseJavaClass(classContent) { 2 | var readPosition = 0; 3 | var reader = { 4 | readU1: function() { return classContent[readPosition++]; }, 5 | readBlock: function(size) { 6 | var data = classContent.slice(readPosition, readPosition + size); /* or subset() */ 7 | readPosition += size; 8 | return data; 9 | }, 10 | readU4: function() { 11 | var n = (classContent[readPosition] << 24) | 12 | (classContent[readPosition + 1] << 16) | 13 | (classContent[readPosition + 2] << 8) | 14 | (classContent[readPosition + 3]); 15 | readPosition += 4; 16 | 17 | return n < 0 ? n + 0x100000000 : n; 18 | }, 19 | readU2: function() { 20 | var n = (classContent[readPosition] << 8) | 21 | (classContent[readPosition + 1]); 22 | readPosition += 2; 23 | return n; 24 | } 25 | }; 26 | 27 | function read_cp_info() { 28 | var info = { tag: reader.readU1() }; 29 | switch (info.tag) { 30 | case 7: 31 | info.type = "CONSTANT_Class"; 32 | var name_index = reader.readU2(); 33 | info.update = function(cp) { 34 | this.name = cp[name_index].value; 35 | }; 36 | break; 37 | case 9: 38 | info.type = "CONSTANT_Fieldref"; 39 | var class_index = reader.readU2(); 40 | var name_and_type_index = reader.readU2(); 41 | info.update = function(cp) { 42 | this.class_ = cp[class_index]; 43 | this.name_and_type = cp[name_and_type_index]; 44 | }; 45 | break; 46 | case 10: 47 | info.type = "CONSTANT_Methodref"; 48 | var class_index = reader.readU2(); 49 | var name_and_type_index = reader.readU2(); 50 | info.update = function(cp) { 51 | this.class_ = cp[class_index]; 52 | this.name_and_type = cp[name_and_type_index]; 53 | }; 54 | break; 55 | case 11: 56 | info.type = "CONSTANT_InterfaceMethodref"; 57 | var class_index = reader.readU2(); 58 | var name_and_type_index = reader.readU2(); 59 | info.update = function(cp) { 60 | this.class_ = cp[class_index]; 61 | this.name_and_type = cp[name_and_type_index]; 62 | }; 63 | break; 64 | case 8: 65 | info.type = "CONSTANT_String"; 66 | var string_index = reader.readU2(); 67 | info.update = function(cp) { 68 | this.value = cp[string_index].value; 69 | }; 70 | break; 71 | case 3: 72 | info.type = "CONSTANT_Integer"; 73 | info.value_type = "I"; 74 | info.value = reader.readU4() | 0; // add sign 75 | break; 76 | case 4: 77 | info.type = "CONSTANT_Float"; 78 | info.value_type = "F"; 79 | var bits = reader.readU4(); 80 | var s = ((bits >>> 31) & 1 === 0) ? 1 : -1; 81 | var e = ((bits >>> 23) & 0xff); 82 | var m = (e === 0) ? 83 | (bits & 0x7fffff) << 1 : 84 | (bits & 0x7fffff) | 0x800000; 85 | info.value = s * m * Math.pow(2, e - 150); 86 | break; 87 | case 5: 88 | info.type = "CONSTANT_Long"; 89 | info.value_type = "J"; 90 | var bytes = reader.readBlock(8); 91 | info.value = new LongValue(bytes); 92 | info.is8ByteContant = true; 93 | break; 94 | case 6: 95 | info.type = "CONSTANT_Double"; 96 | info.value_type = "D"; 97 | var high_bits = reader.readU4(); 98 | var low_bits = reader.readU4(); 99 | var s = ((high_bits >>> 31) & 1 === 0) ? 1 : -1; 100 | var e = (high_bits >>> 20) & 0x7ff; 101 | var high_m = (e === 0) ? 102 | (high_bits & 0xfffff) << 1 : 103 | (high_bits & 0xfffff) | 0x100000; 104 | var low_m = (e === 0) ? low_bits * 2 : low_bits; 105 | info.value = s * (high_m * 0x100000000 + low_m) * Math.pow(2, e - 1075); 106 | info.is8ByteContant = true; 107 | break; 108 | case 12: 109 | info.type = "CONSTANT_NameAndType"; 110 | var name_index = reader.readU2(); 111 | var descriptor_index = reader.readU2(); 112 | info.update = function(cp) { 113 | this.name = cp[name_index].value; 114 | this.descriptor = cp[descriptor_index].value; 115 | }; 116 | break; 117 | case 1: 118 | info.type = "CONSTANT_Utf8"; 119 | var bytesLength = reader.readU2(); 120 | var bytes = reader.readBlock(bytesLength); 121 | var string = ""; 122 | for (var j = 0; j < bytesLength; ++j) { 123 | var charCode = bytes[j]; 124 | if ((charCode & 0x80) !== 0) { // UTF8 125 | var moreBytes = 0, mask = 0x40; 126 | while ((charCode & mask) !== 0) { 127 | moreBytes++; 128 | mask >>= 1; 129 | } 130 | charCode &= (mask - 1); 131 | for (; moreBytes > 0; --moreBytes) { 132 | var nextByte = bytes[++j]; // check for 10xxxxxx? or EOS 133 | charCode = (charCode << 6) | (0x3F & nextByte); 134 | } 135 | } 136 | string += String.fromCharCode(charCode); 137 | } 138 | info.value = string; 139 | break; 140 | default: 141 | throw ("Invalid constant " + info.tag + " @" + readPosition + " " +i); 142 | } 143 | return info; 144 | } 145 | 146 | function read_access_flags() { 147 | var access_flags = reader.readU2(); 148 | var flags = {}; 149 | if ((access_flags & 0x0001) !== 0) { flags.ACC_PUBLIC = true; } 150 | if ((access_flags & 0x0002) !== 0) { flags.ACC_PRIVATE = true; } 151 | if ((access_flags & 0x0004) !== 0) { flags.ACC_PROTECTED = true; } 152 | if ((access_flags & 0x0008) !== 0) { flags.ACC_STATIC = true; } 153 | if ((access_flags & 0x0010) !== 0) { flags.ACC_FINAL = true; } 154 | if ((access_flags & 0x0020) !== 0) { flags.ACC_SUPER = true; } 155 | if ((access_flags & 0x0020) !== 0) { flags.ACC_SYNCHRONIZED = true; } 156 | if ((access_flags & 0x0040) !== 0) { flags.ACC_VOLATILE = true; } 157 | if ((access_flags & 0x0040) !== 0) { flags.ACC_BRIDGE = true; } 158 | if ((access_flags & 0x0080) !== 0) { flags.ACC_TRANSIENT = true; } 159 | if ((access_flags & 0x0080) !== 0) { flags.ACC_VARARGS = true; } 160 | if ((access_flags & 0x0100) !== 0) { flags.ACC_NATIVE = true; } 161 | if ((access_flags & 0x0200) !== 0) { flags.ACC_INTERFACE = true; } 162 | if ((access_flags & 0x0400) !== 0) { flags.ACC_ABSTRACT = true; } 163 | if ((access_flags & 0x0800) !== 0) { flags.ACC_STRICT = true; } 164 | if ((access_flags & 0x1000) !== 0) { flags.ACC_SYNTHETIC = true; } 165 | if ((access_flags & 0x2000) !== 0) { flags.ACC_ANNOTATION = true; } 166 | if ((access_flags & 0x4000) !== 0) { flags.ACC_ENUM = true; } 167 | return flags; 168 | } 169 | 170 | function find_attribute(name) { 171 | for (var i = 0, l = this.attributes.length; i < l; ++i) { 172 | if (this.attributes[i].attribute_name === name) { 173 | return this.attributes[i]; 174 | } 175 | } 176 | return null; 177 | } 178 | 179 | function read_element_value(constant_pool) { 180 | var element_value = {}; 181 | element_value.tag = reader.readU1(); 182 | switch (String.fromCharCode(element_value.tag)) { 183 | case "B": 184 | case "C": 185 | case "D": 186 | case "F": 187 | case "I": 188 | case "J": 189 | case "S": 190 | case "Z": 191 | case "s": 192 | var const_value_index = reader.readU2(); 193 | element_value.value = constant_pool[const_value_index].value; 194 | break; 195 | case "e": 196 | var enum_const_value = {}; 197 | var type_name_index = reader.readU2(); 198 | element_const_value.type_name = constant_pool[type_name_index].value; 199 | var const_name_index = reader.readU2(); 200 | element_const_value.const_name = constant_pool[const_name_index].value; 201 | element_value.value = element_const_value; 202 | break; 203 | case "c": 204 | var class_info_index = reader.readU2(); 205 | element_value.value = constant_pool[class_info_index].value; 206 | break; 207 | case "@": 208 | element_value.value = read_annotation(constant_pool); 209 | break; 210 | case "[": 211 | var num_values = reader.readU2(); 212 | var values = []; 213 | for (var j = 0; j < num_values; ++j) { 214 | values.push(read_element_value(constant_pool)); 215 | } 216 | element_value.value = values; 217 | break; 218 | } 219 | return element_value; 220 | } 221 | 222 | function read_annotation(constant_pool) { 223 | var annotation = {}; 224 | var type_index = reader.readU2(); 225 | annotation.type = constant_pool[type_index].value; 226 | var num_element_value_pairs = reader.readU2(); 227 | var element_value_pairs = []; 228 | for (var q = 0; q < num_element_value_pairs; ++q) { 229 | var element_value_pair = {}; 230 | var element_name_index = reader.readU2(); 231 | element_value_pair.element_name = constant_pool[element_name_index].value; 232 | element_value_pair.value = read_element_value(constant_pool); 233 | 234 | element_value_pairs.push(element_value_pair); 235 | } 236 | annotation.element_value_pairs = element_value_pairs; 237 | return annotation; 238 | } 239 | 240 | function read_attribute_info(constant_pool) { 241 | var info = {}; 242 | var attribute_name_index = reader.readU2(); 243 | info.attribute_name = constant_pool[attribute_name_index].value; 244 | var attribute_length = reader.readU4(); 245 | switch (info.attribute_name) { 246 | case "ConstantValue": 247 | var constantvalue_index = reader.readU2(); 248 | info.constantvalue = constant_pool[constantvalue_index]; 249 | break; 250 | case "Code": 251 | info.max_stack = reader.readU2(); 252 | info.max_locals = reader.readU2(); 253 | var code_length = reader.readU4(); 254 | info.code = reader.readBlock(code_length); 255 | var exception_table_length = reader.readU2(); 256 | var exception_table = []; 257 | for (var j = 0; j < exception_table_length; j++) { 258 | var exception = {}; 259 | exception.start_pc = reader.readU2(); 260 | exception.end_pc = reader.readU2(); 261 | exception.handler_pc = reader.readU2(); 262 | var catch_type = reader.readU2(); 263 | if (catch_type > 0) { 264 | exception.catch_type = constant_pool[catch_type]; 265 | } 266 | exception_table.push(exception); 267 | } 268 | info.exception_table = exception_table; 269 | var attributes_count = reader.readU2(); 270 | var attributes = []; 271 | for (var j = 0; j < attributes_count; j++) { 272 | attributes.push(read_attribute_info(constant_pool)); 273 | } 274 | info.find_attribute = find_attribute; 275 | info.attributes = attributes; 276 | break; 277 | case "Exceptions": 278 | var number_of_exceptions = reader.readU2(); 279 | var exception_table = []; 280 | for (var j = 0; j < number_of_exceptions; j++) { 281 | var exception_index = reader.readU2(); 282 | exception_table.push(constant_pool[exception_index]); 283 | } 284 | info.exception_table = exception_table; 285 | break; 286 | case "InnerClasses": 287 | var number_of_classes = reader.readU2(); 288 | var classes = []; 289 | for (var j = 0; j < number_of_classes; j++) { 290 | var class_ = {}; 291 | var inner_class_info_index = reader.readU2(); 292 | if (inner_class_info_index > 0) { 293 | class_.inner_class_info = constant_pool[inner_class_info_index]; 294 | } 295 | var outer_class_info_index = reader.readU2(); 296 | if (outer_class_info_index > 0) { 297 | class_.outer_class_info = constant_pool[outer_class_info_index]; 298 | } 299 | var inner_name_index = reader.readU2(); 300 | if (inner_name_index > 0) { 301 | class_.inner_name = constant_pool[inner_name_index]; 302 | } 303 | class_.inner_class_access_flags = read_access_flags(); 304 | classes.push(class_); 305 | } 306 | info.classes = classes; 307 | break; 308 | case "SourceFile": 309 | var sourcefile_index = reader.readU2(); 310 | info.sourcefile = constant_pool[sourcefile_index].value; 311 | break; 312 | case "LineNumberTable": 313 | var line_number_table_length = reader.readU2(); 314 | var line_number_table = []; 315 | for (var j = 0; j < line_number_table_length; j++) { 316 | var line_number = {}; 317 | line_number.start_pc = reader.readU2(); 318 | line_number.line_number = reader.readU2(); 319 | line_number_table.push(line_number); 320 | } 321 | info.line_number_table = line_number_table; 322 | break; 323 | case "LocalVariableTable": 324 | var local_variable_table_length = reader.readU2(); 325 | var local_variable_table = []; 326 | for (var j = 0; j < local_variable_table_length; j++) { 327 | var local_variable = {}; 328 | local_variable.start_pc = reader.readU2(); 329 | local_variable.use_length = reader.readU2(); 330 | var name_index = reader.readU2(); 331 | local_variable.name = constant_pool[name_index].value; 332 | var descriptor_index = reader.readU2(); 333 | local_variable.descriptor = constant_pool[descriptor_index].value; 334 | local_variable.index = reader.readU2(); 335 | 336 | local_variable_table.push(local_variable); 337 | if (local_variable.descriptor === "D" || local_variable.descriptor === "J") { 338 | j++; 339 | local_variable_table.push(local_variable); 340 | } 341 | } 342 | info.local_variable_table = local_variable_table; 343 | break; 344 | case "EnclosingMethod": 345 | var class_index = reader.readU2(); 346 | info.class_ = constant_pool[class_index]; 347 | var method_index = reader.readU2(); 348 | info.method = constant_pool[method_index]; 349 | break; 350 | case "Signature": 351 | var signature_index = reader.readU2(); 352 | info.signature = constant_pool[signature_index].value; 353 | break; 354 | case "LocalVariableTypeTable": 355 | var local_variable_type_table_length = reader.readU2(); 356 | var local_variable_type_table = []; 357 | for (var j = 0; j < local_variable_type_table_length; ++j) { 358 | var local_variable_type = {}; 359 | local_variable_type.start_pc = reader.readU2(); 360 | local_variable_type.length_ = reader.readU2(); 361 | var name_index = reader.readU2(); 362 | local_variable_type.name = constant_pool[name_index].value; 363 | var signature_index = reader.readU2(); 364 | local_variable_type.signature = constant_pool[signature_index].value; 365 | local_variable_type.index = reader.readU2(); 366 | 367 | local_variable_type_table.push(local_variable_type); 368 | } 369 | info.local_variable_type_table = local_variable_type_table; 370 | break; 371 | case "RuntimeVisibleAnnotations": 372 | case "RuntimeInvisibleAnnotations": 373 | var num_annotations = reader.readU2(); 374 | var annotations = []; 375 | for (var j = 0; j < num_annotations; ++j) { 376 | annotations.push(read_annotation(constant_pool)); 377 | } 378 | info.annotations = annotations; 379 | break; 380 | case "RuntimeVisibleParameterAnnotations": 381 | case "RuntimeInvisibleParameterAnnotations": 382 | var num_parameters = reader.readU1(); 383 | var parameter_annotations = []; 384 | for (var j = 0; j < num_parameters; ++j) { 385 | var num_annotations = reader.readU2(); 386 | var annotations = []; 387 | for (var q = 0; q < num_annotations; ++q) { 388 | annotations.push(read_annotation(constant_pool)); 389 | } 390 | info.annotations = annotations; 391 | 392 | parameter_annotations.push(annotations); 393 | } 394 | info.parameter_annotations = parameter_annotations; 395 | break; 396 | case "Synthetic": 397 | case "Depricated": 398 | default: 399 | if (attribute_length > 0) { 400 | info.info = reader.readBlock(attribute_length); 401 | } 402 | break; 403 | } 404 | return info; 405 | } 406 | 407 | function read_field_info(constant_pool) { 408 | var info = {}; 409 | info.access_flags = read_access_flags(); 410 | var name_index = reader.readU2(); 411 | info.name = constant_pool[name_index].value; 412 | var descriptor_index = reader.readU2(); 413 | info.descriptor = constant_pool[descriptor_index].value; 414 | var attributes_count = reader.readU2(), attributes = []; 415 | for (var j = 0; j < attributes_count; j++) { 416 | attributes.push(read_attribute_info(constant_pool)); 417 | } 418 | info.find_attribute = find_attribute; 419 | info.attributes = attributes; 420 | return info; 421 | } 422 | 423 | function read_method_info(constant_pool) { 424 | var info = {}; 425 | info.access_flags = read_access_flags(); 426 | var name_index = reader.readU2(); 427 | info.name = constant_pool[name_index].value; 428 | var descriptor_index = reader.readU2(); 429 | info.descriptor = constant_pool[descriptor_index].value; 430 | var attributes_count = reader.readU2(), attributes = []; 431 | for (var j = 0; j < attributes_count; j++) { 432 | attributes.push(read_attribute_info(constant_pool)); 433 | } 434 | info.find_attribute = find_attribute; 435 | info.attributes = attributes; 436 | return info; 437 | } 438 | 439 | var magic = reader.readU4(); 440 | if (magic !== 0xCAFEBABE) { 441 | throw "Invalid class file signature"; 442 | } 443 | 444 | var classFile = {}; 445 | var minor_version = reader.readU2(); 446 | var major_version = reader.readU2(); 447 | classFile.version = { major: major_version, minor: minor_version }; 448 | 449 | var constant_pool_count = reader.readU2(), constant_pool = [null]; 450 | for (var i = 1; i < constant_pool_count; ++i) { 451 | var constant = read_cp_info(); 452 | constant_pool.push(constant); 453 | if (constant.is8ByteContant) { 454 | i++; 455 | constant_pool.push(constant); 456 | } 457 | } 458 | for (var i = 1; i < constant_pool_count; ++i) { 459 | if ("update" in constant_pool[i]) { 460 | constant_pool[i].update(constant_pool); 461 | delete constant_pool[i].update; 462 | } 463 | } 464 | classFile.constant_pool = constant_pool; 465 | 466 | classFile.access_flags = read_access_flags(); 467 | 468 | var this_class = reader.readU2(); 469 | classFile.this_class = constant_pool[this_class]; 470 | 471 | var super_class = reader.readU2(); 472 | if (super_class > 0) { 473 | classFile.super_class = constant_pool[super_class]; 474 | } 475 | 476 | var interfaces_count = reader.readU2(), interfaces = []; 477 | for (var i = 0; i < interfaces_count; ++i) { 478 | interfaces.push(constant_pool[reader.readU2()]); 479 | } 480 | classFile.interfaces = interfaces; 481 | 482 | var fields_count = reader.readU2(), fields = []; 483 | for (var i = 0; i < fields_count; ++i) { 484 | fields.push(read_field_info(constant_pool)); 485 | } 486 | classFile.fields = fields; 487 | 488 | var methods_count = reader.readU2(), methods = []; 489 | for (var i = 0; i < methods_count; ++i) { 490 | methods.push(read_method_info(constant_pool)); 491 | } 492 | classFile.methods = methods; 493 | 494 | var attributes_count = reader.readU2(), attributes = []; 495 | for (var i = 0; i < attributes_count; ++i) { 496 | attributes.push(read_attribute_info(constant_pool)); 497 | } 498 | classFile.find_attribute = find_attribute; 499 | classFile.attributes = attributes; 500 | 501 | return classFile; 502 | } 503 | 504 | function loadFileAsync(classUrl, callback) { 505 | var request = new XMLHttpRequest(); 506 | request.onreadystatechange = function() { 507 | if(request.readyState == 4) { 508 | if (request.status == 200 || request.status == 0) { 509 | var data = []; 510 | var s = request.responseText; 511 | for (var j = 0, l = s.length; j < l; ++j) { 512 | data.push(s.charCodeAt(j) & 0xFF); 513 | } 514 | callback(data); 515 | } else { 516 | callback(null); 517 | } 518 | } 519 | }; 520 | request.open('GET', classUrl, true); 521 | request.overrideMimeType('text/plain; charset=x-user-defined'); 522 | request.send(); 523 | } 524 | 525 | function loadFile(classUrl) { 526 | var request = new XMLHttpRequest(); 527 | request.open('GET', classUrl, false); 528 | request.overrideMimeType('text/plain; charset=x-user-defined'); 529 | request.send(); 530 | 531 | if (request.status != 200 && request.status != 0) { 532 | throw "File " + classUrl + " is not available: " + request.statusText; 533 | } 534 | 535 | var data = []; 536 | var s = request.responseText; 537 | for (var j = 0, l = s.length; j < l; ++j) { 538 | data.push(s.charCodeAt(j) & 0xFF); 539 | } 540 | return data; 541 | } 542 | 543 | function loadJarFile(url) { 544 | var data = loadFile(url); 545 | return readJarContent(data); 546 | } 547 | -------------------------------------------------------------------------------- /jvm.js: -------------------------------------------------------------------------------- 1 | var runtime; 2 | 3 | function MethodProxy(method, constant_pool, obj, args) { 4 | function getValueCategory(value) { 5 | return value.type === "D" || value.type === "J" ? 2 : 1; 6 | } 7 | 8 | function getArgumentsFromDescriptor(descriptor) { 9 | var i = descriptor.indexOf("("), j = descriptor.indexOf(")"); 10 | var regexp = /\[*(L[^;]*;|[BCDFIJSZ])/g; 11 | var args = [], m, argsString = descriptor.substring(i + 1, j); 12 | while ((m = regexp.exec(argsString)) !== null) { 13 | args.push(m[0]); 14 | } 15 | return args; 16 | } 17 | 18 | function getArgumentsCountFromDescriptor(descriptor) { 19 | return getArgumentsFromDescriptor(descriptor).length; 20 | } 21 | 22 | function hasReturnValueFromDescriptor(descriptor) { 23 | return descriptor.indexOf(")V") < 0; 24 | } 25 | 26 | var methodCode = method.find_attribute("Code"); 27 | var exceptionTable = methodCode.exception_table; 28 | var isStatic = "ACC_STATIC" in method.access_flags; 29 | var argumentDescriptors = getArgumentsFromDescriptor(method.descriptor); 30 | 31 | var bytecode = methodCode.code; 32 | var stack = []; 33 | var locals = []; 34 | if (!isStatic) { 35 | locals.push(obj); 36 | } 37 | for (var i = 0; i < argumentDescriptors.length; i++) { 38 | locals.push(args[i]); 39 | if (getValueCategory(argumentDescriptors[i]) === 2) { 40 | locals.push(args[i]); 41 | } 42 | } 43 | 44 | var pc = 0, lastKnownPc; 45 | var wideFound = false; 46 | 47 | this.execute = function() { 48 | try { 49 | var limit = 30000; 50 | while (this.step()) { 51 | if (--limit < 0) { throw "too many steps"; } 52 | } 53 | return stack.pop(); 54 | } catch (ex) { 55 | if (ex instanceof MethodExecutionException && ex.nativeException) { 56 | throw ex.nativeException.$self; 57 | } else { 58 | throw ex; 59 | } 60 | } 61 | }; 62 | 63 | this.step = function() { 64 | var raiseExceptionCookie = {}; 65 | 66 | function validateArrayref(arrayref) { 67 | if (arrayref === null) { 68 | raiseException("java/lang/NullPointerException"); 69 | } 70 | } 71 | 72 | function validateArrayrefAndIndex(arrayref, index) { 73 | validateArrayref(arrayref); 74 | if (!(index.value >= 0 && index.value < arrayref.length)) { 75 | raiseException("java/lang/ArrayIndexOutOfBoundsException"); 76 | } 77 | } 78 | 79 | function raiseException(typeName) { 80 | var ex = runtime.newexception(typeName); 81 | processThrow(ex); 82 | } 83 | 84 | function processThrow(objectref) { 85 | // check table 86 | var handler; 87 | for (var i = 0, l = exceptionTable.length; i < l; ++i) { 88 | if (exceptionTable[i].start_pc <= lastKnownPc && lastKnownPc < exceptionTable[i].end_pc) { 89 | if (!exceptionTable[i].catch_type || instanceOf(objectref, exceptionTable[i].catch_type)) { 90 | handler = exceptionTable[i]; 91 | break; 92 | } 93 | } 94 | } 95 | if (handler) { 96 | stack.push(objectref); 97 | pc = exceptionTable[i].handler_pc; 98 | throw raiseExceptionCookie; 99 | } else { 100 | if (!("stackTrace" in objectref)) { 101 | objectref.stackTrace = []; 102 | } 103 | objectref.stackTrace.push({method: method, pc: lastKnownPc}); 104 | throw new MethodExecutionException("Exception", objectref); 105 | } 106 | } 107 | 108 | function validateNonNull(objectref) { 109 | if (objectref === null) { 110 | raiseException("java/lang/NullPointerException"); 111 | } 112 | } 113 | 114 | function convertForStore(value, oldValue) { 115 | if (typeof value !== "object" || typeof oldValue !== "object" || 116 | !("type" in value) || !("value" in value)) { 117 | return value; 118 | } 119 | if (value.type === oldValue.type) { 120 | return value; 121 | } else if (value.type === "J") { 122 | return {value:value.value.toNumeric(), type:oldValue.type}; 123 | } else if (oldValue.type === "J") { 124 | return {value:LongValue.fromNumeric(value.value), type:oldValue.type}; 125 | } else { 126 | return {value:value.value, type:oldValue.type}; 127 | } 128 | } 129 | 130 | function getDefaultValue(atype) { 131 | switch (atype) { 132 | case 4: // T_BOOLEAN 133 | return { value: 0, type: "Z" }; 134 | case 5: // T_CHAR 135 | return { value: 0, type: "C" }; 136 | case 6: // T_FLOAT 137 | return { value: 0, type: "F" }; 138 | case 7: // T_DOUBLE 139 | return { value: 0, type: "D" }; 140 | case 8: // T_BYTE 141 | return { value: 0, type: "B" }; 142 | case 9: // T_SHORT 143 | return { value: 0, type: "S" }; 144 | case 10: // T_INT 145 | return { value: 0, type: "I" }; 146 | case 11: // T_LONG 147 | return { value: LongValue.Zero, type: "J" }; 148 | } 149 | return null; 150 | } 151 | 152 | function createAArray(counts, class_) { 153 | var ar = []; 154 | for (var i = 0, l = counts[0]; i < l; ++i) { 155 | ar.push( counts.length <= 1 ? null : 156 | createAArray(counts.slice(1, counts.length), class_) ); 157 | } 158 | return ar; 159 | } 160 | 161 | function createArray(count, atype) { 162 | var ar = [], defaultValue = getDefaultValue(atype); 163 | for (var i = 0, l = count.value; i < l; ++i) { 164 | ar.push(defaultValue); 165 | } 166 | return ar; 167 | } 168 | 169 | function checkCast(objectref, type) { 170 | if (!runtime.instanceof_(objectref, type)) { 171 | raiseException("java/lang/ClassCastException"); 172 | } 173 | } 174 | 175 | function instanceOf(objectref, type) { 176 | return runtime.instanceof_(objectref, type) ? 1 : 0; 177 | } 178 | 179 | lastKnownPc = pc; 180 | 181 | try { 182 | var op = bytecode[pc++]; 183 | var jumpToAddress = null; 184 | // log("OP="+ op + "; CP=" + (pc-1) + "; STACK=" + uneval(stack) + "; LOCALS=" + uneval(locals)); 185 | 186 | switch (op) { 187 | case 0: // (0x00) nop 188 | break; 189 | case 1: // (0x01) aconst_null 190 | stack.push(null); 191 | break; 192 | case 2: // (0x02) iconst_m1 193 | case 3: // (0x03) iconst_0 194 | case 4: // (0x04) iconst_1 195 | case 5: // (0x05) iconst_2 196 | case 6: // (0x06) iconst_3 197 | case 7: // (0x07) iconst_4 198 | case 8: // (0x08) iconst_5 199 | var n = op - 3; 200 | stack.push({value: n, type: "I"}); 201 | break; 202 | case 9: // (0x09) lconst_0 203 | case 10: // (0x0a) lconst_1 204 | var n = op - 9; 205 | stack.push({value: new LongValue([0,0,0,0,0,0,0,n]), type: "J"}); 206 | break; 207 | case 11: // (0x0b) fconst_0 208 | case 12: // (0x0c) fconst_1 209 | case 13: // (0x0d) fconst_2 210 | var n = op - 11; 211 | stack.push({value: n, type: "F"}); 212 | break; 213 | case 14: // (0x0e) dconst_0 214 | case 15: // (0x0f) dconst_1 215 | var n = op - 14; 216 | stack.push({value: n, type: "D"}); 217 | break; 218 | case 16: // (0x10) bipush 219 | var n = bytecode[pc++]; 220 | stack.push({value: n > 0x80 ? n - 0x100 : n, type: "I"}); 221 | break; 222 | case 17: // (0x11) sipush 223 | var n = (bytecode[pc] << 8) | bytecode[pc + 1]; 224 | pc += 2; 225 | stack.push({value: n > 0x8000 ? n - 0x10000 : n, type: "I"}); 226 | break; 227 | case 18: // (0x12) ldc 228 | var index = bytecode[pc++]; 229 | var const_ = constant_pool[index]; 230 | if ("value_type" in const_) { 231 | stack.push({value: const_.value, type: const_.value_type}); 232 | } else { 233 | stack.push(const_.value); 234 | } 235 | break; 236 | case 19: // (0x13) ldc_w 237 | case 20: // (0x14) ldc2_w 238 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 239 | pc += 2; 240 | var const_ = constant_pool[index]; 241 | if ("value_type" in const_) { 242 | stack.push({value: const_.value, type: const_.value_type}); 243 | } else { 244 | stack.push(const_.value); 245 | } 246 | break; 247 | case 21: // (0x15) iload 248 | case 22: // (0x16) lload 249 | case 23: // (0x17) fload 250 | case 24: // (0x18) dload 251 | case 25: // (0x19) aload 252 | var index; 253 | if (wideFound) { 254 | wideFound = false; 255 | index = (bytecode[pc] << 8) | bytecode[pc + 1]; 256 | pc += 2; 257 | } else { 258 | index = bytecode[pc++]; 259 | } 260 | stack.push(locals[index]); 261 | break; 262 | case 26: // (0x1a) iload_0 263 | case 30: // (0x1e) lload_0 264 | case 34: // (0x22) fload_0 265 | case 38: // (0x26) dload_0 266 | case 42: // (0x2a) aload_0 267 | stack.push(locals[0]); 268 | break; 269 | case 27: // (0x1b) iload_1 270 | case 31: // (0x1f) lload_1 271 | case 35: // (0x23) fload_1 272 | case 39: // (0x27) dload_1 273 | case 43: // (0x2b) aload_1 274 | stack.push(locals[1]); 275 | break; 276 | case 32: // (0x20) lload_2 277 | case 28: // (0x1c) iload_2 278 | case 36: // (0x24) fload_2 279 | case 40: // (0x28) dload_2 280 | case 44: // (0x2c) aload_2 281 | stack.push(locals[2]); 282 | break; 283 | case 29: // (0x1d) iload_3 284 | case 33: // (0x21) lload_3 285 | case 37: // (0x25) fload_3 286 | case 41: // (0x29) dload_3 287 | case 45: // (0x2d) aload_3 288 | stack.push(locals[3]); 289 | break; 290 | case 46: // (0x2e) iaload 291 | case 47: // (0x2f) laload 292 | case 48: // (0x30) faload 293 | case 49: // (0x31) daload 294 | case 50: // (0x32) aaload 295 | case 51: // (0x33) baload 296 | case 52: // (0x34) caload 297 | case 53: // (0x35) saload 298 | var index = stack.pop(); 299 | var arrayref = stack.pop(); 300 | validateArrayrefAndIndex(arrayref, index); 301 | stack.push(arrayref.value[index.value]); 302 | break; 303 | case 54: // (0x36) istore 304 | case 55: // (0x37) lstore 305 | case 56: // (0x38) fstore 306 | case 57: // (0x39) dstore 307 | case 58: // (0x3a) astore 308 | var index; 309 | if (wideFound) { 310 | wideFound = false; 311 | index = (bytecode[pc] << 8) | bytecode[pc + 1]; 312 | pc += 2; 313 | } else { 314 | index = bytecode[pc++]; 315 | } 316 | locals[index] = convertForStore(stack.pop(), locals[index]); 317 | break; 318 | case 59: // (0x3b) istore_0 319 | case 63: // (0x3f) lstore_0 320 | case 67: // (0x43) fstore_0 321 | case 71: // (0x47) dstore_0 322 | case 75: // (0x4b) astore_0 323 | locals[0] = convertForStore(stack.pop(), locals[0]); 324 | break; 325 | case 60: // (0x3c) istore_1 326 | case 64: // (0x40) lstore_1 327 | case 68: // (0x44) fstore_1 328 | case 72: // (0x48) dstore_1 329 | case 76: // (0x4c) astore_1 330 | locals[1] = convertForStore(stack.pop(), locals[1]); 331 | break; 332 | case 61: // (0x3d) istore_2 333 | case 65: // (0x41) lstore_2 334 | case 69: // (0x45) fstore_2 335 | case 73: // (0x49) dstore_2 336 | case 77: // (0x4d) astore_2 337 | locals[2] = convertForStore(stack.pop(), locals[2]); 338 | break; 339 | case 62: // (0x3e) istore_3 340 | case 66: // (0x42) lstore_3 341 | case 70: // (0x46) fstore_3 342 | case 74: // (0x4a) dstore_3 343 | case 78: // (0x4e) astore_3 344 | locals[3] = convertForStore(stack.pop(), locals[3]); 345 | break; 346 | case 79: // (0x4f) iastore 347 | case 80: // (0x50) lastore 348 | case 81: // (0x51) fastore 349 | case 82: // (0x52) dastore 350 | case 83: // (0x53) aastore 351 | case 84: // (0x54) bastore 352 | case 85: // (0x55) castore 353 | case 86: // (0x56) sastore 354 | var value = stack.pop(); 355 | var index = stack.pop(); 356 | var arrayref = stack.pop(); 357 | validateArrayrefAndIndex(arrayref, index); 358 | arrayref.value[index.value] = convertForStore(value, arrayref.value[index.value]); 359 | break; 360 | case 87: // (0x57) pop 361 | stack.pop(); 362 | break; 363 | case 88: // (0x58) pop2 364 | if (getValueCategory(stack.pop()) === 1) { 365 | stack.pop(); 366 | } 367 | break; 368 | case 89: // (0x59) dup 369 | var value = stack.pop(); 370 | stack.push(value); 371 | stack.push(value); 372 | break; 373 | case 90: // (0x5a) dup_x1 374 | var value1 = stack.pop(); 375 | var value2 = stack.pop(); 376 | stack.push(value1); 377 | stack.push(value2); 378 | stack.push(value1); 379 | break; 380 | case 91: // (0x5b) dup_x2 381 | var value1 = stack.pop(); 382 | var value2 = stack.pop(); 383 | if (getValueCategory(value1) === 1) { 384 | var value3 = stack.pop(); 385 | stack.push(value1); 386 | stack.push(value3); 387 | stack.push(value2); 388 | stack.push(value1); 389 | } else { 390 | stack.push(value1); 391 | stack.push(value2); 392 | stack.push(value1); 393 | } 394 | break; 395 | case 92: // (0x5c) dup2 396 | var value1 = stack.pop(); 397 | if (getValueCategory(value1) === 1) { 398 | var value2 = stack.pop(); 399 | stack.push(value2); 400 | stack.push(value1); 401 | stack.push(value2); 402 | stack.push(value1); 403 | } else { 404 | stack.push(value1); 405 | stack.push(value1); 406 | } 407 | break; 408 | case 93: // (0x5d) dup2_x1 409 | var value1 = stack.pop(); 410 | var value2 = stack.pop(); 411 | if (getValueCategory(value1) === 1) { 412 | var value3 = stack.pop(); 413 | stack.push(value2); 414 | stack.push(value1); 415 | stack.push(value3); 416 | stack.push(value2); 417 | stack.push(value1); 418 | } else { 419 | stack.push(value1); 420 | stack.push(value2); 421 | stack.push(value1); 422 | } 423 | break; 424 | case 94: // (0x5e) dup2_x2 425 | var value1 = stack.pop(); 426 | var value2 = stack.pop(); 427 | if (getValueCategory(value1) === 1) { 428 | var value3 = stack.pop(); 429 | if(getValueCategory(value3) === 1) { 430 | var value4 = stack.pop(); 431 | // form 1 432 | stack.push(value2); 433 | stack.push(value1); 434 | stack.push(value4); 435 | stack.push(value3); 436 | stack.push(value2); 437 | stack.push(value1); 438 | } else { 439 | // form 3 440 | stack.push(value2); 441 | stack.push(value1); 442 | stack.push(value3); 443 | stack.push(value2); 444 | stack.push(value1); 445 | } 446 | } else { 447 | if(getValueCategory(value2) === 1) { 448 | var value3 = stack.pop(); 449 | // form 2 450 | stack.push(value1); 451 | stack.push(value3); 452 | stack.push(value2); 453 | stack.push(value1); 454 | } else { 455 | // form 4 456 | stack.push(value1); 457 | stack.push(value2); 458 | stack.push(value1); 459 | } 460 | } 461 | break; 462 | case 95: // (0x5f) swap 463 | var value1 = stack.pop(); 464 | var value2 = stack.pop(); 465 | stack.push(value1); 466 | stack.push(value2); 467 | break; 468 | case 96: // (0x60) iadd 469 | var value2 = stack.pop(); 470 | var value1 = stack.pop(); 471 | var resultValue = (value1.value + value2.value) | 0; 472 | stack.push({value: resultValue, type: "I"}); 473 | break; 474 | case 97: // (0x61) ladd 475 | var value2 = stack.pop(); 476 | var value1 = stack.pop(); 477 | var resultValue = value1.value.add(value2.value); 478 | stack.push({value: resultValue, type: "J"}); 479 | break; 480 | case 98: // (0x62) fadd 481 | var value2 = stack.pop(); 482 | var value1 = stack.pop(); 483 | var resultValue = value1.value + value2.value; 484 | stack.push({value: resultValue, type: "F"}); 485 | break; 486 | case 99: // (0x63) dadd 487 | var value2 = stack.pop(); 488 | var value1 = stack.pop(); 489 | var resultValue = value1.value + value2.value; 490 | stack.push({value: resultValue, type: "D"}); 491 | break; 492 | case 100: // (0x64) isub 493 | var value2 = stack.pop(); 494 | var value1 = stack.pop(); 495 | var resultValue = (value1.value - value2.value) | 0; 496 | stack.push({value: resultValue, type: "I"}); 497 | break; 498 | case 101: // (0x65) lsub 499 | var value2 = stack.pop(); 500 | var value1 = stack.pop(); 501 | var resultValue = value1.value.sub(value2.value); 502 | stack.push({value: resultValue, type: "J"}); 503 | break; 504 | case 102: // (0x66) fsub 505 | var value2 = stack.pop(); 506 | var value1 = stack.pop(); 507 | var resultValue = value1.value - value2.value; 508 | stack.push({value: resultValue, type: "F"}); 509 | break; 510 | case 103: // (0x67) dsub 511 | var value2 = stack.pop(); 512 | var value1 = stack.pop(); 513 | var resultValue = value1.value - value2.value; 514 | stack.push({value: resultValue, type: "D"}); 515 | break; 516 | case 104: // (0x68) imul 517 | var value2 = stack.pop(); 518 | var value1 = stack.pop(); 519 | var resultValue = (value1.value * value2.value) | 0; 520 | stack.push({value: resultValue, type: "I"}); 521 | break; 522 | case 105: // (0x69) lmul 523 | var value2 = stack.pop(); 524 | var value1 = stack.pop(); 525 | var resultValue = value1.value.mul(value2.value); 526 | stack.push({value: resultValue, type: "J"}); 527 | break; 528 | case 106: // (0x6a) fmul 529 | var value2 = stack.pop(); 530 | var value1 = stack.pop(); 531 | var resultValue = value1.value * value2.value; 532 | stack.push({value: resultValue, type: "F"}); 533 | break; 534 | case 107: // (0x6b) dmul 535 | var value2 = stack.pop(); 536 | var value1 = stack.pop(); 537 | var resultValue = value1.value * value2.value; 538 | stack.push({value: resultValue, type: "D"}); 539 | break; 540 | case 108: // (0x6c) idiv 541 | var value2 = stack.pop(); 542 | var value1 = stack.pop(); 543 | if (value2.value === 0) raiseException("java/lang/ArithmeticException"); 544 | var resultValue = (value1.value / value2.value) | 0; 545 | stack.push({value: resultValue, type: "I"}); 546 | break; 547 | case 109: // (0x6d) ldiv 548 | var value2 = stack.pop(); 549 | var value1 = stack.pop(); 550 | if (value2.value.cmp(LongValue.Zero) === 0) raiseException("java/lang/ArithmeticException"); 551 | var resultValue = value1.value.div(value2.value); 552 | stack.push({value: resultValue, type: "J"}); 553 | break; 554 | case 110: // (0x6e) fdiv 555 | var value2 = stack.pop(); 556 | var value1 = stack.pop(); 557 | var resultValue = value1.value / value2.value; 558 | stack.push({value: resultValue, type: "F"}); 559 | break; 560 | case 111: // (0x6f) ddiv 561 | var value2 = stack.pop(); 562 | var value1 = stack.pop(); 563 | var resultValue = value1.value / value2.value; 564 | stack.push({value: resultValue, type: "D"}); 565 | break; 566 | case 112: // (0x70) irem 567 | var value2 = stack.pop(); 568 | var value1 = stack.pop(); 569 | if (value2.value === 0) raiseException("java/lang/ArithmeticException"); 570 | var resultValue = value1.value - ((value1.value / value2.value) | 0) * value2.value; 571 | stack.push({value: resultValue, type: "I"}); 572 | break; 573 | case 113: // (0x71) lrem 574 | var value2 = stack.pop(); 575 | var value1 = stack.pop(); 576 | if (value2.value.cmp(LongValue.Zero) === 0) raiseException("java/lang/ArithmeticException"); 577 | var resultValue = value1.value.rem(value2.value); 578 | stack.push({value: resultValue, type: "J"}); 579 | break; 580 | case 114: // (0x72) frem 581 | var value2 = stack.pop(); 582 | var value1 = stack.pop(); 583 | if (value2.value === 0 || isNaN(value2.value)) { 584 | stack.push({value: NaN, type: "F"}); 585 | } else { 586 | var resultValue = value1.value - Math.floor(value1.value / value2.value) * value2.value; 587 | stack.push({value: resultValue, type: "F"}); 588 | } 589 | break; 590 | case 115: // (0x73) drem 591 | var value2 = stack.pop(); 592 | var value1 = stack.pop(); 593 | if (value2.value === 0 || isNaN(value2.value)) { 594 | stack.push({value: NaN, type: "D"}); 595 | } else { 596 | var resultValue = value1.value - Math.floor(value1.value / value2.value) * value2.value; 597 | stack.push({value: resultValue, type: "D"}); 598 | } 599 | break; 600 | case 116: // (0x74) ineg 601 | var value = stack.pop(); 602 | var resultValue = (-value2.value) | 0; 603 | stack.push({value: resultValue, type: "I"}); 604 | break; 605 | case 117: // (0x75) lneg 606 | var value = stack.pop(); 607 | var resultValue = value2.value.neg(); 608 | stack.push({value: resultValue, type: "J"}); 609 | break; 610 | case 118: // (0x76) fneg 611 | var value = stack.pop(); 612 | var resultValue = -value2.value; 613 | stack.push({value: resultValue, type: "F"}); 614 | break; 615 | case 119: // (0x77) dneg 616 | var value = stack.pop(); 617 | var resultValue = -value2.value; 618 | stack.push({value: resultValue, type: "D"}); 619 | break; 620 | case 120: // (0x78) ishl 621 | var value2 = stack.pop(); 622 | var value1 = stack.pop(); 623 | var resultValue = (value1.value << (value2.value & 0x3F)); 624 | stack.push({value: resultValue, type: "I"}); 625 | break; 626 | case 121: // (0x79) lshl 627 | var value2 = stack.pop(); 628 | var value1 = stack.pop(); 629 | var resultValue = value1.value.shl(value2.value & 0x3F); 630 | stack.push({value: resultValue, type: "J"}); 631 | break; 632 | case 122: // (0x7a) ishr 633 | var value2 = stack.pop(); 634 | var value1 = stack.pop(); 635 | var resultValue = (value1.value >> (value2.value & 0x3F)); 636 | stack.push({value: resultValue, type: "I"}); 637 | break; 638 | case 123: // (0x7b) lshr 639 | var value2 = stack.pop(); 640 | var value1 = stack.pop(); 641 | var resultValue = value1.value.shr(value2.value & 0x3F); 642 | stack.push({value: resultValue, type: "J"}); 643 | break; 644 | case 124: // (0x7c) iushr 645 | var value2 = stack.pop(); 646 | var value1 = stack.pop(); 647 | var resultValue = (value1.value >>> (value2.value & 0x3F)); 648 | stack.push({value: resultValue, type: "I"}); 649 | break; 650 | case 125: // (0x7d) lushr 651 | var value2 = stack.pop(); 652 | var value1 = stack.pop(); 653 | var resultValue = value1.value.ushr(value2.value & 0x3F); 654 | stack.push({value: resultValue, type: "J"}); 655 | break; 656 | case 126: // (0x7e) iand 657 | var value2 = stack.pop(); 658 | var value1 = stack.pop(); 659 | var resultValue = (value1.value & value2.value); 660 | stack.push({value: resultValue, type: "I"}); 661 | break; 662 | case 127: // (0x7f) land 663 | var value2 = stack.pop(); 664 | var value1 = stack.pop(); 665 | var resultValue = value1.value.and(value2.value); 666 | stack.push({value: resultValue, type: "J"}); 667 | break; 668 | case 128: // (0x80) ior 669 | var value2 = stack.pop(); 670 | var value1 = stack.pop(); 671 | var resultValue = (value1.value | value2.value); 672 | stack.push({value: resultValue, type: "I"}); 673 | break; 674 | case 129: // (0x81) lor 675 | var value2 = stack.pop(); 676 | var value1 = stack.pop(); 677 | var resultValue = value1.value.or(value2.value); 678 | stack.push({value: resultValue, type: "J"}); 679 | break; 680 | case 130: // (0x82) ixor 681 | var value2 = stack.pop(); 682 | var value1 = stack.pop(); 683 | var resultValue = (value1.value ^ value2.value); 684 | stack.push({value: resultValue, type: "I"}); 685 | break; 686 | case 131: // (0x83) lxor 687 | var value2 = stack.pop(); 688 | var value1 = stack.pop(); 689 | var resultValue = value1.value.xor(value2.value); 690 | stack.push({value: resultValue, type: "J"}); 691 | break; 692 | case 132: // (0x84) iinc 693 | var index, const_; 694 | if (wideFound) { 695 | wideFound = false; 696 | index = (bytecode[pc] << 8) | bytecode[pc + 1]; 697 | const_ = (bytecode[pc + 2] << 8) | bytecode[pc + 3]; 698 | pc += 4; 699 | if (const_ >= 0x8000) { const_ -= 0x10000; } 700 | } else { 701 | index = bytecode[pc++]; 702 | const_ = bytecode[pc++]; 703 | if (const_ >= 0x80) { const_ -= 0x100; } 704 | } 705 | locals[index].value = (locals[index].value + const_) | 0; 706 | break; 707 | case 133: // (0x85) i2l 708 | var value = stack.pop(); 709 | var sign = ((value.value >> 31) & 1) === 0 ? 0 : 0xFF; 710 | var resultValue = new LongValue([sign,sign,sign,sign, 711 | (value.value >> 24) & 0xFF, (value.value >> 16) & 0xFF, 712 | (value.value >> 8) & 0xFF, value.value & 0xFF]); 713 | stack.push({value: resultValue, type: "J"}); 714 | break; 715 | case 134: // (0x86) i2f 716 | case 144: // (0x90) d2f 717 | var value = stack.pop(); 718 | stack.push({value: value, type: "F"}); 719 | break; 720 | case 135: // (0x87) i2d 721 | case 141: // (0x8d) f2d 722 | var value = stack.pop(); 723 | stack.push({value: value, type: "D"}); 724 | break; 725 | case 136: // (0x88) l2i 726 | var value = stack.pop(), bytes = value.value.bytes; 727 | var resultValue = (bytes[4] << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7]; 728 | stack.push({value: resultValue, type: "I"}); 729 | break; 730 | case 139: // (0x8b) f2i 731 | case 142: // (0x8e) d2i 732 | var value = stack.pop(); 733 | var resultValue = (value.value | 0); 734 | stack.push({value: resultValue, type: "I"}); 735 | break; 736 | case 137: // (0x89) l2f 737 | case 138: // (0x8a) l2d 738 | var value = stack.pop(); 739 | var resultValue = value.value.toNumeric(); 740 | stack.push({value: resultValue, type: op === 137 ? "F" : "D" }); 741 | break; 742 | case 140: // (0x8c) f2l 743 | case 143: // (0x8f) d2l 744 | var value = stack.pop(); 745 | var resultValue = LongValue.fromNumeric(value.value); 746 | stack.push({value: resultValue, type: "J" }); 747 | break; 748 | case 145: // (0x91) i2b 749 | var value = stack.pop(); 750 | var resultValue = value.value & 0xFF; 751 | stack.push({value: resultValue, type: "B" }); 752 | break; 753 | case 146: // (0x92) i2c 754 | var value = stack.pop(); 755 | var resultValue = value.value & 0xFFFF; 756 | stack.push({value: resultValue, type: "C" }); 757 | break; 758 | case 147: // (0x93) i2s 759 | var value = stack.pop(); 760 | var resultValue = value.value & 0xFFFF; 761 | if ((resultValue & 0x8000) !== 0) { resultValue -= 0x10000; } 762 | stack.push({value: resultValue, type: "S" }); 763 | break; 764 | case 148: // (0x94) lcmp 765 | var value2 = stack.pop(); 766 | var value1 = stack.pop(); 767 | var resultValue = value1.value.cmp(value2.value); 768 | stack.push({value: resultValue, type: "I" }); 769 | break; 770 | case 149: // (0x95) fcmpl 771 | case 150: // (0x96) fcmpg 772 | case 151: // (0x97) dcmpl 773 | case 152: // (0x98) dcmpg 774 | var value2 = stack.pop(); 775 | var value1 = stack.pop(); 776 | var resultValue = isNaN(value1.value) || isNaN(value2.value) ? 777 | ((op === 149 || op === 151) ? -1 : 1) : 778 | value1.value == value2.value ? 0 : 779 | value1.value < value2.value ? -1 : 1; 780 | stack.push({value: resultValue, type: "I" }); 781 | break; 782 | case 153: // (0x99) ifeq 783 | case 154: // (0x9a) ifne 784 | case 155: // (0x9b) iflt 785 | case 156: // (0x9c) ifge 786 | case 157: // (0x9d) ifgt 787 | case 158: // (0x9e) ifle 788 | var value = stack.pop(); 789 | var branch = (bytecode[pc] << 8) | bytecode[pc + 1]; 790 | pc += 2; 791 | if ( 792 | (op === 153 && value.value == 0) || 793 | (op === 154 && value.value != 0) || 794 | (op === 155 && value.value < 0) || 795 | (op === 156 && value.value >= 0) || 796 | (op === 157 && value.value > 0) || 797 | (op === 158 && value.value <= 0)) { 798 | if (branch >= 0x8000) { 799 | jumpToAddress = pc + branch - 0x10003; 800 | } else { 801 | jumpToAddress = pc + branch - 3; 802 | } 803 | } 804 | break; 805 | case 159: // (0x9f) if_icmpeq 806 | case 160: // (0xa0) if_icmpne 807 | case 161: // (0xa1) if_icmplt 808 | case 162: // (0xa2) if_icmpge 809 | case 163: // (0xa3) if_icmpgt 810 | case 164: // (0xa4) if_icmple 811 | var value2 = stack.pop(); 812 | var value1 = stack.pop(); 813 | var branch = (bytecode[pc] << 8) | bytecode[pc + 1]; 814 | pc += 2; 815 | if ( 816 | (op === 159 && value1.value == value2.value) || 817 | (op === 160 && value1.value != value2.value) || 818 | (op === 161 && value1.value < value2.value) || 819 | (op === 162 && value1.value >= value2.value) || 820 | (op === 163 && value1.value > value2.value) || 821 | (op === 164 && value1.value <= value2.value)) { 822 | if (branch >= 0x8000) { 823 | jumpToAddress = pc + branch - 0x10003; 824 | } else { 825 | jumpToAddress = pc + branch - 3; 826 | } 827 | } 828 | break; 829 | case 165: // (0xa5) if_acmpeq 830 | case 166: // (0xa6) if_acmpne 831 | var value2 = stack.pop(); 832 | var value1 = stack.pop(); 833 | var branch = (bytecode[pc] << 8) | bytecode[pc + 1]; 834 | pc += 2; 835 | if ( 836 | (op === 165 && value1 === value2) || 837 | (op === 166 && value1 !== value2)) { 838 | if (branch >= 0x8000) { 839 | jumpToAddress = pc + branch - 0x10003; 840 | } else { 841 | jumpToAddress = pc + branch - 3; 842 | } 843 | } 844 | break; 845 | case 167: // (0xa7) goto 846 | var branch = (bytecode[pc] << 8) | bytecode[pc + 1]; 847 | pc += 2; 848 | if (branch >= 0x8000) { 849 | jumpToAddress = pc + branch - 0x10003; 850 | } else { 851 | jumpToAddress = pc + branch - 3; 852 | } 853 | break; 854 | case 168: // (0xa8) jsr 855 | var branch = (bytecode[pc] << 8) | bytecode[pc + 1]; 856 | pc += 2; 857 | var returnAddress; 858 | if (branch >= 0x8000) { 859 | returnAddress = pc + branch - 0x10003; 860 | } else { 861 | returnAddress = pc + branch - 3; 862 | } 863 | stack.push({returnAddress: returnAddress}); 864 | break; 865 | case 169: // (0xa9) ret 866 | var index; 867 | if (wideFound) { 868 | wideFound = false; 869 | index = (bytecode[pc] << 8) | bytecode[pc + 1]; 870 | pc += 2; 871 | } else { 872 | index = bytecode[pc++]; 873 | } 874 | jumpToAddress = locals[index].returnAddress; 875 | break; 876 | case 170: // (0xaa) tableswitch 877 | var padding = pc % 4, tableswitchAddress = pc - 1; 878 | pc += padding; 879 | var index = stack.pop(); 880 | var defaultOffset = (bytecode[pc] << 24) | (bytecode[pc + 1] << 16) | (bytecode[pc + 2] << 8) | bytecode[pc + 3]; 881 | var lowValue = (bytecode[pc + 4] << 24) | (bytecode[pc + 5] << 16) | (bytecode[pc + 6] << 8) | bytecode[pc + 7]; 882 | var highValue = (bytecode[pc + 8] << 24) | (bytecode[pc + 9] << 16) | (bytecode[pc + 10] << 8) | bytecode[pc + 11]; 883 | if (index.value < lowValue || index.value > highValue) { 884 | jumpToAddress = tableswitchAddress + defaultOffset; 885 | } else { 886 | var i = (index.value - lowValue) << 2 + pc + 12; 887 | var offset = (bytecode[i] << 24) | (bytecode[i + 1] << 16) | (bytecode[i + 2] << 8) | bytecode[i + 3]; 888 | jumpToAddress = tableswitchAddress + offset; 889 | } 890 | break; 891 | case 171: // (0xab) lookupswitch 892 | var padding = pc % 4, lookupswitchAddress = pc - 1; 893 | pc += padding; 894 | var key = stack.pop(); 895 | var defaultOffset = (bytecode[pc] << 24) | (bytecode[pc + 1] << 16) | (bytecode[pc + 2] << 8) | bytecode[pc + 3]; 896 | var npairs = (bytecode[pc + 4] << 24) | (bytecode[pc + 5] << 16) | (bytecode[pc + 6] << 8) | bytecode[pc + 7]; 897 | pc += 8; 898 | var offset = defaultOffset; 899 | for (var i = 0; i < npairs; ++i) { 900 | var pairKey = (bytecode[pc] << 24) | (bytecode[pc + 1] << 16) | (bytecode[pc + 2] << 8) | bytecode[pc + 3]; 901 | if (pairKey == key.value) { 902 | offset = (bytecode[pc + 4] << 24) | (bytecode[pc + 5] << 16) | (bytecode[pc + 6] << 8) | bytecode[pc + 7]; 903 | break; 904 | } 905 | pc += 8; 906 | } 907 | jumpToAddress = tableswitchAddress + offset; 908 | break; 909 | case 172: // (0xac) ireturn 910 | case 173: // (0xad) lreturn 911 | case 174: // (0xae) freturn 912 | case 175: // (0xaf) dreturn 913 | case 176: // (0xb0) areturn 914 | case 177: // (0xb1) return 915 | return false; 916 | case 178: // (0xb2) getstatic 917 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 918 | pc += 2; 919 | resultValue = runtime.getstatic(constant_pool[index]); 920 | stack.push(resultValue); 921 | break; 922 | case 179: // (0xb3) putstatic 923 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 924 | pc += 2; 925 | var value = stack.pop(); 926 | runtime.putstatic(constant_pool[index], value); 927 | break; 928 | case 180: // (0xb4) getfield 929 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 930 | pc += 2; 931 | var objectref = stack.pop(); 932 | validateNonNull(objectref); 933 | var resultValue = runtime.getfield(objectref, constant_pool[index]); 934 | stack.push(resultValue); 935 | break; 936 | case 181: // (0xb5) putfield 937 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 938 | pc += 2; 939 | var value = stack.pop(); 940 | var objectref = stack.pop(); 941 | validateNonNull(objectref); 942 | runtime.putfield(objectref, constant_pool[index], value); 943 | break; 944 | case 182: // (0xb6) invokevirtual 945 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 946 | pc += 2; 947 | var args = [], args_count = getArgumentsCountFromDescriptor(constant_pool[index].name_and_type.descriptor); 948 | for (var i = 0; i < args_count; ++i) { 949 | args.unshift(stack.pop()); 950 | } 951 | var objectref = stack.pop(); 952 | validateNonNull(objectref); 953 | var resultValue = runtime.invokevirtual(objectref, constant_pool[index], args); 954 | if (hasReturnValueFromDescriptor(constant_pool[index].name_and_type.descriptor)) { 955 | stack.push(resultValue); 956 | } 957 | break; 958 | case 183: // (0xb7) invokespecial 959 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 960 | pc += 2; 961 | var args = [], args_count = getArgumentsCountFromDescriptor(constant_pool[index].name_and_type.descriptor); 962 | for (var i = 0; i < args_count; ++i) { 963 | args.unshift(stack.pop()); 964 | } 965 | var objectref = stack.pop(); 966 | validateNonNull(objectref); 967 | var resultValue = runtime.invokespecial(objectref, constant_pool[index], args); 968 | if (hasReturnValueFromDescriptor(constant_pool[index].name_and_type.descriptor)) { 969 | stack.push(resultValue); 970 | } 971 | break; 972 | case 184: // (0xb8) invokestatic 973 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 974 | pc += 2; 975 | var args = [], args_count = getArgumentsCountFromDescriptor(constant_pool[index].name_and_type.descriptor); 976 | for (var i = 0; i < args_count; ++i) { 977 | args.unshift(stack.pop()); 978 | } 979 | var resultValue = runtime.invokestatic(constant_pool[index], args); 980 | if (hasReturnValueFromDescriptor(constant_pool[index].name_and_type.descriptor)) { 981 | stack.push(resultValue); 982 | } 983 | break; 984 | case 185: // (0xb9) invokeinterface 985 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 986 | pc += 4; 987 | var args = [], args_count = getArgumentsCountFromDescriptor(constant_pool[index].name_and_type.descriptor); 988 | for (var i = 0; i < args_count; ++i) { 989 | args.unshift(stack.pop()); 990 | } 991 | var objectref = stack.pop(); 992 | validateNonNull(objectref); 993 | var resultValue = runtime.invokeinterface(objectref, constant_pool[index], args); 994 | if (hasReturnValueFromDescriptor(constant_pool[index].name_and_type.descriptor)) { 995 | stack.push(resultValue); 996 | } 997 | break; 998 | case 187: // (0xbb) new 999 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 1000 | pc += 2; 1001 | var resultValue = runtime.new_(constant_pool[index]); 1002 | stack.push(resultValue); 1003 | break; 1004 | case 188: // (0xbc) newarray 1005 | var atype = bytecode[pc++]; 1006 | var count = stack.pop(); 1007 | stack.push(createArray(count, atype)); 1008 | break; 1009 | case 189: // (0xbd) anewarray 1010 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 1011 | pc += 2; 1012 | var count = stack.pop(); 1013 | stack.push(createAArray([count], constant_pool[index])); 1014 | break; 1015 | case 190: // (0xbe) arraylength 1016 | var arrayref = stack.pop(); 1017 | validateArrayref(arrayref); 1018 | stack.push({value: arrayref.length, type: "I" }); 1019 | break; 1020 | case 191: // (0xbf) athrow 1021 | var objectref = stack.pop(); 1022 | validateNotNull(objectref); 1023 | processThrow(objectref); 1024 | break; 1025 | case 192: // (0xc0) checkcast 1026 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 1027 | pc += 2; 1028 | var objectref = stack.pop(); 1029 | checkCast(objectref, constant_pool[index]); 1030 | stack.push(objectref); 1031 | break; 1032 | case 193: // (0xc1) instanceof 1033 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 1034 | pc += 2; 1035 | var objectref = stack.pop(); 1036 | var resultValue = instanceOf(objectref, constant_pool[index]); 1037 | stack.push({value: resultValue, type: "I"}); 1038 | break; 1039 | case 194: // (0xc2) monitorenter 1040 | var objectref = stack.pop(); 1041 | validateNotNull(objectref); 1042 | monitorEnter(objectref); 1043 | break; 1044 | case 195: // (0xc3) monitorexit 1045 | var objectref = stack.pop(); 1046 | validateNotNull(objectref); 1047 | monitorExit(objectref); 1048 | break; 1049 | case 196: // (0xc4) wide 1050 | wideFound = true; 1051 | break; 1052 | case 197: // (0xc5) multianewarray 1053 | var index = (bytecode[pc] << 8) | bytecode[pc + 1]; 1054 | var dimensions = bytecode[pc + 3]; 1055 | pc += 3; 1056 | var counts = []; 1057 | for (var i = 0; i < dimensions; ++i) { 1058 | counts.unshift(stack.pop()); 1059 | } 1060 | stack.push(createAArray(counts, constant_pool[index])); 1061 | break; 1062 | case 198: // (0xc6) ifnull 1063 | case 199: // (0xc7) ifnonnull 1064 | var value = stack.pop(); 1065 | var branch = (bytecode[pc] << 8) | bytecode[pc + 1]; 1066 | pc += 2; 1067 | if ( (op === 198) === (value == null) ) { 1068 | if (branch >= 0x8000) { 1069 | jumpToAddress = pc + branch - 0x10003; 1070 | } else { 1071 | jumpToAddress = pc + branch - 3; 1072 | } 1073 | } 1074 | break; 1075 | case 200: // (0xc8) goto_w 1076 | var branch = (bytecode[pc] << 24) | (bytecode[pc + 1] << 16) | (bytecode[pc + 2] << 8) | bytecode[pc + 3]; 1077 | jumpToAddress = pc - 3 + branch; 1078 | break; 1079 | case 201: // (0xc9) jsr_w 1080 | var branch = (bytecode[pc] << 24) | (bytecode[pc + 1] << 16) | (bytecode[pc + 2] << 8) | bytecode[pc + 3]; 1081 | var returnAddress = pc - 3 + branch; 1082 | stack.push({returnAddress: returnAddress}); 1083 | break; 1084 | 1085 | case 186: // (0xba) xxxunusedxxx1 1086 | case 202: // (0xca) breakpoint 1087 | case 254: // (0xfe) impdep1 1088 | case 255: // (0xff) impdep2 1089 | default: 1090 | throw "invalid operation " + op + " @" + pc; 1091 | } 1092 | 1093 | if (jumpToAddress !== null) { 1094 | pc = jumpToAddress; 1095 | } 1096 | } catch(ex) { 1097 | if (ex === raiseExceptionCookie) { 1098 | return true; // skip scheduled exception 1099 | } 1100 | log(ex.toString()); 1101 | if (typeof ex === "object" && "nativeException" in ex) { 1102 | processThrow(ex.nativeException); 1103 | } else { 1104 | if (ex instanceof MethodExecutionException) { 1105 | throw ex; 1106 | } 1107 | throw new MethodExecutionException(ex.toString()); 1108 | } 1109 | } 1110 | 1111 | return true; 1112 | }; 1113 | } 1114 | 1115 | var factories = {}; 1116 | 1117 | function getFactory(className) { 1118 | if (className in factories) { 1119 | return factories[className]; 1120 | } 1121 | 1122 | try { 1123 | var searchLocations = ["."]; 1124 | if (getFactory.searchLocations) { 1125 | searchLocations = getFactory.searchLocations; 1126 | } 1127 | var data, filePath = className.replace(/\./g, "/") + ".class"; 1128 | for (var i = 0; i < searchLocations.length; ++i) { 1129 | if (typeof searchLocations[i] === "object") { 1130 | if (!searchLocations[i].hasOwnProperty(filePath)) { 1131 | continue; 1132 | } 1133 | data = searchLocations[i][filePath]; 1134 | break; 1135 | } 1136 | 1137 | try { 1138 | var resourceUrl = searchLocations[i] + "/" + filePath; 1139 | data = loadFile(resourceUrl); 1140 | log("Class " + className + " was found at " + resourceUrl + "\n"); 1141 | break; 1142 | } catch(ex) { 1143 | // failed, trying again 1144 | } 1145 | } 1146 | if (!data) { 1147 | throw "Class " + className + " was not found"; 1148 | } 1149 | 1150 | var classFile = parseJavaClass(data); 1151 | var factory = new ClassFactory(classFile); 1152 | 1153 | factories[className] = factory; 1154 | 1155 | factory.superFactory = getFactory(classFile.super_class.name); 1156 | 1157 | if ("" in factory.statics) { 1158 | factory.statics[""](); 1159 | } 1160 | 1161 | } catch (ex) { 1162 | throw "Unable to load '" + className + "' class: " + ex; 1163 | } 1164 | 1165 | return factory; 1166 | } 1167 | 1168 | function ClassFactory(classFile) { 1169 | this.classFile = classFile; 1170 | this.className = classFile.this_class.name; 1171 | 1172 | var factory = this; 1173 | 1174 | function create() { 1175 | var obj = {}; 1176 | for (var i = 0, l = classFile.fields.length; i < l; ++i) { 1177 | obj[classFile.fields[i].name] = 0; 1178 | } 1179 | for (var i = 0, l = classFile.methods.length; i < l; ++i) { 1180 | if (("ACC_STATIC" in classFile.methods[i].access_flags)) { continue; } 1181 | (function(method) { 1182 | obj[method.name] = function() { 1183 | var vm = new MethodProxy(method, classFile.constant_pool, obj, arguments); 1184 | return vm.execute(); 1185 | }; 1186 | })(classFile.methods[i]); 1187 | } 1188 | return obj; 1189 | } 1190 | 1191 | // TODO intefaces static methods 1192 | var statics = {}; 1193 | for (var i = 0, l = classFile.methods.length; i < l; ++i) { 1194 | if (!("ACC_STATIC" in classFile.methods[i].access_flags)) { continue; } 1195 | (function(method) { 1196 | statics[method.name] = function() { 1197 | var vm = new MethodProxy(method, classFile.constant_pool, null, arguments); 1198 | return vm.execute(); 1199 | }; 1200 | })(classFile.methods[i]); 1201 | } 1202 | 1203 | var methods = [], fields = [], interfaces = []; 1204 | for (var i = 0, l = classFile.methods.length; i < l; ++i) { 1205 | if (("ACC_STATIC" in classFile.methods[i].access_flags) || ("ACC_PRIVATE" in classFile.methods[i].access_flags)) { continue; } 1206 | methods.push(classFile.methods[i].name); 1207 | } 1208 | for (var i = 0, l = classFile.fields.length; i < l; ++i) { 1209 | if (("ACC_STATIC" in classFile.fields[i].access_flags) || ("ACC_PRIVATE" in classFile.fields[i].access_flags)) { continue; } 1210 | fields.push(classFile.fields[i].name); 1211 | } 1212 | 1213 | this.statics = statics; 1214 | this.create = create; 1215 | this.instanceMethods = methods; 1216 | this.instanceFields = fields; 1217 | this.interfaces = interfaces; 1218 | } 1219 | 1220 | function MethodExecutionException(message, nativeException) { 1221 | this.message = message; 1222 | this.nativeException = nativeException; 1223 | } 1224 | MethodExecutionException.prototype.toString = function() { 1225 | return this.message; 1226 | } 1227 | 1228 | function normalizeObject(object, className) { 1229 | if (typeof object === "object") { 1230 | if (!("$self" in object)) { 1231 | return object; 1232 | } 1233 | if (object.$factory.className === className) { 1234 | return object; 1235 | } 1236 | var self = object.$self; 1237 | while (self != null) { 1238 | if (self.$factory.className === className) { 1239 | return self; 1240 | } 1241 | self = self.$super; 1242 | } 1243 | return object; 1244 | } 1245 | if (typeof object === "string") { 1246 | object = new JavaString(object); 1247 | return className === "java/lang/Object" ? object.$super : object; 1248 | } 1249 | return object; 1250 | } 1251 | 1252 | function buildVirtualTable(object) { 1253 | function proxyMethod(name) { 1254 | object[name] = function() { 1255 | return object.$super[name].apply(object.$super, arguments); 1256 | }; 1257 | } 1258 | 1259 | function proxyField(name) { 1260 | Object.defineProperty(object, name, { 1261 | get: function() { 1262 | return object.$super[name]; 1263 | }, 1264 | set: function(value) { 1265 | object.$super[name] = value; 1266 | } 1267 | }); 1268 | } 1269 | 1270 | var meta = { methods: [], fields: [] }; 1271 | if (object.$super) { 1272 | meta = buildVirtualTable(object.$super); 1273 | for (var i = 0, l = meta.methods.length; i < l; ++i) { 1274 | if (object.hasOwnProperty(meta.methods[i])) { continue; } 1275 | proxyMethod(meta.methods[i]); 1276 | } 1277 | for (var i = 0, l = meta.fields.length; i < l; ++i) { 1278 | if (object.hasOwnProperty(meta.fields[i])) { continue; } 1279 | proxyField(meta.fields[i]); 1280 | } 1281 | } 1282 | if (object.$factory.instanceMethods) { 1283 | meta.methods = meta.methods.concat(object.$factory.instanceMethods); 1284 | } 1285 | if (object.$factory.instanceFields) { 1286 | meta.fields = meta.fields.concat(object.$factory.instanceFields); 1287 | } 1288 | return meta; 1289 | } 1290 | 1291 | runtime = { 1292 | getstatic: function(field) { 1293 | var factory = getFactory(field.class_.name); 1294 | if (!(field.name_and_type.name in factory.statics)) { 1295 | throw "Static field " + field.class_.name + ":" + field.name_and_type.name + " not found"; 1296 | } 1297 | return factory.statics[field.name_and_type.name]; 1298 | }, 1299 | putstatic: function(field, value) { 1300 | var factory = getFactory(field.class_.name); 1301 | factory.statics[field.name_and_type.name] = value; 1302 | }, 1303 | getfield: function(object, field) { 1304 | object = normalizeObject(object, field.class_.name); 1305 | if (!(field.name_and_type.name in object)) { 1306 | throw "Field " + field.class_.name + ":" + field.name_and_type.name + " not found"; 1307 | } 1308 | return object[field.name_and_type.name]; 1309 | }, 1310 | putfield: function(object, field, value) { 1311 | object = normalizeObject(object, field.class_.name); 1312 | object[field.name_and_type.name] = value; 1313 | }, 1314 | instanceof_: function(object, class_) { 1315 | if (object == null) { 1316 | return true; 1317 | } 1318 | object = normalizeObject(object, class_.name); 1319 | return object.$factory.className === class_.name; 1320 | }, 1321 | invokestatic: function(method, args) { 1322 | var factory = getFactory(method.class_.name); 1323 | if (!(method.name_and_type.name in factory.statics)) { 1324 | throw "Static method " + method.class_.name + ":" + method.name_and_type.name + " not found"; 1325 | } 1326 | return factory.statics[method.name_and_type.name].apply(null, args); 1327 | }, 1328 | invokespecial: function(object, method, args) { 1329 | object = normalizeObject(object, method.class_.name); 1330 | if (!(method.name_and_type.name in object)) { 1331 | throw "Special method " + method.class_.name + ":" + method.name_and_type.name + " not found"; 1332 | } 1333 | var result = object[method.name_and_type.name].apply(object, args); 1334 | return result; 1335 | }, 1336 | invokevirtual: function(object, method, args) { 1337 | var object = "$self" in object ? object.$self : object; 1338 | if (!(method.name_and_type.name in object)) { 1339 | throw "Method " + method.class_.name + ":" + method.name_and_type.name + " not found"; 1340 | } 1341 | return object[method.name_and_type.name].apply(object, args); 1342 | }, 1343 | invokeinterface: function(object, method, args) { 1344 | var object = "$self" in object ? object.$self : object; 1345 | if (!(method.name_and_type.name in object)) { 1346 | throw "Interface method " + method.class_.name + ":" + method.name_and_type.name + " not found"; 1347 | } 1348 | return object[method.name_and_type.name].apply(object, args); 1349 | }, 1350 | new_: function(class_) { 1351 | var factory = getFactory(class_.name); 1352 | var object = factory.create(); 1353 | object.$factory = factory; 1354 | object.$self = object; 1355 | var sf, prev = object; 1356 | for (sf = factory.superFactory; sf; sf = sf.superFactory) { 1357 | var super_ = sf.create(); 1358 | super_.$factory = sf; 1359 | prev.$super = super_; 1360 | super_.$upcast = prev; 1361 | super_.$self = object; 1362 | prev = super_; 1363 | } 1364 | buildVirtualTable(object); 1365 | return object; 1366 | }, 1367 | newexception: function(typeName) { 1368 | var object = this.new_({name: typeName}); 1369 | this.invokespecial(object, {class_:typeName, name_and_type: {name: "", description: "()V"}}, []); 1370 | return object; 1371 | } 1372 | }; 1373 | 1374 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | This Educational Community License (the "License") applies 2 | to any original work of authorship (the "Original Work") whose owner 3 | (the "Licensor") has placed the following notice immediately following 4 | the copyright notice for the Original Work: 5 | 6 | Copyright (c) 2011 notmasteryet 7 | 8 | Licensed under the Educational Community License version 1.0 9 | 10 | This Original Work, including software, source code, documents, 11 | or other related items, is being provided by the copyright holder(s) 12 | subject to the terms of the Educational Community License. By 13 | obtaining, using and/or copying this Original Work, you agree that you 14 | have read, understand, and will comply with the following terms and 15 | conditions of the Educational Community License: 16 | 17 | Permission to use, copy, modify, merge, publish, distribute, and 18 | sublicense this Original Work and its documentation, with or without 19 | modification, for any purpose, and without fee or royalty to the 20 | copyright holder(s) is hereby granted, provided that you include the 21 | following on ALL copies of the Original Work or portions thereof, 22 | including modifications or derivatives, that you make: 23 | 24 | The full text of the Educational Community License in a location viewable to 25 | users of the redistributed or derivative work. 26 | 27 | Any pre-existing intellectual property disclaimers, notices, or terms and 28 | conditions. 29 | 30 | Notice of any changes or modifications to the Original Work, including the 31 | date the changes were made. 32 | 33 | Any modifications of the Original Work must be distributed in such a manner as 34 | to avoid any confusion with the Original Work of the copyright holders. 35 | 36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 37 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 38 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 39 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 40 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 41 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 42 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 43 | 44 | The name and trademarks of copyright holder(s) may NOT be used 45 | in advertising or publicity pertaining to the Original or Derivative 46 | Works without specific, written prior permission. Title to copyright in 47 | the Original Work and any associated documentation will at all times 48 | remain with the copyright holders. 49 | -------------------------------------------------------------------------------- /longvalue.js: -------------------------------------------------------------------------------- 1 | 2 | function LongValue(bytes) { 3 | this.bytes = bytes; 4 | } 5 | LongValue.prototype = { 6 | sign: function() { 7 | if (this.bytes[0] >= 0x80) { 8 | return -1; 9 | } 10 | var i = 0; 11 | while(i < 8 && this.bytes[i] === 0) { 12 | ++i; 13 | } 14 | return i < 8 ? 1 : 0; 15 | }, 16 | add: function(other) { 17 | var c = 0, result = []; 18 | for (var i = 7; i >= 0; i--) { 19 | var n = c + this.bytes[i] + other.bytes[i]; 20 | c = 0; 21 | while (n >= 0x100) { 22 | n -= 0x100; 23 | c++; 24 | } 25 | result[i] = n; 26 | } 27 | return new LongValue(result); 28 | }, 29 | not: function() { 30 | var result = []; 31 | for (var i = 0; i < 8; i++) { 32 | result.push(0x100 - this.bytes[i]); 33 | } 34 | return new LongValue(result); 35 | }, 36 | neg: function() { 37 | return this.not().add(LongValue.One); 38 | }, 39 | sub: function(other) { 40 | return this.add(other.neg()); 41 | }, 42 | cmp: function(other) { 43 | return this.sub(other).sign(); 44 | }, 45 | mul: function(other) { 46 | var result = [], c = 0; 47 | for (var i = 7; i >= 0; --i) { 48 | for (var j = 0; j <= i; --j) { 49 | c += this.bytes[j] * other.bytes[i - j]; 50 | } 51 | var n = Math.floor(c / 256); 52 | result.push(c - n * 256); 53 | c = n; 54 | } 55 | return new LongValue(result); 56 | }, 57 | div: function(other) { 58 | var signOfThis = this.sign(), signOfOther = other.sign(); 59 | if (signOfOther === 0) { return; } 60 | if (signOfThis === 0) { return LongValue.Zero; } 61 | var dividend = signOfThis < 0 ? this.neg() : this; 62 | var divisor = signOfOther < 0 ? other.neg() : other; 63 | 64 | if (dividend.cmp(divisor) < 0) { return LongValue.Zero; } 65 | 66 | var multiplier = LongValue.One, iterations = [[divisor,multiplier]]; 67 | while(divisor.bytes[0] < 0x40 && dividend.cmd(divisor.add(divisor)) >= 0) { 68 | multiplier = multiplier.add(multiplier); // x2 69 | divisor = divisor.add(divisor); 70 | iterations.push([divisor, multiplier]); 71 | } 72 | var result = LongValue.Zero; 73 | while (iterations.length > 0) { 74 | var i = iterations.pop(); 75 | if(dividend.cmd(i[0]) >= 0) { 76 | result = result.add(i[1]); 77 | dividend = dividend.sub(i[0]); 78 | } 79 | } 80 | return signOfThis === signOfOther ? result : result.neg(); 81 | }, 82 | rem: function(other) { 83 | return this.sub(this.div(other).mul(other)); 84 | }, 85 | shl: function(sh) { 86 | throw "not implemented"; 87 | }, 88 | shr: function(sh) { 89 | throw "not implemented"; 90 | }, 91 | ushr: function(sh) { 92 | throw "not implemented"; 93 | }, 94 | and: function(other) { 95 | var result = []; 96 | for (var i = 0; i < 8; ++i) { 97 | result[i] = this.bytes[i] & other.bytes[i]; 98 | } 99 | return new LongValue(result); 100 | }, 101 | or: function(other) { 102 | var result = []; 103 | for (var i = 0; i < 8; ++i) { 104 | result[i] = this.bytes[i] | other.bytes[i]; 105 | } 106 | return new LongValue(result); 107 | }, 108 | xor: function(other) { 109 | var result = []; 110 | for (var i = 0; i < 8; ++i) { 111 | result[i] = this.bytes[i] ^ other.bytes[i]; 112 | } 113 | return new LongValue(result); 114 | }, 115 | toNumeric: function() { 116 | var sign = 1, bytes = this.bytes; 117 | if (this.sign() < 0) { 118 | sign = -1; 119 | bytes = this.neg().bytes; 120 | } 121 | var resultValue = 0; 122 | for (var i = 0; i < bytes.length; ++i) { 123 | resultValue = resultValue * 256 + bytes[i]; 124 | } 125 | return resultValue * sign; 126 | } 127 | }; 128 | LongValue.fromNumeric = function(value) { 129 | var sign = 1, bytes = []; 130 | if (value < 0) { 131 | sign = -1; 132 | value = -value; 133 | } 134 | var n = Math.floor(value); 135 | for (var i = 7; i >= 0; i--) { 136 | var m = Math.floor(n / 256); 137 | bytes[i] = 0 | (n - m * 256); 138 | n = m; 139 | } 140 | var resultValue = new LongValue(bytes); 141 | if (sign < 0) { 142 | resultValue = resultValue.neg(); 143 | } 144 | return resultValue; 145 | }; 146 | LongValue.Zero = new LongValue([0,0,0,0,0,0,0,0]); 147 | LongValue.One = new LongValue([0,0,0,0,0,0,0,1]); 148 | LongValue.Two = new LongValue([0,0,0,0,0,0,0,2]); 149 | LongValue.MinusOne = new LongValue([255,255,255,255,255,255,255,255]); 150 | 151 | 152 | -------------------------------------------------------------------------------- /run.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 20 |
21 | 42 |

43 | 44 | -------------------------------------------------------------------------------- /sandbox/generics/Gen1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/generics/Gen1.class -------------------------------------------------------------------------------- /sandbox/generics/Gen1.java: -------------------------------------------------------------------------------- 1 | import java.lang.*; 2 | import gen1.ClassGen1; 3 | 4 | @Deprecated 5 | public class Gen1 { 6 | public static void main(String[] args) { 7 | ClassGen1 t = new ClassGen1("Test1"); 8 | t.print(); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /sandbox/generics/gen1/ClassGen1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/generics/gen1/ClassGen1.class -------------------------------------------------------------------------------- /sandbox/generics/gen1/ClassGen1.java: -------------------------------------------------------------------------------- 1 | package gen1; 2 | 3 | import java.lang.System; 4 | 5 | public class ClassGen1 { 6 | T a; 7 | 8 | public ClassGen1(T a) { 9 | this.a = a; 10 | } 11 | 12 | public void print() { 13 | System.out.println(a); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sandbox/jar/TestJar.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/jar/TestJar.class -------------------------------------------------------------------------------- /sandbox/jar/TestJar.java: -------------------------------------------------------------------------------- 1 | import testjar.ClassA; 2 | 3 | public class TestJar { 4 | public static void main(String[] args) { 5 | ClassA a = new ClassA(); 6 | a.test(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sandbox/jar/testjar.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/jar/testjar.jar -------------------------------------------------------------------------------- /sandbox/jar/testjar/ClassA.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/jar/testjar/ClassA.class -------------------------------------------------------------------------------- /sandbox/jar/testjar/ClassA.java: -------------------------------------------------------------------------------- 1 | package testjar; 2 | 3 | import java.lang.*; 4 | 5 | public class ClassA { 6 | public void test() { 7 | System.out.println("TestJar"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sandbox/simple/Bottles.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/Bottles.class -------------------------------------------------------------------------------- /sandbox/simple/Bottles.java: -------------------------------------------------------------------------------- 1 | class Bottles 2 | { 3 | public static void main(String args[]) { 4 | System.out.println("99 bottles of beer on the wall, 99 bottles of beer."); 5 | for (int beers = 98; beers > 0; --beers) { 6 | String bottleWord = beers == 1 ? "bottle" : "bottles"; 7 | System.out.println("Take one down and pass it around, " + beers + " " + bottleWord + " of beer on the wall."); 8 | System.out.println(); 9 | System.out.println(beers + " " + bottleWord + " of beer on the wall, " + beers + " " + bottleWord + " of beer."); 10 | } 11 | System.out.println("Take one down and pass it around, no more bottles of beer on the wall."); 12 | System.out.println(); 13 | 14 | System.out.println("No more bottles of beer on the wall, no more bottles of beer."); 15 | System.out.println("Go to the store and buy some more, 99 bottles of beer on the wall."); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sandbox/simple/Class1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/Class1.class -------------------------------------------------------------------------------- /sandbox/simple/Class1.java: -------------------------------------------------------------------------------- 1 | import class1.*; 2 | import java.lang.*; 3 | 4 | public class Class1 { 5 | public static void main(String argc[]) { 6 | ClassA a = new ClassB(); 7 | System.out.println("" + a.test()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sandbox/simple/Hello.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/Hello.class -------------------------------------------------------------------------------- /sandbox/simple/Hello.java: -------------------------------------------------------------------------------- 1 | import java.lang.*; 2 | 3 | public class Hello { 4 | public static void main(String[] args) { 5 | System.out.println("Hello, world!"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /sandbox/simple/ZeroDiv.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/ZeroDiv.class -------------------------------------------------------------------------------- /sandbox/simple/ZeroDiv.java: -------------------------------------------------------------------------------- 1 | import java.lang.*; 2 | 3 | public class ZeroDiv { 4 | public static void main(String[] args) { 5 | int i = 1, j = 0; 6 | int t = i / j; 7 | System.out.println(i + "/" + j + "=" + t); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sandbox/simple/ZeroDivCatch.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/ZeroDivCatch.class -------------------------------------------------------------------------------- /sandbox/simple/ZeroDivCatch.java: -------------------------------------------------------------------------------- 1 | import java.lang.*; 2 | 3 | public class ZeroDivCatch { 4 | public static void main(String[] args) { 5 | try { 6 | int i = 1, j = 0; 7 | int t = i / j; 8 | System.out.println(i + "/" + j + "=" + t); 9 | } catch (ArithmeticException ex) { 10 | System.out.println("ArithmeticException was raised"); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sandbox/simple/class1/ClassA.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/class1/ClassA.class -------------------------------------------------------------------------------- /sandbox/simple/class1/ClassA.java: -------------------------------------------------------------------------------- 1 | package class1; 2 | 3 | public class ClassA { 4 | int i = 1; 5 | 6 | public int test() { 7 | return i; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sandbox/simple/class1/ClassB.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notmasteryet/jvm-js/447643db2ded7f56ea8b5fe209a03bcc8c991b3d/sandbox/simple/class1/ClassB.class -------------------------------------------------------------------------------- /sandbox/simple/class1/ClassB.java: -------------------------------------------------------------------------------- 1 | package class1; 2 | 3 | public class ClassB extends ClassA { 4 | public int test() { 5 | return super.test() + 6; 6 | } 7 | } 8 | --------------------------------------------------------------------------------