java runtime: add simple version of instanceof
authorBernhard Urban <lewurm@gmail.com>
Fri, 17 Aug 2012 17:21:45 +0000 (19:21 +0200)
committerBernhard Urban <lewurm@gmail.com>
Fri, 17 Aug 2012 13:47:04 +0000 (15:47 +0200)
just works if we check for the same type, like:
>  A a = new A();
>   if (a instanceof A) {
>   [...]

Mate/Types.hs
Mate/X86CodeGen.hs
Mate/X86TrapHandling.hs
tests/InstanceOf1.java [new file with mode: 0644]

index 1f67aa6844cdedfeb69977f988407066af9c5dcb..65c8546dc9b4429971430cac5a904c2b562b0a61 100644 (file)
@@ -40,6 +40,7 @@ data TrapCause =
   StaticMethod MethodInfo | -- for static calls
   VirtualMethod Bool MethodInfo | -- for virtual calls
   InterfaceMethod Bool MethodInfo | -- for interface calls
+  InstanceOf B.ByteString | -- class name
   StaticField StaticFieldInfo deriving Show
 
 data StaticFieldInfo = StaticFieldInfo {
index 710b5b60d5a1589adc5c1d7253dd0ef23416ac89..448c966e19d5f41e51003e39685ac0a21f7e2601 100644 (file)
@@ -173,6 +173,17 @@ emitFromBB cls method = do
       mov eax (Addr 0x00000000) -- it's a trap
       push eax
       return $ Just (trapaddr, StaticField $ buildStaticFieldID cls cpidx)
+    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) >> emit8 (0x90 :: Word8)
+      cmp eax edx
+      sete al
+      movzxb eax al
+      push eax
+      return $ Just (trapaddr, InstanceOf $ buildClassID cls cpidx)
     emit' insn = emit insn >> return Nothing
 
     emit :: J.Instruction -> CodeGen e s ()
@@ -236,10 +247,6 @@ emitFromBB cls method = do
       mtable <- liftIO $ getMethodTable objname
       mov (Disp 0, eax) mtable
     emit (CHECKCAST _) = nop -- TODO(bernhard): ...
-    -- TODO(bernhard): ...
-    emit (INSTANCEOF _) = do
-      pop eax
-      push (1 :: Word32)
     emit ATHROW = -- TODO(bernhard): ...
         emit32 (0xffffffff :: Word32)
     emit I2C = do
index f89e2b8f77493ac5b6d3df60b802aaac5688220f..ad7e043ec6d70ed047e2089343c9c206bdf78b22 100644 (file)
@@ -8,6 +8,7 @@ module Mate.X86TrapHandling (
   ) where
 
 import qualified Data.Map as M
+import qualified Data.ByteString.Lazy as B
 
 import Foreign
 import Foreign.C.Types
@@ -24,12 +25,14 @@ data TrapType =
   | StaticFieldAccess
   | VirtualMethodCall Bool
   | InterfaceMethodCall Bool
+  | InstanceOfMiss B.ByteString
 
 getTrapType :: TrapMap -> CPtrdiff -> CPtrdiff -> TrapType
 getTrapType tmap signal_from from2 =
   case M.lookup (fromIntegral signal_from) tmap of
     (Just (StaticMethod _)) -> StaticMethodCall
     (Just (StaticField _)) -> StaticFieldAccess
+    (Just (InstanceOf cn)) -> InstanceOfMiss cn
     (Just _) -> error "getTrapMap: doesn't happen"
     -- maybe we've a hit on the second `from' value
     Nothing -> case M.lookup (fromIntegral from2) tmap of
@@ -46,6 +49,7 @@ mateHandler eip eax ebx esp = do
   case getTrapType tmap eip callerAddr of
     StaticMethodCall  -> staticCallHandler eip
     StaticFieldAccess -> staticFieldHandler eip
+    (InstanceOfMiss cn) -> instanceOfMissHandler eip cn
     VirtualMethodCall imm8   -> invokeHandler eax eax esp imm8
     InterfaceMethodCall imm8 -> invokeHandler eax ebx esp imm8
 
@@ -81,6 +85,21 @@ staticFieldHandler eip = do
       return eip
     else error "staticFieldHandler: something is wrong here. abort.\n"
 
+instanceOfMissHandler :: CPtrdiff -> B.ByteString -> IO CPtrdiff
+instanceOfMissHandler eip classname = do
+  -- first byte is going to be the opcode
+  let insn_ptr = intPtrToPtr (fromIntegral eip) :: Ptr CUChar
+  -- the next four bytes are the immediate
+  let imm_ptr = intPtrToPtr (fromIntegral (eip + 1)) :: Ptr CPtrdiff
+  checkMe <- peek imm_ptr
+  if checkMe == 0x909090ff then -- safety check...
+    do
+      mtable <- getMethodTable classname
+      poke imm_ptr (fromIntegral mtable)
+      poke insn_ptr 0xba -- `mov edx' opcode
+      return eip
+    else error "instanceOfMissHandler: something is wrong here. abort.\n"
+
 invokeHandler :: CPtrdiff -> CPtrdiff -> CPtrdiff -> Bool -> IO CPtrdiff
 invokeHandler method_table table2patch esp imm8 = do
   -- table2patch: note, that can be a method-table or a interface-table
diff --git a/tests/InstanceOf1.java b/tests/InstanceOf1.java
new file mode 100644 (file)
index 0000000..faf3dd9
--- /dev/null
@@ -0,0 +1,17 @@
+package tests;
+
+public class InstanceOf1 {
+       public static void main(String []args) {
+               Instance1 x = new Instance1();
+               if (x instanceof Instance1) {
+                       System.out.printf("x is instance of Instance1 :-)\n");
+               } else {
+                       System.out.printf("x is *not* instance of Instance1 :-(\n");
+               }
+               if (x instanceof Instance2) {
+                       System.out.printf("x is instance of Instance2 :-)\n");
+               } else {
+                       System.out.printf("x is *not* instance of Instance2 :-(\n");
+               }
+       }
+}