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

org.truffleruby.cext.ValueWrapper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2018, 2024 Oracle and/or its affiliates. All rights reserved. This
 * code is released under a tri EPL/GPL/LGPL license. You can use it,
 * redistribute it and/or modify it under the terms of the:
 *
 * Eclipse Public License version 2.0, or
 * GNU General Public License version 2, or
 * GNU Lesser General Public License version 2.1.
 */
package org.truffleruby.cext;

import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
import org.truffleruby.RubyLanguage;
import org.truffleruby.cext.ValueWrapperManager.AllocateHandleNode;
import org.truffleruby.cext.ValueWrapperManager.HandleBlock;
import org.truffleruby.core.MarkingServiceNodes.KeepAliveNode;
import org.truffleruby.debug.VariableNamesObject;
import org.truffleruby.interop.TranslateInteropExceptionNode;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Exclusive;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;

/** This object represents a VALUE in C which wraps the raw Ruby object. This allows foreign access methods to be set up
 * which convert these value wrappers to native pointers without affecting the semantics of the wrapped objects. */
@ExportLibrary(InteropLibrary.class)
public final class ValueWrapper implements TruffleObject {

    private final Object object;
    private volatile long handle;
    @SuppressWarnings("unused")
    // The handleBlock is held here to stop it being GCed and the memory freed while wrappers still
    // exist with handles in it.
    private volatile HandleBlock handleBlock;

    public ValueWrapper(Object object, long handle, HandleBlock handleBlock) {
        this.object = object;
        this.handle = handle;
        this.handleBlock = handleBlock;
    }

    public Object getObject() {
        return object;
    }

    public long getHandle() {
        return handle;
    }

    public void setHandle(long handle, HandleBlock handleBlock) {
        this.handle = handle;
        this.handleBlock = handleBlock;
    }

    @ExportMessage
    protected boolean hasLanguage() {
        return true;
    }

    @ExportMessage
    protected Class getLanguage() {
        return RubyLanguage.class;
    }

    @TruffleBoundary
    @Override
    public String toString() {
        if (object != null) {
            return "ValueWrapper[" + object + "]";
        } else {
            assert ValueWrapperManager.isTaggedLong(handle);
            return "ValueWrapper[" + ValueWrapperManager.untagTaggedLong(handle) + "]";
        }
    }

    @TruffleBoundary
    @ExportMessage
    protected String toDisplayString(boolean allowSideEffects) {
        if (object != null) {
            final InteropLibrary interop = InteropLibrary.getUncached();
            try {
                return "VALUE: " + interop.asString(interop.toDisplayString(object, allowSideEffects));
            } catch (UnsupportedMessageException e) {
                throw TranslateInteropExceptionNode.executeUncached(e);
            }
        } else {
            return "VALUE: " + this;
        }
    }

    @ExportMessage
    protected boolean isPointer() {
        return handle != ValueWrapperManager.UNSET_HANDLE;
    }

    @ExportMessage
    static void toNative(ValueWrapper wrapper,
            @Cached AllocateHandleNode createNativeHandleNode,
            @Cached @Exclusive InlinedBranchProfile createHandleProfile,
            @Bind("$node") Node node) {
        if (!wrapper.isPointer()) {
            createHandleProfile.enter(node);
            createNativeHandleNode.execute(node, wrapper);
        }
    }

    @ExportMessage
    static long asPointer(ValueWrapper wrapper,
            @Cached KeepAliveNode keepAliveNode,
            @Cached @Exclusive InlinedBranchProfile taggedObjectProfile,
            @Bind("$node") Node node) {
        long handle = wrapper.getHandle();
        assert handle != ValueWrapperManager.UNSET_HANDLE;

        if (ValueWrapperManager.isTaggedObject(handle)) {
            taggedObjectProfile.enter(node);

            keepAliveNode.execute(node, wrapper);
        }

        return handle;
    }

    @ExportMessage
    protected boolean hasMembers() {
        return true;
    }

    @ExportMessage
    protected Object getMembers(boolean includeInternal) {
        return new VariableNamesObject(new String[]{ "value" });
    }

    @ExportMessage
    protected boolean isMemberReadable(String member) {
        return "value".equals(member);
    }

    @ExportMessage
    static Object readMember(ValueWrapper wrapper, String member,
            @Cached @Exclusive InlinedBranchProfile errorProfile,
            @Bind("$node") Node node) throws UnknownIdentifierException {
        if ("value".equals(member)) {
            if (wrapper.object != null) {
                return wrapper.object;
            } else {
                return ValueWrapperManager.untagTaggedLong(wrapper.handle);
            }
        } else {
            errorProfile.enter(node);
            throw UnknownIdentifierException.create(member);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy