To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

NativeCallHelper.scala 15.6 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
1
2
package uvm.refimpl.nat

3
4
import java.nio.ByteBuffer
import java.nio.ByteOrder
5
import scala.collection.mutable.HashMap
6
import org.slf4j.LoggerFactory
Kunshan Wang's avatar
Kunshan Wang committed
7
import com.kenai.jffi.{ Type => JType, Struct => JStruct, Function => JFunction, HeapInvocationBuffer, Invoker }
8
9
import com.kenai.jffi.CallingConvention
import com.kenai.jffi.Closure
10
import com.typesafe.scalalogging.Logger
Kunshan Wang's avatar
Kunshan Wang committed
11
import uvm.FuncSig
12
import uvm.{ Function => MFunc }
Kunshan Wang's avatar
Kunshan Wang committed
13
import uvm.refimpl.UvmRefImplException
14
import uvm.refimpl.UvmRuntimeException
15
import uvm.refimpl.itpr._
Kunshan Wang's avatar
Kunshan Wang committed
16
import uvm.refimpl.itpr.ValueBox
17
import uvm.refimpl.mem.TypeSizes
Kunshan Wang's avatar
Kunshan Wang committed
18
import uvm.refimpl.mem.TypeSizes.Word
19
import uvm.ssavariables.ExposedFunc
Kunshan Wang's avatar
Kunshan Wang committed
20
21
import uvm.types._
import uvm.types.{ Type => MType }
22
import uvm.utils.HexDump
23
24
import uvm.utils.LazyPool
import uvm.refimpl.UvmRefImplException
Kunshan Wang's avatar
Kunshan Wang committed
25
import jnr.ffi.Pointer
26

Kunshan Wang's avatar
Kunshan Wang committed
27
object NativeCallHelper {
28
  val logger = Logger(LoggerFactory.getLogger(getClass.getName))
Kunshan Wang's avatar
Kunshan Wang committed
29
30
31
32
33
34
35
36
37
38

  private def storeBoxToPtr(ptr: Pointer, off: Int, mty: MType, vb: ValueBox): Unit = {
    mty match {
      case TypeInt(8)   => ptr.putByte(off, vb.asInstanceOf[BoxInt].value.toByte)
      case TypeInt(16)  => ptr.putShort(off, vb.asInstanceOf[BoxInt].value.toShort)
      case TypeInt(32)  => ptr.putInt(off, vb.asInstanceOf[BoxInt].value.toInt)
      case TypeInt(64)  => ptr.putLong(off, vb.asInstanceOf[BoxInt].value.toLong)
      case TypeFloat()  => ptr.putFloat(off, vb.asInstanceOf[BoxFloat].value)
      case TypeDouble() => ptr.putDouble(off, vb.asInstanceOf[BoxDouble].value)
      case s @ TypeStruct(flds) => {
Kunshan Wang's avatar
Kunshan Wang committed
39
        val fldvbs = vb.asInstanceOf[BoxSeq].values
Kunshan Wang's avatar
Kunshan Wang committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
        for (((fty, fvb), i) <- (flds zip fldvbs).zipWithIndex) {
          val off2 = TypeSizes.fieldOffsetOf(s, i)
          storeBoxToPtr(ptr, off + off2.toInt, fty, fvb)
        }
      }
      case _: AbstractPointerType => ptr.putLong(off, vb.asInstanceOf[BoxPointer].addr)
    }
  }

  private def loadBoxFromPtr(ptr: Pointer, off: Long, mty: MType, vb: ValueBox): Unit = {
    mty match {
      case TypeInt(8)   => vb.asInstanceOf[BoxInt].value = OpHelper.trunc(ptr.getByte(off), 8)
      case TypeInt(16)  => vb.asInstanceOf[BoxInt].value = OpHelper.trunc(ptr.getShort(off), 16)
      case TypeInt(32)  => vb.asInstanceOf[BoxInt].value = OpHelper.trunc(ptr.getInt(off), 32)
      case TypeInt(64)  => vb.asInstanceOf[BoxInt].value = OpHelper.trunc(ptr.getLong(off), 64)
      case TypeFloat()  => vb.asInstanceOf[BoxFloat].value = ptr.getFloat(off)
      case TypeDouble() => vb.asInstanceOf[BoxDouble].value = ptr.getDouble(off)
      case s @ TypeStruct(flds) => {
Kunshan Wang's avatar
Kunshan Wang committed
58
        val fldvbs = vb.asInstanceOf[BoxSeq].values
Kunshan Wang's avatar
Kunshan Wang committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        for (((fty, fvb), i) <- (flds zip fldvbs).zipWithIndex) {
          val off2 = TypeSizes.fieldOffsetOf(s, i)
          loadBoxFromPtr(ptr, off + off2, fty, fvb)
        }
      }
      case _: AbstractPointerType => vb.asInstanceOf[BoxPointer].addr = ptr.getAddress(off)
    }
  }

