suspendThreadMethod :: Bool -> Code
suspendThreadMethod interruptible =
     loadContext
  <> contextMyCapability
  -- <> dup capabilityType
  <> iconst jbool (boolToInt interruptible)
  <> invokevirtual (mkMethodRef capability "suspendThread" [jbool] (ret taskType))
  where boolToInt True = 1
        boolToInt False = 0

resumeThreadMethod :: Code
resumeThreadMethod =
     invokestatic (mkMethodRef capability "resumeThread" [taskType] (ret capabilityType))
  <> loadContext
  <> swap capabilityType contextType
  <> contextMyCapabilitySet

stgExceptionGroup, ioGroup, stmGroup, concGroup, parGroup, interpGroup, stgGroup :: Text
stgExceptionGroup = exception "StgException"
ioGroup = io "IO"
stmGroup = stm "STM"
concGroup = conc "Concurrent"
stgGroup = stg "Stg"
parGroup = par "Parallel"
interpGroup = interp "Interpreter"

mkRtsFunCall :: (Text, Text) -> Code
mkRtsFunCall (group, name) =
     getstatic (mkFieldRef group name rtsFunType)
  <> loadContext
  <> invokevirtual (mkMethodRef rtsFun "enter" [contextType] void)

-- Types
buffer :: Text
buffer = "java/nio/Buffer"

bufferType :: FieldType
bufferType = obj buffer

byteBuffer :: Text
byteBuffer = "java/nio/ByteBuffer"

byteBufferType :: FieldType
byteBufferType = obj byteBuffer

byteArrayBuf :: Code
byteArrayBuf = getfield $ mkFieldRef stgByteArray "buf" byteBufferType

byteBufferCapacity :: Code
byteBufferCapacity = invokevirtual $ mkMethodRef byteBuffer "capacity" [] (ret jint)

byteBufferGet :: FieldType -> Code
byteBufferGet ft = invokevirtual $ mkMethodRef byteBuffer name [jint] (ret ft)
  where name = append "get" $ fieldTypeSuffix ft

byteBufferPut :: FieldType -> Code
byteBufferPut ft = invokevirtual $ mkMethodRef byteBuffer name [jint, ft] (ret byteBufferType)
  where name = append "put" $ fieldTypeSuffix ft

byteBufferPosGet :: Code
byteBufferPosGet = invokevirtual $ mkMethodRef byteBuffer "position" [] (ret jint)

byteBufferAddrGet :: Code
byteBufferAddrGet = invokestatic $ mkMethodRef memoryManager "getAddress" [byteBufferType] (ret jint)

byteBufferPosSet :: Code
byteBufferPosSet = invokevirtual $ mkMethodRef byteBuffer "position" [jint] (ret bufferType)

byteBufferDup :: Code
byteBufferDup = invokevirtual $ mkMethodRef byteBuffer "duplicate" [] (ret byteBufferType)

fieldTypeSuffix :: FieldType -> Text
fieldTypeSuffix (BaseType prim) =
  case prim of
    JBool   -> "Int"
    JChar   -> "Char"
    JFloat  -> "Float"
    JDouble -> "Double"
    JByte   -> ""
    JShort  -> "Short"
    JInt    -> "Int"
    JLong   -> "Long"
fieldTypeSuffix ft = error $ "fieldTypeSuffix: " ++ show ft

mutVarValue :: Code
mutVarValue = getfield $ mkFieldRef stgMutVar "value" closureType

mutVarSetValue :: Code
mutVarSetValue = putfield $ mkFieldRef stgMutVar "value" closureType

mVarValue :: Code
mVarValue = getfield $ mkFieldRef stgMVar "value" closureType

barf :: Text -> Code
barf text = sconst text
         <> iconst jint (0)
         <> new arrayFt
         <> invokestatic (mkMethodRef (rts "RtsMessages") "barf" [jstring, arrayFt] void)
  where arrayFt = jarray jobject

hsResultCap :: Code
hsResultCap = getfield $ mkFieldRef hsResult "cap" capabilityType

hsResultValue :: Code
hsResultValue = getfield $ mkFieldRef hsResult "result" closureType

trueClosure :: Code
trueClosure = invokestatic . mkMethodRef "ghczmprim/ghc/Types" "DTrue_closure" [] $ Just closureType

falseClosure :: Code
falseClosure = invokestatic . mkMethodRef "ghczmprim/ghc/Types" "DFalse_closure" [] $ Just closureType

getTagMethod :: Code -> Code
getTagMethod code
  = code
 <> gconv closureType conType
 <> invokevirtual (mkMethodRef stgConstr "getTag" [] (ret jint))

printStream :: Text
printStream = "java/io/PrintStream"

printStreamType :: FieldType
printStreamType = obj printStream

debugPrint :: FieldType -> Code
debugPrint ft = dup ft
             <> getstatic (mkFieldRef "java/lang/System" "out" printStreamType)
             <> swap ft printStreamType
             <> invokevirtual (mkMethodRef printStream "println" [genFt ft] void)
  where genFt (ObjectType _) = jobject
        genFt (ArrayType _)  = jobject
        genFt ft             = ft

nullAddr :: Code
nullAddr = getstatic $ mkFieldRef memoryManager "nullAddress" byteBufferType
suspendThreadMethod :: Bool -> Code
suspendThreadMethod interruptible =
     loadContext
  <> contextMyCapability
  -- <> dup capabilityType
  <> iconst jbool (boolToInt interruptible)
  <> invokevirtual (mkMethodRef capability "suspendThread" [jbool] (ret taskType))
  where boolToInt True = 1
        boolToInt False = 0

resumeThreadMethod :: Code
resumeThreadMethod =
     invokestatic (mkMethodRef capability "resumeThread" [taskType] (ret capabilityType))
  <> loadContext
  <> swap capabilityType contextType
  <> contextMyCapabilitySet

stgExceptionGroup, ioGroup, stmGroup, concGroup, parGroup, interpGroup, stgGroup :: Text
stgExceptionGroup = exception "StgException"
ioGroup = io "IO"
stmGroup = stm "STM"
concGroup = conc "Concurrent"
stgGroup = stg "Stg"
parGroup = par "Parallel"
interpGroup = interp "Interpreter"

mkRtsFunCall :: (Text, Text) -> Code
mkRtsFunCall (group, name) =
     getstatic (mkFieldRef group name rtsFunType)
  <> loadContext
  <> invokevirtual (mkMethodRef rtsFun "enter" [contextType] void)

-- Types
buffer :: Text
buffer = "java/nio/Buffer"

bufferType :: FieldType
bufferType = obj buffer

byteBuffer :: Text
byteBuffer = "java/nio/ByteBuffer"

byteBufferType :: FieldType
byteBufferType = obj byteBuffer

byteArrayBuf :: Code
byteArrayBuf = getfield $ mkFieldRef stgByteArray "buf" byteBufferType

byteBufferCapacity :: Code
byteBufferCapacity = invokevirtual $ mkMethodRef byteBuffer "capacity" [] (ret jint)

byteBufferGet :: FieldType -> Code
byteBufferGet ft = invokevirtual $ mkMethodRef byteBuffer name [jint] (ret ft)
  where name = append "get" $ fieldTypeSuffix ft

byteBufferPut :: FieldType -> Code
byteBufferPut ft = invokevirtual $ mkMethodRef byteBuffer name [jint, ft] (ret byteBufferType)
  where name = append "put" $ fieldTypeSuffix ft

byteBufferPosGet :: Code
byteBufferPosGet = invokevirtual $ mkMethodRef byteBuffer "position" [] (ret jint)

byteBufferAddrGet :: Code
byteBufferAddrGet = invokestatic $ mkMethodRef memoryManager "getAddress" [byteBufferType] (ret jint)

