com.oracle.svm.jni.hosted.JNIPrimitiveArrayOperationMethod Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of library-support Show documentation
Show all versions of library-support Show documentation
SubstrateVM basic library-support components
/*
* Copyright (c) 2017, 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.svm.jni.hosted;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.java.FrameStateBuilder;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.ValuePhiNode;
import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
import org.graalvm.compiler.nodes.java.NewArrayNode;
import org.graalvm.nativeimage.c.function.CEntryPoint.FatalExceptionHandler;
import org.graalvm.nativeimage.c.type.CIntPointer;
import org.graalvm.nativeimage.c.type.WordPointer;
import com.oracle.graal.pointsto.meta.HostedProviders;
import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue;
import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue;
import com.oracle.svm.core.c.function.CEntryPointOptions.Publish;
import com.oracle.svm.core.graal.nodes.CEntryPointEnterNode;
import com.oracle.svm.core.graal.nodes.CEntryPointEnterNode.EnterAction;
import com.oracle.svm.core.graal.nodes.CEntryPointLeaveNode;
import com.oracle.svm.core.graal.nodes.CEntryPointLeaveNode.LeaveAction;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.code.CEntryPointData;
import com.oracle.svm.jni.nativeapi.JNIEnvironment;
import com.oracle.svm.jni.nativeapi.JNIObjectHandle;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
/**
* Generated method for operations on an array with a primitive element type via JNI. An accessor is
* specific to the {@link JavaKind element kind} of the array, and to an {@link Operation}.
*/
public final class JNIPrimitiveArrayOperationMethod extends JNIGeneratedMethod {
public enum Operation {
NEW,
GET_ELEMENTS,
RELEASE_ELEMENTS,
GET_REGION,
SET_REGION,
}
private final JavaKind elementKind;
private final Operation operation;
private final ResolvedJavaType declaringClass;
private final ConstantPool constantPool;
private final String name;
private final Signature signature;
public JNIPrimitiveArrayOperationMethod(JavaKind elementKind, Operation operation, ResolvedJavaType declaringClass, ConstantPool constantPool, MetaAccessProvider metaAccess) {
if (!EnumSet.of(JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short,
JavaKind.Int, JavaKind.Long, JavaKind.Float, JavaKind.Double).contains(elementKind)) {
throw VMError.shouldNotReachHere();
}
this.elementKind = elementKind;
this.operation = operation;
this.declaringClass = declaringClass;
this.constantPool = constantPool;
this.name = createName();
this.signature = createSignature(metaAccess);
}
private String createName() {
StringBuilder sb = new StringBuilder(32);
String kindName = elementKind.name();
switch (operation) {
case NEW:
sb.append("New").append(kindName).append("Array");
break;
case GET_ELEMENTS:
sb.append("Get").append(kindName).append("ArrayElements");
break;
case RELEASE_ELEMENTS:
sb.append("Release").append(kindName).append("ArrayElements");
break;
case GET_REGION:
sb.append("Get").append(kindName).append("ArrayRegion");
break;
case SET_REGION:
sb.append("Set").append(kindName).append("ArrayRegion");
break;
}
return sb.toString();
}
private JNISignature createSignature(MetaAccessProvider metaAccess) {
ResolvedJavaType objectHandleType = metaAccess.lookupJavaType(JNIObjectHandle.class);
ResolvedJavaType intType = metaAccess.lookupJavaType(int.class);
ResolvedJavaType returnType;
List args = new ArrayList<>();
args.add(metaAccess.lookupJavaType(JNIEnvironment.class));
if (operation == Operation.NEW) {
args.add(intType); // jsize length;
returnType = objectHandleType;
} else {
args.add(objectHandleType); // jArray array;
if (operation == Operation.GET_ELEMENTS) {
args.add(metaAccess.lookupJavaType(CIntPointer.class)); // jboolean *isCopy;
returnType = metaAccess.lookupJavaType(WordPointer.class);
} else if (operation == Operation.RELEASE_ELEMENTS) {
args.add(metaAccess.lookupJavaType(WordPointer.class)); // NativeType *elems;
args.add(intType); // jint mode;
returnType = metaAccess.lookupJavaType(Void.TYPE);
} else if (operation == Operation.GET_REGION || operation == Operation.SET_REGION) {
args.add(intType); // jsize start;
args.add(intType); // jsize len;
args.add(metaAccess.lookupJavaType(WordPointer.class)); // NativeType *buf;
returnType = metaAccess.lookupJavaType(Void.TYPE);
} else {
throw VMError.shouldNotReachHere();
}
}
return new JNISignature(args, returnType);
}
@Override
public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) {
JNIGraphKit kit = new JNIGraphKit(debug, providers, method);
StructuredGraph graph = kit.getGraph();
FrameStateBuilder state = new FrameStateBuilder(null, method, graph);
state.initializeForMethodStart(null, true, providers.getGraphBuilderPlugins());
ValueNode vmThread = kit.loadLocal(0, signature.getParameterKind(0));
kit.append(new CEntryPointEnterNode(EnterAction.Enter, vmThread));
List arguments = kit.loadArguments(signature.toParameterTypes(null));
ValueNode result = null;
switch (operation) {
case NEW:
result = newArray(providers, kit, arguments);
break;
case GET_ELEMENTS: {
ValueNode arrayHandle = arguments.get(1);
ValueNode array = kit.unboxHandle(arrayHandle);
ValueNode isCopy = arguments.get(2);
result = kit.pinArrayAndGetAddress(array, isCopy);
break;
}
case RELEASE_ELEMENTS: {
ValueNode address = arguments.get(2);
kit.unpinArrayByAddress(address);
break;
}
case GET_REGION:
case SET_REGION: {
ValueNode arrayHandle = arguments.get(1);
ValueNode array = kit.unboxHandle(arrayHandle);
ValueNode start = arguments.get(2);
ValueNode count = arguments.get(3);
ValueNode buffer = arguments.get(4);
if (operation == Operation.GET_REGION) {
kit.getPrimitiveArrayRegionRetainException(elementKind, array, start, count, buffer);
} else {
kit.setPrimitiveArrayRegionRetainException(elementKind, array, start, count, buffer);
}
break;
}
default:
throw VMError.shouldNotReachHere();
}
kit.append(new CEntryPointLeaveNode(LeaveAction.Leave));
kit.createReturn(result, (result != null) ? result.getStackKind() : JavaKind.Void);
assert graph.verify();
return graph;
}
private ValueNode newArray(HostedProviders providers, JNIGraphKit kit, List arguments) {
ResolvedJavaType elementType = providers.getMetaAccess().lookupJavaType(elementKind.toJavaClass());
ValueNode length = arguments.get(1);
ConstantNode zero = kit.createInt(0);
kit.startIf(new IntegerLessThanNode(length, zero), BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY);
kit.thenPart();
ValueNode nullHandle = kit.createConstant(JavaConstant.INT_0, providers.getWordTypes().getWordKind());
kit.elsePart();
ValueNode array = kit.append(new NewArrayNode(elementType, length, true));
ValueNode arrayHandle = kit.boxObjectInLocalHandle(array);
AbstractMergeNode merge = kit.endIf();
Stamp handleStamp = providers.getWordTypes().getWordStamp(providers.getMetaAccess().lookupJavaType(JNIObjectHandle.class));
return kit.unique(new ValuePhiNode(handleStamp, merge, new ValueNode[]{nullHandle, arrayHandle}));
}
@Override
public String getName() {
return name;
}
@Override
public Signature getSignature() {
return signature;
}
@Override
public ResolvedJavaType getDeclaringClass() {
return declaringClass;
}
@Override
public ConstantPool getConstantPool() {
return constantPool;
}
public CEntryPointData createEntryPointData() {
return CEntryPointData.create(this, CEntryPointData.DEFAULT_NAME, CEntryPointData.DEFAULT_NAME_TRANSFORMATION, "",
NoPrologue.class, NoEpilogue.class, FatalExceptionHandler.class, Publish.NotPublished);
}
}