  private def makeBoxFromPtr(ptr: Pointer, off: Long, mty: MType): ValueBox = mty match {
    case TypeInt(8)   => BoxInt(OpHelper.trunc(ptr.getByte(off), 8))
    case TypeInt(16)  => BoxInt(OpHelper.trunc(ptr.getShort(off), 16))
    case TypeInt(32)  => BoxInt(OpHelper.trunc(ptr.getInt(off), 32))
    case TypeInt(64)  => BoxInt(OpHelper.trunc(ptr.getLong(off), 64))
    case TypeFloat()  => BoxFloat(ptr.getFloat(off))
    case TypeDouble() => BoxDouble(ptr.getDouble(off))
    case s @ TypeStruct(flds) => {
      val fldvbs = for ((fty, i) <- flds.zipWithIndex) yield {
        val off2 = TypeSizes.fieldOffsetOf(s, i)
        makeBoxFromPtr(ptr, off + off2, fty)
      }
Kunshan Wang's avatar
Kunshan Wang committed
80
      BoxSeq(fldvbs)
Kunshan Wang's avatar
Kunshan Wang committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    }
    case _: AbstractPointerType => BoxPointer(ptr.getAddress(off))
  }

  private val FORCE_ALIGN_UP = 16L

  private def putArg(hib: HeapInvocationBuffer, mty: MType, vb: ValueBox): Unit = {
    mty match {
      case TypeInt(8)   => hib.putByte(vb.asInstanceOf[BoxInt].value.toByte)
      case TypeInt(16)  => hib.putShort(vb.asInstanceOf[BoxInt].value.toShort)
      case TypeInt(32)  => hib.putInt(vb.asInstanceOf[BoxInt].value.toInt)
      case TypeInt(64)  => hib.putLong(vb.asInstanceOf[BoxInt].value.toLong)
      case TypeFloat()  => hib.putFloat(vb.asInstanceOf[BoxFloat].value)
      case TypeDouble() => hib.putDouble(vb.asInstanceOf[BoxDouble].value)
      case TypeStruct(flds) => {
        // Always allocate more space so that C may access the word that contains the byte instead of just the byte.
        val sz = TypeSizes.alignUp(TypeSizes.sizeOf(mty), FORCE_ALIGN_UP).intValue()
        val buf = ByteBuffer.allocate(sz).order(ByteOrder.LITTLE_ENDIAN)
        val ptr = Pointer.wrap(NativeSupport.jnrRuntime, buf)
        storeBoxToPtr(ptr, 0, mty, vb)
        logger.debug("Hexdump:\n" + HexDump.dumpByteBuffer(buf))
        hib.putStruct(buf.array(), buf.arrayOffset())
      }
      case _: AbstractPointerType => hib.putAddress(vb.asInstanceOf[BoxPointer].addr)
    }
  }

  def makeBoxFromClosureBufParam(cbuf: Closure.Buffer, index: Int, mty: MType): ValueBox = mty match {
    case TypeInt(8)   => BoxInt(OpHelper.trunc(cbuf.getByte(index), 8))
    case TypeInt(16)  => BoxInt(OpHelper.trunc(cbuf.getShort(index), 16))
    case TypeInt(32)  => BoxInt(OpHelper.trunc(cbuf.getInt(index), 32))
    case TypeInt(64)  => BoxInt(OpHelper.trunc(cbuf.getLong(index), 64))
    case TypeFloat()  => BoxFloat(cbuf.getFloat(index))
    case TypeDouble() => BoxDouble(cbuf.getDouble(index))
    case s @ TypeStruct(flds) => {
      val mem = cbuf.getStruct(index)
      makeBoxFromPtr(NativeSupport.theMemory, mem, mty)
    }
    case _: AbstractPointerType => BoxPointer(cbuf.getAddress(index))
  }

