Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 015d17c88155
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 63b893cfd50f
Choose a head ref
  • 8 commits
  • 18 files changed
  • 1 contributor

Commits on May 9, 2016

  1. Copy the full SHA
    8fc4803 View commit details
  2. Copy the full SHA
    c39b204 View commit details
  3. Copy the full SHA
    931b8b5 View commit details
  4. Copy the full SHA
    beb571d View commit details
  5. Copy the full SHA
    1c1853a View commit details
  6. Copy the full SHA
    a7ac13a View commit details
  7. Copy the full SHA
    2b7c369 View commit details
  8. 1
    Copy the full SHA
    63b893c View commit details
Showing with 139 additions and 192 deletions.
  1. +107 −0 truffle/src/main/java/org/jruby/truffle/builtins/AmbiguousOptionalArgumentChecker.java
  2. +0 −34 truffle/src/main/java/org/jruby/truffle/builtins/BinaryCoreMethodNode.java
  3. +6 −15 truffle/src/main/java/org/jruby/truffle/builtins/CallPrimitiveNode.java
  4. +5 −16 truffle/src/main/java/org/jruby/truffle/builtins/CoreMethod.java
  5. +0 −107 truffle/src/main/java/org/jruby/truffle/builtins/CoreMethodNodeManager.java
  6. +2 −2 ...ain/java/org/jruby/truffle/builtins/{InvokeRubiniusPrimitiveNode.java → InvokePrimitiveNode.java}
  7. +5 −3 truffle/src/main/java/org/jruby/truffle/builtins/PrimitiveConstructor.java
  8. +2 −2 truffle/src/main/java/org/jruby/truffle/builtins/PrimitiveNodeConstructor.java
  9. +1 −1 truffle/src/main/java/org/jruby/truffle/{core → builtins}/ReturnEnumeratorIfNoBlockNode.java
  10. +1 −2 truffle/src/main/java/org/jruby/truffle/core/basicobject/BasicObjectNodes.java
  11. +1 −1 truffle/src/main/java/org/jruby/truffle/core/hash/HashNodes.java
  12. +2 −1 truffle/src/main/java/org/jruby/truffle/core/hash/LookupEntryNode.java
  13. +1 −1 truffle/src/main/java/org/jruby/truffle/core/hash/SetNode.java
  14. +1 −1 truffle/src/main/java/org/jruby/truffle/core/kernel/KernelNodes.java
  15. +1 −1 truffle/src/main/java/org/jruby/truffle/core/method/MethodNodes.java
  16. +2 −2 truffle/src/main/java/org/jruby/truffle/core/rubinius/VMPrimitiveNodes.java
  17. +1 −2 truffle/src/main/java/org/jruby/truffle/core/symbol/SymbolNodes.java
  18. +1 −1 truffle/src/main/java/org/jruby/truffle/language/parser/jruby/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2013, 2016 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.builtins;

