All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.svm.jni.hosted.JNIPrimitiveArrayOperationMethod Maven / Gradle / Ivy

There is a newer version: 19.2.1
Show newest version
/*
 * 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.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.hosted.code.SimpleSignature;
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 SimpleSignature 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 SimpleSignature(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(CEntryPointEnterNode.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);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy