org.truffleruby.extra.TruffleRubyNodes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ruby-language Show documentation
Show all versions of ruby-language Show documentation
Core module of Ruby on Truffle
The newest version!
/*
* Copyright (c) 2013, 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.extra;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.GenerateCached;
import com.oracle.truffle.api.dsl.GenerateInline;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObjectLibrary;
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
import com.oracle.truffle.api.strings.TruffleString;
import org.truffleruby.Layouts;
import org.truffleruby.RubyContext;
import org.truffleruby.RubyLanguage;
import org.truffleruby.annotations.CoreMethod;
import org.truffleruby.annotations.Split;
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
import org.truffleruby.builtins.CoreMethodNode;
import org.truffleruby.annotations.CoreModule;
import org.truffleruby.core.encoding.Encodings;
import org.truffleruby.core.mutex.MutexOperations;
import org.truffleruby.core.proc.RubyProc;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleOptions;
import com.oracle.truffle.api.dsl.Specialization;
import org.truffleruby.language.RubyBaseNode;
import org.truffleruby.language.RubyDynamicObject;
import org.truffleruby.language.yield.CallBlockNode;
import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.ReentrantLock;
@CoreModule("TruffleRuby")
public abstract class TruffleRubyNodes {
@CoreMethod(names = "graalvm_home", onSingleton = true)
public abstract static class GraalvmHomeNode extends CoreMethodArrayArgumentsNode {
@Specialization
Object graalvmHome(
@Cached TruffleString.FromJavaStringNode fromJavaStringNode) {
String value = getProperty("org.graalvm.home");
if (value == null) {
return nil;
} else {
return createString(fromJavaStringNode, value, Encodings.UTF_8);
}
}
@TruffleBoundary
private static String getProperty(String key) {
return System.getProperty(key);
}
}
@CoreMethod(names = "jit?", onSingleton = true)
public abstract static class GraalNode extends CoreMethodArrayArgumentsNode {
@TruffleBoundary
@Specialization
static boolean isGraal() {
return Truffle.getRuntime().getName().contains("Graal");
}
}
@CoreMethod(names = "native?", onSingleton = true)
public abstract static class NativeNode extends CoreMethodArrayArgumentsNode {
@Specialization
boolean isNative() {
return TruffleOptions.AOT;
}
}
@CoreMethod(names = "cexts?", onSingleton = true)
public abstract static class SulongNode extends CoreMethodArrayArgumentsNode {
@Specialization
boolean isSulong() {
return isSulongAvailable(getContext());
}
@TruffleBoundary
public static boolean isSulongAvailable(RubyContext context) {
return context.getEnv().isMimeTypeSupported(RubyLanguage.LLVM_BITCODE_MIME_TYPE);
}
}
@CoreMethod(names = "full_memory_barrier", onSingleton = true)
public abstract static class FullMemoryBarrierPrimitiveNode extends CoreMethodNode {
@Specialization
Object fullMemoryBarrier() {
VarHandle.fullFence();
return nil;
}
}
@CoreMethod(names = "synchronized", onSingleton = true, required = 1, needsBlock = true, split = Split.ALWAYS)
public abstract static class SynchronizedNode extends CoreMethodArrayArgumentsNode {
/** We must not allow to synchronize on boxed primitives as that would be misleading. We use a ReentrantLock and
* not simply Java's {@code synchronized} here as we need to be able to interrupt for guest safepoints and it is
* not possible to interrupt Java's {@code synchronized (object) {}}. */
@Specialization
static Object synchronize(RubyDynamicObject object, RubyProc block,
@Cached GetLockNode getLockNode,
@Cached CallBlockNode yieldNode,
@Bind("this") Node node) {
final ReentrantLock lock = getLockNode.execute(node, object);
MutexOperations.lockInternal(getContext(node), lock, node);
try {
return yieldNode.yield(node, block);
} finally {
MutexOperations.unlockInternal(lock);
}
}
}
@GenerateInline
@GenerateCached(false)
public abstract static class GetLockNode extends RubyBaseNode {
public abstract ReentrantLock execute(Node node, RubyDynamicObject object);
@Specialization(limit = "getDynamicObjectCacheLimit()")
static ReentrantLock getLock(Node node, RubyDynamicObject object,
@CachedLibrary("object") DynamicObjectLibrary objectLibrary,
@Cached InlinedBranchProfile initializeLockProfile) {
ReentrantLock lock = (ReentrantLock) objectLibrary.getOrDefault(object, Layouts.OBJECT_LOCK, null);
if (lock != null) {
return lock;
}
initializeLockProfile.enter(node);
synchronized (object) {
lock = (ReentrantLock) objectLibrary.getOrDefault(object, Layouts.OBJECT_LOCK, null);
if (lock != null) {
return lock;
} else {
lock = new ReentrantLock();
objectLibrary.put(object, Layouts.OBJECT_LOCK, lock);
return lock;
}
}
}
}
}