byteBufferPosSet :: Code
byteBufferPosSet = invokevirtual $ mkMethodRef byteBuffer "position" [jint] (ret bufferType)

byteBufferDup :: Code
byteBufferDup = invokevirtual $ mkMethodRef byteBuffer "duplicate" [] (ret byteBufferType)

fieldTypeSuffix :: FieldType -> Text
fieldTypeSuffix (BaseType prim) =
  case prim of
    JBool   -> "Int"
    JChar   -> "Char"
    JFloat  -> "Float"
    JDouble -> "Double"
    JByte   -> ""
    JShort  -> "Short"
    JInt    -> "Int"
    JLong   -> "Long"
fieldTypeSuffix ft = error $ "fieldTypeSuffix: " ++ show ft

mutVarValue :: Code
mutVarValue = getfield $ mkFieldRef stgMutVar "value" closureType

mutVarSetValue :: Code
mutVarSetValue = putfield $ mkFieldRef stgMutVar "value" closureType

mVarValue :: Code
mVarValue = getfield $ mkFieldRef stgMVar "value" closureType

barf :: Text -> Code
barf text = sconst text
         <> iconst jint (0)
         <> new arrayFt
         <> invokestatic (mkMethodRef (rts "RtsMessages") "barf" [jstring, arrayFt] void)
  where arrayFt = jarray jobject

hsResultCap :: Code
hsResultCap = getfield $ mkFieldRef hsResult "cap" capabilityType

hsResultValue :: Code
hsResultValue = getfield $ mkFieldRef hsResult "result" closureType

trueClosure :: Code
trueClosure = invokestatic . mkMethodRef "ghczmprim/ghc/Types" "DTrue_closure" [] $ Just closureType

falseClosure :: Code
falseClosure = invokestatic . mkMethodRef "ghczmprim/ghc/Types" "DFalse_closure" [] $ Just closureType

getTagMethod :: Code -> Code
getTagMethod code
  = code
 <> gconv closureType conType
 <> invokevirtual (mkMethodRef stgConstr "getTag" [] (ret jint))

printStream :: Text
printStream = "java/io/PrintStream"

printStreamType :: FieldType
printStreamType = obj printStream

debugPrint :: FieldType -> Code
debugPrint ft = dup ft
             <> getstatic (mkFieldRef "java/lang/System" "out" printStreamType)
             <> swap ft printStreamType
             <> invokevirtual (mkMethodRef printStream "println" [genFt ft] void)
  where genFt (ObjectType _) = jobject
        genFt (ArrayType _)  = jobject
        genFt ft             = ft

nullAddr :: Code
nullAddr = getstatic $ mkFieldRef memoryManager "nullAddress" byteBufferType
suspendThreadMethod interruptible =
     loadContext
  <> contextMyCapability
  -- <> dup capabilityType
  <> iconst jbool (boolToInt interruptible)
  <> invokevirtual (mkMethodRef capability "suspendThread" [jbool] (ret taskType))
  where boolToInt True = 1
        boolToInt False = 0

resumeThreadMethod :: Code
resumeThreadMethod =
     invokestatic (mkMethodRef capability "resumeThread" [taskType] (ret capabilityType))
  <> loadContext
  <> swap capabilityType contextType
  <> contextMyCapabilitySet

stgExceptionGroup, ioGroup, stmGroup, concGroup, parGroup, interpGroup, stgGroup :: Text
stgExceptionGroup = exception "StgException"
ioGroup = io "IO"
stmGroup = stm "STM"
concGroup = conc "Concurrent"
stgGroup = stg "Stg"
parGroup = par "Parallel"
interpGroup = interp "Interpreter"

mkRtsFunCall :: (Text, Text) -> Code
mkRtsFunCall (group, name) =
     getstatic (mkFieldRef group name rtsFunType)
  <> loadContext
  <> invokevirtual (mkMethodRef rtsFun "enter" [contextType] void)

-- Types
buffer :: Text
buffer = "java/nio/Buffer"

