codegen: handle exceptions of a method master
authorBernhard Urban <lewurm@gmail.com>
Sun, 9 Sep 2012 16:03:45 +0000 (18:03 +0200)
committerBernhard Urban <lewurm@gmail.com>
Sun, 9 Sep 2012 16:03:45 +0000 (18:03 +0200)
also, use bimap for mapping jpc and npc values

TODO: if no handler is found, throw it to caller method

Mate/BasicBlocks.hs
Mate/MethodPool.hs
Mate/Types.hs
Mate/X86CodeGen.hs
Mate/X86TrapHandling.hs
java/lang/IllegalArgumentException.java [new file with mode: 0644]
tests/Exception2.java [new file with mode: 0644]
tests/Exception3.java [new file with mode: 0644]
tests/Exception4.java [new file with mode: 0644]
tools/installhaskellenv.sh

index af0074980304d46240f287156071856805b21b32..2f96a40fe66ee6ce5b86b644141b3e3cf269b964 100644 (file)
@@ -113,7 +113,11 @@ parseMethod cls methodname sig = do
               else M.insert key [value] emap
               where
                 key = (&&&) eStartPC eEndPC ce
-                value = (&&&) (buildClassID cls . eCatchType) eHandlerPC ce
+                value = (&&&) g eHandlerPC ce
+                  where
+                    g ce' = case eCatchType ce' of
+                        0 -> B.empty
+                        x -> buildClassID cls x
 
   let msig = methodSignature method
   printfBb $ printf "BB: analysing \"%s\"\n" $ toString (methodname `B.append` ": " `B.append` encode msig)
@@ -139,12 +143,12 @@ testCFG c = buildCFG (codeInstructions c) (codeExceptions c)
 
 parseBasicBlock :: Int -> [OffIns] -> BasicBlock
 parseBasicBlock i insns = emptyBasicBlock
