- 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)
+ 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 two nop's at the end, therefore the disasm doesn't screw up
+ emit32 (0x9090ffff :: Word32); nop
+ -- discard arguments on stack
+ let argcnt = ((if hasThis then 1 else 0) + methodGetArgsCount (methodNameTypeByIdx cls cpidx)) * ptrSize
+ when (argcnt > 0) (add esp argcnt)
+ -- push result on stack if method has a return value
+ when (methodHaveReturnValue cls cpidx) (push eax)
+ return $ Just (calladdr, StaticMethod l)
+
+ virtualCall :: Word16 -> Bool -> CodeGen e s (Maybe (Word32, TrapCause))
+ virtualCall cpidx isInterface = do
+ let mi@(MethodInfo methodname objname msig@(MethodSignature args _)) = buildMethodID cls cpidx
+ newNamedLabel (show mi) >>= defineLabel
+ -- get method offset for call @ runtime
+ let offset = if isInterface
+ then getInterfaceMethodOffset objname methodname (encode msig)
+ else getMethodOffset objname (methodname `B.append` encode msig)
+ let argsLen = genericLength args
+ -- objref lives somewhere on the argument stack
+ mov ebx (Disp (argsLen * ptrSize), esp)
+ if isInterface
+ then mov ebx (Disp 0, ebx) -- get method-table-ptr, keep it in ebx
+ else return () -- invokevirtual
+ -- get method-table-ptr (or interface-table-ptr)
+ mov eax (Disp 0, ebx)
+ -- make actual (indirect) call
+ calladdr <- getCurrentOffset
+ -- will be patched to this: call (Disp 0xXXXXXXXX, eax)
+ emit32 (0x9090ffff :: Word32); nop; nop
+ -- discard arguments on stack (`+1' for "this")
+ let argcnt = ptrSize * (1 + methodGetArgsCount (methodNameTypeByIdx cls cpidx))
+ when (argcnt > 0) (add esp argcnt)
+ -- push result on stack if method has a return value
+ when (methodHaveReturnValue cls cpidx) (push eax)
+ -- 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
+ return $ Just (calladdr, VirtualCall isInterface mi offset)