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: e92392d2a76a
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ff65fb8eeb98
Choose a head ref
  • 2 commits
  • 5 files changed
  • 1 contributor

Commits on Apr 14, 2015

  1. Copy the full SHA
    4789abd View commit details
  2. [Truffle] Copy class and module state better.

    * Handle BasicObject.superclass.
    * Error on invalid copies.
    * Remove unused subClasses.
    eregon committed Apr 14, 2015
    Copy the full SHA
    ff65fb8 View commit details
Original file line number Diff line number Diff line change
@@ -166,8 +166,13 @@ public SuperClassNode(SuperClassNode prev) {
}

@Specialization
public RubyClass getSuperClass(RubyClass rubyClass) {
return rubyClass.getSuperClass();
public Object getSuperClass(RubyClass rubyClass) {
RubyClass superclass = rubyClass.getSuperClass();
if (superclass == null) {
return nil();
} else {
return superclass;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
import org.jruby.truffle.nodes.cast.NumericToFloatNodeFactory;
import org.jruby.truffle.nodes.coerce.ToStrNodeFactory;
import org.jruby.truffle.nodes.control.WhileNode;
import org.jruby.truffle.nodes.core.KernelNodesFactory.CopyNodeFactory;
import org.jruby.truffle.nodes.core.KernelNodesFactory.SameOrEqualNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.globals.WrapInThreadLocalNode;
@@ -396,17 +397,44 @@ public RubyClass getClass(Object self) {

}

public abstract static class CopyNode extends UnaryCoreMethodNode {

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

public CopyNode(CopyNode prev) {
super(prev);
}

public abstract RubyBasicObject executeCopy(VirtualFrame frame, RubyBasicObject self);

@Specialization
public RubyBasicObject copy(VirtualFrame frame, RubyBasicObject self) {
// This method is pretty crappy for compilation - it should improve with the OM

final RubyBasicObject newObject = self.getLogicalClass().allocate(this);

newObject.getOperations().setInstanceVariables(newObject, self.getOperations().getInstanceVariables(self));

return newObject;
}

}

@CoreMethod(names = "clone", taintFromSelf = true)
public abstract static class CloneNode extends CoreMethodNode {

private final ConditionProfile frozenProfile = ConditionProfile.createBinaryProfile();

@Child private CopyNode copyNode;
@Child private CallDispatchHeadNode initializeCloneNode;
@Child private IsFrozenNode isFrozenNode;
@Child private FreezeNode freezeNode;

public CloneNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
copyNode = CopyNodeFactory.create(context, sourceSection, null);
// Calls private initialize_clone on the new copy.
initializeCloneNode = DispatchHeadNodeFactory.createMethodCall(context, true, MissingBehavior.CALL_METHOD_MISSING);
isFrozenNode = IsFrozenNodeFactory.create(context, sourceSection, null);
@@ -415,23 +443,23 @@ public CloneNode(RubyContext context, SourceSection sourceSection) {

public CloneNode(CloneNode prev) {
super(prev);
copyNode = prev.copyNode;
initializeCloneNode = prev.initializeCloneNode;
isFrozenNode = prev.isFrozenNode;
freezeNode = prev.freezeNode;
}

@Specialization
public Object clone(VirtualFrame frame, RubyBasicObject self) {
public RubyBasicObject clone(VirtualFrame frame, RubyBasicObject self) {
notDesignedForCompilation();

final RubyBasicObject newObject = self.getLogicalClass().allocate(this);
final RubyBasicObject newObject = copyNode.executeCopy(frame, self);

// Copy the singleton class if any.
if (self.getMetaClass().isSingleton()) {
newObject.getSingletonClass(this).initCopy(self.getMetaClass());
}

newObject.getOperations().setInstanceVariables(newObject, self.getOperations().getInstanceVariables(self));
initializeCloneNode.call(frame, newObject, "initialize_clone", null, self);

if (frozenProfile.profile(isFrozenNode.executeIsFrozen(self))) {
@@ -446,25 +474,26 @@ public Object clone(VirtualFrame frame, RubyBasicObject self) {
@CoreMethod(names = "dup", taintFromSelf = true)
public abstract static class DupNode extends CoreMethodNode {

@Child private CopyNode copyNode;
@Child private CallDispatchHeadNode initializeDupNode;

public DupNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
copyNode = CopyNodeFactory.create(context, sourceSection, null);
// Calls private initialize_dup on the new copy.
initializeDupNode = DispatchHeadNodeFactory.createMethodCall(context, true, MissingBehavior.CALL_METHOD_MISSING);
}

public DupNode(DupNode prev) {
super(prev);
copyNode = prev.copyNode;
initializeDupNode = prev.initializeDupNode;
}

@Specialization
public Object dup(VirtualFrame frame, RubyBasicObject self) {
// This method is pretty crappy for compilation - it should improve with the OM
public RubyBasicObject dup(VirtualFrame frame, RubyBasicObject self) {
final RubyBasicObject newObject = copyNode.executeCopy(frame, self);

final RubyBasicObject newObject = self.getLogicalClass().allocate(this);
newObject.getOperations().setInstanceVariables(newObject, self.getOperations().getInstanceVariables(self));
initializeDupNode.call(frame, newObject, "initialize_dup", null, self);

return newObject;
Original file line number Diff line number Diff line change
@@ -1076,11 +1076,27 @@ public InitializeCopyNode(InitializeCopyNode prev) {
super(prev);
}

@Specialization(guards = { "!isRubyClass(arguments[0])", "!isRubyClass(arguments[1])" })
public Object initializeCopy(RubyModule self, RubyModule from) {
notDesignedForCompilation();

self.initCopy(from);
return nil();
}

@Specialization
public Object initializeCopy(RubyModule self, RubyModule other) {
public Object initializeCopy(RubyClass self, RubyClass from) {
notDesignedForCompilation();

self.initCopy(other);
if (from == getContext().getCoreLibrary().getBasicObjectClass()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError("can't copy the root class", this));
} else if (from.isSingleton()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError("can't copy singleton class", this));
}

self.initCopy(from);
return nil();
}

Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;

import org.jruby.truffle.nodes.RubyNode;
@@ -32,7 +33,6 @@ public class RubyClass extends RubyModule {
@CompilationFinal Allocator allocator;

private final boolean isSingleton;
private final Set<RubyClass> subClasses = Collections.newSetFromMap(new WeakHashMap<RubyClass, Boolean>());
private final RubyModule attached;

/**
@@ -87,16 +87,15 @@ protected void unsafeSetSuperclass(RubyClass superClass) {

parentModule = superClass;
superClass.addDependent(this);
superClass.subClasses.add(this);

newVersion();
}

@Override
public void initCopy(RubyModule other) {
assert other instanceof RubyClass;
super.initCopy(other);
this.allocator = ((RubyClass) other).allocator;
public void initCopy(RubyClass from) {
super.initCopy(from);
this.allocator = ((RubyClass) from).allocator;
// isSingleton is false as we cannot copy a singleton class.
// and therefore attached is null.
}

private RubyClass ensureSingletonConsistency() {
Original file line number Diff line number Diff line change
@@ -160,12 +160,14 @@ private void updateAnonymousChildrenModules() {
}

@TruffleBoundary
public void initCopy(RubyModule other) {
public void initCopy(RubyModule from) {
// Do not copy name, the copy is an anonymous module
this.parentModule = other.parentModule;
this.methods.putAll(other.methods);
this.constants.putAll(other.constants);
this.classVariables.putAll(other.classVariables);
this.parentModule = from.parentModule;
if (parentModule != null)
parentModule.getActualModule().addDependent(this);
this.methods.putAll(from.methods);
this.constants.putAll(from.constants);
this.classVariables.putAll(from.classVariables);
}

/** If this instance is a module and not a class. */