-          { code = insonly
+          { code = zip offsets insonly
           , bblength = lastoff - i + (insnLength lastins)
           , successor = endblock }
   where
     (lastblock, is) = takeWhilePlusOne validins omitins insns
-    (_, _, insonly) = unzip3 is
+    (offsets, _, insonly) = unzip3 is
     (lastoff, Just endblock, lastins) = fromJust lastblock
 
     -- also take last (non-matched) element and return it
index 5918a2f1bb655112369af4b1c5047d7add87a4d7..d1df9cf1bb27fe95354b4a2a2daa72c7eab8081c 100644 (file)
@@ -5,6 +5,7 @@ module Mate.MethodPool where
 import Data.Binary
 import Data.String.Utils
 import qualified Data.Map as M
+import qualified Data.Bimap as BI
 import qualified Data.Set as S
 import qualified Data.ByteString.Lazy as B
 import System.Plugins
@@ -57,11 +58,11 @@ getMethodEntry mi@(MethodInfo method cm sig) = do
                 if scm == "jmate/lang/MateRuntime" then
                   case smethod of
                     "loadLibrary" ->
-                       return (funPtrToAddr loadLibraryAddr, M.empty)
+                       return (funPtrToAddr loadLibraryAddr, BI.empty)
                     "printGCStats" ->
-                       return (funPtrToAddr printGCStatsAddr, M.empty)
+                       return (funPtrToAddr printGCStatsAddr, BI.empty)
                     "printMemoryUsage" ->
-                       return (funPtrToAddr printMemoryUsageAddr, M.empty)
+                       return (funPtrToAddr printMemoryUsageAddr, BI.empty)
                     _ ->
                        error $ "native-call: " ++ smethod ++ " not found."
                 else do
@@ -72,7 +73,7 @@ getMethodEntry mi@(MethodInfo method cm sig) = do
                       symbol = sym1 ++ "__" ++ smethod ++ "__" ++ sym2
                   printfMp $ printf "native-call: symbol: %s\n" symbol
                   nf <- loadNativeFunction symbol
-                  let nf' = (nf, M.empty)
+                  let nf' = (nf, BI.empty)
                   setMethodMap $ M.insert mi nf' mmap
                   return nf'
               else do
@@ -141,7 +142,7 @@ compileBB mi rawmethod methodinfo = do
   printfJit $ printf "emit code of \"%s\" from \"%s\":\n" (toString $ methName methodinfo) (toString $ methClassName methodinfo)
   let ebb = emitFromBB cls mi rawmethod
   let cgconfig = defaultCodeGenConfig { codeBufferSize = fromIntegral $ rawCodeLength rawmethod * 32 }
-  (jnmap, Right right) <- runCodeGenWithConfig ebb () M.empty cgconfig
+  (jnmap, Right right) <- runCodeGenWithConfig ebb () BI.empty cgconfig
 
   let ((entry, _, new_tmap), _) = right
   setTrapMap $ tmap `M.union` new_tmap -- prefers elements in tmap
index eea9550e37e36ae72df49b2537c24e55fa28681c..d3bc626300fbad81f692e75de8f9e78b8e470fd4 100644 (file)
@@ -7,6 +7,7 @@ module Mate.Types
   , ExceptionMap
   , JpcNpcMap
   , RawMethod(..)
+  , TrapPatcher, TrapPatcherEax, TrapPatcherEaxEsp
   , TrapMap, MethodMap, ClassMap, FieldMap
   , StringMap, VirtualMap, InterfaceMap
   , InterfaceMethodMap
@@ -27,6 +28,7 @@ import Data.Int
 import Data.Functor
 import Data.Word
 import qualified Data.Map as M
+import qualified Data.Bimap as BI
 import qualified Data.ByteString.Lazy as B
 
 import Data.IORef
@@ -44,7 +46,7 @@ import Mate.NativeSizes
 type BlockID = Int
 -- Represents a CFG node
 data BasicBlock = BasicBlock {
-  code :: [Instruction],
+  code :: [(Int, Instruction)],
   bblength :: Int,
   successor :: BBEnd }
 
@@ -60,7 +62,7 @@ type MapBB = M.Map BlockID BasicBlock
 type ExceptionMap = M.Map (Word16, Word16) [(B.ByteString, Word16)]
 
 -- java byte code PC -> native PC
-type JpcNpcMap = M.Map Word32 Int
+type JpcNpcMap = BI.Bimap Int Word32
 
 data RawMethod = RawMethod {
   rawMapBB :: MapBB,
@@ -76,14 +78,14 @@ data RawMethod = RawMethod {
 type TrapMap = M.Map NativeWord TrapCause
 
 type TrapPatcher = CPtrdiff -> CodeGen () () CPtrdiff
-type TrapPatcherEax = CPtrdiff -> CPtrdiff -> CodeGen () () CPtrdiff
-type TrapPatcherEsp = TrapPatcherEax
+type TrapPatcherEax = CPtrdiff -> TrapPatcher
+type TrapPatcherEaxEsp =  CPtrdiff -> TrapPatcherEax
 
 data TrapCause
   = StaticMethod TrapPatcher -- for static calls
   | VirtualCall Bool MethodInfo (IO NativeWord) -- for invoke{interface,virtual}
   | InstanceOf TrapPatcherEax
-  | ThrowException TrapPatcherEsp
+  | ThrowException TrapPatcherEaxEsp
   | NewObject TrapPatcher
   | StaticField StaticFieldInfo
   | ObjectField TrapPatcher
index 79586ef02dd49ab33e512484d7d9c86558844201..a61fac314b6d142c4f8dff0289a290c1a252e18f 100644 (file)
@@ -7,8 +7,9 @@ import Data.Binary
 import Data.BinaryState
 import Data.Int
 import Data.Maybe
-import Data.List (genericLength)
+import Data.List (genericLength, find)
 import qualified Data.Map as M
+import qualified Data.Bimap as BI
 import qualified Data.ByteString.Lazy as B
 import Control.Monad
 import Control.Applicative
@@ -20,7 +21,7 @@ import qualified JVM.Assembler as J
 import JVM.Assembler hiding (Instruction)
 import JVM.ClassFile
 
-import Harpy
+import Harpy hiding (fst)
 import Harpy.X86Disassembler
 
 import Mate.BasicBlocks
@@ -31,6 +32,7 @@ import Mate.ClassPool
 import Mate.ClassHierarchy
 import {-# SOURCE #-} Mate.MethodPool
 import Mate.Strings
+import Mate.Debug
 
 
 foreign import ccall "&mallocObjectGC"
@@ -137,11 +139,11 @@ emitFromBB cls miThis method = do
       -- depending on the method-table-ptr
       return $ Just (calladdr, VirtualCall isInterface mi offset)
 
-    emit'' :: J.Instruction -> CodeGen e JpcNpcMap (Maybe (Word32, TrapCause))
-    emit'' insn = do
-      ep <- (fromIntegral . ptrToIntPtr) <$> getEntryPoint
+    emit'' :: (Int, J.Instruction) -> CodeGen e JpcNpcMap (Maybe (Word32, TrapCause))
+    emit'' (jpc, insn) = do
+      npc <- getCurrentOffset
       jpcrpc <- getState
-      setState (M.insert ep bid jpcrpc)
+      setState (BI.insert jpc npc jpcrpc)
       newNamedLabel ("jvm_insn: " ++ show insn) >>= defineLabel >> emit' insn
 
     emit' :: J.Instruction -> CodeGen e s (Maybe (Word32, TrapCause))
@@ -216,12 +218,40 @@ emitFromBB cls miThis method = do
       return $ Just (trapaddr, NewObject patcher)
 
     emit' ATHROW = do
+      pop eax
+      push eax
+      mov eax (Disp 0, eax)
       trapaddr <- emitSigIllTrap 2
-      let patcher resp reip = do
+      let patcher :: TrapPatcherEaxEsp
+          patcher reax resp reip = do
+            liftIO $ printfJit $ printf "reip: %d\n" (fromIntegral reip :: Word32)
+            liftIO $ printfJit $ printf "reax: %d\n" (fromIntegral reax :: Word32)
             (_, jnmap) <- liftIO $ getMethodEntry miThis
-            error "no athrow for you, sorry"
+            liftIO $ printfJit $ printf "size: %d\n" (BI.size jnmap)
+            liftIO $ printfJit $ printf "jnmap: %s\n" (show $ BI.toList jnmap)
+            -- TODO: (-4) is a hack (due to the insns above)
+            let jpc = fromIntegral (jnmap BI.!> (fromIntegral reip - 4))
+            let exceptionmap = rawExcpMap method
+            liftIO $ printfJit $ printf "exmap: %s\n" (show $ M.toList exceptionmap)
+            let key =
+                  case find f $ M.keys exceptionmap of
+                    Just x -> x
+                    Nothing -> error "exception: no handler found. (TODO1)"
+                  where
+                    f (x, y) = jpc >= x && jpc <= y
+            liftIO $ printfJit $ printf "exception: key is: %s\n" (show key)
+            let handlerJPCs = exceptionmap M.! key
+            let f (x, y) = do x' <- getMethodTable x; return (fromIntegral x', y)
+            handlers <- liftIO $ mapM f handlerJPCs
+            liftIO $ printfJit $ printf "exception: handlers: %s\n" (show handlers)
+            let handlerJPC =
+                  case find ((==) reax . fst) handlers of
+                    Just x -> x
+                    Nothing -> error "exception: no handler found (TODO2)"
+            let handlerNPC = jnmap BI.! (fromIntegral $ snd handlerJPC)
+            liftIO $ printfJit $ printf "exception: handler at: 0x%08x\n" handlerNPC
             emitSigIllTrap 2
-            return reip
+            return $ fromIntegral handlerNPC
       return $ Just (trapaddr, ThrowException patcher)
 
     emit' insn = emit insn >> return Nothing
index b4bf8ca2b5eaa536e36e58fd7b198128546acbd1..82ed7ca0d738ca3ad52b1a0f23562ac8ae0e9597 100644 (file)
@@ -41,7 +41,7 @@ mateHandler reip reax rebx resi resp = do
     (Just (InstanceOf patcher))  ->
         patchWithHarpy (patcher reax) reip >>= delFalse
     (Just (ThrowException patcher)) ->
-        patchWithHarpy (patcher resp) reip >>= delFalse
+        patchWithHarpy (patcher reax resp) reip >>= delFalse
     (Just (NewObject patcher))   ->
         patchWithHarpy patcher reip >>= delTrue
     (Just (VirtualCall False mi io_offset)) ->
@@ -52,8 +52,8 @@ mateHandler reip reax rebx resi resp = do
         >>= delFalse
     Nothing -> case resi of
         0x13371234 -> delFalse (-1)
-        _ -> error $ "getTrapType: abort :-( " ++ showHex reip ". "
-             ++ concatMap (`showHex` ", ") (M.keys tmap)
+        _ -> error $ "getTrapType: abort :-( eip: "
+             ++ showHex reip ". " ++ concatMap (`showHex` ", ") (M.keys tmap)
   when deleteMe $ setTrapMap $ M.delete reipw32 tmap
   return ret_nreip
     where
diff --git a/java/lang/IllegalArgumentException.java b/java/lang/IllegalArgumentException.java
new file mode 100644 (file)
index 0000000..46f906e
--- /dev/null
@@ -0,0 +1,3 @@
+package java.lang;
+
+public class IllegalArgumentException extends RuntimeException { }
diff --git a/tests/Exception2.java b/tests/Exception2.java
new file mode 100644 (file)
index 0000000..ae4bc86
--- /dev/null
@@ -0,0 +1,11 @@
+package tests;
+
+public class Exception2 {
+       public static void main(String []args) {
+               try {
+                       throw new NullPointerException();
+               } catch (NullPointerException _) {
+                       System.out.printf("NullPointerException\n");
+               }
+       }
+}
diff --git a/tests/Exception3.java b/tests/Exception3.java
new file mode 100644 (file)
index 0000000..c9b9fed
--- /dev/null
@@ -0,0 +1,35 @@
+package tests;
+
+public class Exception3 {
+       public static void main(String []args) {
+               try {
+                       throw new NullPointerException();
+               } catch (NullPointerException _) {
+                       System.out.printf("NullPointerException\n");
+               } catch (IllegalArgumentException _) {
+                       System.out.printf("IllegalArgumentException\n");
+               }
+               try {
+                       throw new NullPointerException();
+               } catch (IllegalArgumentException _) {
+                       System.out.printf("IllegalArgumentException\n");
+               } catch (NullPointerException _) {
+                       System.out.printf("NullPointerException\n");
+               }
+               try {
+                       throw new IllegalArgumentException();
+               } catch (NullPointerException _) {
+                       System.out.printf("NullPointerException\n");
+               } catch (IllegalArgumentException _) {
+                       System.out.printf("IllegalArgumentException\n");
+               }
+               try {
+                       throw new IllegalArgumentException();
+               } catch (IllegalArgumentException _) {
+                       System.out.printf("IllegalArgumentException\n");
+               } catch (NullPointerException _) {
+                       System.out.printf("NullPointerException\n");
+               }
+               System.out.printf("hmmm\n");
+       }
+}
diff --git a/tests/Exception4.java b/tests/Exception4.java
new file mode 100644 (file)
index 0000000..03495fd
--- /dev/null
@@ -0,0 +1,20 @@
+package tests;
+
+public class Exception4 {
+       public static void main(String []args) {
+               try {
+                       throw new NullPointerException();
+               } catch (NullPointerException _) {
+                       System.out.printf("NullPointerException\n");
+               } finally {
+                       System.out.printf("it's finally over\n");
+               }
+
+               try {
+                       System.out.printf("I'm fine\n");
+               } finally {
+                       System.out.printf("o rly\n");
+               }
+               System.out.printf("hmmm\n");
+       }
+}
index ea663decab0bb4a08e636f9c40a76ae15c6e1200..906974ed24f9a9b033713cf9fda2c7c18f9632dc 100755 (executable)
@@ -32,6 +32,7 @@ cabal install missingh $CABAL_OPT
 cabal install heap $CABAL_OPT
 cabal install plugins $CABAL_OPT
 cabal install split $CABAL_OPT
+cabal install bimap $CABAL_OPT
 
 # cabal install hs-java $CABAL_OPT
 gitinstall git://wien.tomnetworks.com/hs-java.git