Skip to content

Commit 86ae087

Browse files
committed
Double opcodes, Math.random, Math.sqrt, another java function to test
1 parent 8f8863b commit 86ae087

File tree

7 files changed

+138
-19
lines changed

7 files changed

+138
-19
lines changed

example/Hello.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,22 @@ public static void fizzbuzz() {
4949
}
5050
}
5151
}
52+
53+
public static double monteCarloPi(int n){
54+
int inCircle = 0;
55+
56+
for (int i = 0; i < n; i++) {
57+
// a square with a side of length 2 centered at 0 has
58+
// x and y range of -1 to 1
59+
double randX = Math.random() * 2 - 1; //range -1 to 1
60+
double randY = Math.random() * 2 - 1; //range -1 to 1
61+
double dist = Math.sqrt(randX * randX + randY * randY);
62+
63+
if(dist < 1) {
64+
inCircle++;
65+
}
66+
}
67+
68+
return 4.0 * inCircle / n;
69+
}
5270
}

pyjvm/CPInfo.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class CPTag(Enum):
77
METHODREF = 10
88
STRING = 8
99
INTEGER = 3
10+
DOUBLE = 6
1011
NAMEANDTYPE = 12
1112
UTF8 = 1
1213

@@ -28,6 +29,8 @@ def from_reader(self, r):
2829
self.parse_string(r)
2930
elif self.tag == CPTag.INTEGER:
3031
self.parse_integer(r)
32+
elif self.tag == CPTag.DOUBLE:
33+
self.parse_double(r)
3134
elif self.tag == CPTag.NAMEANDTYPE:
3235
self.parse_nameandtype(r)
3336
elif self.tag == CPTag.UTF8:
@@ -48,6 +51,9 @@ def parse_string(self, r):
4851
def parse_integer(self, r):
4952
self.integer = struct.unpack('!i', r.read(4))[0]
5053

54+
def parse_double(self, r):
55+
self.double = struct.unpack('!d', r.read(8))[0]
56+
5157
def parse_nameandtype(self, r):
5258
self.name_index = struct.unpack('!H', r.read(2))[0]
5359
self.desc_index = struct.unpack('!H', r.read(2))[0]

pyjvm/ClassFile.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import struct
2-
from .CPInfo import CPInfo
2+
from .CPInfo import CPInfo, CPTag
33
from .CodeAttr import CodeAttr
44
from .Frame import Frame
55
from .FieldInfo import FieldInfo
@@ -75,10 +75,17 @@ def from_file(self, path):
7575
const_count = struct.unpack('!H', cf.read(2))[0]
7676
self.const_pool = []
7777

78-
for i in range(const_count - 1):
78+
i = 1
79+
while i < const_count:
7980
c = CPInfo().from_reader(cf)
8081
self.const_pool.append(c)
8182

83+
if c.tag == CPTag.DOUBLE:
84+
self.const_pool.append(CPInfo())
85+
i += 1
86+
87+
i += 1
88+
8289
self.replace_indexes(self.const_pool)
8390

8491
self.access_flags = struct.unpack('!H', cf.read(2))[0]

