/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.truffle.nfi.test; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.nfi.types.NativeSimpleType; import com.oracle.truffle.tck.TruffleRunner; import com.oracle.truffle.tck.TruffleRunner.Inject; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) @Parameterized.UseParametersRunnerFactory(TruffleRunner.ParametersFactory.class) public class ArrayNFITest extends NFITest { @Parameters(name = "{0}, {1}") public static Collection<Object[]> data() { ArrayList<Object[]> ret = new ArrayList<>(); ret.add(new Object[]{NativeSimpleType.UINT8, boolean.class}); ret.add(new Object[]{NativeSimpleType.UINT8, byte.class}); ret.add(new Object[]{NativeSimpleType.SINT8, boolean.class}); ret.add(new Object[]{NativeSimpleType.SINT8, byte.class}); ret.add(new Object[]{NativeSimpleType.UINT16, short.class}); ret.add(new Object[]{NativeSimpleType.UINT16, char.class}); ret.add(new Object[]{NativeSimpleType.SINT16, short.class}); ret.add(new Object[]{NativeSimpleType.SINT16, char.class}); ret.add(new Object[]{NativeSimpleType.UINT32, int.class}); ret.add(new Object[]{NativeSimpleType.SINT32, int.class}); ret.add(new Object[]{NativeSimpleType.UINT64, long.class}); ret.add(new Object[]{NativeSimpleType.SINT64, long.class}); ret.add(new Object[]{NativeSimpleType.FLOAT, float.class}); ret.add(new Object[]{NativeSimpleType.DOUBLE, double.class}); return ret; } @Parameter(0) public NativeSimpleType nativeType; @Parameter(1) public Class<?> javaType; public class CreateAndSumArray extends NFITestRootNode { private final Class<?> finalJavaType; private final TruffleObject store; private final TruffleObject sum; @Child Node executeStore = Message.createExecute(3).createNode(); @Child Node executeSum = Message.createExecute(2).createNode(); public CreateAndSumArray() { this.finalJavaType = javaType; this.store = lookupAndBind("store_" + nativeType, String.format("([%s], uint32, %s) : void", nativeType, nativeType)); this.sum = lookupAndBind("sum_" + nativeType, String.format("([%s], uint32) : %s", nativeType, nativeType)); } @TruffleBoundary private void verifyArray(Object array) { int length = Array.getLength(array); for (int i = 0; i < length; i++) { Object elem = Array.get(array, i); Assert.assertThat("array element", elem, is(instanceOf(finalJavaType))); long actual = 0; long expected = i + 1; if (elem instanceof Number) { actual = ((Number) elem).longValue(); } else if (elem instanceof Character) { actual = (Character) elem; } else if (elem instanceof Boolean) { /* * The conversion from native byte to Java boolean is undefined and may be * different on different VM versions. */ return; } Assert.assertEquals("array element", expected, actual); } } @Override public Object executeTest(VirtualFrame frame) { int arrayLength = (Integer) frame.getArguments()[0]; Object array = Array.newInstance(finalJavaType, arrayLength); TruffleObject wrappedArray = JavaInterop.asTruffleObject(array); try { for (int i = 0; i < arrayLength; i++) { ForeignAccess.sendExecute(executeStore, store, wrappedArray, i, i + 1); } verifyArray(array); return ForeignAccess.sendExecute(executeSum, sum, wrappedArray, arrayLength); } catch (InteropException ex) { throw new AssertionError(ex); } } } @Test public void testSumArray(@Inject(CreateAndSumArray.class) CallTarget callTarget) { int arrayLength = 5; Object ret = callTarget.call(arrayLength); Assert.assertThat("return value", ret, is(instanceOf(Number.class))); Assert.assertEquals("return value", arrayLength * (arrayLength + 1) / 2, ((Number) ret).intValue()); } }