bufferType :: FieldType
bufferType = obj buffer

byteBuffer :: Text
byteBuffer = "java/nio/ByteBuffer"

byteBufferType :: FieldType
byteBufferType = obj byteBuffer

byteArrayBuf :: Code
byteArrayBuf = getfield $ mkFieldRef stgByteArray "buf" byteBufferType

byteBufferCapacity :: Code
byteBufferCapacity = invokevirtual $ mkMethodRef byteBuffer "capacity" [] (ret jint)

byteBufferGet :: FieldType -> Code
byteBufferGet ft = invokevirtual $ mkMethodRef byteBuffer name [jint] (ret ft)
  where name = append "get" $ fieldTypeSuffix ft

byteBufferPut :: FieldType -> Code
byteBufferPut ft = invokevirtual $ mkMethodRef byteBuffer name [jint, ft] (ret byteBufferType)
  where name = append "put" $ fieldTypeSuffix ft

byteBufferPosGet :: Code
byteBufferPosGet = invokevirtual $ mkMethodRef byteBuffer "position" [] (ret jint)

byteBufferAddrGet :: Code
byteBufferAddrGet = invokestatic $ mkMethodRef memoryManager "getAddress" [byteBufferType] (ret jint)

byteBufferPosSet :: Code
byteBufferPosSet = invokevirtual $ mkMethodRef byteBuffer "position" [jint] (ret bufferType)

byteBufferDup :: Code
byteBufferDup = invokevirtual $ mkMethodRef byteBuffer "duplicate" [] (ret byteBufferType)

fieldTypeSuffix :: FieldType -> Text
fieldTypeSuffix (BaseType prim) =
  case prim of
    JBool   -> "Int"
    JChar   -> "Char"
    JFloat  -> "Float"
    JDouble -> "Double"
    JByte   -> ""
    JShort  -> "Short"
    JInt    -> "Int"
    JLong   -> "Long"
fieldTypeSuffix ft = error $ "fieldTypeSuffix: " ++ show ft

mutVarValue :: Code
mutVarValue = getfield $ mkFieldRef stgMutVar "value" closureType

mutVarSetValue :: Code
mutVarSetValue = putfield $ mkFieldRef stgMutVar "value" closureType

mVarValue :: Code
mVarValue = getfield $ mkFieldRef stgMVar "value" closureType

barf :: Text -> Code
barf text = sconst text
         <> iconst jint (0)
         <> new arrayFt
         <> invokestatic (mkMethodRef (rts "RtsMessages") "barf" [jstring, arrayFt] void)
  where arrayFt = jarray jobject

hsResultCap :: Code
hsResultCap = getfield $ mkFieldRef hsResult "cap" capabilityType

hsResultValue :: Code
hsResultValue = getfield $ mkFieldRef hsResult "result" closureType

trueClosure :: Code
trueClosure = invokestatic . mkMethodRef "ghczmprim/ghc/Types" "DTrue_closure" [] $ Just closureType

falseClosure :: Code
falseClosure = invokestatic . mkMethodRef "ghczmprim/ghc/Types" "DFalse_closure" [] $ Just closureType

getTagMethod :: Code -> Code
getTagMethod code
  = code
 <> gconv closureType conType
 <> invokevirtual (mkMethodRef stgConstr "getTag" [] (ret jint))

printStream :: Text
printStream = "java/io/PrintStream"

printStreamType :: FieldType
printStreamType = obj printStream

debugPrint :: FieldType -> Code
debugPrint ft = dup ft
             <> getstatic (mkFieldRef "java/lang/System" "out" printStreamType)
             <> swap ft printStreamType
             <> invokevirtual (mkMethodRef printStream "println" [genFt ft] void)
  where genFt (ObjectType _) = jobject
        genFt (ArrayType _)  = jobject
        genFt ft             = ft

nullAddr :: Code
nullAddr = getstatic $ mkFieldRef memoryManager "nullAddress" byteBufferType