instanceOf: class hierarchy are considered properly now
authorBernhard Urban <lewurm@gmail.com>
Tue, 28 Aug 2012 17:39:50 +0000 (19:39 +0200)
committerBernhard Urban <lewurm@gmail.com>
Tue, 28 Aug 2012 22:59:24 +0000 (00:59 +0200)
TODO: interfaces

Mate/ClassHierarchy.hs
Mate/ClassHierarchy.hs-boot [new file with mode: 0644]
Mate/ClassPool.hs
Mate/X86CodeGen.hs
tests/InstanceOf2.java [new file with mode: 0644]

index c501ed941fe32ad2df8e617ef04fc435561e7f32..628d426f41fe62fe7e9f4793daf6580bf1664f66 100644 (file)
@@ -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 (file)
index 0000000..f274b83
--- /dev/null
@@ -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 ()
index c99478a17e0930a7c3bab71c6f70cf986d1739b6..0e188a6f5a80f22f6ad0ca972d4c0067859437e2 100644 (file)
@@ -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
 
 
index fe1fe5d0c76fed2ad38e22b09c673b7d81f316fe..c42ccadaf2c185e6457d5d97326aaa4aa7aa9844 100644 (file)
@@ -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 (file)
index 0000000..1ca8bb1
--- /dev/null
@@ -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 {
+}