From: Bernhard Urban Date: Sun, 26 Aug 2012 22:22:26 +0000 (+0200) Subject: lazy classloading: yet another bug X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mate.git;a=commitdiff_plain;h=e233bbb3bd29c6665239c7a9139826ce21913d29 lazy classloading: yet another bug by computing the field access offset, the class has to loaded. but this should happen at runtime, on the first field access, not at compile time. see tests/Instance7.java --- diff --git a/Mate/MethodPool.hs b/Mate/MethodPool.hs index 223f509..4a7cf7e 100644 --- a/Mate/MethodPool.hs +++ b/Mate/MethodPool.hs @@ -52,10 +52,6 @@ getMethodEntry signal_from methodtable = do (VirtualCall _ (MethodInfo methname _ msig) _) -> newMi methname msig _ -> error "getMethodEntry: no TrapCause found. abort." where newMi mn = MethodInfo mn (vmap M.! fromIntegral methodtable) - -- bernhard (TODO): doesn't work with gnu classpath at some point. didn't - -- figured out the problem yet :/ therefore, I have no - -- testcase for replaying the situation. - -- setTrapMap $ M.delete w32_from tmap entryaddr <- case M.lookup mi' mmap of Nothing -> do cls <- getClassFile cm diff --git a/Mate/Types.hs b/Mate/Types.hs index 3bcf657..060ffb7 100644 --- a/Mate/Types.hs +++ b/Mate/Types.hs @@ -29,6 +29,9 @@ import qualified Data.ByteString.Lazy as B import Data.IORef import System.IO.Unsafe +import Harpy +import Foreign.C.Types + import JVM.ClassFile import JVM.Assembler @@ -63,12 +66,15 @@ data RawMethod = RawMethod { -- MethodInfo = relevant information about callee type TrapMap = M.Map NativeWord TrapCause +type TrapPatcher = CPtrdiff -> CodeGen () () CPtrdiff + data TrapCause = StaticMethod MethodInfo -- for static calls | VirtualCall Bool MethodInfo (IO NativeWord) -- for invoke{interface,virtual} | InstanceOf B.ByteString -- class name | NewObject B.ByteString -- class name | StaticField StaticFieldInfo + | ObjectField TrapPatcher data StaticFieldInfo = StaticFieldInfo { sfiClassName :: B.ByteString, diff --git a/Mate/X86CodeGen.hs b/Mate/X86CodeGen.hs index 1a04579..9b39388 100644 --- a/Mate/X86CodeGen.hs +++ b/Mate/X86CodeGen.hs @@ -154,6 +154,7 @@ emitFromBB cls method = do emit' (INVOKESTATIC cpidx) = emitInvoke cpidx False emit' (INVOKEINTERFACE cpidx _) = virtualCall cpidx True emit' (INVOKEVIRTUAL cpidx) = virtualCall cpidx False + emit' (PUTSTATIC cpidx) = do pop eax trapaddr <- getCurrentOffset @@ -164,6 +165,31 @@ emitFromBB cls method = do mov eax (Addr 0x00000000) -- it's a trap push eax return $ Just (trapaddr, StaticField $ buildStaticFieldID cls cpidx) + + emit' (GETFIELD x) = do + pop eax -- this pointer + trapaddr <- getCurrentOffset + -- like: 099db064 ff b0 e4 14 00 00 pushl 5348(%eax) + emit32 (0x9090ffff :: Word32); nop; nop + let patcher reip = do + let (cname, fname) = buildFieldOffset cls x + offset <- liftIO $ getFieldOffset cname fname + push32_rel_eax (Disp (fromIntegral offset)) -- get field + return reip + return $ Just (trapaddr, ObjectField patcher) + emit' (PUTFIELD x) = do + pop ebx -- value to write + pop eax -- this pointer + trapaddr <- getCurrentOffset + -- like: 4581fc6b 89 98 30 7b 00 00 movl %ebx,31536(%eax) + emit32 (0x9090ffff :: Word32); nop; nop + let patcher reip = do + let (cname, fname) = buildFieldOffset cls x + offset <- liftIO $ getFieldOffset cname fname + mov32_rel_ebx_eax (Disp (fromIntegral offset)) -- set field + return reip + return $ Just (trapaddr, ObjectField patcher) + emit' (INSTANCEOF cpidx) = do pop eax mov eax (Disp 0, eax) -- mtable of objectref @@ -277,13 +303,6 @@ emitFromBB cls method = do (CInteger i) -> liftIO $ return i e -> error $ "LDCI... missing impl.: " ++ show e push value - emit (GETFIELD x) = do - offset <- emitFieldOffset x - push (Disp (fromIntegral offset), eax) -- get field - emit (PUTFIELD x) = do - pop ebx -- value to write - offset <- emitFieldOffset x - mov (Disp (fromIntegral offset), eax) ebx -- set field emit IADD = do pop ebx; pop eax; add eax ebx; push eax emit ISUB = do pop ebx; pop eax; sub eax ebx; push eax @@ -319,13 +338,6 @@ emitFromBB cls method = do emit IRETURN = do pop eax; emit RETURN emit invalid = error $ "insn not implemented yet: " ++ show invalid - -- TODO(bernhard): delay to runtime (find counter example!) - emitFieldOffset :: Word16 -> CodeGen e s Int32 - emitFieldOffset x = do - pop eax -- this pointer - let (cname, fname) = buildFieldOffset cls x - liftIO $ getFieldOffset cname fname - emitIF :: CMP -> CodeGen e s () emitIF cond = let sid = case successor bb of TwoTarget _ t -> t; _ -> error "bad" @@ -367,11 +379,22 @@ callMalloc = do add esp (ptrSize :: Word32) push eax --- the regular push implementation, considers the provided immediate and selects --- a different instruction if it fits in 8bit. but this is not useful for --- patching. + +-- harpy tries to cut immediates (or displacements), if they fit in 8bit. +-- however, this is bad for patching so we want to put always 32bit. + +-- push imm32 push32 :: Word32 -> CodeGen e s () push32 imm32 = emit8 0x68 >> emit32 imm32 +-- call disp32(%eax) call32_eax :: Disp -> CodeGen e s () call32_eax (Disp disp32) = emit8 0xff >> emit8 0x90 >> emit32 disp32 + +-- push disp32(%eax) +push32_rel_eax :: Disp -> CodeGen e s () +push32_rel_eax (Disp disp32) = emit8 0xff >> emit8 0xb0 >> emit32 disp32 + +-- mov %ebx, disp32(%eax) +mov32_rel_ebx_eax :: Disp -> CodeGen e s () +mov32_rel_ebx_eax (Disp disp32) = emit8 0x89 >> emit8 0x98 >> emit32 disp32 diff --git a/Mate/X86TrapHandling.hs b/Mate/X86TrapHandling.hs index 23be786..bf4b288 100644 --- a/Mate/X86TrapHandling.hs +++ b/Mate/X86TrapHandling.hs @@ -36,6 +36,8 @@ mateHandler reip reax rebx resi = do patchWithHarpy patchStaticCall reip >>= delTrue (Just (StaticField _)) -> staticFieldHandler reip >>= delTrue + (Just (ObjectField patcher)) -> + patchWithHarpy patcher reip >>= delTrue (Just (InstanceOf cn)) -> patchWithHarpy (`patchInstanceOf` cn) reip >>= delFalse (Just (NewObject cn)) -> @@ -55,7 +57,7 @@ mateHandler reip reax rebx resi = do else return () return ret_nreip where - delTrue = (\nreip -> return (False, nreip)) + delTrue = (\nreip -> return (False, nreip)) -- TODO: FIXME delFalse = (\nreip -> return (False, nreip)) diff --git a/tests/Instance7.java b/tests/Instance7.java new file mode 100644 index 0000000..8c7e3f9 --- /dev/null +++ b/tests/Instance7.java @@ -0,0 +1,21 @@ +package tests; + +public class Instance7 { + public static void main(String []args) { + int i_am_null = 0; + System.out.printf("before\n"); + if (i_am_null > 0) { + Instance7_notload a = new Instance7_notload(); + System.out.printf("loaded notload stuff o_O: %d\n", a.foo); + } else { + System.out.printf("Nothing to do here\n"); + } + } +} + +class Instance7_notload { + static { + System.out.printf("sup, I'm Instance7_notload\n"); + } + public int foo = 6; +}