Skip to content

Commit

Permalink
Inline nil? calls in the AST
Browse files Browse the repository at this point in the history
* Unfortunately, this requires NilClass#nil? to be defined in Java,
  as otherwise we cannot replace nil? calls in the core library safely.
  • Loading branch information
eregon committed Nov 20, 2017
1 parent 1195722 commit 5762800
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/main/java/org/truffleruby/builtins/BuiltinsClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import org.truffleruby.core.binding.TruffleBindingNodesFactory;
import org.truffleruby.core.bool.FalseClassNodesBuiltins;
import org.truffleruby.core.bool.FalseClassNodesFactory;
import org.truffleruby.core.bool.NilClassNodesBuiltins;
import org.truffleruby.core.bool.NilClassNodesFactory;
import org.truffleruby.core.bool.TrueClassNodesBuiltins;
import org.truffleruby.core.bool.TrueClassNodesFactory;
import org.truffleruby.core.encoding.EncodingConverterNodesBuiltins;
Expand Down Expand Up @@ -208,6 +210,7 @@ public static void setupBuiltinsLazy(CoreMethodNodeManager coreManager, Primitiv
ModuleNodesBuiltins.setup(coreManager, primitiveManager);
MutexNodesBuiltins.setup(coreManager, primitiveManager);
NameErrorNodesBuiltins.setup(coreManager, primitiveManager);
NilClassNodesBuiltins.setup(coreManager, primitiveManager);
NoMethodErrorNodesBuiltins.setup(coreManager, primitiveManager);
ObjectSpaceNodesBuiltins.setup(coreManager, primitiveManager);
ObjSpaceNodesBuiltins.setup(coreManager, primitiveManager);
Expand Down Expand Up @@ -289,6 +292,7 @@ public static List<List<? extends NodeFactory<? extends RubyNode>>> getCoreNodeF
ModuleNodesFactory.getFactories(),
MutexNodesFactory.getFactories(),
NameErrorNodesFactory.getFactories(),
NilClassNodesFactory.getFactories(),
NoMethodErrorNodesFactory.getFactories(),
ObjectSpaceNodesFactory.getFactories(),
ObjSpaceNodesFactory.getFactories(),
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/org/truffleruby/core/bool/NilClassNodes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2017 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.truffleruby.core.bool;

import org.truffleruby.builtins.CoreClass;
import org.truffleruby.builtins.CoreMethod;
import org.truffleruby.builtins.CoreMethodNode;
import org.truffleruby.core.inlined.InlinedIsNilNode;

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

@CoreClass("NilClass")
public abstract class NilClassNodes {

/** Needs to be in Java for {@link InlinedIsNilNode} */
@CoreMethod(names = "nil?", needsSelf = false)
public abstract static class AndNode extends CoreMethodNode {

@Specialization
public boolean isNil() {
return true;
}
}

}
9 changes: 9 additions & 0 deletions src/main/java/org/truffleruby/core/inlined/CoreMethods.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@ public class CoreMethods {
final Assumption fixnumLessThanAssumption, fixnumLessOrEqualAssumption;
final Assumption fixnumGreaterThanAssumption, fixnumGreaterOrEqualAssumption;

final Assumption nilClassIsNilAssumption;

public final InternalMethod BLOCK_GIVEN;
public final InternalMethod NOT;
public final InternalMethod KERNEL_IS_NIL;

public CoreMethods(RubyContext context) {
this.context = context;
final DynamicObject basicObjectClass = context.getCoreLibrary().getBasicObjectClass();
final DynamicObject kernelModule = context.getCoreLibrary().getKernelModule();
final DynamicObject fixnumClass = context.getCoreLibrary().getFixnumClass();
final DynamicObject floatClass = context.getCoreLibrary().getFloatClass();
final DynamicObject nilClass = context.getCoreLibrary().getNilClass();

fixnumAddAssumption = registerAssumption(fixnumClass, "+");
floatAddAssumption = registerAssumption(floatClass, "+");
Expand Down Expand Up @@ -74,8 +78,11 @@ public CoreMethods(RubyContext context) {
fixnumGreaterThanAssumption = registerAssumption(fixnumClass, ">");
fixnumGreaterOrEqualAssumption = registerAssumption(fixnumClass, ">=");

nilClassIsNilAssumption = registerAssumption(nilClass, "nil?");

BLOCK_GIVEN = getMethod(kernelModule, "block_given?");
NOT = getMethod(basicObjectClass, "!");
KERNEL_IS_NIL = getMethod(kernelModule, "nil?");
}

private Assumption registerAssumption(DynamicObject klass, String methodName) {
Expand Down Expand Up @@ -109,6 +116,8 @@ public RubyNode createCallNode(RubyCallNodeParameters callParameters) {
return InlinedBlockGivenNodeGen.create(context, callParameters, self);
}
break;
case "nil?":
return InlinedIsNilNodeGen.create(context, callParameters, self);
default:
}
} else if (n == 2) {
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/org/truffleruby/core/inlined/InlinedIsNilNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2017 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.truffleruby.core.inlined;

import org.truffleruby.RubyContext;
import org.truffleruby.language.dispatch.RubyCallNodeParameters;
import org.truffleruby.language.methods.LookupMethodNode;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;

public abstract class InlinedIsNilNode extends UnaryInlinedOperationNode {

protected static final String METHOD = "nil?";

public InlinedIsNilNode(RubyContext context, RubyCallNodeParameters callNodeParameters) {
super(callNodeParameters,
context.getCoreMethods().nilClassIsNilAssumption);
}

@Specialization(guards = "isNil(self)", assumptions = "assumptions")
boolean nil(Object self) {
return true;
}

@Specialization(guards = {
"!isForeignObject(self)",
"lookupNode.lookup(frame, self, METHOD) == coreMethods().KERNEL_IS_NIL",
}, assumptions = "assumptions", limit = "1")
boolean notNil(VirtualFrame frame, Object self,
@Cached("create()") LookupMethodNode lookupNode) {
return false;
}

@Specialization
Object fallback(VirtualFrame frame, Object self) {
return rewriteAndCall(frame, self);
}

}
4 changes: 0 additions & 4 deletions src/main/ruby/core/nil.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ def inspect
'nil'
end

def nil?
true
end

def to_a
[]
end
Expand Down

0 comments on commit 5762800

Please sign in to comment.