Skip to content

Commit aa53d2b

Browse files
author
Louis Jenkins
committed
More refactoring and documentation
1 parent 785a61a commit aa53d2b

File tree

2 files changed

+33
-31
lines changed

2 files changed

+33
-31
lines changed

VirtualMachine/ByteCode.hs

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module VirtualMachine.ByteCode where
2525
execute :: Runtime_Environment -> IO ()
2626
execute env = head <$> readIORef (stack env) -- Take the head of the stack (current stack frame)
2727
>>= \frame -> when (debug_mode env) (debugFrame frame >>= putStrLn) -- Optional Debug
28-
>> getPC' frame >>= \pc -> maxPC frame >>= \max_pc ->
28+
>> getPC' frame >>= \pc -> maxPC frame >>= \max_pc -> -- Program Counters for comparison
2929
-- While valid program_counter, execute instruction
3030
unless (pc >= max_pc) (getNextBC frame >>= execute' frame >> execute env)
3131
where
@@ -73,15 +73,15 @@ module VirtualMachine.ByteCode where
7373
-- invokevirtual: (append, println). NOTE: MUST HAVE ONLY ONE PARAMETER ELSE UNDEFINED
7474
| bc == 182 = getNextShort frame >>= \method_idx -> (readIORef . current_class) env
7575
>>= \c -> case methodName c method_idx of
76-
"append" -> ((\x y -> VString $ show y ++ show x) <$> popOp frame <*> popOp frame)
77-
>>= pushOp frame
78-
"println" -> popOp frame >>= print
79-
"toString" -> return ()
76+
"append" -> ((\x y -> VString $ show y ++ show x) <$> popOp frame <*> popOp frame) >>= pushOp frame
77+
"println" -> popOp frame >>= print -- Defer I/O to Haskell
78+
"toString" -> return () -- StringBuilder object is already a 'VString'
8079
_ -> error "Bad Method Call!"
81-
-- Used to call <init>, but we don't deal with that... yet
80+
-- Invokespecial is used to call <init>, but we don't deal with that... yet
8281
| bc == 183 = void $ getNextShort frame
8382
-- Laziness: 'new' must refer to StringBuilder... otherwise it's undefined anyway
8483
| bc == 187 = getNextShort frame >> pushOp frame (VString "")
84+
| otherwise = error $ "Bad ByteCode Instruction: " ++ show bc
8585
where
8686
methodName :: Class -> Word16 -> String
8787
methodName clazz method_idx = let
@@ -91,35 +91,30 @@ module VirtualMachine.ByteCode where
9191
utf8_name = cpool !! fromIntegral (name_index name_and_type)
9292
in show . utf8_bytes $ utf8_name
9393

94-
{-
95-
Loads transfer values from a slot in the Local Variable array to the Operand
96-
Stack. Note as well that we can safely ignore the second index for DWORD-sized
97-
variables.
98-
-}
94+
{- Loads from local_variables to operand_stack -}
9995
loadOp :: StackFrame -> ByteCode -> IO ()
10096
loadOp frame bc
101-
-- Loads which have the index as the next bytecode instruction
102-
| bc >= 21 && bc <=25 = getNextBC frame >>= getLocal frame >>= pushOp frame
103-
-- Loads which have a constant index (I.E: ILOAD_0 to ILOAD_3)
104-
| bc >= 26 && bc <= 45 = getLocal frame ((bc - 26) `mod` 4) >>= pushOp frame
97+
-- Loads with the index as the next bytecode instruction
98+
| bc >= 21 && bc <=25 = getNextBC frame >>= getLocal' frame >>= pushOp frame
99+
-- Loads with a constant index (I.E: ILOAD_0 to ILOAD_3 have indice 0 to 3 respectively)
100+
| bc >= 26 && bc <= 45 = getLocal' frame ((bc - 26) `mod` 4) >>= pushOp frame
105101
| otherwise = error $ "Bad ByteCode Instruction: " ++ show bc
106102

107-
{-
108-
Stores transfer the top value of the Operand Stack to an indice in the
109-
Local Variable array. The JVM specification specifies that for DWORD sized
110-
types (I.E: Long and Double) take up two slots in the Local Variable
111-
array (the lower index contains the higher WORD, higher index contains the
112-
lower WORD), so we store a dummy value (Null reference) in the higher index.
113-
-}
103+
{- Stores from operand_stack to local_variables -}
114104
storeOp :: StackFrame -> ByteCode -> IO ()
115105
storeOp frame bc
116-
-- Stores which have the Index as the next bytecode instruction
106+
-- Stores with the index as the next bytecode instruction
117107
| bc >= 54 && bc <= 58 = popOp frame >>= \op -> getNextBC frame >>= \idx -> putLocal frame idx op
118108
>> when (bc == 55 || bc == 57) (putLocal frame (idx + 1) (VReference 0))
119-
-- Stores which have a constant index
120-
| bc >= 59 && bc <= 78 = popOp frame >>= putLocal frame ((bc - 59) `mod` 4)
109+
-- Stores with a constant index (I.E: ISTORE_0 to ISTORE_3 have indice 0 to 3 respectively)
110+
| bc >= 59 && bc <= 78 = let idx = ((bc - 59) `mod` 4) in
111+
popOp frame >>= putLocal frame idx
112+
-- Special Case: Double word-sized variables, such as 'long' and 'double' must
113+
-- take up two slots. We fit both types in a single slot, but the compiler generates
114+
-- ByteCode that are sensitive to these invariants, so we insert a dummy null reference
115+
-- in the second slot to restore that balance.
121116
>> when ((bc >= 63 && bc <= 66) || (bc >= 71 && bc <= 74))
122-
(putLocal frame (((bc - 59) `mod` 4) + 1) (VReference 0))
117+
((putLocal frame $ idx + 1) (VReference 0))
123118
| otherwise = error $ "Bad ByteCode Instruction: " ++ show bc
124119

125120

@@ -162,7 +157,8 @@ module VirtualMachine.ByteCode where
162157
applyBinaryOp :: (Operand -> Operand -> Operand) -> IO ()
163158
applyBinaryOp f = replicateM 2 (popOp frame) >>= \(x:y:_) -> pushOp frame (f y x)
164159
increment :: IO ()
165-
increment = getNextBC frame >>= \idx -> getLocal frame idx >>= \l -> getNextBC frame >>= \n -> putLocal frame idx (l + fromIntegral n)
160+
increment = -- 'iinc' has local variable index as first, with value as second indice
161+
join $ modifyLocal frame <$> getNextBC frame <*> ((+) . fromIntegral <$> getNextBC frame)
166162

167163
cmpOp :: StackFrame -> ByteCode -> IO ()
168164
cmpOp frame bc

VirtualMachine/Stack_Frame.hs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ module VirtualMachine.Stack_Frame where
4242
setPC frame pc = getPC frame >>= flip writeIORef (fromIntegral pc)
4343

4444
modifyPC :: Integral a => StackFrame -> (a -> a) -> IO ()
45-
modifyPC frame f = (f <$> getPC' frame) >>= setPC frame >> getPC' frame >>= print
45+
modifyPC frame f = (f <$> getPC' frame) >>= setPC frame
4646

4747
maxPC :: Integral a => StackFrame -> IO a
4848
maxPC frame = fromIntegral . length <$> getInstructions frame
@@ -67,13 +67,19 @@ module VirtualMachine.Stack_Frame where
6767
Pushes a value as a local variable at the given index.
6868
-}
6969
putLocal :: (Integral a) => StackFrame -> a -> Value -> IO ()
70-
putLocal frame idx val = readIORef frame >>= \f -> writeIORef (local_variables f !! fromIntegral idx) val
70+
putLocal frame idx val = getLocal frame idx >>= flip writeIORef val
71+
72+
modifyLocal :: (Integral a) => StackFrame -> a -> (Value -> Value) -> IO ()
73+
modifyLocal frame idx f = getLocal frame idx >>= flip modifyIORef f
7174

7275
{-
7376
Returns the value associated the given index.
7477
-}
75-
getLocal :: (Integral a) => StackFrame -> a -> IO Value
76-
getLocal frame idx = readIORef frame >>= \f -> readIORef (local_variables f !! fromIntegral idx)
78+
getLocal' :: (Integral a) => StackFrame -> a -> IO Value
79+
getLocal' frame idx = readIORef frame >>= \f -> readIORef (local_variables f !! fromIntegral idx)
80+
81+
getLocal :: Integral a => StackFrame -> a -> IO (IORef Value)
82+
getLocal frame idx = (!! fromIntegral idx) . local_variables <$> readIORef frame
7783

7884
{-
7985
Pops off N operands off of the stack

0 commit comments

Comments
 (0)