+ getCurrentOffset :: CodeGen e s Word32
+ getCurrentOffset = do
+ ep <- getEntryPoint
+ let w32_ep = (fromIntegral $ ptrToIntPtr ep) :: Word32
+ offset <- getCodeOffset
+ return $ w32_ep + fromIntegral offset
+
+ emitInvoke :: Word16 -> Bool -> CodeGen e s (Maybe (Word32, TrapCause))
+ emitInvoke cpidx hasThis = do
+ let l = buildMethodID cls cpidx
+ calladdr <- getCurrentOffset
+ newNamedLabel (show l) >>= defineLabel
+ -- causes SIGILL. in the signal handler we patch it to the acutal call.
+ -- place a nop at the end, therefore the disasm doesn't screw up
+ emit32 (0xffff9090 :: Word32) >> emit8 (0x90 :: Word8)
+ -- discard arguments on stack
+ let argcnt = ((if hasThis then 1 else 0) + methodGetArgsCount cls cpidx) * 4
+ when (argcnt > 0) (add esp argcnt)
+ -- push result on stack if method has a return value
+ when (methodHaveReturnValue cls cpidx) (push eax)
+ -- +2 is for correcting eip in trap context
+ return $ Just (calladdr + 2, StaticMethod l)
+
+ invokeEpilog :: Word16 -> Word32 -> (Bool -> TrapCause) -> CodeGen e s (Maybe (Word32, TrapCause))
+ invokeEpilog cpidx offset trapcause = do
+ -- make actual (indirect) call
+ calladdr <- getCurrentOffset
+ call (Disp offset, eax)
+ -- discard arguments on stack (+4 for "this")
+ let argcnt = 4 + 4 * methodGetArgsCount cls cpidx
+ when (argcnt > 0) (add esp argcnt)
+ -- push result on stack if method has a return value
+ when (methodHaveReturnValue cls cpidx) (push eax)
+ let imm8 = is8BitOffset offset
+ return $ Just (calladdr + (if imm8 then 3 else 6), trapcause imm8)
+
+ emit'' :: J.Instruction -> CodeGen e s (Maybe (Word32, TrapCause))
+ emit'' insn = newNamedLabel ("jvm_insn: " ++ show insn) >>= defineLabel >> emit' insn
+
+ emit' :: J.Instruction -> CodeGen e s (Maybe (Word32, TrapCause))
+ emit' (INVOKESPECIAL cpidx) = emitInvoke cpidx True
+ emit' (INVOKESTATIC cpidx) = emitInvoke cpidx False
+ emit' (INVOKEINTERFACE cpidx _) = do
+ -- get methodInfo entry
+ let mi@(MethodInfo methodname ifacename msig@(MethodSignature args _)) = buildMethodID cls cpidx
+ newNamedLabel (show mi) >>= defineLabel
+ -- objref lives somewhere on the argument stack
+ mov eax (Disp ((*4) $ fromIntegral $ length args), esp)
+ -- get method-table-ptr, keep it in eax (for trap handling)
+ mov eax (Disp 0, eax)
+ -- get interface-table-ptr
+ mov ebx (Disp 0, eax)
+ -- get method offset
+ offset <- liftIO $ getInterfaceMethodOffset ifacename methodname (encode msig)
+ -- note, that "mi" has the wrong class reference here.
+ -- we figure that out at run-time, in the methodpool,
+ -- depending on the method-table-ptr
+ invokeEpilog cpidx offset (`InterfaceMethod` mi)
+ emit' (INVOKEVIRTUAL cpidx) = do
+ -- get methodInfo entry
+ let mi@(MethodInfo methodname objname msig@(MethodSignature args _)) = buildMethodID cls cpidx
+ newNamedLabel (show mi) >>= defineLabel
+ -- objref lives somewhere on the argument stack
+ mov eax (Disp ((*4) $ fromIntegral $ length args), esp)
+ -- get method-table-ptr
+ mov eax (Disp 0, eax)
+ -- get method offset
+ let nameAndSig = methodname `B.append` encode msig
+ offset <- liftIO $ getMethodOffset objname nameAndSig
+ -- note, that "mi" has the wrong class reference here.
+ -- we figure that out at run-time, in the methodpool,
+ -- depending on the method-table-ptr
+ invokeEpilog cpidx offset (`VirtualMethod` mi)
+ emit' (PUTSTATIC cpidx) = do
+ pop eax
+ trapaddr <- getCurrentOffset
+ mov (Addr 0x00000000) eax -- it's a trap
+ return $ Just (trapaddr, StaticField $ buildStaticFieldID cls cpidx)
+ emit' (GETSTATIC cpidx) = do
+ trapaddr <- getCurrentOffset
+ mov eax (Addr 0x00000000) -- it's a trap
+ push eax
+ return $ Just (trapaddr, StaticField $ buildStaticFieldID cls cpidx)
+ emit' insn = emit insn >> return Nothing
+