Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Truffle] Allow Rubinius primitives to be written entirely in Ruby wi…
Browse files Browse the repository at this point in the history
…th Truffle::Primitive.install_rubinius_primitive
chrisseaton committed Jun 22, 2015
1 parent e44e450 commit 051adb3
Showing 10 changed files with 167 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@

/**
* Defines the method on the singleton class.
* {@link needsSelf} is always false.
* {@link #needsSelf} is always false.
* */
boolean onSingleton() default false;

@@ -39,7 +39,7 @@
/**
* Defines the method as public on the singleton class
* and as a private instance method.
* {@link needsSelf} is always false.
* {@link #needsSelf} is always false.
*/
boolean isModuleFunction() default false;

Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.hash.BucketsStrategy;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.subsystems.SimpleShell;
import org.jruby.util.Memo;

@@ -472,4 +473,19 @@ public Object atExit(boolean always, RubyProc block) {
}
}

@CoreMethod(names = "install_rubinius_primitive", isModuleFunction = true, required = 2)
public abstract static class InstallRubiniusPrimitiveNode extends CoreMethodArrayArgumentsNode {

public InstallRubiniusPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization(guards = "isRubySymbol(name)")
public Object installRubiniusPrimitive(RubyModule module, RubyBasicObject name) {
getContext().getRubiniusPrimitiveManager().installPrimitive(module, SymbolNodes.getString(name));
return nil();
}
}

}
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ private Object[] splat(Object argument) {

if (!(argument instanceof RubyArray)) {
CompilerDirectives.transferToInterpreter();
throw new UnsupportedOperationException(argument.toString());
throw new UnsupportedOperationException(argument.getClass().toString());
}

final RubyArray array = (RubyArray) argument;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2015 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 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.rubinius;

import org.jruby.truffle.runtime.core.RubyModule;

public class RubiniusPrimitiveCallConstructor implements RubiniusPrimitiveConstructor {

private final RubyModule module;
private final String method;

public RubiniusPrimitiveCallConstructor(RubyModule module, String method) {
this.module = module;
this.method = method;
}

public RubyModule getModule() {
return module;
}

public String getMethod() {
return method;
}
}
Original file line number Diff line number Diff line change
@@ -9,28 +9,6 @@
*/
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.dsl.NodeFactory;
import org.jruby.truffle.nodes.RubyNode;

/**
* Packages up the original {@link RubiniusPrimitive annotation} with the {@link NodeFactory}.
*/
public class RubiniusPrimitiveConstructor {

private final RubiniusPrimitive annotation;
private final NodeFactory<? extends RubyNode> factory;

public RubiniusPrimitiveConstructor(RubiniusPrimitive annotation, NodeFactory<? extends RubyNode> factory) {
this.annotation = annotation;
this.factory = factory;
}

public RubiniusPrimitive getAnnotation() {
return annotation;
}

public NodeFactory<? extends RubyNode> getFactory() {
return factory;
}
public interface RubiniusPrimitiveConstructor {

}
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
import com.oracle.truffle.api.dsl.GeneratedBy;
import com.oracle.truffle.api.dsl.NodeFactory;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.core.RubyModule;

import java.util.ArrayList;
import java.util.HashMap;
@@ -53,7 +54,6 @@ public static RubiniusPrimitiveManager create() {
nodeFactories.addAll(EncodingPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(EncodingConverterPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(RegexpPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(ModulePrimitiveNodesFactory.getFactories());
nodeFactories.addAll(RandomPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(ArrayPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(StatPrimitiveNodesFactory.getFactories());
@@ -74,10 +74,13 @@ public static RubiniusPrimitiveManager create() {
final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
final Class<?> nodeClass = generatedBy.value();
final RubiniusPrimitive annotation = nodeClass.getAnnotation(RubiniusPrimitive.class);
primitives.put(annotation.name(), new RubiniusPrimitiveConstructor(annotation, nodeFactory));
primitives.put(annotation.name(), new RubiniusPrimitiveNodeConstructor(annotation, nodeFactory));
}

return new RubiniusPrimitiveManager(primitives);
}

public void installPrimitive(RubyModule module, String method) {
primitives.put(method, new RubiniusPrimitiveCallConstructor(module, method));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2015 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 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.dsl.NodeFactory;
import org.jruby.truffle.nodes.RubyNode;

public class RubiniusPrimitiveNodeConstructor implements RubiniusPrimitiveConstructor {

private final RubiniusPrimitive annotation;
private final NodeFactory<? extends RubyNode> factory;

public RubiniusPrimitiveNodeConstructor(RubiniusPrimitive annotation, NodeFactory<? extends RubyNode> factory) {
this.annotation = annotation;
this.factory = factory;
}

public RubiniusPrimitive getAnnotation() {
return annotation;
}

public NodeFactory<? extends RubyNode> getFactory() {
return factory;
}

}
102 changes: 77 additions & 25 deletions truffle/src/main/java/org/jruby/truffle/translator/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.ThreadLocalObjectNode;
import org.jruby.truffle.nodes.arguments.MissingArgumentBehaviour;
import org.jruby.truffle.nodes.arguments.ReadAllArgumentsNode;
import org.jruby.truffle.nodes.arguments.ReadPreArgumentNode;
import org.jruby.truffle.nodes.cast.*;
import org.jruby.truffle.nodes.cast.LambdaNode;
@@ -452,28 +453,54 @@ private RubyNode translateRubiniusPrimitive(SourceSection sourceSection, CallNod

final RubiniusPrimitiveConstructor primitive = context.getRubiniusPrimitiveManager().getPrimitive(primitiveName);

final List<RubyNode> arguments = new ArrayList<>();
if (primitive instanceof RubiniusPrimitiveNodeConstructor) {
final RubiniusPrimitiveNodeConstructor nodeConstructor = (RubiniusPrimitiveNodeConstructor) primitive;

int argumentsCount = primitive.getFactory().getExecutionSignature().size();
final List<RubyNode> arguments = new ArrayList<>();

if (primitive.getAnnotation().needsSelf()) {
arguments.add(new SelfNode(context, sourceSection));
argumentsCount--;
}
int argumentsCount = nodeConstructor.getFactory().getExecutionSignature().size();

if (nodeConstructor.getAnnotation().needsSelf()) {
arguments.add(new SelfNode(context, sourceSection));
argumentsCount--;
}

for (int n = 0; n < argumentsCount; n++) {
RubyNode readArgumentNode = new ReadPreArgumentNode(context, sourceSection, n, MissingArgumentBehaviour.UNDEFINED);
for (int n = 0; n < argumentsCount; n++) {
RubyNode readArgumentNode = new ReadPreArgumentNode(context, sourceSection, n, MissingArgumentBehaviour.UNDEFINED);

if (ArrayUtils.contains(primitive.getAnnotation().lowerFixnumParameters(), n)) {
readArgumentNode = new FixnumLowerNode(readArgumentNode);
if (ArrayUtils.contains(nodeConstructor.getAnnotation().lowerFixnumParameters(), n)) {
readArgumentNode = new FixnumLowerNode(readArgumentNode);
}

arguments.add(readArgumentNode);
}

arguments.add(readArgumentNode);
}
return new CallRubiniusPrimitiveNode(context, sourceSection,
nodeConstructor.getFactory().createNode(context, sourceSection, arguments.toArray(new RubyNode[arguments.size()])),
environment.getReturnID());
} else if (primitive instanceof RubiniusPrimitiveCallConstructor) {
final RubiniusPrimitiveCallConstructor callConstructor = (RubiniusPrimitiveCallConstructor) primitive;

return new CallRubiniusPrimitiveNode(context, sourceSection,
primitive.getFactory().createNode(context, sourceSection, arguments.toArray(new RubyNode[arguments.size()])),
environment.getReturnID());
final List<RubyNode> arguments = new ArrayList<>();

final int argumentsCount = callConstructor.getModule().getMethods().get(callConstructor.getMethod()).getSharedMethodInfo().getArity().getRequired();

for (int n = 0; n < argumentsCount; n++) {
RubyNode readArgumentNode = new ReadPreArgumentNode(context, sourceSection, n, MissingArgumentBehaviour.UNDEFINED);
arguments.add(readArgumentNode);
}

return new RubyCallNode(
context,
sourceSection,
callConstructor.getMethod(),
new LiteralNode(context, sourceSection, callConstructor.getModule()),
null,
false,
arguments.toArray(new RubyNode[arguments.size()]));
} else {
throw new UnsupportedOperationException();
}
}

private RubyNode translateRubiniusInvokePrimitive(SourceSection sourceSection, CallNode node) {
@@ -495,21 +522,46 @@ private RubyNode translateRubiniusInvokePrimitive(SourceSection sourceSection, C

final RubiniusPrimitiveConstructor primitive = context.getRubiniusPrimitiveManager().getPrimitive(primitiveName);

final List<RubyNode> arguments = new ArrayList<>();
if (primitive instanceof RubiniusPrimitiveNodeConstructor) {
final RubiniusPrimitiveNodeConstructor nodeConstructor = (RubiniusPrimitiveNodeConstructor) primitive;

final List<RubyNode> arguments = new ArrayList<>();

// The first argument was the symbol so we ignore it
for (int n = 1; n < node.getArgsNode().childNodes().size(); n++) {
RubyNode readArgumentNode = node.getArgsNode().childNodes().get(n).accept(this);
// The first argument was the symbol so we ignore it
for (int n = 1; n < node.getArgsNode().childNodes().size(); n++) {
RubyNode readArgumentNode = node.getArgsNode().childNodes().get(n).accept(this);

if (ArrayUtils.contains(primitive.getAnnotation().lowerFixnumParameters(), n)) {
readArgumentNode = new FixnumLowerNode(readArgumentNode);
if (ArrayUtils.contains(nodeConstructor.getAnnotation().lowerFixnumParameters(), n)) {
readArgumentNode = new FixnumLowerNode(readArgumentNode);
}

arguments.add(readArgumentNode);
}

arguments.add(readArgumentNode);
return new InvokeRubiniusPrimitiveNode(context, sourceSection,
nodeConstructor.getFactory().createNode(context, sourceSection, arguments.toArray(new RubyNode[arguments.size()])));
} else if (primitive instanceof RubiniusPrimitiveCallConstructor) {
final RubiniusPrimitiveCallConstructor callConstructor = (RubiniusPrimitiveCallConstructor) primitive;

final List<RubyNode> arguments = new ArrayList<>();

// The first argument was the symbol so we ignore it
for (int n = 1; n < node.getArgsNode().childNodes().size(); n++) {
RubyNode readArgumentNode = node.getArgsNode().childNodes().get(n).accept(this);
arguments.add(readArgumentNode);
}

return new RubyCallNode(
context,
sourceSection,
callConstructor.getMethod(),
new LiteralNode(context, sourceSection, callConstructor.getModule()),
null,
false,
arguments.toArray(new RubyNode[arguments.size()]));
} else {
throw new UnsupportedOperationException();
}

return new InvokeRubiniusPrimitiveNode(context, sourceSection,
primitive.getFactory().createNode(context, sourceSection, arguments.toArray(new RubyNode[arguments.size()])));
}

private RubyNode translateRubiniusPrivately(SourceSection sourceSection, CallNode node) {
2 changes: 1 addition & 1 deletion truffle/src/main/ruby/core/rubinius/api/shims/mirror.rb
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@
module Rubinius
class Mirror

# Implementation of the :module_mirror Rubinius primitive.
def self.module_mirror(obj)
if obj.is_a?(::Numeric)
Rubinius::Mirror::Numeric
@@ -31,6 +30,7 @@ def self.module_mirror(obj)
end
end
end
Truffle::Primitive.install_rubinius_primitive self, :module_mirror

end
end

0 comments on commit 051adb3

Please sign in to comment.