  def putBoxToClosureBufRv(cbuf: Closure.Buffer, mty: MType, vb: ValueBox): Unit = mty match {
    case TypeInt(8)   => cbuf.setByteReturn(vb.asInstanceOf[BoxInt].value.toByte)
    case TypeInt(16)  => cbuf.setShortReturn(vb.asInstanceOf[BoxInt].value.toShort)
    case TypeInt(32)  => cbuf.setIntReturn(vb.asInstanceOf[BoxInt].value.toInt)
    case TypeInt(64)  => cbuf.setLongReturn(vb.asInstanceOf[BoxInt].value.toLong)
    case TypeFloat()  => cbuf.setFloatReturn(vb.asInstanceOf[BoxFloat].value)
    case TypeDouble() => cbuf.setDoubleReturn(vb.asInstanceOf[BoxDouble].value)
    case s @ TypeStruct(flds) => {
      // Always allocate more space so that C may access the word that contains the byte instead of just the byte.
      val sz = TypeSizes.alignUp(TypeSizes.sizeOf(mty), FORCE_ALIGN_UP).intValue()
      val buf = ByteBuffer.allocate(sz).order(ByteOrder.LITTLE_ENDIAN)
      val ptr = Pointer.wrap(NativeSupport.jnrRuntime, buf)
      storeBoxToPtr(ptr, 0, mty, vb)
      logger.debug("Hexdump:\n" + HexDump.dumpByteBuffer(buf))
      cbuf.setStructReturn(buf.array(), buf.arrayOffset())
    }
    case _: AbstractPointerType => cbuf.setAddressReturn(vb.asInstanceOf[BoxPointer].addr)
  }

141
}
Kunshan Wang's avatar
Kunshan Wang committed
142
143

/**
Kunshan Wang's avatar
Kunshan Wang committed
144
 * Helps calling native functions and supports callbacks from native. Based on JFFI.
Kunshan Wang's avatar
Kunshan Wang committed
145
 */
