| Module | Ruva::VM::Opcodes |
| In: |
lib/ruva/opcodes.rb
|
Provides the standard opcode implementations. The VM will use the standard opcodes by default. If you want to pass custom opcodes, you can base your modifications off the hash in Opcodes::OPCODES
| __any_cmpg | -> | __any_cmpl |
| NaN treated the same right now | ||
| __any_aload | -> | op50 |
| AALOAD (0x32) () …, arrayref, idx => …, value | ||
| __any_astore | -> | op83 |
| AASTORE (0x53) () …, arrayref, idx, value => … | ||
| __any_load | -> | op25 |
| ALOAD (0x19) (idx) …, => …, objectref | ||
| __any_return | -> | op176 |
| ARETURN (0xB0) () …, value => (^) objectref | ||
| __any_store | -> | op58 |
ASTORE (0x3A)(idx) ..., objectref => ... |
||
| __any_aload | -> | op51 |
| BALOAD (0x33) () …, arrayref, idx => …, value | ||
| __any_aload | -> | op52 |
| CALOAD (0x34) () …, arrayref, idx => …, value | ||
| __any_aload | -> | op49 |
| DALOAD (0x31) () …, arrayref, idx => …, value | ||
| __any_load | -> | op24 |
| DLOAD (0x18) (idx) …, => …, value | ||
| __any_aload | -> | op48 |
| FALOAD (0x30) () …, arrayref, idx => …, value | ||
| __any_load | -> | op23 |
| FLOAD (0x17) (idx) …, => …, value | ||
| __any_aload | -> | op46 |
| IALOAD (0x2E) () …, arrayref, idx => …, value | ||
| __any_load | -> | op21 |
| ILOAD (0x15) (idx) …, => …, value | ||
| __any_aload | -> | op47 |
| LALOAD (0x2f) () …, arrayref, idx => …, value | ||
| op19 | -> | op20 |
| LDC2W (0x14) (idx1, idx2) … => …, value | ||
| __any_load | -> | op22 |
| LLOAD (0x16) (idx) …, => …, value | ||
| __any_aload | -> | op53 |
| SALOAD (0x35) () …, arrayref, idx => …, value | ||
# File lib/ruva/opcodes.rb, line 150
150: def __any_add(vm)
151: v2 = vm.stack.pop
152: v1 = vm.stack.pop
153: vm.stack.push(v1 + v2)
154: end
IMPLEMENTATION OPCODES () …, arrayref, idx => …, value
# File lib/ruva/opcodes.rb, line 127
127: def __any_aload(vm)
128: idx = vm.stack.pop
129: arr = vm.stack.pop
130: vm.stack.push(arr[idx])
131: end
() …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 135
135: def __any_astore(vm)
136: value = vm.stack.pop
137: idx = vm.stack.pop
138: arr = vm.stack.pop
139: arr[idx] = value
140: end
# File lib/ruva/opcodes.rb, line 156
156: def __any_cmpg(vm)
157: v2 = vm.stack.pop
158: v1 = vm.stack.pop
159: vm.stack.push(v1 <=> v2)
160: end
# File lib/ruva/opcodes.rb, line 165
165: def __any_div(vm)
166: v2 = vm.stack.pop
167: v1 = vm.stack.pop
168: vm.stack.push(v1 / v2)
169: end
# File lib/ruva/opcodes.rb, line 142
142: def __any_load(vm, idx)
143: vm.stack.push(vm.locals[idx])
144: end
# File lib/ruva/opcodes.rb, line 171
171: def __any_mul(vm)
172: v2 = vm.stack.pop
173: v1 = vm.stack.pop
174: vm.stack.push(v1 * v2)
175: end
# File lib/ruva/opcodes.rb, line 183
183: def __any_neg(vm)
184: vm.stack.push(-vm.stack.pop)
185: end
# File lib/ruva/opcodes.rb, line 187
187: def __any_rem(vm)
188: v2 = vm.stack.pop
189: v1 = vm.stack.pop
190: vm.stack.push(v1 % v2)
191: end
# File lib/ruva/opcodes.rb, line 193
193: def __any_return(vm)
194: r = vm.stack.pop
195: vm.pop_frame
196: vm.stack.push(r)
197: end
# File lib/ruva/opcodes.rb, line 146
146: def __any_store(vm, idx)
147: vm.locals[idx] = vm.stack.pop
148: end
# File lib/ruva/opcodes.rb, line 177
177: def __any_sub(vm)
178: v2 = vm.stack.pop
179: v1 = vm.stack.pop
180: vm.stack.push(v1 - v2)
181: end
Check a ruby Integer is in byte range. Do this before pushing it.
# File lib/ruva/opcodes.rb, line 20
20: def check_byte(b)
21: raise IllegalArgumentError, "Invalid byte #{b.inspect}" unless b && b.is_a?(Integer) && (-128..127).member?(b)
22: b.is_a?(VM::Types::Cat2Value) ? b.__value : b
23: end
Check a ruby Integer is in char range. Do this before pushing it.
# File lib/ruva/opcodes.rb, line 26
26: def check_char(c)
27: raise IllegalArgumentError, "Invalid char #{c.inspect}" unless c && c.is_a?(Integer) && (0..65535).member?(c)
28: c.is_a?(VM::Types::Cat2Value) ? c.__value : c
29: end
Check a ruby Float as a double and wrap it in a VM::Types::Cat2Value Do this before pushing it.
# File lib/ruva/opcodes.rb, line 52
52: def check_double(d)
53: raise IllegalArgumentError, "Invalid double #{d.inspect}" unless d && d.is_a?(Float)
54: d.is_a?(VM::Types::Cat2Value) ? d : VM::Types::Cat2Value.new(d)
55: end
Check a ruby Float as a float. Do this before pushing it.
# File lib/ruva/opcodes.rb, line 58
58: def check_float(f)
59: raise IllegalArgumentError, "Invalid float #{f.inspect}" unless f && f.is_a?(Float)
60: f.is_a?(VM::Types::Cat2Value) ? f.__value : f
61: end
Check a ruby Integer is in int range. Do this before pushing it.
# File lib/ruva/opcodes.rb, line 38
38: def check_int(i)
39: raise IllegalArgumentError, "Invalid int #{i.inspect}" unless i.is_a?(Integer)
40: i.is_a?(VM::Types::Cat2Value) ? i.__value : i
41: end
Check a ruby Integer is in long range and wrap it in a VM::Types::Cat2Value. Do this before pushing it.
# File lib/ruva/opcodes.rb, line 45
45: def check_long(i)
46: raise IllegalArgumentError, "Invalid long #{i.inspect}" unless i.is_a?(Integer)
47: i.is_a?(VM::Types::Cat2Value) ? i : VM::Types::Cat2Value.new(i)
48: end
Check a ruby Integer is in short range. Do this before pushing it.
# File lib/ruva/opcodes.rb, line 32
32: def check_short(s)
33: raise IllegalArgumentError, "Invalid short #{s.inspect}" unless s && s.is_a?(Integer) && (-32768..32767).member?(s)
34: s.is_a?(VM::Types::Cat2Value) ? s.__value : s
35: end
Encode the supplied (char-range) operands as a long (32-bit) jump target instruction offset. This is calculated as the operands value as a short, minus five (to account for the fact that pc will already point to the next instruction).
# File lib/ruva/opcodes.rb, line 118
118: def long_jump(b1, b2, b3, b4)
119: signed_long(operands_long(b1, b2, b3, b4)) - 5
120: end
Decode the supplied long (32-bit) operands to a quad of char-range operands.
# File lib/ruva/opcodes.rb, line 81
81: def long_operands(long)
82: # TODO reverse for little-endian plaf?
83: # How does JVM behave?
84: [(long & 0xFF000000) >> 24,
85: (long & 0x00FF0000) >> 16,
86: (long & 0x0000FF00) >> 8,
87: long & 0x000000FF]
88: end
# File lib/ruva/opcodes.rb, line 15
15: def not_yet
16: raise Ruva::VM::VMError, "Unimplemented Opcode (defined: #{caller[-1]})"
17: end
NOP (0x00) () …
# File lib/ruva/opcodes.rb, line 1908
1908: def op0(vm, *operands)
1909: # nop
1910: end
ACONSTNULL (0x01) () …, => …, null
# File lib/ruva/opcodes.rb, line 217
217: def op1(vm)
218: vm.stack.push nil
219: end
LCONST_1 (0x0a) () … => …, const
# File lib/ruva/opcodes.rb, line 1660
1660: def op10(vm)
1661: vm.stack.push(check_long(1))
1662: end
ISUB (0x64) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1552
1552: def op100(vm)
1553: b, a = vm.stack.pop, vm.stack.pop
1554: check_int(a) and check_int(b)
1555: vm.stack.push(a) and vm.stack.push(b)
1556: __any_sub(vm)
1557: end
LSUB (0x65) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1838
1838: def op101(vm)
1839: b, a = vm.stack.pop, vm.stack.pop
1840: vm.stack.push(check_long(a - b))
1841: end
FSUB (0x66) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 815
815: def op102(vm)
816: b, a = vm.stack.pop, vm.stack.pop
817: check_float(a) and check_float(b)
818: vm.stack.push(a) and vm.stack.push(b)
819: __any_sub(vm)
820: end
DSUB (0x67) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 544
544: def op103(vm)
545: b, a = vm.stack.pop, vm.stack.pop
546: vm.stack.push(check_double(a - b))
547: end
IMUL (0x68) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1226
1226: def op104(vm)
1227: b, a = vm.stack.pop, vm.stack.pop
1228: check_int(a) and check_int(b)
1229: vm.stack.push(a) and vm.stack.push(b)
1230: __any_mul(vm)
1231: end
LMUL (0x69) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1737
1737: def op105(vm)
1738: b, a = vm.stack.pop, vm.stack.pop
1739: vm.stack.push(check_long(a * b))
1740: end
FMUL (0x6A) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 743
743: def op106(vm)
744: b, a = vm.stack.pop, vm.stack.pop
745: check_float(a) and check_float(b)
746: vm.stack.push(a) and vm.stack.push(b)
747: __any_mul(vm)
748: end
DMUL (0x6B) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 476
476: def op107(vm)
477: b, a = vm.stack.pop, vm.stack.pop
478: vm.stack.push(check_double(a * b))
479: end
IDIV (0x6C) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1045
1045: def op108(vm)
1046: b, a = vm.stack.pop, vm.stack.pop
1047: check_int(a) and check_int(b)
1048: vm.stack.push(a) and vm.stack.push(b)
1049: __any_div(vm)
1050: end
LDIV (0x6d) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1696
1696: def op109(vm)
1697: b, a = vm.stack.pop, vm.stack.pop
1698: vm.stack.push(check_long(a / b))
1699: end
FCONST_0 (0x0B) () … => …, const
# File lib/ruva/opcodes.rb, line 679
679: def op11(vm)
680: vm.stack.push(0.0)
681: end
FDIV (0x6E) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 700
700: def op110(vm)
701: b, a = vm.stack.pop, vm.stack.pop
702: check_float(a) and check_float(b)
703: vm.stack.push(a) and vm.stack.push(b)
704: __any_div(vm)
705: end
DDIV (0x6F) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 435
435: def op111(vm)
436: b, a = vm.stack.pop, vm.stack.pop
437: vm.stack.push(check_double(a / b))
438: end
IREM (0x70) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1480
1480: def op112(vm)
1481: b, a = vm.stack.pop, vm.stack.pop
1482: check_int(a) and check_int(b)
1483: vm.stack.push(a) and vm.stack.push(b)
1484: __any_rem(vm)
1485: end
LREM (0x71) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1767
1767: def op113(vm)
1768: b, a = vm.stack.pop, vm.stack.pop
1769: vm.stack.push(check_long(a % b))
1770: end
FREM (0x72) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 761
761: def op114(vm)
762: b, a = vm.stack.pop, vm.stack.pop
763: check_float(a) and check_float(b)
764: vm.stack.push(a) and vm.stack.push(b)
765: __any_rem(vm)
766: end
DREM (0x73) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 492
492: def op115(vm)
493: b, a = vm.stack.pop, vm.stack.pop
494: vm.stack.push(check_double(a % b))
495: end
INEG (0x74) () …, value => …, result
# File lib/ruva/opcodes.rb, line 1236
1236: def op116(vm)
1237: vm.stack.push(check_int(vm.stack.pop))
1238: __any_neg(vm)
1239: end
LNEG (0x75) () …, value => …, result
# File lib/ruva/opcodes.rb, line 1745
1745: def op117(vm)
1746: vm.stack.push(check_long(-vm.stack.pop))
1747: end
FNEG (0x76) () …, value => …, result
# File lib/ruva/opcodes.rb, line 753
753: def op118(vm)
754: vm.stack.push(check_float(vm.stack.pop))
755: __any_neg(vm)
756: end
DNEG (0x77) () …, value => …, result
# File lib/ruva/opcodes.rb, line 484
484: def op119(vm)
485: a = vm.stack.pop
486: vm.stack.push(check_double(-a))
487: end
FCONST_1 (0x0C) () … => …, const
# File lib/ruva/opcodes.rb, line 686
686: def op12(vm)
687: vm.stack.push(1.0)
688: end
ISHL (0x78) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1498
1498: def op120(vm)
1499: b, a = check_int(vm.stack.pop), check_int(vm.stack.pop)
1500: vm.stack.push(a << b)
1501: end
LSHL (0x79) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1784
1784: def op121(vm)
1785: v2 = vm.stack.pop
1786: v1 = vm.stack.pop
1787: vm.stack.push(check_long(v1 << v2))
1788: end
ISHR (0x7A) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1506
1506: def op122(vm)
1507: v2 = vm.stack.pop
1508: v1 = vm.stack.pop
1509: check_int(v1) and check_int(v2)
1510: vm.stack.push(v1 >> v2)
1511: end
LSHR (0x7B) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1793
1793: def op123(vm)
1794: v2 = vm.stack.pop
1795: v1 = vm.stack.pop
1796: vm.stack.push(check_long(v1 >> v2))
1797: end
IUSHR (0x7C) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1562
1562: def op124(vm)
1563: b, a = check_int(vm.stack.pop), check_int(vm.stack.pop)
1564: vm.stack.push([a].pack('l').unpack('L').first >> b)
1565: end
LUSHR (0x7D) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1846
1846: def op125(vm)
1847: not_yet
1848: end
IAND (0x7E) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 980
980: def op126(vm)
981: b, a = check_int(vm.stack.pop), check_int(vm.stack.pop)
982: vm.stack.push(a & b)
983: end
LAND (0x7f) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1630
1630: def op127(vm)
1631: b,a = vm.stack.pop, vm.stack.pop
1632: vm.stack.push(check_long(a & b))
1633: end
INT ##################
IOR (0x80) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1471
1471: def op128(vm)
1472: v2 = vm.stack.pop
1473: v1 = vm.stack.pop
1474: vm.stack.push(v1 | v2)
1475: end
LOR (0x81) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1759
1759: def op129(vm)
1760: b,a = vm.stack.pop, vm.stack.pop
1761: vm.stack.push(check_long(b | a))
1762: end
FCONST_2 (0x0D) () … => …, const
# File lib/ruva/opcodes.rb, line 693
693: def op13(vm)
694: vm.stack.push(2.0)
695: end
IXOR (0x82) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1570
1570: def op130(vm)
1571: v2 = vm.stack.pop
1572: v1 = vm.stack.pop
1573: vm.stack.push(v1 ^ v2)
1574: end
LXOR (0x83) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1853
1853: def op131(vm)
1854: b,a = vm.stack.pop, vm.stack.pop
1855: vm.stack.push(check_long(b ^ a))
1856: end
IINC (0x84) (idx, const) …, => …
# File lib/ruva/opcodes.rb, line 1185
1185: def op132(vm, idx, const)
1186: locals = vm.locals
1187: locals[idx] = check_int(locals[idx]) + check_byte(signed_byte(const))
1188: end
I2L (0x85) () …, value => …, long
# File lib/ruva/opcodes.rb, line 951
951: def op133(vm)
952: vm.stack.push(check_long(Integer(vm.stack.pop)))
953: end
I2F (0x86) () …, value => …, float
# File lib/ruva/opcodes.rb, line 944
944: def op134(vm)
945: vm.stack.push(check_float(Float(vm.stack.pop)))
946: end
I2D (0x87) …, value => …, double
# File lib/ruva/opcodes.rb, line 937
937: def op135(vm)
938: vm.stack.push(check_double(Float(vm.stack.pop)))
939: end
L2I (0x88) () …, value => …, int
# File lib/ruva/opcodes.rb, line 1610
1610: def op136(vm)
1611: vm.stack.push(check_int([vm.stack.pop & 0xFFFFFFFF].pack('Q').unpack('q').first))
1612: end
L2F (0x89) () …, value => …, long
# File lib/ruva/opcodes.rb, line 1603
1603: def op137(vm)
1604: vm.stack.push(check_float(Float(vm.stack.pop.__value)))
1605: end
LONG ################
L2D (0x8a) () …, value => …, double
# File lib/ruva/opcodes.rb, line 1596
1596: def op138(vm)
1597: vm.stack.push(check_double(Float(vm.stack.pop.__value)))
1598: end
F2I (0x8B) () …, value => …, int
# File lib/ruva/opcodes.rb, line 622
622: def op139(vm)
623: vm.stack.push(Integer(vm.stack.pop))
624: end
DCONST_0 (0x0E) () … => …, const
# File lib/ruva/opcodes.rb, line 421
421: def op14(vm)
422: vm.stack.push(check_double(0.0))
423: end
F2L (0x8C) () …, value => …, long
# File lib/ruva/opcodes.rb, line 629
629: def op140(vm)
630: vm.stack.push(check_long(Integer(vm.stack.pop)))
631: end
FLOAT ######################
F2D (0x8D) () …, value => …, double
# File lib/ruva/opcodes.rb, line 615
615: def op141(vm)
616: vm.stack.push(check_double(vm.stack.pop))
617: end
D2I (0x8E) () …, value => …, int
# File lib/ruva/opcodes.rb, line 366
366: def op142(vm)
367: vm.stack.push(check_int(Integer(vm.stack.pop.__value)))
368: end
D2L (0x8F) () …, value => …, long
# File lib/ruva/opcodes.rb, line 373
373: def op143(vm)
374: vm.stack.push(check_long(Integer(vm.stack.pop.__value)))
375: end
DOUBLE ######################
D2F (0x90) () …, value => …, float
# File lib/ruva/opcodes.rb, line 359
359: def op144(vm)
360: vm.stack.push(check_float(vm.stack.pop.__value))
361: end
INT ######################
I2B (0x91) () …, value => …, byte
# File lib/ruva/opcodes.rb, line 925
925: def op145(vm)
926: vm.stack.push(check_byte([vm.stack.pop & 0xFF].pack('C').unpack('c').first))
927: end
I2C (0x92) …, value => …, char
# File lib/ruva/opcodes.rb, line 931
931: def op146(vm)
932: vm.stack.push(check_char(vm.stack.pop & 0xFFFF))
933: end
I2S (0x93) () …, value => …, short
# File lib/ruva/opcodes.rb, line 958
958: def op147(vm)
959: vm.stack.push(check_short([vm.stack.pop & 0xFFFF].pack('S').unpack('s').first))
960: end
LCMP (0x94) () …, value1, value2 => …, result
# File lib/ruva/opcodes.rb, line 1646
1646: def op148(vm)
1647: not_yet
1648: end
FCMPL (0x95) () …, value1, value2 => …, result_int
# File lib/ruva/opcodes.rb, line 669
669: def op149(vm)
670: b, a = vm.stack.pop, vm.stack.pop
671: check_float(a) and check_float(b)
672: vm.stack.push(a) and vm.stack.push(b)
673: __any_cmpl(vm)
674: end
DCONST_1 (0x0F) () … => …, const
# File lib/ruva/opcodes.rb, line 428
428: def op15(vm)
429: vm.stack.push(check_double(1.0))
430: end
FCMPG (0x96) () …, value1, value2 => …, result_int
# File lib/ruva/opcodes.rb, line 659
659: def op150(vm)
660: b, a = vm.stack.pop, vm.stack.pop
661: check_float(a) and check_float(b)
662: vm.stack.push(a) and vm.stack.push(b)
663: __any_cmpg(vm)
664: end
DCMPL (0x97) () …, value1, value2 => …, result_int
# File lib/ruva/opcodes.rb, line 411
411: def op151(vm)
412: b, a = vm.stack.pop, vm.stack.pop
413: check_double(a) and check_double(b)
414: vm.stack.push(a) and vm.stack.push(b)
415: __any_cmpl(vm)
416: end
DCMPG (0x98) () …, value1, value2 => …, result_int
# File lib/ruva/opcodes.rb, line 401
401: def op152(vm)
402: b, a = vm.stack.pop, vm.stack.pop
403: check_double(a) and check_double(b)
404: vm.stack.push(a) and vm.stack.push(b)
405: __any_cmpg(vm)
406: end
IFEQ (0x99) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1123
1123: def op153(vm, b1, b2)
1124: val = check_int(vm.stack.pop)
1125: vm.frame.pc += short_jump(b1, b2) if val == 0
1126: end
IFNE (0x9A) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1131
1131: def op154(vm, b1, b2)
1132: val = check_int(vm.stack.pop)
1133: vm.frame.pc += short_jump(b1, b2) if val != 0
1134: end
IFLT (0x9B) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1139
1139: def op155(vm, b1, b2)
1140: val = check_int(vm.stack.pop)
1141: vm.frame.pc += short_jump(b1, b2) if val < 0
1142: end
IFGE (0x9C) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1147
1147: def op156(vm, b1, b2)
1148: val = check_int(vm.stack.pop)
1149: vm.frame.pc += short_jump(b1, b2) if val >= 0
1150: end
IFGT (0x9D) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1155
1155: def op157(vm, b1, b2)
1156: val = check_int(vm.stack.pop)
1157: vm.frame.pc += short_jump(b1, b2) if val > 0
1158: end
IFLE (0x9E) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1163
1163: def op158(vm, b1, b2)
1164: val = check_int(vm.stack.pop)
1165: vm.frame.pc += short_jump(b1, b2) if val <= 0
1166: end
IFICMPEQ (0x9F) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1069
1069: def op159(vm, b1, b2)
1070: b, a = vm.stack.pop, vm.stack.pop # need to pop both even on err
1071: check_int(a) and check_int(b) # raise if not
1072: vm.frame.pc += short_jump(b1, b2) if b == a
1073: end
BIPUSH (0x10) (byte) -> sign-extend to int … => …, byte
# File lib/ruva/opcodes.rb, line 331
331: def op16(vm, byte)
332: vm.stack.push(check_byte(byte))
333: end
IFICMPNE (0xA0) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1078
1078: def op160(vm, b1, b2)
1079: b, a = vm.stack.pop, vm.stack.pop # need to pop both even on err
1080: check_int(a) and check_int(b) # raise if not
1081: vm.frame.pc += short_jump(b1, b2) unless b == a
1082: end
IFICMPLT (0xA1) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1087
1087: def op161(vm, b1, b2)
1088: b, a = vm.stack.pop, vm.stack.pop
1089: check_int(a) and check_int(b)
1090: vm.frame.pc += short_jump(b1, b2) if a < b
1091: end
IFICMPGE (0xA2) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1096
1096: def op162(vm, b1, b2)
1097: b, a = vm.stack.pop, vm.stack.pop
1098: check_int(a) and check_int(b)
1099: vm.frame.pc += short_jump(b1, b2) if a >= b
1100: end
IFICMPGT (0xA3) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1105
1105: def op163(vm, b1, b2)
1106: b, a = vm.stack.pop, vm.stack.pop
1107: check_int(a) and check_int(b)
1108: vm.frame.pc += short_jump(b1, b2) if a > b
1109: end
IFICMPLE (0xA4) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1114
1114: def op164(vm, b1, b2)
1115: b, a = vm.stack.pop, vm.stack.pop
1116: check_int(a) and check_int(b)
1117: vm.frame.pc += short_jump(b1, b2) if a <= b
1118: end
IFACMPEQ (0xA5) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1055
1055: def op165(vm, b1, b2)
1056: vm.frame.pc += short_jump(b1,b2) if vm.stack.pop == vm.stack.pop
1057: end
IFACMPNE (0xA6) (branch1, branch2) …, value1, value2 => …
# File lib/ruva/opcodes.rb, line 1062
1062: def op166(vm, b1, b2)
1063: vm.frame.pc += short_jump(b1, b2) unless vm.stack.pop == vm.stack.pop
1064: end
GOTO (0xA7) (branch1, branch2) … => …
# File lib/ruva/opcodes.rb, line 910
910: def op167(vm, b1, b2)
911: vm.frame.pc += short_jump(b1, b2)
912: end
JSR (0xA8) (branch1, branch2) … => …, address
# File lib/ruva/opcodes.rb, line 1579
1579: def op168(vm, b1, b2)
1580: vm.stack.push Ruva::VM::Types::ReturnAddress.new(vm.frame.pc)
1581: vm.frame.pc += short_jump(b1,b2)
1582: end
RET (0xA9) (idx) … => …
# File lib/ruva/opcodes.rb, line 1992
1992: def op169(vm, idx)
1993: raise VM::IllegalArgumentError, "RET to non-address" unless (ret = vm.locals[idx]).is_a?(Ruva::VM::Types::ReturnAddress)
1994: vm.frame.pc = ret.pc
1995: end
SIPUSH (0x11) (byte1, byte2) -> short … => …, short
# File lib/ruva/opcodes.rb, line 2021
2021: def op17(vm, b1, b2)
2022: vm.stack.push(check_short(signed_short(operands_short(b1,b2))))
2023: end
TABLESWITCH (0xAA) (VARIABLE) …, index => …
# File lib/ruva/opcodes.rb, line 2037
2037: def op170(vm, *operands)
2038: not_yet
2039: end
LOOKUPSWITCH (0xAB) (VARIABLE) …, key => …
# File lib/ruva/opcodes.rb, line 1752
1752: def op171(vm, *operands)
1753: not_yet
1754: end
IRETURN (0xAC) () …, value => (^) value
# File lib/ruva/opcodes.rb, line 1490
1490: def op172(vm)
1491: vm.stack.push(check_int(vm.stack.pop))
1492: __any_return(vm)
1493: end
LRETURN (0xAD) () …, value => (^) value
# File lib/ruva/opcodes.rb, line 1776
1776: def op173(vm)
1777: vm.stack.push(check_long(vm.stack.pop))
1778: __any_return(vm)
1779: end
FRETURN (0xAE) () …, value => (^) value
# File lib/ruva/opcodes.rb, line 771
771: def op174(vm)
772: vm.stack.push(check_float(vm.stack.pop))
773: __any_return(vm)
774: end
DRETURN (0xAF) () …, value => (^) value
# File lib/ruva/opcodes.rb, line 500
500: def op175(vm)
501: vm.stack.push(check_double(vm.stack.pop))
502: __any_return(vm)
503: end
RETURN (0xB1) () … => [empty]
# File lib/ruva/opcodes.rb, line 2000
2000: def op177(vm)
2001: # can't use any return for this.
2002: vm.pop_frame
2003: end
GETSTATIC (0xB2) (idx1, idx2) … => …, value
# File lib/ruva/opcodes.rb, line 865
865: def op178(vm, idx1, idx2)
866: clz = vm.frame.clz
867: fli = clz.pool[operands_short(idx1, idx2)]
868: clz = vm.find_class(fli[:class]) unless clz.name == fli[:class]
869:
870: if !clz.initialized? && method_idx = clz.method_lookup['<clinit>()V']
871: # FIXME this is pretty nasty. If the class isn't initialized,
872: # we need to initialize it now (or statics mightn't have their value yet).
873: # This should really be done in some common way when the class is first
874: # accessed, but I need to find the right place for that to happen...
875: #
876: # Firstly, let's scroll back this frame to the start of this getstatic insn
877: vm.frame.pc -= 3
878:
879: # Now lets push a new frame for the clinit. When that returns, we'll be back
880: # to this instruction again.
881: vm.push_frame(Ruva::VM::Stack::Frame.new(clz, method_idx))
882:
883: # And remember not to do this again...
884: clz.initialized = true
885: else
886: field_idx = clz.field_lookup[fli[:name] + fli[:desc]]
887: field = clz.fields[field_idx]
888:
889: unless field.static?
890: raise IllegalAccessError, "GETSTATIC with non-static field `#{field}')"
891: end
892:
893: if field.value.nil? && field.primitive?
894: # Have to default primitive fields
895: case field.desc
896: when 'B', 'C', 'I', 'S', 'Z', 'J'
897: field.value = 0
898: when 'F', 'D'
899: field.value = 0.0
900: end
901: end
902:
903: vm.stack.push(field.value)
904: end
905: end
PUTSTATIC (0xB3) (idx1, idx2) …, value => …
# File lib/ruva/opcodes.rb, line 1964
1964: def op179(vm, idx1, idx2)
1965: clz = vm.frame.clz
1966: fli = clz.pool[operands_short(idx1, idx2)]
1967: clz = vm.find_class(fli[:class]) unless clz.name == fli[:class]
1968:
1969: if !clz.initialized? && method_idx = clz.method_lookup['<clinit>()V']
1970: # FIXME See GETSTATIC.
1971:
1972: # We have to do it here in case the class isn't initialized, we set a field,
1973: # and then a method gets called, invoking clinit, and overwriting our value.
1974: vm.frame.pc -= 3
1975: vm.push_frame(Ruva::VM::Stack::Frame.new(clz, method_idx))
1976: clz.initialized = true
1977: else
1978: field_idx = clz.field_lookup[fli[:name] + fli[:desc]]
1979: field = clz.fields[field_idx]
1980:
1981: unless field.static?
1982: raise IllegalAccessError, "GETSTATIC with non-static field `#{field}')"
1983: end
1984:
1985: field.value = vm.stack.pop
1986: end
1987: end
LDC (0x12) (idx) … => …, value
# File lib/ruva/opcodes.rb, line 1667
1667: def op18(vm, idx)
1668: if (pool = vm.frame.clz.pool).length > idx
1669: ele = pool[idx]
1670: vm.stack.push(ele)
1671: else
1672: raise IllegalArgumentError, "Index #{idx} out of constant pool"
1673: end
1674: end
GETFIELD (0xB4) (idx1, idx2) …, objectref => …, value
# File lib/ruva/opcodes.rb, line 826
826: def op180(vm, idx1, idx2)
827: clz = vm.frame.clz
828: fli = clz.pool[operands_short(idx1, idx2)]
829: clz = vm.find_class(fli[:class]) unless clz.name == fli[:class]
830: field_idx = clz.field_lookup[fli[:name] + fli[:desc]]
831: field = clz.fields[field_idx]
832:
833: if field.static?
834: raise IllegalAccessError, "GETFIELD with static field `#{field}')"
835: end
836:
837: objref = vm.stack.pop
838:
839: #puts "\n\nGETFIELD #{field} (#{field_idx} of #{objref.fields.length})"
840: #puts "#{objref.fields.inspect}\n\n"
841:
842: raise VM::NullPointerError, "GETFIELD on NULL object" if objref.nil?
843:
844: if objref.fields[clz.name][field_idx].nil? && field.primitive?
845: # Have to default primitive fields
846: case field.desc
847: when 'B', 'C', 'I', 'S', 'Z', 'J'
848: objref.fields[clz.name][field_idx] = 0
849: when 'F', 'D'
850: objref.fields[clz.name][field_idx] = 0.0
851: end
852: end
853:
854: # TODO need this check with inheritance
855: #unless objref.clz.name == fli[:class]
856: # raise IllegalAccessError, "GETFIELD for incompatible object reference (Expected #{fli[:class]} but got #{objref.clz.name})"
857: #end
858:
859: vm.stack.push(objref.fields[clz.name][field_idx])
860: end
PUTFIELD (0xB5) (idx1, idx2) …, objectref, value => …
# File lib/ruva/opcodes.rb, line 1934
1934: def op181(vm, idx1, idx2)
1935: clz = vm.frame.clz
1936: fli = clz.pool[operands_short(idx1, idx2)]
1937: clz = vm.find_class(fli[:class]) unless clz.name == fli[:class]
1938: field_idx = clz.field_lookup[fli[:name] + fli[:desc]]
1939: field = clz.fields[field_idx]
1940:
1941: if field.static?
1942: raise IllegalAccessError, "PUTFIELD with static field `#{field}')"
1943: end
1944:
1945: value = vm.stack.pop
1946: objref = vm.stack.pop
1947:
1948: #puts "\n\nPUTFIELD #{field} (on #{clz}) with value #{value} (#{field_idx} of #{objref.fields.length})"
1949: #puts "Fields were: #{objref.fields.inspect}\n\n"
1950:
1951: raise VM::NullPointerError, "GETFIELD on NULL object" if objref.nil?
1952:
1953: # TODO this doesn't work, we need to check inheritance
1954: #unless objref.clz.name == fli[:class]
1955: # raise IllegalAccessError, "PUTFIELD for incompatible object reference (Expected #{fli[:class]} but got #{objref.clz.name})"
1956: #end
1957:
1958: objref.fields[clz.name][field_idx] = value
1959: end
INVOKEVIRTUAL (0xB6) (idx1, idx2) …, objectref, [arg1, [arg2 …]] => …
# File lib/ruva/opcodes.rb, line 1407
1407: def op182(vm, idx1, idx2)
1408: # TODO method lookup is getting confused by abstract methods.
1409: # Check it's not running backwards or something...
1410: idx = operands_short(idx1, idx2)
1411:
1412: clz = vm.frame.clz
1413: meth_info = vm.frame.clz.pool[idx]
1414: oclzname, name, desc = meth_info[:class], meth_info[:name], meth_info[:desc]
1415:
1416: unless (mc = meth_info[:class]) == clz.name
1417: clz = vm.find_class(mc)
1418: end
1419:
1420: oclz = clz
1421: until oclz.nil? || ometh = oclz.find_method(name, desc)
1422: oclz = vm.find_class(oclz.super_name)
1423: end
1424:
1425: unless ometh# = clz.find_method(name, desc)
1426: raise NoSuchMethodError, "Method #{name + desc} not found"
1427: end
1428:
1429: raise IllegalAccessError, "Static method `#{ometh}' cannot be invoked as virtual" if ometh.static?
1430: raise IllegalAccessError, "Private method `#{ometh}' cannot be invoked as virtual" if ometh.private?
1431: raise IllegalAccessError, "Special method `#{ometh}' cannot be invoked as virtual" if ometh.name =~ /^</
1432:
1433: arg_len = ometh.arg_length + 1 # +1 for object ref
1434: unless (ref_and_args = vm.stack.pop_args(arg_len))
1435: # stack is too short
1436: raise VM::StackStateError, "Incorrect argument count #{vm.stack.length} (expected #{arg_len})"
1437: end
1438:
1439: unless ref = ref_and_args.first
1440: raise VM::NullPointerError, "Cannot invoke `#{ometh}' on NULL object"
1441: end
1442: unless ref.is_a?(VM::Types::ObjectRef) || ref.is_a?(Array)
1443: raise VM::IllegalArgumentError, "Invalid (non-object) reference to `this' on stack (#{ref.class}: #{ref.inspect})"
1444: end
1445: # TODO need to check reference type matches class. The following *doesn't* work
1446: # Need to use instof_classes instead...
1447: #unless ref_and_args.first.clz == oclz
1448: # raise VM::IllegalArgumentError, "Invalid typed object reference to `this': #{ref_and_args.first.clz.name} (Expected #{oclz.name})"
1449: #end
1450:
1451: rclz = ref.is_a?(Array) ? vm.find_class('java/lang/Object') : ref.clz
1452: until rclz.nil? || idx = rclz.method_lookup[name+desc]
1453: rclz = vm.find_class(rclz.super_name)
1454: end
1455:
1456: unless idx
1457: raise AbstractMethodError, "Method #{meth_info[:name] + meth_info[:desc]} not found"
1458: end
1459:
1460: new_frame = VM::Stack::Frame.new(rclz, idx, [])
1461: m = new_frame.method
1462:
1463: new_frame.locals = ref_and_args
1464: vm.push_frame(new_frame)
1465: end
INVOKESPECIAL (0xB7) (idx1, idx2) …, objectref, [arg1, [arg2 …]] => …
# File lib/ruva/opcodes.rb, line 1316
1316: def op183(vm, idx1, idx2)
1317: idx = operands_short(idx1, idx2)
1318:
1319: clz = vm.frame.clz
1320: meth_info = vm.frame.clz.pool[idx]
1321:
1322: unless (mc = meth_info[:class]) == clz.name
1323: clz = vm.find_class(mc)
1324: end
1325:
1326: oclz = clz;
1327:
1328: until clz.nil? || idx = clz.method_lookup[meth_info[:name] + meth_info[:desc]]
1329: clz = vm.find_class(clz.super_name)
1330: end
1331:
1332: unless idx
1333: raise NoSuchMethodError, "Method #{meth_info[:name] + meth_info[:desc]} not found"
1334: end
1335:
1336: new_frame = VM::Stack::Frame.new(clz, idx, [])
1337: m = new_frame.method
1338:
1339: # TODO proper access checks
1340: raise IllegalAccessError, "Static method `#{m}' invoked as special" if m.static?
1341:
1342: arg_types = m.arg_types
1343: arg_len = m.arg_length + 1 # +1 for object ref
1344: # TODO cat2 support
1345:
1346: unless (ref_and_args = vm.stack.pop_args(arg_len))
1347: # stack is too short
1348: raise VM::StackStateError, "Incorrect argument count #{vm.stack.length} (expected #{arg_len})"
1349: end
1350:
1351: unless ref = ref_and_args.first
1352: raise VM::NullPointerError, "Cannot invoke `#{m}' on NULL object"
1353: end
1354:
1355: unless ref.is_a?(VM::Types::ObjectRef) || ref.is_a?(Array)
1356: raise VM::IllegalArgumentError, "Invalid (non-object) reference to `this' on stack (#{ref.class}: #{ref.inspect})"
1357: end
1358:
1359: # TODO need to check reference type matches class. The following *doesn't* work
1360: #unless ref_and_args.first.clz == oclz
1361: # raise VM::IllegalArgumentError, "Invalid typed object reference to `this': #{ref_and_args.first.clz.name} (Expected #{oclz.name})"
1362: #end
1363:
1364: new_frame.locals = ref_and_args
1365: vm.push_frame(new_frame)
1366: end
INVOKESTATIC (0xB8) (idx1, idx2) …, [arg1, [arg2 …]] => …
# File lib/ruva/opcodes.rb, line 1371
1371: def op184(vm, idx1, idx2)
1372: idx = operands_short(idx1, idx2)
1373:
1374: clz = vm.frame.clz
1375: meth_info = vm.frame.clz.pool[idx]
1376:
1377: unless (mc = meth_info[:class]) == clz.name
1378: clz = vm.find_class(mc)
1379: end
1380:
1381: unless idx = clz.method_lookup[meth_info[:name] + meth_info[:desc]]
1382: raise NoSuchMethodError, "Method #{meth_info[:name] + meth_info[:desc]} not found"
1383: end
1384:
1385: # Easiest way to lookup the method and get all it's info is to make a new frame.
1386: new_frame = VM::Stack::Frame.new(clz, idx, [])
1387: m = new_frame.method
1388:
1389: # TODO proper access checks
1390: raise IllegalAccessError,"Non-static method `#{m}' invoked as static" unless m.static?
1391:
1392: arg_types = m.arg_types
1393: arg_len = m.arg_length
1394:
1395: # TODO cat2 support
1396: unless (args = vm.stack.pop_args(arg_len)).length == arg_len
1397: raise StackStateError, "Incorrect argument count #{args.length} (expected #{arg_len}"
1398: end
1399:
1400: new_frame.locals = args
1401: vm.push_frame(new_frame)
1402: end
INVOKEINTERFACE (0xB9) (idx1, idx2, count, 0) …, objectref, [arg1, [arg2 …]] => …
# File lib/ruva/opcodes.rb, line 1272
1272: def op185(vm, idx1, idx2, count, tag)
1273: idx = operands_short(idx1, idx2)
1274: callclz = vm.frame.clz
1275: meth_info = callclz.pool[idx]
1276: mname, mdesc = meth_info[:name], meth_info[:desc]
1277: arg_len = count
1278:
1279: unless (ref_and_args = vm.stack.pop_args(arg_len))
1280: # stack is too short
1281: raise VM::StackStateError, "Incorrect argument count #{vm.stack.length} (expected #{arg_len})"
1282: end
1283: unless ref = ref_and_args.first
1284: raise VM::NullPointerError, "Cannot invoke `#{imeth}' on NULL object"
1285: end
1286: unless ref.is_a?(VM::Types::ObjectRef) || ref.is_a?(Array)
1287: raise VM::IllegalArgumentError, "Invalid (non-object) reference to `this' on stack (#{ref.class}: #{ref.inspect})"
1288: end
1289:
1290: rclz = ref.clz;
1291:
1292: until rclz.nil? || idx = rclz.find_method_idx(mname, mdesc)
1293: rclz = vm.find_class(rclz.super_name)
1294: end
1295:
1296: unless idx
1297: raise AbstractMethodError, "Method `#{meth_info[:name] + meth_info[:desc]}' not found"
1298: end
1299:
1300: new_frame = VM::Stack::Frame.new(rclz, idx, [], ref_and_args)
1301: m = new_frame.method
1302:
1303: # TODO proper access checks
1304: raise IllegalAccessError, "Static method `#{m}' invoked as interface" if m.static?
1305: raise AbstractMethodError, "Method `#{m}' is abstract" if m.abstract?
1306:
1307: vm.push_frame(new_frame)
1308: end
NEW (0xBB) (idx1, idx2) … => …, objectref
# File lib/ruva/opcodes.rb, line 1884
1884: def op187(vm, idx1, idx2)
1885: clz = vm.frame.clz.pool[operands_short(idx1, idx2)].const_clz
1886: vm.stack.push VM::Types::ObjectRef.new(clz)
1887: end
NEWARRAY (0xBC) (type (4=bool 5=char 6=float 7=double 8=byte 9=short 10=int 11=long)) … => …, arrayref
# File lib/ruva/opcodes.rb, line 1892
1892: def op188(vm, type)
1893: size = vm.stack.pop
1894:
1895: case type
1896: when 4, 5, 8, 9, 10, 11
1897: vm.stack.push Array.new(size, 0)
1898: when 6, 7
1899: vm.stack.push Array.new(size, 0.0)
1900: else
1901: raise VM::IllegalArgumentError, "Unrecognised primitive array type #{type}"
1902: end
1903: end
ANEWARRAY (0xBD) (idx_byte1, idx_byte2) …, count => …, arrayref
# File lib/ruva/opcodes.rb, line 257
257: def op189(vm, idx1, idx2)
258: size = vm.stack.pop
259: vm.stack.push Array.new(size)
260: end
LDCW (0x13) (idx1, idx2) … => …, value
# File lib/ruva/opcodes.rb, line 1679
1679: def op19(vm, idx1, idx2)
1680: idx = operands_short(idx1, idx2)
1681: if (pool = vm.frame.clz.pool).length > idx
1682: vm.stack.push(pool[idx])
1683: else
1684: raise IllegalArgumentError, "Index #{idx} out of constant pool"
1685: end
1686: end
ARRAYLENGTH (0xBE) () …, arrayref => …, int
# File lib/ruva/opcodes.rb, line 270
270: def op190(vm)
271: ary = vm.stack.pop or raise NullPointerError, "Cannot get length of NULL array"
272: vm.stack.push(ary.length)
273: end
ATHROW (0xBF) () …, objectref => (^) objectref
# File lib/ruva/opcodes.rb, line 311
311: def op191(vm)
312: vm.exception_unwind(vm.stack.pop)
313: end
CHECKCAST (0xC0) (idx_byte1, idx_byte2) …, objectref => …, objectref
# File lib/ruva/opcodes.rb, line 351
351: def op192(vm, idx1, idx2)
352: # nop, all currently valid
353: end
INSTANCEOF (0xC1) (idx1, idx2) …, objectref => …, result
# File lib/ruva/opcodes.rb, line 1244
1244: def op193(vm, idx1, idx2)
1245: obj = vm.stack.pop
1246: clz_name = vm.frame.clz.pool[operands_short(idx1, idx2)].const_clz_name
1247:
1248: if obj.is_a?(VM::Types::ObjectRef) && obj.java_instof?(vm, clz_name)
1249: vm.stack.push(1)
1250: elsif obj.is_a?(Array) && (clz_name == 'java/lang/Cloneable' || clz_name == 'java/lang/Serializable')
1251: # special case for arrays, which are cloneable/serializable
1252: vm.stack.push(1)
1253: else
1254: vm.stack.push(0)
1255: end
1256: end
MONITORENTER (0xC2) () …, objectref => …
# File lib/ruva/opcodes.rb, line 1863
1863: def op194(vm)
1864: # nop
1865: end
MONITOREXIT (0xC3) () …, objectref => …
# File lib/ruva/opcodes.rb, line 1870
1870: def op195(vm)
1871: # nop
1872: end
WIDE (0xC4) (VARIABLE) dependent on modified instruction
# File lib/ruva/opcodes.rb, line 2044
2044: def op196(vm, *operands)
2045: not_yet
2046: end
MULTIANEWARRAY - (0xC5) (idx1, idx2, dimensions) … => …, arrayref
# File lib/ruva/opcodes.rb, line 1877
1877: def op197(vm, idx1, idx2, dims)
1878: not_yet
1879: end
IFNULL (0xC6) (branch1, branch2) …, value => …
# File lib/ruva/opcodes.rb, line 1178
1178: def op198(vm, b1, b2)
1179: vm.frame.pc += short_jump(b1, b2) unless vm.stack.pop
1180: end
IFNONNULL (0xC7) (branch1, branch2) …, value => …
# File lib/ruva/opcodes.rb, line 1171
1171: def op199(vm, b1, b2)
1172: vm.frame.pc += short_jump(b1, b2) if vm.stack.pop
1173: end
ICONST_M1 (0x02) () … => …, const
# File lib/ruva/opcodes.rb, line 996
996: def op2(vm)
997: vm.stack.push(-1)
998: end
GOTO_W (0xC8) (branch1, branch2, branch3, branch4) … => …
# File lib/ruva/opcodes.rb, line 917
917: def op200(vm, b1, b2, b3, b4)
918: vm.frame.pc += long_jump(b1,b2,b3,b4)
919: end
JSRW (0xC9) (branch1, branch2, branch3, branch4) … => …, address
# File lib/ruva/opcodes.rb, line 1587
1587: def op201(vm, b1, b2, b3, b4)
1588: vm.stack.push Ruva::VM::Types::ReturnAddress.new(vm.frame.pc)
1589: vm.frame.pc += long_jump(b1,b2,b3,b4)
1590: end
# File lib/ruva/opcodes.rb, line 2066
2066: def op202(vm, *operands) # BREAKPOINT
2067: # nop
2068: end
RESERVED OPCODES ################
# File lib/ruva/opcodes.rb, line 2049
2049: def op254(vm, *operands) # IMPDEP1
2050: # nop
2051: end
NATIVERETURN () …, value -> (^) …, value
# File lib/ruva/opcodes.rb, line 2056
2056: def op255(vm)
2057: if vm.frame.method.void?
2058: vm.pop_frame
2059: else
2060: r = vm.stack.pop
2061: vm.pop_frame
2062: vm.stack.push(r)
2063: end
2064: end
ILOAD_0 (0x1a) () …, => …, value
# File lib/ruva/opcodes.rb, line 1198
1198: def op26(vm)
1199: op21(vm,0)
1200: end
ILOAD_1 (0x1b) () …, => …, value
# File lib/ruva/opcodes.rb, line 1205
1205: def op27(vm)
1206: op21(vm,1)
1207: end
ILOAD_2 (0x1c) () …, => …, value
# File lib/ruva/opcodes.rb, line 1212
1212: def op28(vm)
1213: op21(vm,2)
1214: end
ILOAD_3 (0x1d) () …, => …, value
# File lib/ruva/opcodes.rb, line 1219
1219: def op29(vm)
1220: op21(vm,3)
1221: end
ICONST_0 (0x03) () … => …, const
# File lib/ruva/opcodes.rb, line 1003
1003: def op3(vm)
1004: vm.stack.push(0)
1005: end
LLOAD_0 (0x1e) () …, => …, value
# File lib/ruva/opcodes.rb, line 1709
1709: def op30(vm)
1710: op22(vm,0)
1711: end
LLOAD_1 (0x1f) () …, => …, value
# File lib/ruva/opcodes.rb, line 1716
1716: def op31(vm)
1717: op22(vm,1)
1718: end
LLOAD_2 (0x20) () …, => …, value
# File lib/ruva/opcodes.rb, line 1723
1723: def op32(vm)
1724: op22(vm,2)
1725: end
LLOAD_3 (0x21) () …, => …, value
# File lib/ruva/opcodes.rb, line 1730
1730: def op33(vm)
1731: op22(vm,3)
1732: end
FLOAD_0 (0x22) () …, => …, value
# File lib/ruva/opcodes.rb, line 715
715: def op34(vm)
716: op23(vm, 0)
717: end
FLOAD_1 (0x23) () …, => …, value
# File lib/ruva/opcodes.rb, line 722
722: def op35(vm)
723: op23(vm, 1)
724: end
FLOAD_2 (0x24) () …, => …, value
# File lib/ruva/opcodes.rb, line 729
729: def op36(vm)
730: op23(vm, 2)
731: end
FLOAD_3 (0x25) () …, => …, value
# File lib/ruva/opcodes.rb, line 736
736: def op37(vm)
737: op23(vm, 3)
738: end
DLOAD_0 (0x26) () …, => …, value
# File lib/ruva/opcodes.rb, line 448
448: def op38(vm)
449: op24(vm,0)
450: end
DLOAD_1 (0x27) () …, => …, value
# File lib/ruva/opcodes.rb, line 455
455: def op39(vm)
456: op24(vm,1)
457: end
ICONST_1 (0x04) () … => …, const
# File lib/ruva/opcodes.rb, line 1010
1010: def op4(vm)
1011: vm.stack.push(1)
1012: end
DLOAD_2 (0x28) () …, => …, value
# File lib/ruva/opcodes.rb, line 462
462: def op40(vm)
463: op24(vm,2)
464: end
DLOAD_3 (0x29) () …, => …, value
# File lib/ruva/opcodes.rb, line 469
469: def op41(vm)
470: op24(vm,3)
471: end
ALOAD_0 (0x2A) () …, => …, objectref
# File lib/ruva/opcodes.rb, line 229
229: def op42(vm)
230: op25(vm,0)
231: end
ALOAD_1 (0x2B) () …, => …, objectref
# File lib/ruva/opcodes.rb, line 236
236: def op43(vm)
237: op25(vm,1)
238: end
ALOAD_2 (0x2C) () …, => …, objectref
# File lib/ruva/opcodes.rb, line 243
243: def op44(vm)
244: op25(vm,2)
245: end
ALOAD_3 (0x2D) () …, => …, objectref
# File lib/ruva/opcodes.rb, line 250
250: def op45(vm)
251: op25(vm,3)
252: end
ICONST_2 (0x05) () … => …, const
# File lib/ruva/opcodes.rb, line 1017
1017: def op5(vm)
1018: vm.stack.push(2)
1019: end
ISTORE (0x36)
(idx)
..., int => ...
# File lib/ruva/opcodes.rb, line 1516
1516: def op54(vm, idx)
1517: vm.stack.push(check_int(vm.stack.pop))
1518: __any_store(vm, idx)
1519: end
LSTORE (0x37) (idx) …, long => …
# File lib/ruva/opcodes.rb, line 1802
1802: def op55(vm, idx)
1803: vm.stack.push(check_long(vm.stack.pop))
1804: __any_store(vm, idx)
1805: end
FSTORE (0x38) (idx) …, float => …
# File lib/ruva/opcodes.rb, line 779
779: def op56(vm, idx)
780: vm.stack.push(check_float(vm.stack.pop))
781: __any_store(vm, idx)
782: end
DSTORE (0x39) (idx) …, double => …
# File lib/ruva/opcodes.rb, line 508
508: def op57(vm, idx)
509: vm.stack.push(check_double(vm.stack.pop))
510: __any_store(vm, idx)
511: end
ISTORE_0 (0x3B) () …, int => …
# File lib/ruva/opcodes.rb, line 1524
1524: def op59(vm)
1525: op54(vm, 0)
1526: end
ICONST_3 (0x06) () … => …, const
# File lib/ruva/opcodes.rb, line 1024
1024: def op6(vm)
1025: vm.stack.push(3)
1026: end
ISTORE_1 (0x3C) () …, int => …
# File lib/ruva/opcodes.rb, line 1531
1531: def op60(vm)
1532: op54(vm, 1)
1533: end
ISTORE_2 (0x3D) () …, int => …
# File lib/ruva/opcodes.rb, line 1538
1538: def op61(vm)
1539: op54(vm, 2)
1540: end
ISTORE_3 (0x3E) () …, int => …
# File lib/ruva/opcodes.rb, line 1545
1545: def op62(vm)
1546: op54(vm, 3)
1547: end
LSTORE_0 (0x3f) () …, long => …
# File lib/ruva/opcodes.rb, line 1810
1810: def op63(vm)
1811: op55(vm, 0)
1812: end
LSTORE_1 (0x40) () …, long => …
# File lib/ruva/opcodes.rb, line 1817
1817: def op64(vm)
1818: op55(vm, 1)
1819: end
LSTORE_2 (0x41) () …, long => …
# File lib/ruva/opcodes.rb, line 1824
1824: def op65(vm)
1825: op55(vm, 2)
1826: end
LSTORE_3 (0x42) () …, long => …
# File lib/ruva/opcodes.rb, line 1831
1831: def op66(vm)
1832: op55(vm, 3)
1833: end
FSTORE_0 (0x43) () …, float => …
# File lib/ruva/opcodes.rb, line 787
787: def op67(vm)
788: op56(vm, 0)
789: end
FSTORE_1 (0x44) () …, float => …
# File lib/ruva/opcodes.rb, line 794
794: def op68(vm)
795: op56(vm, 1)
796: end
FSTORE_2 (0x45) () …, float => …
# File lib/ruva/opcodes.rb, line 801
801: def op69(vm)
802: op56(vm, 2)
803: end
ICONST_4 (0x07) () … => …, const
# File lib/ruva/opcodes.rb, line 1031
1031: def op7(vm)
1032: vm.stack.push(4)
1033: end
FSTORE_3 (0x46) () …, float => …
# File lib/ruva/opcodes.rb, line 808
808: def op70(vm)
809: op56(vm, 3)
810: end
DSTORE_0 (0x47) () …, double => …
# File lib/ruva/opcodes.rb, line 516
516: def op71(vm)
517: op57(vm, 0)
518: end
DSTORE_1 (0x48) () …, double => …
# File lib/ruva/opcodes.rb, line 523
523: def op72(vm)
524: op57(vm, 0)
525: end
DSTORE_2 (0x49) () …, double => …
# File lib/ruva/opcodes.rb, line 530
530: def op73(vm)
531: op57(vm, 0)
532: end
DSTORE_3 (0x50) () …, double => …
# File lib/ruva/opcodes.rb, line 537
537: def op74(vm)
538: op57(vm, 0)
539: end
ASTORE_0 (0x4B) () …, objectref => …
# File lib/ruva/opcodes.rb, line 283
283: def op75(vm)
284: op58(vm, 0)
285: end
ASTORE_1 (0x4C) () …, objectref => …
# File lib/ruva/opcodes.rb, line 290
290: def op76(vm)
291: op58(vm, 1)
292: end
ASTORE_2 (0x4D) () …, objectref => …
# File lib/ruva/opcodes.rb, line 297
297: def op77(vm)
298: op58(vm, 2)
299: end
ASTORE_3 (0x4E) () …, objectref => …
# File lib/ruva/opcodes.rb, line 304
304: def op78(vm)
305: op58(vm, 3)
306: end
IASTORE (0x4F) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 988
988: def op79(vm)
989: vm.stack.push(check_int(vm.stack.pop))
990: __any_astore(vm)
991: end
ICONST_5 (0x08) () … => …, const
# File lib/ruva/opcodes.rb, line 1038
1038: def op8(vm)
1039: vm.stack.push(5)
1040: end
LASTORE (0x50) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 1638
1638: def op80(vm)
1639: vm.stack.push(check_long(vm.stack.pop))
1640: __any_astore(vm)
1641: end
FASTORE (0x51) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 651
651: def op81(vm)
652: vm.stack.push(check_float(vm.stack.pop))
653: __any_astore(vm)
654: end
DASTORE (0x52) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 393
393: def op82(vm)
394: check_double(vm.stack.peek)
395: __any_astore(vm)
396: end
BASTORE (0x54) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 323
323: def op84(vm)
324: vm.stack.push(check_byte(vm.stack.pop))
325: __any_astore(vm)
326: end
CASTORE (0x55) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 343
343: def op85(vm)
344: vm.stack.push(check_char(vm.stack.pop))
345: __any_astore(vm)
346: end
SASTORE (0x56) () …, arrayref, idx, value => …
# File lib/ruva/opcodes.rb, line 2013
2013: def op86(vm)
2014: vm.stack.push(check_short(vm.stack.pop))
2015: __any_astore(vm)
2016: end
POP (0x57) () …, value => …
# File lib/ruva/opcodes.rb, line 1915
1915: def op87(vm)
1916: # this should raise on a cat2 type, but I don't
1917: # see any point since we only emulate them...
1918: raise VM::StackStateError if vm.stack.empty?
1919: vm.stack.pop
1920: end
POP2 (0x58) () …, value2, value1 => … (v1,v2 are cat 1 type) …, value1 => … (v1 is cat 2 type)
# File lib/ruva/opcodes.rb, line 1926
1926: def op88(vm)
1927: raise VM::StackStateError if vm.stack.empty?
1928: vm.stack.pop unless vm.stack.pop.is_a?(VM::Types::Cat2Value)
1929: end
DUP (0x59) () …, value => …, value, value
# File lib/ruva/opcodes.rb, line 553
553: def op89(vm)
554: vm.stack.push(vm.stack[-1])
555: end
LCONST_0 (0x09) () … => …, const
# File lib/ruva/opcodes.rb, line 1653
1653: def op9(vm)
1654: vm.stack.push(check_long(0))
1655: end
DUPX1 (0x5A) () …, value2, value1 => …, value1, value2, value1
# File lib/ruva/opcodes.rb, line 560
560: def op90(vm)
561: vm.stack[-2,0] = (vm.stack[-1])
562: end
DUPX2 (0x5B) () …, value3, value2, value1 => …, value1, value3, value2, value1 where value1, value2, and value3 are all values of a category 1 computational type
…, value2, value1 => …, value1, value2, value1 where value1 is a value of a category 1 computational type and value2 is a value of a category 2 computational type
# File lib/ruva/opcodes.rb, line 571
571: def op91(vm)
572: # we can do this because cat2s are always followed by a nil
573: vm.stack[-3,0] = vm.stack[-1]
574: end
DUP2 (0x5C) () …, value2, value1 => …, value2, value1, value2, value1 where both value1 and value2 are values of a category 1 computational type …, value => …, value, value where value is a value of a category 2 computational type
# File lib/ruva/opcodes.rb, line 582
582: def op92(vm)
583: # we can do this because cat2s are always followed by a nil
584: vm.stack[-2,0] = vm.stack[-2,2]
585: end
DUP2X1 (0x5D) () …, value3, value2, value1 => …, value2, value1, value3, value2, value1 where value1, value2, and value3 are all values of a category 1 computational type …, value2, value1 => …, value1, value2, value1 where value1 is a value of a category 2 computational type and value2 is a value of a category 1 computational type
# File lib/ruva/opcodes.rb, line 593
593: def op93(vm)
594: not_yet
595: end
DUP2X2 (0x5E) ()
…, value4, value3, value2, value1 …, value2, value1, value4, value3, value2, value1 where value1, value2, value3, and value4 are all values of a category 1 computational type …, value3, value2, value1 …, value1, value3, value2, value1 where value1 is a value of a category 2 computational type and value2 and value3 are both values of a category 1 computational type …, value3, value2, value1 …, value2, value1, value3, value2, value1 where value1 and value2 are both values of a category 1 computational type and value3 is a value of a category 2 computational type …, value2, value1 …, value1, value2, value1 where value1 and value2 are both values of a category 2 computational type
# File lib/ruva/opcodes.rb, line 607
607: def op94(vm)
608: not_yet
609: end
SWAP (0x5F) () …, value1, value2 => …, value2, value1
# File lib/ruva/opcodes.rb, line 2028
2028: def op95(vm)
2029: b, a = vm.stack.pop, vm.stack.pop
2030: vm.stack.push(b)
2031: vm.stack.push(a)
2032: end
IADD (0x60) () …, value1, value2 => …, int
# File lib/ruva/opcodes.rb, line 965
965: def op96(vm)
966: b, a = vm.stack.pop, vm.stack.pop
967: check_int(a) and check_int(b)
968: vm.stack.push(a) and vm.stack.push(b)
969: __any_add(vm)
970: end
LADD (0x61) () …, value1, value2 => …, value
# File lib/ruva/opcodes.rb, line 1617
1617: def op97(vm)
1618: b, a = vm.stack.pop, vm.stack.pop
1619: vm.stack.push(check_long(a + b))
1620: end
FADD (0x62) () …, value1, value2 => …, double
# File lib/ruva/opcodes.rb, line 636
636: def op98(vm)
637: b, a = vm.stack.pop, vm.stack.pop
638: check_float(a) and check_float(b)
639: vm.stack.push(a) and vm.stack.push(b)
640: __any_add(vm)
641: end
DADD (0x63) () …, value1, value2 => …, double
# File lib/ruva/opcodes.rb, line 380
380: def op99(vm)
381: b, a = vm.stack.pop, vm.stack.pop
382: vm.stack.push(check_double(a + b))
383: end
Encode the supplied (char-range) operands as a long (32-bit) operand.
# File lib/ruva/opcodes.rb, line 69
69: def operands_long(b1, b2, b3, b4)
70: (((b1 << 24) | b2 << 16) | b3 << 8) | b4
71: end
Encode the supplied (char-range) operands as a short (16-bit) operand.
# File lib/ruva/opcodes.rb, line 64
64: def operands_short(b1, b2)
65: (b1 << 8) | b2
66: end
Encode the supplied (char-range) operands as a short (16-bit) jump target instruction offset. This is calculated as the operands value as a short, minus three (to account for the fact that pc will already point to the next instruction).
# File lib/ruva/opcodes.rb, line 110
110: def short_jump(b1, b2)
111: signed_short(operands_short(b1, b2)) - 3
112: end
Decode the supplied short (16-bit) operands to a pair of char-range operands.
# File lib/ruva/opcodes.rb, line 74
74: def short_operands(short)
75: # TODO reverse for little-endian plaf?
76: # How does JVM behave?
77: [(short & 0xFF00) >> 8, short & 0x00FF]
78: end
Make an unsigned byte into a signed byte.
# File lib/ruva/opcodes.rb, line 91
91: def signed_byte(ubyte)
92: [ubyte].pack('C').unpack('c').first
93: end
Make an unsigned long into a signed long.
# File lib/ruva/opcodes.rb, line 102
102: def signed_long(ulong)
103: [ulong].pack('L').unpack('l').first
104: end