From 040b92a7a38d2518f5603a6c01db59eb983ad20e Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Tue, 28 Aug 2012 19:39:50 +0200 Subject: [PATCH] instanceOf: class hierarchy are considered properly now TODO: interfaces --- Mate/ClassHierarchy.hs | 46 ++++++++++++++++++++++++++++++++++--- Mate/ClassHierarchy.hs-boot | 10 ++++++++ Mate/ClassPool.hs | 8 +++++++ Mate/X86CodeGen.hs | 14 +++-------- tests/InstanceOf2.java | 44 +++++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 Mate/ClassHierarchy.hs-boot create mode 100644 tests/InstanceOf2.java diff --git a/Mate/ClassHierarchy.hs b/Mate/ClassHierarchy.hs index c501ed9..628d426 100644 --- a/Mate/ClassHierarchy.hs +++ b/Mate/ClassHierarchy.hs @@ -1,11 +1,17 @@ module Mate.ClassHierarchy ( isInstanceOf + , addClassEntry ) where +import qualified Data.Map as M import qualified Data.ByteString.Lazy as B import Control.Applicative +import Control.Monad import Text.Printf +import Foreign +import Data.IORef + import Mate.NativeSizes import Mate.ClassPool @@ -13,7 +19,7 @@ import Mate.ClassPool data Class = Class { clMtable :: NativeWord - , clSuperClass :: Class + , clSuperClass :: NativeWord , clInterfaces :: [Interface] } | JavaLangObject @@ -25,6 +31,40 @@ data Interface { ifSuperInterfaces :: [Interface] } +type HierMap = (M.Map NativeWord Class) +classHier :: IORef HierMap +{-# NOINLINE classHier #-} +classHier = unsafePerformIO $ newIORef M.empty + +readHier :: IO HierMap +readHier = readIORef classHier + +writeHier :: HierMap -> IO () +writeHier = writeIORef classHier + + isInstanceOf :: NativeWord -> B.ByteString -> IO Bool -isInstanceOf obj_mtable classname = do - (== obj_mtable) <$> getMethodTable classname +isInstanceOf 0 _ = return False +isInstanceOf obj classname = do + obj_mtable <- peek (intPtrToPtr . fromIntegral $ obj) + class_mtable <- getMethodTable classname + ch <- readHier + return $ checkInstance obj_mtable class_mtable ch + +checkInstance :: NativeWord -> NativeWord -> HierMap -> Bool +checkInstance obj cl_mtable ch + | obj == cl_mtable = True + | otherwise = + case ch M.! obj of + Class _ super _ -> checkInstance super cl_mtable ch + JavaLangObject _ -> False + +addClassEntry :: NativeWord -> NativeWord -> IO () +addClassEntry mtable 0 = do + ch <- readHier + writeHier (M.insert mtable (JavaLangObject mtable) ch) +addClassEntry mtable super_mtable = do + ch <- readHier + when (not $ M.member super_mtable ch) $ error "classhierarchy: superclass should be in hierarchy!" + let cl = Class mtable super_mtable [] + writeHier (M.insert mtable cl ch) diff --git a/Mate/ClassHierarchy.hs-boot b/Mate/ClassHierarchy.hs-boot new file mode 100644 index 0000000..f274b83 --- /dev/null +++ b/Mate/ClassHierarchy.hs-boot @@ -0,0 +1,10 @@ +module Mate.ClassHierarchy + ( isInstanceOf + , addClassEntry + ) where + +import qualified Data.ByteString.Lazy as B +import Mate.NativeSizes + +isInstanceOf :: NativeWord -> B.ByteString -> IO Bool +addClassEntry :: NativeWord -> NativeWord -> IO () diff --git a/Mate/ClassPool.hs b/Mate/ClassPool.hs index c99478a..0e188a6 100644 --- a/Mate/ClassPool.hs +++ b/Mate/ClassPool.hs @@ -43,6 +43,7 @@ import Mate.Types import Mate.Debug import Mate.GarbageAlloc import Mate.NativeSizes +import {-# SOURCE #-} Mate.ClassHierarchy getClassInfo :: B.ByteString -> IO ClassInfo getClassInfo path = do @@ -165,6 +166,13 @@ readClass path = do class_map <- getClassMap let new_ci = ClassInfo path cfile staticmap fieldmap methodmap mbase False setClassMap $ M.insert path new_ci class_map + + -- add Class to Hierarchy + super_mtable <- case superclass of + Nothing -> return 0 + Just x -> getMethodTable $ ciName x + addClassEntry mbase super_mtable + return new_ci diff --git a/Mate/X86CodeGen.hs b/Mate/X86CodeGen.hs index fe1fe5d..c42ccad 100644 --- a/Mate/X86CodeGen.hs +++ b/Mate/X86CodeGen.hs @@ -199,26 +199,18 @@ emitFromBB cls method = do emit' (INSTANCEOF cpidx) = do pop eax - mov eax (Disp 0, eax) -- mtable of objectref trapaddr <- getCurrentOffset -- place something like `mov edx $mtable_of_objref' instead - emit32 (0x9090ffff :: Word32); nop + emit32 (0x9090ffff :: Word32) push (0 :: Word32) let patcher reax reip = do - -- mtable <- liftIO $ getMethodTable (buildClassID cls cpidx) - -- mov edx mtable - emit32 (0x9090ffff :: Word32); nop + emit32 (0x9090ffff :: Word32) let classname = buildClassID cls cpidx check <- liftIO $ isInstanceOf (fromIntegral reax) classname if check then push (1 :: Word32) else push (0 :: Word32) - return (reip + 5) - -- cmp eax edx - -- sete al - -- movzxb eax al - -- push eax - -- forceRegDump + return (reip + 4) return $ Just (trapaddr, InstanceOf patcher) emit' (NEW objidx) = do let objname = buildClassID cls objidx diff --git a/tests/InstanceOf2.java b/tests/InstanceOf2.java new file mode 100644 index 0000000..1ca8bb1 --- /dev/null +++ b/tests/InstanceOf2.java @@ -0,0 +1,44 @@ +package tests; + +public class InstanceOf2 { + public static void main(String []args) { + System.out.printf("x = new InstanceOf2_local;\n"); + Instance1 x = new InstanceOf2_local(); + checkInstance(null instanceof Instance1, "null", "Instance1"); + checkInstance(x instanceof Instance1, "x", "Instance1"); + checkInstance(x instanceof Instance2, "x", "Instance2"); + checkInstance(x instanceof InstanceOf2_local, "x", "InstanceOf2_local"); + checkInstance(x instanceof Object, "x", "Object"); + checkInstance(x instanceof InstanceOf2_local2, "x", "InstanceOf2_local2"); + + System.out.printf("\n\n"); + System.out.printf("y = new InstanceOf2_local2;\n"); + Object y = new InstanceOf2_local2(); + checkInstance(null instanceof Instance1, "null", "Instance1"); + checkInstance(y instanceof Instance1, "y", "Instance1"); + checkInstance(y instanceof Instance2, "y", "Instance2"); + checkInstance(y instanceof InstanceOf2_local, "y", "InstanceOf2_local"); + checkInstance(y instanceof Object, "y", "Object"); + checkInstance(y instanceof InstanceOf2_local2, "y", "InstanceOf2_local2"); + } + + public static void checkInstance(boolean cond, String obj, String classname) { + System.out.printf(obj); + if (cond) { + System.out.printf(" is instance of "); + System.out.printf(classname); + System.out.printf(" :-)\n"); + } else { + System.out.printf(" is *not* instance of "); + System.out.printf(classname); + System.out.printf(" :-(\n"); + } + } +} + + +class InstanceOf2_local extends Instance1 { +} + +class InstanceOf2_local2 extends InstanceOf2_local { +} -- 2.25.1