import com.oracle.truffle.api.dsl.Specialization;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class AmbiguousOptionalArgumentChecker {

public static boolean SUCCESS = true;

public static void verifyNoAmbiguousOptionalArguments(CoreMethodNodeManager.MethodDetails methodDetails) {
try {
verifyNoAmbiguousOptionalArgumentsWithReflection(methodDetails);
} catch (Exception e) {
e.printStackTrace();
SUCCESS = false;
}
}

private static void verifyNoAmbiguousOptionalArgumentsWithReflection(CoreMethodNodeManager.MethodDetails methodDetails) throws ReflectiveOperationException {
final CoreMethod methodAnnotation = methodDetails.getMethodAnnotation();
if (methodAnnotation.optional() > 0 || methodAnnotation.needsBlock()) {
int opt = methodAnnotation.optional();
if (methodAnnotation.needsBlock()) {
opt++;
}

Class<?> node = methodDetails.getNodeFactory().getNodeClass();

for (int i = 1; i <= opt; i++) {
boolean unguardedObjectArgument = false;
StringBuilder errors = new StringBuilder();
for (Method method : node.getDeclaredMethods()) {
if (method.isAnnotationPresent(Specialization.class)) {
// count from the end to ignore optional VirtualFrame in front.
Class<?>[] parameterTypes = method.getParameterTypes();
int n = parameterTypes.length - i;
if (methodAnnotation.rest()) {
n--; // ignore final Object[] argument
}
Class<?> parameterType = parameterTypes[n];
Parameter[] parameters = method.getParameters();

Parameter parameter = parameters[n];
boolean isNamePresent = parameter.isNamePresent();
if (!isNamePresent) {
System.err.println("Method parameters names are not available for " + method);
System.exit(1);
}
String name = parameter.getName();

if (parameterType == Object.class && !name.startsWith("unused") && !name.equals("maybeBlock")) {
String[] guards = method.getAnnotation(Specialization.class).guards();
if (!isGuarded(name, guards)) {
unguardedObjectArgument = true;
errors.append("\"").append(name).append("\" in ").append(methodToString(method, parameterTypes, parameters)).append("\n");
}
}
}
}

if (unguardedObjectArgument) {
SUCCESS = false;
System.err.println("Ambiguous optional argument in " + node.getCanonicalName() + ":");
System.err.println(errors);
}
}
}
}

private static boolean isGuarded(String name, String[] guards) {
for (String guard : guards) {
if (guard.equals("wasProvided(" + name + ")") ||
guard.equals("wasNotProvided(" + name + ")") ||
guard.equals("wasNotProvided(" + name + ") || isRubiniusUndefined(" + name + ")") ||
guard.equals("isNil(" + name + ")")) {
return true;
}
}
return false;
}

private static String methodToString(Method method, Class<?>[] parameterTypes, Parameter[] parameters) throws ReflectiveOperationException {
StringBuilder str = new StringBuilder();
str.append(method.getName()).append("(");
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String name = parameter.getName();
str.append(parameterTypes[i].getSimpleName()).append(" ").append(name);
if (i < parameters.length - 1) {
str.append(", ");
}
}
str.append(")");
return str.toString();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -17,16 +17,12 @@
import org.jruby.truffle.language.control.ReturnException;
import org.jruby.truffle.language.control.ReturnID;

/**
* Node which wraps a {@link PrimitiveNode}, providing the implicit control flow that you get with calls to
* Rubinius primitives.
*/
public class CallPrimitiveNode extends RubyNode {

@Child private RubyNode primitive;
private final ReturnID returnID;

private final ConditionProfile primitiveSucceededCondition = ConditionProfile.createBinaryProfile();
private final ConditionProfile failedProfile = ConditionProfile.createBinaryProfile();

public CallPrimitiveNode(RubyContext context, SourceSection sourceSection, RubyNode primitive, ReturnID returnID) {
super(context, sourceSection);
@@ -35,22 +31,17 @@ public CallPrimitiveNode(RubyContext context, SourceSection sourceSection, RubyN
}

@Override
public void executeVoid(VirtualFrame frame) {
public Object execute(VirtualFrame frame) {
final Object value = primitive.execute(frame);

if (primitiveSucceededCondition.profile(value != null)) {
if (failedProfile.profile(value == null)) {
// Primitives fail by returning null, allowing the method to continue (the fallback)
return nil();
} else {
// If the primitive didn't fail its value is returned in the calling method

throw new ReturnException(returnID, value);
}

// Primitives may return null to indicate that they have failed, in which case we continue with the fallback
}

@Override
public Object execute(VirtualFrame frame) {
executeVoid(frame);
return nil();
}

}
21 changes: 5 additions & 16 deletions truffle/src/main/java/org/jruby/truffle/builtins/CoreMethod.java
Original file line number Diff line number Diff line change
@@ -24,14 +24,12 @@

String[] names();

// where the method is to be defined
Visibility visibility() default Visibility.PUBLIC;

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

/**
@@ -40,31 +38,23 @@
boolean constructor() default false;

/**
* Defines the method as public on the singleton class
* and as a private instance method.
* {@link #needsSelf() needsSelf} is always false
* as it could be either a module or any receiver.
* Defines the method as public on the singleton class and as a private instance method.
* {@link #needsSelf() needsSelf} is always false as it could be either a module or any receiver.
*/
boolean isModuleFunction() default false;

boolean needsCallerFrame() default false;

// arguments specification
/** Whether <code>self</code> is passed as first argument to specializations. */
boolean needsSelf() default true;

int required() default 0;

int optional() default 0;

/**
* Give the remaining arguments as a Object[] and allows unlimited arguments.
*/
boolean rest() default false;

boolean needsBlock() default false;

// arguments transformation
boolean lowerFixnumSelf() default false;

int[] lowerFixnumParameters() default {};
@@ -77,7 +67,6 @@

int[] raiseIfFrozenParameters() default {};

// extra behavior
UnsupportedOperationBehavior unsupportedOperationBehavior() default UnsupportedOperationBehavior.TYPE_ERROR;

boolean returnsEnumeratorIfNoBlock() default false;
Original file line number Diff line number Diff line change
@@ -12,15 +12,13 @@
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.GeneratedBy;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.RaiseIfFrozenNode;
import org.jruby.truffle.core.ReturnEnumeratorIfNoBlockNode;
import org.jruby.truffle.core.array.ArrayUtils;
import org.jruby.truffle.core.cast.TaintResultNode;
import org.jruby.truffle.core.module.ModuleOperations;
@@ -46,7 +44,6 @@
import org.jruby.truffle.language.parser.jruby.Translator;
import org.jruby.truffle.platform.UnsafeGroup;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -355,108 +352,4 @@ public String getIndicativeName() {
}
}

private static class AmbiguousOptionalArgumentChecker {

private static final Method GET_PARAMETERS = checkParametersNamesAvailable();
private static boolean SUCCESS = true;

private static Method checkParametersNamesAvailable() {
try {
return Method.class.getMethod("getParameters");
} catch (NoSuchMethodException | SecurityException e) {
// Java 7 or could not find how to get names of method parameters
System.err.println("Could not find method Method.getParameters()");
System.exit(1);
return null;
}
}

private static void verifyNoAmbiguousOptionalArguments(MethodDetails methodDetails) {
try {
verifyNoAmbiguousOptionalArgumentsWithReflection(methodDetails);
} catch (Exception e) {
e.printStackTrace();
SUCCESS = false;
}
}

private static void verifyNoAmbiguousOptionalArgumentsWithReflection(MethodDetails methodDetails) throws ReflectiveOperationException {
final CoreMethod methodAnnotation = methodDetails.getMethodAnnotation();
if (methodAnnotation.optional() > 0 || methodAnnotation.needsBlock()) {
int opt = methodAnnotation.optional();
if (methodAnnotation.needsBlock()) {
opt++;
}

Class<?> node = methodDetails.getNodeFactory().getNodeClass();

for (int i = 1; i <= opt; i++) {
boolean unguardedObjectArgument = false;
StringBuilder errors = new StringBuilder();
for (Method method : node.getDeclaredMethods()) {
if (method.isAnnotationPresent(Specialization.class)) {
// count from the end to ignore optional VirtualFrame in front.
Class<?>[] parameterTypes = method.getParameterTypes();
int n = parameterTypes.length - i;
if (methodAnnotation.rest()) {
n--; // ignore final Object[] argument
}
Class<?> parameterType = parameterTypes[n];
Object[] parameters = (Object[]) GET_PARAMETERS.invoke(method);

Object parameter = parameters[n];
boolean isNamePresent = (boolean) parameter.getClass().getMethod("isNamePresent").invoke(parameter);
if (!isNamePresent) {
System.err.println("Method parameters names are not available for " + method);
System.exit(1);
}
String name = (String) parameter.getClass().getMethod("getName").invoke(parameter);

if (parameterType == Object.class && !name.startsWith("unused") && !name.equals("maybeBlock")) {
String[] guards = method.getAnnotation(Specialization.class).guards();
if (!isGuarded(name, guards)) {
unguardedObjectArgument = true;
errors.append("\"").append(name).append("\" in ").append(methodToString(method, parameterTypes, parameters)).append("\n");
}
}
}
}

if (unguardedObjectArgument) {
SUCCESS = false;
System.err.println("Ambiguous optional argument in " + node.getCanonicalName() + ":");
System.err.println(errors);
}
}
}
}

private static boolean isGuarded(String name, String[] guards) {
for (String guard : guards) {
if (guard.equals("wasProvided(" + name + ")") ||
guard.equals("wasNotProvided(" + name + ")") ||
guard.equals("wasNotProvided(" + name + ") || isRubiniusUndefined(" + name + ")") ||
guard.equals("isNil(" + name + ")")) {
return true;
}
}
return false;
}

private static String methodToString(Method method, Class<?>[] parameterTypes, Object[] parameters) throws ReflectiveOperationException {
StringBuilder str = new StringBuilder();
str.append(method.getName()).append("(");
for (int i = 0; i < parameters.length; i++) {
Object parameter = parameters[i];
String name = (String) parameter.getClass().getMethod("getName").invoke(parameter);
str.append(parameterTypes[i].getSimpleName()).append(" ").append(name);
if (i < parameters.length - 1) {
str.append(", ");
}
}
str.append(")");
return str.toString();
}
}

}
Original file line number Diff line number Diff line change
@@ -15,13 +15,13 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;

public class InvokeRubiniusPrimitiveNode extends RubyNode {
public class InvokePrimitiveNode extends RubyNode {

@Child private RubyNode primitive;

private final ConditionProfile primitiveSucceededCondition = ConditionProfile.createBinaryProfile();

public InvokeRubiniusPrimitiveNode(RubyContext context, SourceSection sourceSection, RubyNode primitive) {
public InvokePrimitiveNode(RubyContext context, SourceSection sourceSection, RubyNode primitive) {
super(context, sourceSection);
this.primitive = primitive;
}
Original file line number Diff line number Diff line change
@@ -15,9 +15,11 @@
import org.jruby.truffle.language.control.ReturnID;

public interface PrimitiveConstructor {
public int getPrimitiveArity();

public RubyNode createCallPrimitiveNode(RubyContext context, SourceSection sourceSection, ReturnID returnID);
int getPrimitiveArity();

RubyNode createCallPrimitiveNode(RubyContext context, SourceSection sourceSection, ReturnID returnID);

RubyNode createInvokePrimitiveNode(RubyContext context, SourceSection sourceSection, RubyNode[] arguments);

public RubyNode createInvokePrimitiveNode(RubyContext context, SourceSection sourceSection, RubyNode[] arguments);
}
Original file line number Diff line number Diff line change
@@ -99,10 +99,10 @@ public RubyNode createInvokePrimitiveNode(RubyContext context, SourceSection sou
List<Class<?>> signature = signatures.get(0);

if (signature.get(0) == RubyContext.class) {
return new InvokeRubiniusPrimitiveNode(context, sourceSection,
return new InvokePrimitiveNode(context, sourceSection,
factory.createNode(context, sourceSection, arguments));
} else {
return new InvokeRubiniusPrimitiveNode(context, sourceSection,
return new InvokePrimitiveNode(context, sourceSection,
factory.createNode(new Object[]{arguments}));
}
}
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core;
package org.jruby.truffle.builtins;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
Original file line number Diff line number Diff line change
@@ -24,7 +24,6 @@
import org.jcodings.specific.ASCIIEncoding;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.BinaryCoreMethodNode;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
@@ -93,7 +92,7 @@ public boolean equal(VirtualFrame frame, Object a, Object b) {
}

@CoreMethod(names = { "equal?", "==" }, required = 1)
public abstract static class ReferenceEqualNode extends BinaryCoreMethodNode {
public abstract static class ReferenceEqualNode extends CoreMethodArrayArgumentsNode {

public abstract boolean executeReferenceEqual(VirtualFrame frame, Object a, Object b);

Original file line number Diff line number Diff line change
@@ -185,7 +185,7 @@ public GetIndexNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
hashNode = new HashNode(context, sourceSection);
eqlNode = DispatchHeadNodeFactory.createMethodCall(context);
equalNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(null, null);
equalNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(new RubyNode[]{null, null});
callDefaultNode = DispatchHeadNodeFactory.createMethodCall(context);
lookupEntryNode = new LookupEntryNode(context, sourceSection);
}
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
import org.jruby.truffle.core.basicobject.BasicObjectNodes;
import org.jruby.truffle.core.basicobject.BasicObjectNodesFactory;
import org.jruby.truffle.language.RubyBaseNode;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;

@@ -33,7 +34,7 @@ public LookupEntryNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
hashNode = new HashNode(context, sourceSection);
eqlNode = DispatchHeadNodeFactory.createMethodCall(context);
equalNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(null, null);
equalNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(new RubyNode[]{null, null});
}

public HashLookupResult lookup(VirtualFrame frame, DynamicObject hash, Object key) {
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ public SetNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
hashNode = new HashNode(context, sourceSection);
eqlNode = DispatchHeadNodeFactory.createMethodCall(context);
equalNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(null, null);
equalNode = BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(new RubyNode[]{null, null});
}

public abstract Object executeSet(VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity);
Original file line number Diff line number Diff line change
@@ -231,7 +231,7 @@ public boolean sameOrEqual(VirtualFrame frame, Object a, Object b) {
private boolean areSame(VirtualFrame frame, Object left, Object right) {
if (referenceEqualNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(null, null));
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(new RubyNode[]{null, null}));
}

return referenceEqualNode.executeReferenceEqual(frame, left, right);
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ public abstract static class EqualNode extends CoreMethodArrayArgumentsNode {
protected boolean areSame(VirtualFrame frame, Object left, Object right) {
if (referenceEqualNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(null, null));
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(new RubyNode[]{null, null}));
}
return referenceEqualNode.executeReferenceEqual(frame, left, right);
}
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ public CatchNode(RubyContext context, SourceSection sourceSection) {
private boolean areSame(VirtualFrame frame, Object left, Object right) {
if (referenceEqualNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(null, null));
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(new RubyNode[]{null, null}));
}
return referenceEqualNode.executeReferenceEqual(frame, left, right);
}
@@ -237,7 +237,7 @@ public static abstract class VMObjectEqualPrimitiveNode extends PrimitiveArrayAr

public VMObjectEqualPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
referenceEqualNode = ReferenceEqualNodeFactory.create(null, null);
referenceEqualNode = ReferenceEqualNodeFactory.create(new RubyNode[]{null, null});
}

@Specialization
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.runtime.ArgumentDescriptor;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.builtins.BinaryCoreMethodNode;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
@@ -58,7 +57,7 @@ public DynamicObject allSymbols() {
}

@CoreMethod(names = { "==", "eql?" }, required = 1)
public abstract static class EqualNode extends BinaryCoreMethodNode {
public abstract static class EqualNode extends CoreMethodArrayArgumentsNode {

@Specialization(guards = "isRubySymbol(b)")
public boolean equal(DynamicObject a, DynamicObject b) {
Original file line number Diff line number Diff line change
@@ -593,7 +593,7 @@ private RubyNode translateRubiniusInvokePrimitive(SourceSection sourceSection, o
*
* into
*
* InvokeRubiniusPrimitiveNode(FooNode(arg1, arg2, ..., argN))
* InvokePrimitiveNode(FooNode(arg1, arg2, ..., argN))
*
* or
*