pyjvm/Machine.py

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ class Inst(Enum):
1616
ICONST_5 = 0x08
1717
LCONST_0 = 0x09
1818
LCONST_1 = 0x0A
19+
DCONST_0 = 0x0E
20+
DCONST_1 = 0x0F
1921
BIPUSH = 0x10
2022
SIPUSH = 0x11
2123
LDC = 0x12
24+
LDC2_W = 0x14
2225
ILOAD = 0x15
2326
LLOAD = 0x16
27+
DLOAD = 0x18
2428
ILOAD_0 = 0x1A
2529
ILOAD_1 = 0x1B
2630
ILOAD_2 = 0x1C
@@ -29,11 +33,13 @@ class Inst(Enum):
2933
LLOAD_1 = 0x1F
3034
LLOAD_2 = 0x20
3135
LLOAD_3 = 0x21
36+
DLOAD_3 = 0x29
3237
ALOAD_0 = 0x2A
3338
ALOAD_1 = 0x2B
3439
ALOAD_2 = 0x2C
3540
ISTORE = 0x36
3641
LSTORE = 0x37
42+
DSTORE = 0x39
3743
ISTORE_0 = 0x3B
3844
ISTORE_1 = 0x3C
3945
ISTORE_2 = 0x3D
@@ -42,6 +48,7 @@ class Inst(Enum):
4248
LSTORE_1 = 0x40
4349
LSTORE_2 = 0x41
4450
LSTORE_3 = 0x42
51+
DSTORE_3 = 0x4A
4552
ASTORE_0 = 0x4B
4653
ASTORE_1 = 0x4C
4754
ASTORE_2 = 0x4D
@@ -50,19 +57,27 @@ class Inst(Enum):
5057
DUP = 0x59
5158
IADD = 0x60
5259
LADD = 0x61
60+
DADD = 0x63
5361
ISUB = 0x64
62+
DSUB = 0x67
5463
IMUL = 0x68
64+
DMUL = 0x6B
65+
DDIV = 0x6F
5566
IREM = 0x70
5667
IINC = 0x84
68+
I2D = 0x87
5769
I2C = 0x92
70+
DCMPG = 0x98
5871
IFNE = 0x9A
72+
IFGE = 0x9C
5973
IFLE = 0x9E
6074
IF_ICMPLT = 0xA1
6175
IF_ICMPGE = 0xA2
6276
IF_ICMPGT = 0xA3
6377
GOTO = 0xA7
6478
IRET = 0xAC
6579
LRET = 0xAD
80+
DRETURN = 0xAF
6681
ARETURN = 0xB0
6782
RETURN = 0xB1
6883
GETSTATIC = 0xB2
@@ -148,6 +163,14 @@ def iconst_4(frame):
148163
def iconst_5(frame):
149164
frame.push(5)
150165

166+
@opcode(Inst.DCONST_0)
167+
def dconst_0(frame):
168+
frame.push(0.0)
169+
170+
@opcode(Inst.DCONST_1)
171+
def dconst_1(frame):
172+
frame.push(1.0)
173+
151174
@opcode(Inst.BIPUSH)
152175
def bipush(frame):
153176
val = read_byte(frame)
@@ -158,8 +181,28 @@ def sipush(frame):
158181
val = read_signed_short(frame)
159182
frame.push(val)
160183

184+
@opcode(Inst.LDC)
185+
def ldc(frame):
186+
index = read_byte(frame)
187+
const = frame.current_class.const_pool[index - 1]
188+
189+
if 'integer' in const.__dict__:
190+
const = const.integer
191+
else:
192+
const = const.string
193+
194+
frame.push(const)
195+
196+
@opcode(Inst.LDC2_W)
197+
def ldc2_w(frame):
198+
index = read_unsigned_short(frame)
199+
const = frame.current_class.const_pool[index - 1].double
200+
201+
frame.push(const)
202+
161203
@opcode(Inst.ILOAD)
162204
@opcode(Inst.LLOAD)
205+
@opcode(Inst.DLOAD)
163206
def iload(frame):
164207
index = read_byte(frame)
165208
frame.push(frame.get_local(index))
@@ -184,11 +227,13 @@ def iload_2(frame):
184227

185228
@opcode(Inst.ILOAD_3)
186229
@opcode(Inst.LLOAD_3)
230+
@opcode(Inst.DLOAD_3)
187231
def iload_3(frame):
188232
frame.push(frame.get_local(3))
189233

190234
@opcode(Inst.ISTORE)
191235
@opcode(Inst.LSTORE)
236+
@opcode(Inst.DSTORE)
192237
def istore(frame):
193238
index = read_byte(frame)
194239
val = frame.pop()
@@ -210,6 +255,7 @@ def lstore_2(frame):
210255
frame.set_local(1, val)
211256

212257
@opcode(Inst.LSTORE_3)
258+
@opcode(Inst.DSTORE_3)
213259
def lstore_3(frame):
214260
val = frame.pop()
215261
frame.set_local(3, val)
@@ -226,10 +272,12 @@ def dup(frame):
226272

227273
@opcode(Inst.IADD)
228274
@opcode(Inst.LADD)
275+
@opcode(Inst.DADD)
229276
def iadd(frame):
230277
frame.push(frame.pop() + frame.pop())
231278

232279
@opcode(Inst.ISUB)
280+
@opcode(Inst.DSUB)
233281
def isub(frame):
234282
val2 = frame.pop()
235283
val1 = frame.pop()
@@ -243,15 +291,38 @@ def isub(frame):
243291
frame.push(val1 - val2)
244292

245293
@opcode(Inst.IMUL)
294+
@opcode(Inst.DMUL)
246295
def imul(frame):
247296
val2 = frame.pop()
248297
val1 = frame.pop()
249298
frame.push(val2 * val1)
250299

