001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.nfi.test; 024 025import static java.io.File.*; 026import static java.lang.System.*; 027import static jdk.internal.jvmci.common.UnsafeAccess.*; 028import static org.junit.Assert.*; 029import static org.junit.Assume.*; 030 031import java.io.*; 032import java.util.*; 033 034import org.junit.*; 035 036import com.oracle.nfi.*; 037import com.oracle.nfi.api.*; 038 039public class NativeFunctionInterfaceTest { 040 041 public final NativeFunctionInterface nfi; 042 043 public NativeFunctionInterfaceTest() { 044 nfi = NativeFunctionInterfaceRuntime.getNativeFunctionInterface(); 045 } 046 047 private List<Long> allocations = new ArrayList<>(); 048 049 protected long malloc(int length) { 050 long buf = unsafe.allocateMemory(length); 051 allocations.add(buf); 052 return buf; 053 } 054 055 @Before 056 public void setUp() { 057 // Ignore on SPARC 058 Assume.assumeFalse(System.getProperty("os.arch").toUpperCase().contains("SPARC")); 059 } 060 061 @After 062 public void cleanup() { 063 for (long buf : allocations) { 064 unsafe.freeMemory(buf); 065 } 066 } 067 068 private static void assertCStringEquals(long cString, String s) { 069 for (int i = 0; i < s.length(); i++) { 070 assertEquals(unsafe.getByte(cString + i) & 0xFF, (byte) s.charAt(i)); 071 } 072 assertEquals(unsafe.getByte(cString + s.length()) & 0xFF, (byte) '\0'); 073 } 074 075 @Test 076 public void test1() { 077 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 078 NativeFunctionHandle malloc = nfi.getFunctionHandle("malloc", long.class, int.class); 079 NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class); 080 NativeFunctionHandle free = nfi.getFunctionHandle("free", void.class, long.class); 081 082 String string = "GRAAL"; 083 int bufferLength = string.length() + 1; 084 long cString = (long) malloc.call(bufferLength); 085 writeCString(string, cString); 086 087 long cStringCopy = malloc(bufferLength); 088 int result = (int) snprintf.call(cStringCopy, bufferLength, cString); 089 Assert.assertEquals(string.length(), result); 090 assertCStringEquals(cString, string); 091 assertCStringEquals(cStringCopy, string); 092 093 free.call(cString); 094 } 095 096 @Test 097 public void test2() { 098 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 099 String formatString = "AB %f%f"; 100 long formatCString = writeCString("AB %f%f", malloc(formatString.length() + 1)); 101 102 String referenceString = "AB 1.0000001.000000"; 103 int bufferLength = referenceString.length() + 1; 104 long buffer = malloc(bufferLength); 105 106 NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, double.class, double.class); 107 int result = (int) snprintf.call(buffer, bufferLength, formatCString, 1.0D, 1.0D); 108 109 assertCStringEquals(buffer, referenceString); 110 Assert.assertEquals(referenceString.length(), result); 111 } 112 113 @Test 114 public void test3() { 115 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 116 String format = "%i%i%i%i%i%i%i%i%i%i%i%i"; 117 long formatCString = writeCString(format, malloc(format.length() + 1)); 118 String referenceString = "01234567891011"; 119 120 int bufferLength = referenceString.length() + 1; 121 long buffer = malloc(bufferLength); 122 123 NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class, 124 int.class, int.class, int.class, int.class, int.class); 125 126 int result = (int) snprintf.call(buffer, bufferLength, formatCString, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); 127 assertCStringEquals(buffer, referenceString); 128 Assert.assertEquals(referenceString.length(), result); 129 } 130 131 @Test 132 public void test4() { 133 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 134 long str = malloc(49); 135 int[] val = new int[12]; 136 for (int i = 0; i < 12; i++) { 137 unsafe.putByte(str + 2 * i, (byte) '%'); 138 unsafe.putByte(str + 2 * i + 1, (byte) 'i'); 139 val[i] = i; 140 } 141 double[] dval = new double[12]; 142 for (int i = 12; i < 24; i++) { 143 unsafe.putByte(str + 2 * i, (byte) '%'); 144 unsafe.putByte(str + 2 * i + 1, (byte) 'f'); 145 dval[i - 12] = i + 0.5; 146 } 147 unsafe.putByte(str + 48, (byte) '\0'); 148 149 String referenceString = "0123456789101112.50000013.50000014.50000015.50000016.50000017.50000018.50000019.50000020.500000" + "21.50000022.50000023.500000"; 150 int bufferLength = referenceString.length() + 1; 151 152 long buffer = malloc(bufferLength); 153 154 NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class, 155 int.class, int.class, int.class, int.class, int.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, 156 double.class, double.class, double.class, double.class); 157 158 int result = (int) snprintf.call(buffer, bufferLength, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], dval[0], dval[1], dval[2], 159 dval[3], dval[4], dval[5], dval[6], dval[7], dval[8], dval[9], dval[10], dval[11]); 160 assertCStringEquals(buffer, referenceString); 161 Assert.assertEquals(referenceString.length(), result); 162 } 163 164 @Test 165 public void test5() { 166 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 167 long str = malloc(73); 168 int[] val = new int[12]; 169 for (int i = 0; i < 12; i++) { 170 unsafe.putByte(str + 2 * i, (byte) '%'); 171 unsafe.putByte(str + 2 * i + 1, (byte) 'i'); 172 val[i] = i; 173 } 174 double[] dval = new double[12]; 175 for (int i = 12; i < 24; i++) { 176 unsafe.putByte(str + 2 * i, (byte) '%'); 177 unsafe.putByte(str + 2 * i + 1, (byte) 'f'); 178 dval[i - 12] = i + 0.5; 179 } 180 char[] cval = new char[12]; 181 for (int i = 24; i < 36; i++) { 182 unsafe.putByte(str + 2 * i, (byte) '%'); 183 unsafe.putByte(str + 2 * i + 1, (byte) 'c'); 184 cval[i - 24] = (char) ('a' + (i - 24)); 185 } 186 unsafe.putByte(str + 72, (byte) '\0'); 187 188 String referenceString = "0123456789101112.50000013.50000014.50000015.50000016.50000017.50000018.50000019.50000020.50000021.50000022.50000023.500000abcdefghijkl"; 189 int bufferLength = referenceString.length() + 1; 190 191 long buffer = malloc(bufferLength); 192 193 NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class, 194 int.class, int.class, int.class, int.class, int.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, 195 double.class, double.class, double.class, double.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, 196 char.class, char.class); 197 198 int result = (int) snprintf.call(buffer, bufferLength, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], dval[0], dval[1], dval[2], 199 dval[3], dval[4], dval[5], dval[6], dval[7], dval[8], dval[9], dval[10], dval[11], cval[0], cval[1], cval[2], cval[3], cval[4], cval[5], cval[6], cval[7], cval[8], cval[9], 200 cval[10], cval[11]); 201 assertCStringEquals(buffer, referenceString); 202 Assert.assertEquals(referenceString.length(), result); 203 } 204 205 @Test 206 public void test6() { 207 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 208 NativeFunctionHandle handle = nfi.getFunctionHandle("pow", double.class, double.class, double.class); 209 double result = (double) handle.call(3D, 5.5D); 210 assertEquals(Math.pow(3D, 5.5D), result, 0); 211 } 212 213 @Test 214 public void test7() { 215 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 216 double result = 0; 217 NativeFunctionHandle handle = nfi.getFunctionHandle("pow", double.class, double.class, double.class); 218 for (int i = 0; i < 10; i++) { 219 result = (double) handle.call(3D, 5.5D); 220 } 221 assertEquals(Math.pow(3D, 5.5D), result, 0); 222 } 223 224 @Test 225 public void test8() { 226 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 227 String formatString = "AB %f%f"; 228 long formatCString = writeCString("AB %f%f", malloc(formatString.length() + 1)); 229 230 String expected = "AB 1.0000001.000000"; 231 int bufferLength = expected.length() + 1; 232 byte[] buffer = new byte[bufferLength]; 233 234 NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, byte[].class, int.class, long.class, double.class, double.class); 235 int result = (int) snprintf.call(buffer, bufferLength, formatCString, 1.0D, 1.0D); 236 237 // trim trailing '\0' 238 String actual = new String(buffer, 0, expected.length()); 239 240 assertEquals(expected, actual); 241 Assert.assertEquals(expected.length(), result); 242 } 243 244 private static double[] someDoubles = {2454.346D, 98789.22D, Double.MAX_VALUE, Double.MIN_NORMAL, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}; 245 246 @Test 247 public void test9() { 248 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 249 double[] src = someDoubles.clone(); 250 double[] dst = new double[src.length]; 251 252 NativeFunctionHandle memcpy = nfi.getFunctionHandle("memcpy", void.class, double[].class, double[].class, int.class); 253 memcpy.call(dst, src, src.length * (Double.SIZE / Byte.SIZE)); 254 255 assertArrayEquals(src, dst, 0.0D); 256 } 257 258 private static String getVMName() { 259 String vmName = System.getProperty("java.vm.name").toLowerCase(); 260 String vm = null; 261 if (vmName.contains("server")) { 262 vm = "server"; 263 } else if (vmName.contains("graal")) { 264 vm = "graal"; 265 } else if (vmName.contains("client")) { 266 vm = "client"; 267 } 268 269 Assume.assumeTrue(vm != null); 270 return vm; 271 } 272 273 private static String getVMLibPath() { 274 String vm = getVMName(); 275 276 String path = String.format("%s%c%s%c%s", getProperty("sun.boot.library.path"), separatorChar, vm, separatorChar, mapLibraryName("jvm")); 277 // Only continue if the library file exists 278 Assume.assumeTrue(new File(path).exists()); 279 return path; 280 } 281 282 @Test 283 public void test10() { 284 NativeLibraryHandle vmLib = nfi.getLibraryHandle(getVMLibPath()); 285 NativeFunctionHandle currentTimeMillis = nfi.getFunctionHandle(vmLib, "JVM_CurrentTimeMillis", long.class); 286 long time1 = (long) currentTimeMillis.call(); 287 long time2 = System.currentTimeMillis(); 288 long delta = time2 - time1; 289 290 // The 2 calls to get the current time should not differ by more than 291 // 100 milliseconds at the very most 292 assertTrue(String.valueOf(delta), delta >= 0); 293 assertTrue(String.valueOf(delta), delta < 100); 294 } 295 296 private static String getJavaLibPath() { 297 String path = String.format("%s%c%s", getProperty("sun.boot.library.path"), separatorChar, mapLibraryName("java")); 298 Assume.assumeTrue(new File(path).exists()); 299 return path; 300 } 301 302 private static void testD2L(NativeFunctionHandle d2l) { 303 for (double d : someDoubles) { 304 long expected = Double.doubleToRawLongBits(d); 305 long actual = (long) d2l.call(0L, 0L, d); 306 assertEquals(Double.toString(d), expected, actual); 307 } 308 } 309 310 @Test 311 public void test11() { 312 NativeLibraryHandle javaLib = nfi.getLibraryHandle(getJavaLibPath()); 313 NativeFunctionHandle d2l = nfi.getFunctionHandle(javaLib, "Java_java_lang_Double_doubleToRawLongBits", long.class, long.class, long.class, double.class); 314 testD2L(d2l); 315 } 316 317 @Test 318 public void test12() { 319 NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; 320 NativeFunctionHandle d2l = nfi.getFunctionHandle(libs, "Java_java_lang_Double_doubleToRawLongBits", long.class, long.class, long.class, double.class); 321 testD2L(d2l); 322 323 NativeLibraryHandle[] libsReveresed = {libs[1], libs[0]}; 324 d2l = nfi.getFunctionHandle(libsReveresed, "Java_java_lang_Double_doubleToRawLongBits", long.class, long.class, long.class, double.class); 325 testD2L(d2l); 326 } 327 328 @Test 329 public void test13() { 330 NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; 331 NativeFunctionPointer functionPointer = nfi.getFunctionPointer(libs, "Java_java_lang_Double_doubleToRawLongBits"); 332 NativeFunctionHandle d2l = nfi.getFunctionHandle(functionPointer, long.class, long.class, long.class, double.class); 333 testD2L(d2l); 334 335 NativeLibraryHandle[] libsReveresed = {libs[1], libs[0]}; 336 functionPointer = nfi.getFunctionPointer(libsReveresed, "Java_java_lang_Double_doubleToRawLongBits"); 337 d2l = nfi.getFunctionHandle(functionPointer, long.class, long.class, long.class, double.class); 338 testD2L(d2l); 339 } 340 341 @Test 342 public void test14() { 343 if (!nfi.isDefaultLibrarySearchSupported()) { 344 try { 345 nfi.getFunctionHandle("snprintf", int.class); 346 fail(); 347 } catch (UnsatisfiedLinkError e) { 348 } 349 } 350 } 351 352 @Test 353 public void test15() { 354 assumeTrue(nfi.isDefaultLibrarySearchSupported()); 355 NativeFunctionHandle functionHandle = nfi.getFunctionHandle("an invalid function name", int.class); 356 if (functionHandle != null) { 357 fail(); 358 } 359 } 360 361 @Test 362 public void test16() { 363 NativeLibraryHandle javaLib = nfi.getLibraryHandle(getJavaLibPath()); 364 NativeFunctionHandle functionHandle = nfi.getFunctionHandle(javaLib, "an invalid function name", int.class); 365 if (functionHandle != null) { 366 fail(); 367 } 368 } 369 370 @Test 371 public void test17() { 372 NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; 373 NativeFunctionHandle functionHandle = nfi.getFunctionHandle(libs, "an invalid function name", int.class); 374 if (functionHandle != null) { 375 fail(); 376 } 377 } 378 379 @Test 380 public void test18() { 381 NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; 382 NativeFunctionHandle functionHandle = nfi.getFunctionHandle(libs, "an invalid function name", int.class); 383 if (functionHandle != null) { 384 fail(); 385 } 386 } 387 388 @Test 389 public void test19() { 390 NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; 391 NativeFunctionPointer functionPointer = nfi.getFunctionPointer(libs, "an invalid function name"); 392 if (functionPointer != null) { 393 fail(); 394 } 395 } 396 397 @Test 398 public void test20() { 399 try { 400 nfi.getLibraryHandle("an invalid library name"); 401 fail(); 402 } catch (UnsatisfiedLinkError e) { 403 } 404 } 405 406}