279 }
280
281 public static String toJavaStringInternal(MemorySegment segment, long start) {
282 int len = strlen(segment, start);
283 byte[] bytes = new byte[len];
284 MemorySegment.copy(segment, JAVA_BYTE, start, bytes, 0, len);
285 return new String(bytes, StandardCharsets.UTF_8);
286 }
287
288 private static int strlen(MemorySegment segment, long start) {
289 // iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
290 for (int offset = 0; offset >= 0; offset++) {
291 byte curr = segment.get(JAVA_BYTE, start + offset);
292 if (curr == 0) {
293 return offset;
294 }
295 }
296 throw new IllegalArgumentException("String too large");
297 }
298
299 static long bufferCopySize(CallingSequence callingSequence) {
300 // FIXME: > 16 bytes alignment might need extra space since the
301 // starting address of the allocator might be un-aligned.
302 long size = 0;
303 for (int i = 0; i < callingSequence.argumentCount(); i++) {
304 List<Binding> bindings = callingSequence.argumentBindings(i);
305 for (Binding b : bindings) {
306 if (b instanceof Binding.Copy) {
307 Binding.Copy c = (Binding.Copy) b;
308 size = Utils.alignUp(size, c.alignment());
309 size += c.size();
310 } else if (b instanceof Binding.Allocate) {
311 Binding.Allocate c = (Binding.Allocate) b;
312 size = Utils.alignUp(size, c.alignment());
313 size += c.size();
314 }
315 }
316 }
317 return size;
318 }
319
320 static Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
321 return IntStream.range(0, moves.length)
322 .boxed()
323 .collect(Collectors.toMap(i -> moves[i].storage(), i -> i));
324 }
325
326 static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) {
327 MethodType oldType = mh.type();
328 Class<?> sourceType = oldType.parameterType(sourceIndex);
329 Class<?> destType = oldType.parameterType(destIndex);
330 if (sourceType != destType) {
331 // TODO meet?
332 throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType);
333 }
334 MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1);
335 int[] reorder = new int[oldType.parameterCount()];
336 assert destIndex > sourceIndex;
337 for (int i = 0, index = 0; i < reorder.length; i++) {
338 if (i != destIndex) {
339 reorder[i] = index++;
340 } else {
341 reorder[i] = sourceIndex;
342 }
343 }
344 return permuteArguments(mh, newType, reorder);
345 }
346
347
348 static MethodHandle swapArguments(MethodHandle mh, int firstArg, int secondArg) {
349 MethodType mtype = mh.type();
350 int[] perms = new int[mtype.parameterCount()];
351 MethodType swappedType = MethodType.methodType(mtype.returnType());
352 for (int i = 0 ; i < perms.length ; i++) {
353 int dst = i;
354 if (i == firstArg) dst = secondArg;
355 if (i == secondArg) dst = firstArg;
356 perms[i] = dst;
357 swappedType = swappedType.appendParameterTypes(mtype.parameterType(dst));
358 }
359 return permuteArguments(mh, swappedType, perms);
360 }
361
362 private static MethodHandle reachabilityFenceHandle(Class<?> type) {
363 return MH_REACHBILITY_FENCE.asType(MethodType.methodType(void.class, type));
364 }
365
366 static void handleUncaughtException(Throwable t) {
367 if (t != null) {
368 t.printStackTrace();
369 JLA.exit(1);
370 }
371 }
372
373 static MethodHandle wrapWithAllocator(MethodHandle specializedHandle,
374 int allocatorPos, long bufferCopySize,
375 boolean upcall) {
376 // insert try-finally to close the NativeScope used for Binding.Copy
377 MethodHandle closer;
378 int insertPos;
379 if (specializedHandle.type().returnType() == void.class) {
380 if (!upcall) {
381 closer = empty(methodType(void.class, Throwable.class)); // (Throwable) -> void
382 } else {
383 closer = MH_HANDLE_UNCAUGHT_EXCEPTION;
384 }
385 insertPos = 1;
386 } else {
387 closer = identity(specializedHandle.type().returnType()); // (V) -> V
388 if (!upcall) {
389 closer = dropArguments(closer, 0, Throwable.class); // (Throwable, V) -> V
390 } else {
391 closer = collectArguments(closer, 0, MH_HANDLE_UNCAUGHT_EXCEPTION); // (Throwable, V) -> V
392 }
393 insertPos = 2;
394 }
395
396 // downcalls get the leading NativeSymbol/SegmentAllocator param as well
397 if (!upcall) {
398 closer = collectArguments(closer, insertPos++, reachabilityFenceHandle(NativeSymbol.class));
399 closer = dropArguments(closer, insertPos++, SegmentAllocator.class); // (Throwable, V?, NativeSymbol, SegmentAllocator) -> V/void
400 }
401
402 closer = collectArguments(closer, insertPos++, MH_CLOSE_CONTEXT); // (Throwable, V?, NativeSymbol?, BindingContext) -> V/void
403
404 MethodHandle contextFactory;
405
406 if (bufferCopySize > 0) {
407 contextFactory = MethodHandles.insertArguments(MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR, 0, bufferCopySize);
408 } else if (upcall) {
409 contextFactory = MH_MAKE_CONTEXT_NO_ALLOCATOR;
410 } else {
411 // this path is probably never used now, since ProgrammableInvoker never calls this routine with bufferCopySize == 0
412 contextFactory = constant(Binding.Context.class, Binding.Context.DUMMY);
413 }
414
415 specializedHandle = tryFinally(specializedHandle, closer);
416 specializedHandle = collectArguments(specializedHandle, allocatorPos, contextFactory);
417 return specializedHandle;
418 }
419
420 @ForceInline
421 @SuppressWarnings("fallthrough")
422 public static void acquire(Scoped[] args) {
423 ResourceScope scope4 = null;
424 ResourceScope scope3 = null;
425 ResourceScope scope2 = null;
426 ResourceScope scope1 = null;
427 ResourceScope scope0 = null;
541 acquireHandle = adapter.apply(acquireHandle);
542 releaseHandle = adapter.apply(releaseHandle);
543 }
544
545 tryBlock = foldArguments(tryBlock, acquireHandle);
546 cleanup = collectArguments(cleanup, hasReturn ? 2 : 1, releaseHandle);
547
548 return tryFinally(tryBlock, cleanup);
549 } else {
550 return downcallHandle;
551 }
552 }
553
554 public static void checkExceptions(MethodHandle target) {
555 Class<?>[] exceptions = JLIA.exceptionTypes(target);
556 if (exceptions != null && exceptions.length != 0) {
557 throw new IllegalArgumentException("Target handle may throw exceptions: " + Arrays.toString(exceptions));
558 }
559 }
560
561 // lazy init MH_ALLOC and MH_FREE handles
562 private static class AllocHolder {
563
564 private static final CLinker SYS_LINKER = getSystemLinker();
565
566 static final MethodHandle MH_MALLOC = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("malloc").get(),
567 FunctionDescriptor.of(ADDRESS, JAVA_LONG));
568
569 static final MethodHandle MH_FREE = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("free").get(),
570 FunctionDescriptor.ofVoid(ADDRESS));
571 }
572
573 public static void checkSymbol(NativeSymbol symbol) {
574 checkAddressable(symbol, "Symbol is NULL");
575 }
576
577 public static void checkAddress(MemoryAddress address) {
578 checkAddressable(address, "Address is NULL");
579 }
580
|
279 }
280
281 public static String toJavaStringInternal(MemorySegment segment, long start) {
282 int len = strlen(segment, start);
283 byte[] bytes = new byte[len];
284 MemorySegment.copy(segment, JAVA_BYTE, start, bytes, 0, len);
285 return new String(bytes, StandardCharsets.UTF_8);
286 }
287
288 private static int strlen(MemorySegment segment, long start) {
289 // iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
290 for (int offset = 0; offset >= 0; offset++) {
291 byte curr = segment.get(JAVA_BYTE, start + offset);
292 if (curr == 0) {
293 return offset;
294 }
295 }
296 throw new IllegalArgumentException("String too large");
297 }
298
299 static Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
300 return IntStream.range(0, moves.length)
301 .boxed()
302 .collect(Collectors.toMap(i -> moves[i].storage(), i -> i));
303 }
304
305 static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) {
306 MethodType oldType = mh.type();
307 Class<?> sourceType = oldType.parameterType(sourceIndex);
308 Class<?> destType = oldType.parameterType(destIndex);
309 if (sourceType != destType) {
310 // TODO meet?
311 throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType);
312 }
313 MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1);
314 int[] reorder = new int[oldType.parameterCount()];
315 if (destIndex < sourceIndex)
316 sourceIndex--;
317 for (int i = 0, index = 0; i < reorder.length; i++) {
318 if (i != destIndex) {
319 reorder[i] = index++;
320 } else {
321 reorder[i] = sourceIndex;
322 }
323 }
324 return permuteArguments(mh, newType, reorder);
325 }
326
327
328 static MethodHandle swapArguments(MethodHandle mh, int firstArg, int secondArg) {
329 MethodType mtype = mh.type();
330 int[] perms = new int[mtype.parameterCount()];
331 MethodType swappedType = MethodType.methodType(mtype.returnType());
332 for (int i = 0 ; i < perms.length ; i++) {
333 int dst = i;
334 if (i == firstArg) dst = secondArg;
335 if (i == secondArg) dst = firstArg;
336 perms[i] = dst;
337 swappedType = swappedType.appendParameterTypes(mtype.parameterType(dst));
338 }
339 return permuteArguments(mh, swappedType, perms);
340 }
341
342 private static MethodHandle reachabilityFenceHandle(Class<?> type) {
343 return MH_REACHBILITY_FENCE.asType(MethodType.methodType(void.class, type));
344 }
345
346 static void handleUncaughtException(Throwable t) {
347 if (t != null) {
348 t.printStackTrace();
349 JLA.exit(1);
350 }
351 }
352
353 static MethodHandle wrapWithAllocator(MethodHandle specializedHandle,
354 int allocatorPos, long allocationSize,
355 boolean upcall) {
356 // insert try-finally to close the NativeScope used for Binding.Copy
357 MethodHandle closer;
358 int insertPos;
359 if (specializedHandle.type().returnType() == void.class) {
360 if (!upcall) {
361 closer = empty(methodType(void.class, Throwable.class)); // (Throwable) -> void
362 } else {
363 closer = MH_HANDLE_UNCAUGHT_EXCEPTION;
364 }
365 insertPos = 1;
366 } else {
367 closer = identity(specializedHandle.type().returnType()); // (V) -> V
368 if (!upcall) {
369 closer = dropArguments(closer, 0, Throwable.class); // (Throwable, V) -> V
370 } else {
371 closer = collectArguments(closer, 0, MH_HANDLE_UNCAUGHT_EXCEPTION); // (Throwable, V) -> V
372 }
373 insertPos = 2;
374 }
375
376 // downcalls get the leading SegmentAllocator param as well
377 if (!upcall) {
378 closer = dropArguments(closer, insertPos++, SegmentAllocator.class); // (Throwable, V?, SegmentAllocator, NativeSymbol) -> V/void
379 }
380
381 closer = collectArguments(closer, insertPos, MH_CLOSE_CONTEXT); // (Throwable, V?, SegmentAllocator?, BindingContext) -> V/void
382
383 MethodHandle contextFactory;
384
385 if (allocationSize > 0) {
386 contextFactory = MethodHandles.insertArguments(MH_MAKE_CONTEXT_BOUNDED_ALLOCATOR, 0, allocationSize);
387 } else if (upcall) {
388 contextFactory = MH_MAKE_CONTEXT_NO_ALLOCATOR;
389 } else {
390 // this path is probably never used now, since ProgrammableInvoker never calls this routine with bufferCopySize == 0
391 contextFactory = constant(Binding.Context.class, Binding.Context.DUMMY);
392 }
393
394 specializedHandle = tryFinally(specializedHandle, closer);
395 specializedHandle = collectArguments(specializedHandle, allocatorPos, contextFactory);
396 return specializedHandle;
397 }
398
399 @ForceInline
400 @SuppressWarnings("fallthrough")
401 public static void acquire(Scoped[] args) {
402 ResourceScope scope4 = null;
403 ResourceScope scope3 = null;
404 ResourceScope scope2 = null;
405 ResourceScope scope1 = null;
406 ResourceScope scope0 = null;
520 acquireHandle = adapter.apply(acquireHandle);
521 releaseHandle = adapter.apply(releaseHandle);
522 }
523
524 tryBlock = foldArguments(tryBlock, acquireHandle);
525 cleanup = collectArguments(cleanup, hasReturn ? 2 : 1, releaseHandle);
526
527 return tryFinally(tryBlock, cleanup);
528 } else {
529 return downcallHandle;
530 }
531 }
532
533 public static void checkExceptions(MethodHandle target) {
534 Class<?>[] exceptions = JLIA.exceptionTypes(target);
535 if (exceptions != null && exceptions.length != 0) {
536 throw new IllegalArgumentException("Target handle may throw exceptions: " + Arrays.toString(exceptions));
537 }
538 }
539
540 public static MethodHandle maybeInsertAllocator(MethodHandle handle) {
541 if (!handle.type().returnType().equals(MemorySegment.class)) {
542 // not returning segment, just insert a throwing allocator
543 handle = insertArguments(handle, 1, THROWING_ALLOCATOR);
544 }
545 return handle;
546 }
547
548 // lazy init MH_ALLOC and MH_FREE handles
549 private static class AllocHolder {
550
551 private static final CLinker SYS_LINKER = getSystemLinker();
552
553 static final MethodHandle MH_MALLOC = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("malloc").get(),
554 FunctionDescriptor.of(ADDRESS, JAVA_LONG));
555
556 static final MethodHandle MH_FREE = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("free").get(),
557 FunctionDescriptor.ofVoid(ADDRESS));
558 }
559
560 public static void checkSymbol(NativeSymbol symbol) {
561 checkAddressable(symbol, "Symbol is NULL");
562 }
563
564 public static void checkAddress(MemoryAddress address) {
565 checkAddressable(address, "Address is NULL");
566 }
567
|