300+
@opcode(Inst.DDIV)
301+
def ddiv(frame):
302+
val2 = frame.pop()
303+
val1 = frame.pop()
304+
frame.push(val1 / val2)
305+
306+
@opcode(Inst.I2D)
307+
def i2d(frame):
308+
frame.push(float(frame.pop()))
309+
251310
@opcode(Inst.I2C)
252311
def i2c(frame):
253312
frame.push(chr(frame.pop()))
254313

314+
@opcode(Inst.DCMPG)
315+
def dcmpg(frame):
316+
val2 = frame.pop()
317+
val1 = frame.pop()
318+
319+
if val1 > val2:
320+
frame.push(1)
321+
elif val1 == val2:
322+
frame.push(0)
323+
else:
324+
frame.push(-1)
325+
255326
class Machine:
256327
def __init__(self):
257328
self.class_files = {}
@@ -271,17 +342,6 @@ def execute_code(self, frame):
271342

272343
if inst in OPCODES:
273344
OPCODES[inst](frame)
274-
elif inst == Inst.LDC:
275-
index = read_byte(frame)
276-
277-
const = frame.current_class.const_pool[index - 1]
278-
279-
if 'integer' in const.__dict__:
280-
const = const.integer
281-
else:
282-
const = const.string
283-
284-
frame.stack.append(const)
285345
elif inst == Inst.ISTORE_0:
286346
val = frame.stack.pop()
287347
frame.set_local(0, val)
@@ -320,6 +380,14 @@ def execute_code(self, frame):
320380
if v1 != 0:
321381
frame.ip -= 3
322382
frame.ip += branch
383+
elif inst == Inst.IFGE:
384+
v1 = frame.stack.pop()
385+
386+
branch = read_signed_short(frame)
387+
388+
if v1 >= 0:
389+
frame.ip -= 3
390+
frame.ip += branch
323391
elif inst == Inst.IFLE:
324392
v1 = frame.stack.pop()
325393

@@ -378,7 +446,7 @@ def execute_code(self, frame):
378446

379447
frame.ip -= 3
380448
frame.ip += branch
381-
elif inst == Inst.IRET or inst == Inst.LRET or inst == Inst.ARETURN:
449+
elif inst == Inst.IRET or inst == Inst.LRET or inst == Inst.ARETURN or inst == Inst.DRETURN:
382450
return frame.stack.pop()
383451
elif inst == Inst.RETURN:
384452
return

pyjvm/jstdlib/Math.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from .JavaClass import JavaClass
2+
import random
3+
import math
4+
5+
class Math(JavaClass):
6+
def __init__(self):
7+
super().__init__()
8+
self.class_name = 'java/lang/Math'
9+
10+
def canHandleMethod(self, name, desc):
11+
return name in ['random']
12+
13+
def handleStatic(self, name, desc, frame):
14+
super().handleMethod(name, desc, frame)
15+
if name == 'random':
16+
return random.random()
17+
elif name == 'sqrt':
18+
val = frame.pop()
19+
return math.sqrt(val)

pyjvm/jstdlib/StdlibLoader.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
from .Rng import Rng
55
from .System import System
66
from .String import String
7+
from .Math import Math
78

89
libs = [
910
JavaClass(),
1011
PrintStream(),
1112
StringBuilder(),
1213
System(),
1314
Rng(),
14-
String()
15+
String(),
16+
Math()
1517
]
1618

1719
def load_stdlib_classes(machine):

test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
load_stdlib_classes(m)
99

1010
# Load local classes
11-
#m.load_class_file('example/Hello.class')
11+
m.load_class_file('example/Hello.class')
1212
#m.load_class_file('example/TestImport.class')
13-
m.load_class_file('example/IntegerTest.class')
13+
#m.load_class_file('example/IntegerTest.class')
1414
#m.load_class_file('example/Rot13.class')
1515
#m.load_class_file('example/InstanceTest.class')
1616

1717
# Dump machine state
1818
#m.dump()
1919

20-
print(m.call_function('jvmtest/IntegerTest/iterativeFibonacci', 20))
21-
print(m.call_function('jvmtest/IntegerTest/recursiveFibonacci', 6))
20+
print(m.call_function('com/gkbrk/JVMTest/Hello/monteCarloPi', 5000))

0 commit comments

Comments
 (0)