methodPool: compile methods on-demand
authorBernhard Urban <lewurm@gmail.com>
Sat, 14 Apr 2012 17:54:20 +0000 (19:54 +0200)
committerBernhard Urban <lewurm@gmail.com>
Sat, 14 Apr 2012 17:54:20 +0000 (19:54 +0200)
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.

Makefile
Mate.hs
Mate/BasicBlocks.hs
Mate/MethodPool.hs
Mate/X86CodeGen.hs
ffi/trap.c
tests/Fib.java

index c1712678a767f1f2d41ca01f3a7848e5b08af1e7..e2bead50cc48ab869859fbcb811c197792ac1978 100644 (file)
--- 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 e1473daee9c2851e36bfddee3022ab47723f9b19..d68c8daa849bd7fbdbb060402de16a30310c9333 100644 (file)
--- 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 <class-file>"
index 4ab119ad569d4d50d74b49cc1a92dc3863158716..332bd56a6c7aefbf1784a87b65c9241933ecd1f1 100644 (file)
@@ -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
index 74e4ec63e899ffbf95440bb90774cb86687d9b55..213e44c7cef3289a7f1419a3483ba3c2f1e55331 100644 (file)
@@ -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)
index b33d524f674d5c98e16c791041bc8166226a8db0..608f9bc375feea396a47973783efdeaa3c0f4c27 100644 (file)
@@ -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
index 5a124af2ea77ecc5399a6be9b02daa27a28979fa..897fa7f522194f777cc8d436ba6247c34a8d810b 100644 (file)
@@ -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;
 }
index 0ae8017c7c1e3eb729477172342c60e48fb38290..9dccbcf22176d817d4d709dbc5c6aedaf36512e2 100644 (file)
@@ -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);
        }
 }