Kunshan Wang's avatar
Kunshan Wang committed
146
class NativeCallHelper {
Kunshan Wang's avatar
Kunshan Wang committed
147
  import NativeCallHelper._
Kunshan Wang's avatar
Kunshan Wang committed
148

Kunshan Wang's avatar
Kunshan Wang committed
149
  /** A mapping of Mu types to JFFI types. Cached for struct types. */
Kunshan Wang's avatar
Kunshan Wang committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  val jffiTypePool: LazyPool[MType, JType] = LazyPool {
    case TypeInt(8)       => JType.SINT8
    case TypeInt(16)      => JType.SINT16
    case TypeInt(32)      => JType.SINT32
    case TypeInt(64)      => JType.SINT64
    case TypeFloat()      => JType.FLOAT
    case TypeDouble()     => JType.DOUBLE
    case TypeVector(_, _) => throw new UvmRefImplException("Vectors are not implemented in native calls.")
    case TypeStruct(fields) => {
      val fieldsNativeTypes: Seq[JType] = fields.map(jffiTypePool.apply)
      val strType = JStruct.newStruct(fieldsNativeTypes: _*)
      strType
    }
    case _: AbstractPointerType => JType.POINTER
    case t                      => throw new UvmRefImplException("Type %s cannot be used in native calls.".format(t.repr))
  }

Kunshan Wang's avatar
Kunshan Wang committed
167
168
169
170
171
172
173
174
175
  /** Map Mu-style multi-return types to C-style single return type */
  def getNativeReturnType(retTys: Seq[MType]): JType = {
    retTys match {
      case Seq()  => JType.VOID
      case Seq(t) => jffiTypePool(t)
      case ts     => throw new UvmRefImplException("Multiple return types %s cannot be used in native calls.".format(ts.map(_.repr).mkString(" ")))
    }
  }

Kunshan Wang's avatar
Kunshan Wang committed
176
  /** A mapping from referenced C functions (signature, function pointer) to JFFI functions. Cached. */
Kunshan Wang's avatar
Kunshan Wang committed
177
178
  val jffiFuncPool = LazyPool[(FuncSig, Word), JFunction] {
    case (sig, funcAddr) => {
Kunshan Wang's avatar
Kunshan Wang committed
179
180
      val jParamTypes = sig.paramTys.map(jffiTypePool.apply)
      val jRetTy = getNativeReturnType(sig.retTys)
Kunshan Wang's avatar
Kunshan Wang committed
181
182
183
      new JFunction(funcAddr, jRetTy, jParamTypes: _*)
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
184

Kunshan Wang's avatar
Kunshan Wang committed
185
  /**
186
187
   * A run-time record of an exposed Mu function. A Mu function may be exposed many times. Each ExpFuncRecord
   * corresponds to one such callable instance.
Kunshan Wang's avatar
Kunshan Wang committed
188
189
190
191
   * <p>
   * A ".expose" definition will permanently create an instance.
   * <p>
   * The "@uvm.native.expose" instruction will also create one such instance. Such instances can be removed later by
Kunshan Wang's avatar
Kunshan Wang committed
192
   * "@uvm.native.unexpose". The equivalent API calls do the same.
193
194
195
   *
   * @param isDynamic true if it is exposed via the "@uvm.native.expose" instruction or the equivalent API call. false
   * if it is exposed by the ".expose" top-level definintion of the Mu IR.
Kunshan Wang's avatar
Kunshan Wang committed
196
   */
197
  class ExpFuncRec(val muFunc: MFunc, val cookie: Long, val closure: MuCallbackClosure, val closureHandle: Closure.Handle, val isDynamic: Boolean)
Kunshan Wang's avatar
Kunshan Wang committed
198
199
200

  /**
   * Map each address of closure handle to the DynExpFunc record so that the closure handle can be disposed.
Kunshan Wang's avatar
Kunshan Wang committed
201
   */
202
203
204
205
206
207
208
209
210
211
212
213
214
  val addrToRec = new HashMap[Word, ExpFuncRec]()

  /**
   * Map each uvm.ssavariables.ExpFunc instance to the DynExpFunc record.
   */
  val expFuncToRec = new HashMap[ExposedFunc, ExpFuncRec]()

  /**
   * Get the address to the statically exposed function (.expose) by the ExposedFunc instance.
   */
  def getStaticExpFuncAddr(expFunc: ExposedFunc): Word = {
    expFuncToRec(expFunc).closureHandle.getAddress()
  }
215

Kunshan Wang's avatar
Kunshan Wang committed
216
217
218
219
220
221
222
223
224
225
  /**
   * The current NativeStackKeeper instance that makes the native call.
   * <p>
   * It is set just before entering native, by calling a native function, or returning to a native function which called
   * back to Mu.
   * <p>
   * It is cleared after returning to JVM, either when returning from a native function, or when the native calls back
   * to Mu (to JVM).
   */
  val currentNativeStackKeeper = new ThreadLocal[NativeStackKeeper]()
Kunshan Wang's avatar
Kunshan Wang committed
226

Kunshan Wang's avatar
Kunshan Wang committed
227
228
229
  /**
   * Call a native function. Must be called by a NativeStackKeeper.Slave thread.
   */
Kunshan Wang's avatar
Kunshan Wang committed
230
231
232
  def callNative(nsk: NativeStackKeeper, sig: FuncSig, func: Word, args: Seq[ValueBox]): Option[ValueBox] = {
    assert(Thread.currentThread() == nsk.slaveThread)

Kunshan Wang's avatar
Kunshan Wang committed
233
    val jFunc = jffiFuncPool((sig, func))
234

Kunshan Wang's avatar
Kunshan Wang committed
235
236
    val hib = new HeapInvocationBuffer(jFunc)

Kunshan Wang's avatar
Kunshan Wang committed
237
    for ((mty, vb) <- (sig.paramTys zip args)) {
Kunshan Wang's avatar
Kunshan Wang committed
238
239
      putArg(hib, mty, vb)
    }
240

Kunshan Wang's avatar
Kunshan Wang committed
241
    currentNativeStackKeeper.set(nsk)
242
    assert(currentNativeStackKeeper.get() == nsk)
Kunshan Wang's avatar
Kunshan Wang committed
243
244
245

    val inv = Invoker.getInstance

Kunshan Wang's avatar
Kunshan Wang committed
246
    val maybeRvb = sig.retTys match {
Kunshan Wang's avatar
Kunshan Wang committed
247
      case Seq() => {
Kunshan Wang's avatar
Kunshan Wang committed
248
        inv.invokeLong(jFunc, hib)
Kunshan Wang's avatar
Kunshan Wang committed
249
        None
Kunshan Wang's avatar
Kunshan Wang committed
250
      }
Kunshan Wang's avatar
Kunshan Wang committed
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
      case Seq(t) => {
        val b = t match {
          case TypeInt(8) => {
            val rv = inv.invokeInt(jFunc, hib).toByte
            BoxInt(OpHelper.trunc(BigInt(rv), 8))
          }
          case TypeInt(16) => {
            val rv = inv.invokeInt(jFunc, hib).toShort
            BoxInt(OpHelper.trunc(BigInt(rv), 16))
          }
          case TypeInt(32) => {
            val rv = inv.invokeInt(jFunc, hib)
            BoxInt(OpHelper.trunc(BigInt(rv), 32))
          }
          case TypeInt(64) => {
            val rv = inv.invokeLong(jFunc, hib)
            BoxInt(OpHelper.trunc(BigInt(rv), 64))
          }
          case TypeFloat() => {
            val rv = inv.invokeFloat(jFunc, hib)
            BoxFloat(rv)
          }
          case TypeDouble() => {
            val rv = inv.invokeDouble(jFunc, hib)
            BoxDouble(rv)
          }
          case TypeStruct(flds) => {
            val rv = inv.invokeStruct(jFunc, hib)
            val buf = ByteBuffer.wrap(rv).order(ByteOrder.LITTLE_ENDIAN)
            logger.debug("Hexdump:\n" + HexDump.dumpByteBuffer(buf))
            val ptr = Pointer.wrap(NativeSupport.jnrRuntime, buf)
            makeBoxFromPtr(ptr, 0, t)
          }
          case _: AbstractPointerType => {
            val rv = inv.invokeAddress(jFunc, hib)
            BoxPointer(rv)
          }
Kunshan Wang's avatar
Kunshan Wang committed
288
        }
Kunshan Wang's avatar
Kunshan Wang committed
289
        Some(b)
Kunshan Wang's avatar
Kunshan Wang committed
290
291
      }
    }
292
    currentNativeStackKeeper.remove()
Kunshan Wang's avatar
Kunshan Wang committed
293

Kunshan Wang's avatar
Kunshan Wang committed
294
    maybeRvb
Kunshan Wang's avatar
Kunshan Wang committed
295
  }
Kunshan Wang's avatar
Kunshan Wang committed
296

297
298
299
300
301
  def exposeFuncStatic(expFunc: ExposedFunc): Word = {
    val efr = exposeFunc(expFunc.func, expFunc.cookie.num.toLong, false)
    expFuncToRec(expFunc) = efr
    efr.closureHandle.getAddress
  }
Kunshan Wang's avatar
Kunshan Wang committed
302

303
304
305
306
  def exposeFuncDynamic(muFunc: MFunc, cookie: Long): Word = {
    val efr = exposeFunc(muFunc, cookie, true)
    efr.closureHandle.getAddress
  }
Kunshan Wang's avatar
Kunshan Wang committed
307

Kunshan Wang's avatar
Kunshan Wang committed
308
309
  /**
   * Expose a Mu function.
310
   *
Kunshan Wang's avatar
Kunshan Wang committed
311
312
   * @return the address of the exposed function (i.e. of the closure handle)
   */
313
  private def exposeFunc(muFunc: MFunc, cookie: Long, isDynamic: Boolean): ExpFuncRec = {
Kunshan Wang's avatar
Kunshan Wang committed
314
    val sig = muFunc.sig
Kunshan Wang's avatar
Kunshan Wang committed
315
316
    val jParamTypes = sig.paramTys.map(jffiTypePool.apply)
    val jRetTy = getNativeReturnType(sig.retTys)
317

Kunshan Wang's avatar
Kunshan Wang committed
318
    val clos = new MuCallbackClosure(muFunc, cookie)
319
    val handle = NativeSupport.jffiClosureManager.newClosure(clos, jRetTy, jParamTypes.toArray, CallingConvention.DEFAULT)
Kunshan Wang's avatar
Kunshan Wang committed
320
    val addr = handle.getAddress
321

322
    val efr = new ExpFuncRec(muFunc, cookie, clos, handle, isDynamic)
323

324
    addrToRec(addr) = efr
325

326
    efr
Kunshan Wang's avatar
Kunshan Wang committed
327
  }
328

Kunshan Wang's avatar
Kunshan Wang committed
329
  def unexposeFunc(addr: Word): Unit = {
330
    val efr = addrToRec.get(addr).getOrElse {
Kunshan Wang's avatar
Kunshan Wang committed
331
      throw new UvmRuntimeException("Attempt to unexpose function %d (0x%x) which has not been exposed.".format(addr, addr))
Kunshan Wang's avatar
Kunshan Wang committed
332
    }
333

334
    if (!efr.isDynamic) {
335
336
      throw new UvmRuntimeException("Attempt to unexpose a function %d (0x%x) exposed via the '.expose' top-level definition.".format(addr, addr))
    }
337

338
    addrToRec.remove(addr)
339

340
    efr.closureHandle.dispose()
Kunshan Wang's avatar
Kunshan Wang committed
341
  }
342

Kunshan Wang's avatar
Kunshan Wang committed
343
344
345
  /** Handles calling back from C */
  class MuCallbackClosure(val muFunc: MFunc, val cookie: Long) extends Closure {
    def invoke(buf: Closure.Buffer): Unit = {
346
347
348
      try {
        val nsk = currentNativeStackKeeper.get()
        logger.debug("Called back. nsk = %s, currentThread = %s, muFunc = %s".format(nsk, Thread.currentThread(), muFunc.repr))
Kunshan Wang's avatar
Kunshan Wang committed
349
350
        assert(nsk != null, s"Native calls Mu function ${muFunc.repr} with cookie ${cookie}, but Mu did not call native.")
        assert(Thread.currentThread() == nsk.slaveThread)
351
352
353
        currentNativeStackKeeper.remove()

        val sig = muFunc.sig
354

Kunshan Wang's avatar
Kunshan Wang committed
355
        val paramBoxes = for ((paramTy, i) <- sig.paramTys.zipWithIndex) yield {
Kunshan Wang's avatar
Kunshan Wang committed
356
          makeBoxFromClosureBufParam(buf, i, paramTy)
357
        }
358

Kunshan Wang's avatar
Kunshan Wang committed
359
360
361
362
        val maybeRetTy = sig.retTys match {
          case Seq()  => None
          case Seq(t) => Some(t)
          case ts     => throw new UvmRefImplException("Multiple return types %s cannot be used in native calls.".format(ts.map(_.repr).mkString(" ")))
Kunshan Wang's avatar
Kunshan Wang committed
363
        }
364

Kunshan Wang's avatar
Kunshan Wang committed
365
366
        val maybeRetBox = maybeRetTy.map(ValueBox.makeBoxForType)

367
        logger.debug("Calling to Mu nsk.slave...")
368

Kunshan Wang's avatar
Kunshan Wang committed
369
370
371
372
373
        val maybeRvb = nsk.slave.onCallBack(muFunc, cookie, paramBoxes)

        (maybeRetBox, maybeRvb) match {
          case (None, None)           =>
          case (Some(dst), Some(src)) => dst.copyFrom(src)
Kunshan Wang's avatar
Kunshan Wang committed
374
          case _                      => throw new Error("This is impossible")
Kunshan Wang's avatar
Kunshan Wang committed
375
        }
376

377
        logger.debug("Back from nsk.slave. Returning to native...")
378

Kunshan Wang's avatar
Kunshan Wang committed
379
380
        maybeRetBox.foreach { rvBox =>
          putBoxToClosureBufRv(buf, maybeRetTy.get, rvBox)
Kunshan Wang's avatar
Kunshan Wang committed
381
        }
382

383
384
385
386
387
388
        currentNativeStackKeeper.set(nsk)
      } catch {
        case e: Throwable =>
          logger.debug("Exception occured in the slave thread when there are native threads alive. " +
            "Prepare for undefined behaviours in native frames (or JVM frames if the native calls back again).", e)
          throw e
389

390
      }
391
    }
Kunshan Wang's avatar
Kunshan Wang committed
392
393
  }
}