From: Bernhard Urban Date: Sat, 14 Apr 2012 17:54:20 +0000 (+0200) Subject: methodPool: compile methods on-demand X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mate.git;a=commitdiff_plain;h=73099439d888ced6806791d0e24b2ffae4086f51 methodPool: compile methods on-demand just works with `fib' atm. we need a second "tracker-map" when emitting an `invoke*' instruction. there we have to lookup and save related method information. --- diff --git a/Makefile b/Makefile index c171267..e2bead5 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ GHC_LD := -optl-Xlinker -optl-x all: mate $(CLASS_FILES) test: mate $(CLASS_FILES) - ./$< + ./$< tests/Fib.class %.class: %.java $(JAVAC) $< diff --git a/Mate.hs b/Mate.hs index e1473da..d68c8da 100644 --- a/Mate.hs +++ b/Mate.hs @@ -1,14 +1,32 @@ {-# LANGUAGE OverloadedStrings #-} module Main where +import System.Environment + import Text.Printf +import JVM.Converter +import JVM.Dump + +import Mate.BasicBlocks import Mate.X86CodeGen import Mate.MethodPool main :: IO () main = do - printf "fib Codegen:\n" - test_01 - printf "\n\n\n\nData.Map & FFI:\n" - t_01 + args <- getArgs + register_signal + initMethodPool + case args of + [clspath] -> do + cls <- parseClassFile clspath + dumpClass cls + hmap <- parseMethod cls "main" + printMapBB hmap + case hmap of + Just hmap' -> do + entry <- compileBB hmap' "main" + printf "executing `main' now:\n" + executeFuncPtr entry + Nothing -> error "main not found" + _ -> error "Usage: mate " diff --git a/Mate/BasicBlocks.hs b/Mate/BasicBlocks.hs index 4ab119a..332bd56 100644 --- a/Mate/BasicBlocks.hs +++ b/Mate/BasicBlocks.hs @@ -63,7 +63,8 @@ printMapBB (Just hmap) = do testInstance :: String -> B.ByteString -> IO () testInstance cf method = do - hmap <- parseMethod cf method + cls <- parseClassFile cf + hmap <- parseMethod cls method printMapBB hmap test_main :: IO () @@ -78,9 +79,23 @@ test_02 = testInstance "./tests/While.class" "f" test_03 = testInstance "./tests/While.class" "g" -parseMethod :: String -> B.ByteString -> IO (Maybe MapBB) -parseMethod clspath method = do - cls <- parseClassFile clspath +parseMethod :: Class Resolved -> B.ByteString -> IO (Maybe MapBB) +parseMethod cls method = do + -- TODO(bernhard): remove me! just playing around with + -- hs-java interface. + -- we get that index at the INVOKESTATIC insn + putStrLn "via constpool @2:" + let cp = constsPool cls + let (CMethod rc nt) = cp M.! (2 :: Word16) + -- rc :: Link stage B.ByteString + -- nt :: Link stage (NameType Method) + B.putStrLn $ "rc: " `B.append` rc + B.putStrLn $ "nt: " `B.append` (encode $ ntSignature nt) + + putStrLn "via methods:" + let msig = methodSignature $ (classMethods cls) !! 1 + B.putStrLn (method `B.append` ": " `B.append` (encode msig)) + return $ testCFG $ lookupMethod method cls @@ -153,6 +168,7 @@ calculateInstructionOffset = cio' (0, Nothing) IF_ICMP _ w16 -> twotargets w16 GOTO w16 -> onetarget w16 IRETURN -> notarget + RETURN -> notarget _ -> ((off, Nothing), x):next where notarget = ((off, Just Return), x):next diff --git a/Mate/MethodPool.hs b/Mate/MethodPool.hs index 74e4ec6..213e44c 100644 --- a/Mate/MethodPool.hs +++ b/Mate/MethodPool.hs @@ -3,8 +3,9 @@ module Mate.MethodPool where import Data.Binary +import Data.String import qualified Data.Map as M - +import qualified Data.ByteString.Lazy as B import Text.Printf @@ -13,6 +14,12 @@ import Foreign.C.Types import Foreign.C.String import Foreign.StablePtr +import JVM.Converter + +import Harpy +import Harpy.X86Disassembler + +import Mate.BasicBlocks import Mate.X86CodeGen @@ -22,27 +29,72 @@ foreign import ccall "get_mmap" foreign import ccall "set_mmap" set_mmap :: Ptr () -> IO () -foreign import ccall "demo_mmap" - demo_mmap :: IO () +-- B.ByteString = name of method +-- Word32 = entrypoint of method +type MMap = M.Map B.ByteString Word32 -type MMap = M.Map String Word32 +-- TODO(bernhard): not in use yet +-- Word32 = point of method call +-- B.ByteString = name of called method +type CMap = M.Map Word32 B.ByteString foreign export ccall getMethodEntry :: Ptr () -> CString -> IO CUInt getMethodEntry :: Ptr () -> CString -> IO CUInt getMethodEntry ptr_mmap cstr = do - mmap <- deRefStablePtr $ ((castPtrToStablePtr ptr_mmap) :: StablePtr MMap) - k <- peekCString cstr - case M.lookup k mmap of - Nothing -> return 0 + mmap <- ptr2mmap ptr_mmap + str' <- peekCString cstr + let method = fromString str' + case M.lookup method mmap of + Nothing -> do + printf "getMethodEntry: no method found. compile it\n" + -- TODO(bernhard): hardcoded... fixme! + cls <- parseClassFile "tests/Fib.class" + hmap <- parseMethod cls method + case hmap of + Just hmap' -> do + entry <- compileBB hmap' method + let w32_entry = ((fromIntegral $ ptrToIntPtr entry) :: Word32) + let mmap' = M.insert method w32_entry mmap + mmap2ptr mmap' >>= set_mmap + return $ fromIntegral w32_entry + Nothing -> error $ (show method) ++ " not found. abort" Just w32 -> return (fromIntegral w32) -t_01 :: IO () -t_01 = do - (entry, _) <- testCase "./tests/Fib.class" "fib" - let int_entry = ((fromIntegral $ ptrToIntPtr entry) :: Word32) - let mmap = M.insert ("fib" :: String) int_entry M.empty - mapM_ (\(x,y) -> printf "%s at 0x%08x\n" x y) $ M.toList mmap +-- t_01 :: IO () +-- t_01 = do +-- (entry, _) <- testCase "./tests/Fib.class" "fib" +-- let int_entry = ((fromIntegral $ ptrToIntPtr entry) :: Word32) +-- let mmap = M.insert ("fib" :: String) int_entry M.empty +-- mapM_ (\(x,y) -> printf "%s at 0x%08x\n" x y) $ M.toList mmap +-- mmap2ptr mmap >>= set_mmap +-- demo_mmap -- access Data.Map from C + +initMethodPool :: IO () +initMethodPool = mmap2ptr M.empty >>= set_mmap + +compileBB :: MapBB -> B.ByteString -> IO (Ptr Word8) +compileBB hmap name = do + mmap <- get_mmap >>= ptr2mmap + let ebb = emitFromBB hmap + (_, Right ((entry, bbstarts, end), disasm)) <- runCodeGen ebb () () + let w32_entry = ((fromIntegral $ ptrToIntPtr entry) :: Word32) + let mmap' = M.insert name w32_entry mmap + mmap2ptr mmap' >>= set_mmap + printf "disasm:\n" + mapM_ (putStrLn . showAtt) disasm + return entry + +foreign import ccall "dynamic" + code_void :: FunPtr (IO ()) -> (IO ()) + +executeFuncPtr :: Ptr Word8 -> IO () +executeFuncPtr entry = code_void $ ((castPtrToFunPtr entry) :: FunPtr (IO ())) + +mmap2ptr :: MMap -> IO (Ptr ()) +mmap2ptr mmap = do ptr_mmap <- newStablePtr mmap - set_mmap $ castStablePtrToPtr ptr_mmap - demo_mmap -- access Data.Map from C + return $ castStablePtrToPtr ptr_mmap + +ptr2mmap :: Ptr () -> IO MMap +ptr2mmap vmap = deRefStablePtr $ ((castPtrToStablePtr vmap) :: StablePtr MMap) diff --git a/Mate/X86CodeGen.hs b/Mate/X86CodeGen.hs index b33d524..608f9bc 100644 --- a/Mate/X86CodeGen.hs +++ b/Mate/X86CodeGen.hs @@ -14,6 +14,7 @@ import Text.Printf import qualified JVM.Assembler as J import JVM.Assembler hiding (Instruction) +import JVM.Converter import Harpy import Harpy.X86Disassembler @@ -84,7 +85,8 @@ test_03 = do testCase :: String -> B.ByteString -> IO (Ptr Word8, Int) testCase cf method = do - hmap <- parseMethod cf method + cls <- parseClassFile cf + hmap <- parseMethod cls method printMapBB hmap case hmap of Nothing -> error "sorry, no code generation" @@ -115,15 +117,6 @@ emitFromBB hmap = do push ebp mov ebp esp - -- TODO(bernhard): remove me. just for PoC here - let w32_ep = (fromIntegral $ ptrToIntPtr ep) :: Word32 - push w32_ep - -- '5' is the size of the `call' instruction ( + immediate) - calladdr <- getCodeOffset - let w32_calladdr = 5 + w32_ep + (fromIntegral calladdr) :: Word32 - let trapaddr = (fromIntegral getaddr :: Word32) - call (trapaddr - w32_calladdr) - bbstarts <- efBB (0,(hmap M.! 0)) M.empty lmap d <- disassemble end <- getCodeOffset @@ -154,8 +147,18 @@ emitFromBB hmap = do -- instructions, so we can use patterns for optimizations where emit :: J.Instruction -> CodeGen e s () + emit POP = do -- print dropped value + ep <- getEntryPoint + let w32_ep = (fromIntegral $ ptrToIntPtr ep) :: Word32 + -- '5' is the size of the `call' instruction ( + immediate) + calladdr <- getCodeOffset + let w32_calladdr = 5 + w32_ep + (fromIntegral calladdr) :: Word32 + let trapaddr = (fromIntegral getaddr :: Word32) + call (trapaddr - w32_calladdr) + emit (BIPUSH val) = push ((fromIntegral val) :: Word32) emit (ICONST_1) = push (1 :: Word32) emit (ICONST_2) = push (2 :: Word32) + emit (ICONST_5) = push (5 :: Word32) emit (ILOAD_ x) = do push (Disp (cArgs_ x), ebp) emit (ISTORE_ x) = do @@ -199,6 +202,7 @@ emitFromBB hmap = do -- push result on stack (TODO(bernhard): if any) push eax + emit RETURN = do mov esp ebp; pop ebp; ret emit IRETURN = do pop eax mov esp ebp diff --git a/ffi/trap.c b/ffi/trap.c index 5a124af..897fa7f 100644 --- a/ffi/trap.c +++ b/ffi/trap.c @@ -18,22 +18,16 @@ void *get_mmap() return method_map; } -void demo_mmap() -{ - printf("mmap: 0x%08x\n", getMethodEntry(method_map, "fib")); -} - -unsigned int patchme = 0; -void print_foo(unsigned int addr) +void mainresult(unsigned int a) { - // printf("\n\nprint foo: 0x%08x\n", addr); - patchme = addr; + printf("mainresult: 0x%08x\n", a); } void callertrap(int nSignal, siginfo_t *info, void *ctx) { struct ucontext *uctx = (struct ucontext *) ctx; + unsigned int patchme = getMethodEntry(method_map, "fib"); printf("callertrap(mctx) by 0x%08x\n", (unsigned int) uctx->uc_mcontext.eip); // printf("callertrap(addr) by 0x%08x\n", info->si_addr); @@ -67,5 +61,5 @@ void register_signal(void) unsigned int getaddr(void) { - return (unsigned int) print_foo; + return (unsigned int) mainresult; } diff --git a/tests/Fib.java b/tests/Fib.java index 0ae8017..9dccbcf 100644 --- a/tests/Fib.java +++ b/tests/Fib.java @@ -1,14 +1,10 @@ -public class Fib -{ - public static int fib(int n) - { +public class Fib { + public static int fib(int n) { if(n<=1) return 1; else return fib(n-1) + fib(n-2); } - public static void main(String[] args) - { - for (int i = 0; i < 10; i++) - System.out.println(i + ": " + fib(i)); + public static void main(String[] args) { + fib(40); } }