From c541c18161f42753454ab94bbc5e1a43ef89ae40 Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Sun, 9 Sep 2012 18:03:45 +0200 Subject: [PATCH] codegen: handle exceptions of a method also, use bimap for mapping jpc and npc values TODO: if no handler is found, throw it to caller method --- Mate/BasicBlocks.hs | 10 ++++-- Mate/MethodPool.hs | 11 +++--- Mate/Types.hs | 12 ++++--- Mate/X86CodeGen.hs | 48 ++++++++++++++++++++----- Mate/X86TrapHandling.hs | 6 ++-- java/lang/IllegalArgumentException.java | 3 ++ tests/Exception2.java | 11 ++++++ tests/Exception3.java | 35 ++++++++++++++++++ tests/Exception4.java | 20 +++++++++++ tools/installhaskellenv.sh | 1 + 10 files changed, 132 insertions(+), 25 deletions(-) create mode 100644 java/lang/IllegalArgumentException.java create mode 100644 tests/Exception2.java create mode 100644 tests/Exception3.java create mode 100644 tests/Exception4.java diff --git a/Mate/BasicBlocks.hs b/Mate/BasicBlocks.hs index af00749..2f96a40 100644 --- a/Mate/BasicBlocks.hs +++ b/Mate/BasicBlocks.hs @@ -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 diff --git a/Mate/MethodPool.hs b/Mate/MethodPool.hs index 5918a2f..d1df9cf 100644 --- a/Mate/MethodPool.hs +++ b/Mate/MethodPool.hs @@ -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 diff --git a/Mate/Types.hs b/Mate/Types.hs index eea9550..d3bc626 100644 --- a/Mate/Types.hs +++ b/Mate/Types.hs @@ -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 diff --git a/Mate/X86CodeGen.hs b/Mate/X86CodeGen.hs index 79586ef..a61fac3 100644 --- a/Mate/X86CodeGen.hs +++ b/Mate/X86CodeGen.hs @@ -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 diff --git a/Mate/X86TrapHandling.hs b/Mate/X86TrapHandling.hs index b4bf8ca..82ed7ca 100644 --- a/Mate/X86TrapHandling.hs +++ b/Mate/X86TrapHandling.hs @@ -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 index 0000000..46f906e --- /dev/null +++ b/java/lang/IllegalArgumentException.java @@ -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 index 0000000..ae4bc86 --- /dev/null +++ b/tests/Exception2.java @@ -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 index 0000000..c9b9fed --- /dev/null +++ b/tests/Exception3.java @@ -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 index 0000000..03495fd --- /dev/null +++ b/tests/Exception4.java @@ -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"); + } +} diff --git a/tools/installhaskellenv.sh b/tools/installhaskellenv.sh index ea663de..906974e 100755 --- a/tools/installhaskellenv.sh +++ b/tools/installhaskellenv.sh @@ -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 -- 2.25.1