Skip to content

Commit

Permalink
Showing 43 changed files with 706 additions and 1,074 deletions.
19 changes: 19 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/core/ClassNodes.java
Original file line number Diff line number Diff line change
@@ -53,6 +53,8 @@ public abstract static class NewNode extends CoreMethodNode {

@Child protected AllocateNode allocateNode;
@Child protected DispatchHeadNode initialize;
@CompilerDirectives.CompilationFinal private boolean isCached = true;
@CompilerDirectives.CompilationFinal private RubyClass cachedClass;

public NewNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
@@ -82,6 +84,23 @@ private RubyBasicObject doNewInstance(VirtualFrame frame, RubyClass rubyClass, O
return instance;
}

private RubyClass cachedClass(RubyClass rubyClass) {
if (isCached) {
if (cachedClass == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
cachedClass = rubyClass;
}

if (rubyClass == cachedClass) {
return cachedClass;
} else {
CompilerDirectives.transferToInterpreterAndInvalidate();
isCached = false;
cachedClass = null;
}
}
return rubyClass;
}
}

@CoreMethod(names = "class_variables")
Original file line number Diff line number Diff line change
@@ -421,7 +421,7 @@ public Object clone(VirtualFrame frame, RubyBasicObject self) {
newObject.getSingletonClass(this).initCopy(self.getMetaClass());
}

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

return newObject;
@@ -450,8 +450,7 @@ public Object dup(VirtualFrame frame, RubyBasicObject self) {
// This method is pretty crappy for compilation - it should improve with the OM

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

newObject.setInstanceVariables(self.getFields());
newObject.setInstanceVariables(self.getInstanceVariables());
initializeDupNode.call(frame, newObject, "initialize_dup", null, self);

return newObject;
Original file line number Diff line number Diff line change
@@ -9,44 +9,20 @@
*/
package org.jruby.truffle.nodes.objects;

import com.oracle.truffle.api.*;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.object.Property;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.utilities.BranchProfile;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.RespecializeHook;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.objectstorage.*;

public class ReadInstanceVariableNode extends RubyNode implements ReadNode {

private final RespecializeHook hook = new RespecializeHook() {

@Override
public void hookRead(ObjectStorage object, String name) {
final RubyBasicObject rubyObject = (RubyBasicObject) object;

if (!rubyObject.hasPrivateLayout()) {
rubyObject.updateLayoutToMatchClass();
}
}

@Override
public void hookWrite(ObjectStorage object, String name, Object value) {
final RubyBasicObject rubyObject = (RubyBasicObject) object;

if (!rubyObject.hasPrivateLayout()) {
rubyObject.updateLayoutToMatchClass();
}

rubyObject.setInstanceVariable(name, value);
}

};

@Child protected RubyNode receiver;
@Child protected ReadHeadObjectFieldNode readNode;
private final boolean isGlobal;
@@ -57,7 +33,7 @@ public void hookWrite(ObjectStorage object, String name, Object value) {
public ReadInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, boolean isGlobal) {
super(context, sourceSection);
this.receiver = receiver;
readNode = new ReadHeadObjectFieldNode(name, hook);
readNode = new ReadHeadObjectFieldNode(name);
this.isGlobal = isGlobal;
}

@@ -142,10 +118,10 @@ public Object isDefined(VirtualFrame frame) {
if (receiverObject instanceof RubyBasicObject) {
final RubyBasicObject receiverRubyObject = (RubyBasicObject) receiverObject;

final ObjectLayout layout = receiverRubyObject.getObjectLayout();
final StorageLocation storageLocation = layout.findStorageLocation(readNode.getName());
final Shape layout = receiverRubyObject.getDynamicObject().getShape();
final Property storageLocation = layout.getProperty(readNode.getName());

if (storageLocation.isSet(receiverRubyObject)) {
if (storageLocation != null) {
return context.makeString("instance-variable");
} else {
return getContext().getCoreLibrary().getNilObject();
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
*/
package org.jruby.truffle.nodes.objects;

import com.oracle.truffle.api.*;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
@@ -18,35 +18,9 @@
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyMatchData;
import org.jruby.truffle.runtime.objectstorage.*;

public class WriteInstanceVariableNode extends RubyNode implements WriteNode {

private final RespecializeHook hook = new RespecializeHook() {

@Override
public void hookRead(ObjectStorage object, String name) {
final RubyBasicObject rubyObject = (RubyBasicObject) object;

if (!rubyObject.hasPrivateLayout()) {
rubyObject.updateLayoutToMatchClass();
}
}

@Override
public void hookWrite(ObjectStorage object, String name, Object value) {
final RubyBasicObject rubyObject = (RubyBasicObject) object;

if (!rubyObject.hasPrivateLayout()) {
rubyObject.updateLayoutToMatchClass();
}

rubyObject.setInstanceVariable(name, value);
}

};

@Child protected RubyNode receiver;
@Child protected RubyNode rhs;
@Child protected WriteHeadObjectFieldNode writeNode;
@@ -56,7 +30,7 @@ public WriteInstanceVariableNode(RubyContext context, SourceSection sourceSectio
super(context, sourceSection);
this.receiver = receiver;
this.rhs = rhs;
writeNode = new WriteHeadObjectFieldNode(name, hook);
writeNode = new WriteHeadObjectFieldNode(name);
this.isGlobal = isGlobal;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2013 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.objectstorage;

import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class MigrateNode extends WriteObjectFieldChainNode {

private final Shape expectedShape;

public MigrateNode(Shape expectedShape, WriteObjectFieldNode next) {
super(next);
this.expectedShape = expectedShape;
}

@Override
public void execute(RubyBasicObject object, Object value) {
if (object.getObjectLayout() == expectedShape) {
object.getDynamicObject().updateShape();
}

next.execute(object, value);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2013 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.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.object.BooleanLocation;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadBooleanObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;
private final BooleanLocation storageLocation;

public ReadBooleanObjectFieldNode(Shape objectLayout, BooleanLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.storageLocation = storageLocation;
}

@Override
public boolean executeBoolean(RubyBasicObject object) throws UnexpectedResultException {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.executeBoolean(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.getBoolean(object.getDynamicObject(), objectLayout);
} else {
return next.executeBoolean(object);
}
}

@Override
public Object execute(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.execute(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.get(object.getDynamicObject(), objectLayout);
} else {
return next.execute(object);
}
}

}
Original file line number Diff line number Diff line change
@@ -9,42 +9,57 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.runtime.objectstorage.DoubleStorageLocation;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.DoubleLocation;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadDoubleObjectFieldNode extends ReadObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final DoubleStorageLocation storageLocation;
private final Shape objectLayout;
private final DoubleLocation storageLocation;

public ReadDoubleObjectFieldNode(ObjectLayout objectLayout, DoubleStorageLocation storageLocation, ReadObjectFieldNode next) {
public ReadDoubleObjectFieldNode(Shape objectLayout, DoubleLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.storageLocation = storageLocation;
}

@Override
public double executeDouble(ObjectStorage object) throws UnexpectedResultException {
public double executeDouble(RubyBasicObject object) throws UnexpectedResultException {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.executeDouble(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.readDouble(object, condition);
return storageLocation.getDouble(object.getDynamicObject(), objectLayout);
} else {
return next.executeDouble(object);
}
}

@Override
public Object execute(ObjectStorage object) {
public Object execute(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.execute(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.read(object, condition);
return storageLocation.get(object.getDynamicObject(), objectLayout);
} else {
return next.execute(object);
}
Original file line number Diff line number Diff line change
@@ -11,39 +11,39 @@

import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class ReadHeadObjectFieldNode extends Node {

private final String name;
@Child protected ReadObjectFieldNode first;

public ReadHeadObjectFieldNode(String name, RespecializeHook hook) {
public ReadHeadObjectFieldNode(String name) {
this.name = name;
first = new UninitializedReadObjectFieldNode(name, hook);
first = new UninitializedReadObjectFieldNode(name);
}

public int executeInteger(ObjectStorage object) throws UnexpectedResultException {
public int executeInteger(RubyBasicObject object) throws UnexpectedResultException {
return first.executeInteger(object);
}

public long executeLong(ObjectStorage object) throws UnexpectedResultException {
public long executeLong(RubyBasicObject object) throws UnexpectedResultException {
return first.executeLong(object);
}

public double executeDouble(ObjectStorage object) throws UnexpectedResultException {
public double executeDouble(RubyBasicObject object) throws UnexpectedResultException {
return first.executeDouble(object);
}

public Object execute(ObjectStorage object) {
public Object execute(RubyBasicObject object) {
return first.execute(object);
}

public String getName() {
return name;
}

public boolean isSet(ObjectStorage object) {
public boolean isSet(RubyBasicObject object) {
return first.isSet(object);
}

Original file line number Diff line number Diff line change
@@ -9,42 +9,57 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.runtime.objectstorage.IntegerStorageLocation;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.IntLocation;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadIntegerObjectFieldNode extends ReadObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final IntegerStorageLocation storageLocation;
private final Shape objectLayout;
private final IntLocation storageLocation;

public ReadIntegerObjectFieldNode(ObjectLayout objectLayout, IntegerStorageLocation storageLocation, ReadObjectFieldNode next) {
public ReadIntegerObjectFieldNode(Shape objectLayout, IntLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.storageLocation = storageLocation;
}

@Override
public int executeInteger(ObjectStorage object) throws UnexpectedResultException {
public int executeInteger(RubyBasicObject object) throws UnexpectedResultException {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.executeInteger(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.readInteger(object, condition);
return storageLocation.getInt(object.getDynamicObject(), objectLayout);
} else {
return next.executeInteger(object);
}
}

@Override
public Object execute(ObjectStorage object) {
public Object execute(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.execute(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.read(object, condition);
return storageLocation.get(object.getDynamicObject(), objectLayout);
} else {
return next.execute(object);
}
Original file line number Diff line number Diff line change
@@ -9,42 +9,57 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.runtime.objectstorage.LongStorageLocation;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.LongLocation;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadLongObjectFieldNode extends ReadObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final LongStorageLocation storageLocation;
private final Shape objectLayout;
private final LongLocation storageLocation;

public ReadLongObjectFieldNode(ObjectLayout objectLayout, LongStorageLocation storageLocation, ReadObjectFieldNode next) {
public ReadLongObjectFieldNode(Shape objectLayout, LongLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.storageLocation = storageLocation;
}

@Override
public long executeLong(ObjectStorage object) throws UnexpectedResultException {
public long executeLong(RubyBasicObject object) throws UnexpectedResultException {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.executeLong(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.readLong(object, condition);
return storageLocation.getLong(object.getDynamicObject(), objectLayout);
} else {
return next.executeLong(object);
}
}

@Override
public Object execute(ObjectStorage object) {
public Object execute(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.execute(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.read(object, condition);
return storageLocation.get(object.getDynamicObject(), objectLayout);
} else {
return next.execute(object);
}
Original file line number Diff line number Diff line change
@@ -9,24 +9,32 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadMissingObjectFieldNode extends ReadObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final Shape objectLayout;

public ReadMissingObjectFieldNode(ObjectLayout objectLayout, ReadObjectFieldNode next) {
public ReadMissingObjectFieldNode(Shape objectLayout, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
}

@Override
public Object execute(ObjectStorage object) {
if (object.getObjectLayout() == objectLayout) {
public Object execute(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.execute(object);
}

if (object.getDynamicObject().getShape() == objectLayout) {
return null;
} else {
return next.execute(object);
Original file line number Diff line number Diff line change
@@ -9,9 +9,6 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;

public abstract class ReadObjectFieldChainNode extends ReadObjectFieldNode {

@Child protected ReadObjectFieldNode next;
Original file line number Diff line number Diff line change
@@ -11,13 +11,23 @@

import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.runtime.objectstorage.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public abstract class ReadObjectFieldNode extends Node {

public abstract Object execute(ObjectStorage object);
public abstract Object execute(RubyBasicObject object);

public int executeInteger(ObjectStorage object) throws UnexpectedResultException {
public boolean executeBoolean(RubyBasicObject object) throws UnexpectedResultException {
Object result = execute(object);

if (result instanceof Boolean) {
return (boolean) result;
} else {
throw new UnexpectedResultException(result);
}
}

public int executeInteger(RubyBasicObject object) throws UnexpectedResultException {
Object result = execute(object);

if (result instanceof Integer) {
@@ -27,7 +37,7 @@ public int executeInteger(ObjectStorage object) throws UnexpectedResultException
}
}

public long executeLong(ObjectStorage object) throws UnexpectedResultException {
public long executeLong(RubyBasicObject object) throws UnexpectedResultException {
Object result = execute(object);

if (result instanceof Long) {
@@ -37,7 +47,7 @@ public long executeLong(ObjectStorage object) throws UnexpectedResultException {
}
}

public double executeDouble(ObjectStorage object) throws UnexpectedResultException {
public double executeDouble(RubyBasicObject object) throws UnexpectedResultException {
Object result = execute(object);

if (result instanceof Double) {
@@ -47,7 +57,7 @@ public double executeDouble(ObjectStorage object) throws UnexpectedResultExcepti
}
}

public boolean isSet(ObjectStorage object) {
public boolean isSet(RubyBasicObject object) {
return true;
}

Original file line number Diff line number Diff line change
@@ -9,30 +9,38 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import org.jruby.truffle.runtime.objectstorage.ObjectStorageLocation;
import com.oracle.truffle.api.object.Location;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadObjectObjectFieldNode extends ReadObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final ObjectStorageLocation storageLocation;
private final Shape objectLayout;
private final Location storageLocation;

public ReadObjectObjectFieldNode(ObjectLayout objectLayout, ObjectStorageLocation storageLocation, ReadObjectFieldNode next) {
public ReadObjectObjectFieldNode(Shape objectLayout, Location storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.storageLocation = storageLocation;
}

@Override
public Object execute(ObjectStorage object) {
public Object execute(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.execute(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return storageLocation.read(object, condition);
return storageLocation.get(object.getDynamicObject(), objectLayout);
} else {
return next.execute(object);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013 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:
*
@@ -12,50 +12,69 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.*;
import com.oracle.truffle.api.object.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.UNINITIALIZED)
public class UninitializedReadObjectFieldNode extends ReadObjectFieldNode {

private final String name;
private final RespecializeHook hook;

public UninitializedReadObjectFieldNode(String name, RespecializeHook hook) {
public UninitializedReadObjectFieldNode(String name) {
this.name = name;
this.hook = hook;
}

@Override
public Object execute(ObjectStorage object) {
public Object execute(RubyBasicObject object) {
CompilerDirectives.transferToInterpreterAndInvalidate();

hook.hookRead(object, name);
if (object.getDynamicObject().updateShape()) {
ReadObjectFieldNode topNode = getTopNode();
if (topNode != this) {
// retry existing cache nodes
return topNode.execute(object);
}
}

final ObjectLayout layout = object.getObjectLayout();
final StorageLocation storageLocation = layout.findStorageLocation(name);
final Shape layout = object.getDynamicObject().getShape();
final Property property = layout.getProperty(name);

ReadObjectFieldNode newNode;
final ReadObjectFieldNode newNode;

if (storageLocation == null) {
if (property == null) {
newNode = new ReadMissingObjectFieldNode(layout, this);
} else if (storageLocation instanceof IntegerStorageLocation) {
newNode = new ReadIntegerObjectFieldNode(layout, (IntegerStorageLocation) storageLocation, this);
} else if (storageLocation instanceof LongStorageLocation) {
newNode = new ReadLongObjectFieldNode(layout, (LongStorageLocation) storageLocation, this);
} else if (storageLocation instanceof DoubleStorageLocation) {
newNode = new ReadDoubleObjectFieldNode(layout, (DoubleStorageLocation) storageLocation, this);
} else {
newNode = new ReadObjectObjectFieldNode(layout, (ObjectStorageLocation) storageLocation, this);
final Location storageLocation = property.getLocation();

assert storageLocation != null;

if (storageLocation instanceof BooleanLocation) {
newNode = new ReadBooleanObjectFieldNode(layout, (BooleanLocation) storageLocation, this);
} else if (storageLocation instanceof IntLocation) {
newNode = new ReadIntegerObjectFieldNode(layout, (IntLocation) storageLocation, this);
} else if (storageLocation instanceof LongLocation) {
newNode = new ReadLongObjectFieldNode(layout, (LongLocation) storageLocation, this);
} else if (storageLocation instanceof DoubleLocation) {
newNode = new ReadDoubleObjectFieldNode(layout, (DoubleLocation) storageLocation, this);
} else {
newNode = new ReadObjectObjectFieldNode(layout, storageLocation, this);
}
}

replace(newNode, "adding new read object field node to chain");
return newNode.execute(object);
}

@Override
public boolean isSet(ObjectStorage object) {
return object.getObjectLayout().findStorageLocation(name) != null;

public boolean isSet(RubyBasicObject object) {
return object.getObjectLayout().getProperty(name) != null;
}

private ReadObjectFieldNode getTopNode() {
ReadObjectFieldNode topNode = this;
while (topNode.getParent() instanceof ReadObjectFieldNode) {
topNode = (ReadObjectFieldNode) topNode.getParent();
}
return topNode;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013 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:
*
@@ -12,44 +12,71 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.*;
import com.oracle.truffle.api.object.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.UNINITIALIZED)
public class UninitializedWriteObjectFieldNode extends WriteObjectFieldNode {

private final String name;
private final RespecializeHook hook;

public UninitializedWriteObjectFieldNode(String name, RespecializeHook hook) {
public UninitializedWriteObjectFieldNode(String name) {
this.name = name;
this.hook = hook;

}

@Override
public void execute(ObjectStorage object, Object value) {
public void execute(RubyBasicObject object, Object value) {
CompilerDirectives.transferToInterpreterAndInvalidate();

hook.hookWrite(object, name, value);
final Shape currentShape = object.getDynamicObject().getShape();

// If the current shape is obsolete, add a node to migrate
if (object.getDynamicObject().updateShape()) {
final MigrateNode migrateNode = new MigrateNode(currentShape, this);
replace(migrateNode);
migrateNode.execute(object, value);
return;
}

final Shape newShape;
Location location;

final Property currentProperty = currentShape.getProperty(name);
final Property newProperty;

if (currentProperty != null && currentProperty.getLocation().canSet(object.getDynamicObject(), value)) {
newShape = currentShape;
newProperty = currentProperty;
newProperty.setSafe(object.getDynamicObject(), value, null);
} else {
object.getOperations().setInstanceVariable(object, name, value);
newShape = object.getDynamicObject().getShape();
newProperty = newShape.getProperty(name);

if (newProperty == null) {
throw new IllegalStateException("Property missing from object's shape even after setting it");
}
}

final ObjectLayout layout = object.getObjectLayout();
final StorageLocation storageLocation = layout.findStorageLocation(name);
location = newProperty.getLocation();
assert location.canSet(object.getDynamicObject(), value);

WriteObjectFieldNode newNode;
final WriteObjectFieldChainNode writeNode;

if (storageLocation == null) {
throw new RuntimeException("Storage location should be found at this point");
} else if (storageLocation instanceof IntegerStorageLocation) {
newNode = new WriteIntegerObjectFieldNode(layout, (IntegerStorageLocation) storageLocation, this);
} else if (storageLocation instanceof LongStorageLocation) {
newNode = new WriteLongObjectFieldNode(layout, (LongStorageLocation) storageLocation, this);
} else if (storageLocation instanceof DoubleStorageLocation) {
newNode = new WriteDoubleObjectFieldNode(layout, (DoubleStorageLocation) storageLocation, this);
if (location instanceof BooleanLocation) {
writeNode = new WriteBooleanObjectFieldNode(currentShape, newShape, (BooleanLocation) location, this);
} else if (location instanceof IntLocation) {
writeNode = new WriteIntegerObjectFieldNode(currentShape, newShape, (IntLocation) location, this);
} else if (location instanceof LongLocation) {
writeNode = new WriteLongObjectFieldNode(currentShape, newShape, (LongLocation) location, this);
} else if (location instanceof DoubleLocation) {
writeNode = new WriteDoubleObjectFieldNode(currentShape, newShape, (DoubleLocation) location, this);
} else {
newNode = new WriteObjectObjectFieldNode(layout, (ObjectStorageLocation) storageLocation, this);
writeNode = new WriteObjectObjectFieldNode(currentShape, newShape, location, this);
}

replace(newNode, "adding new write object field node to chain");
newNode.execute(object, value);
replace(writeNode, "adding new write object field node to chain");
// not executing, value is already set
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2013 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.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.object.BooleanLocation;
import com.oracle.truffle.api.object.FinalLocationException;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class WriteBooleanObjectFieldNode extends WriteObjectFieldChainNode {

private final Shape expectedLayout;
private final Shape newLayout;
private final BooleanLocation storageLocation;

public WriteBooleanObjectFieldNode(Shape expectedLayout, Shape newLayout, BooleanLocation storageLocation, WriteObjectFieldNode next) {
super(next);
this.expectedLayout = expectedLayout;
this.newLayout = newLayout;
this.storageLocation = storageLocation;
}

@Override
public void execute(RubyBasicObject object, boolean value) {
try {
expectedLayout.getValidAssumption().check();
newLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
next.execute(object, value);
return;
}

if (object.getObjectLayout() == expectedLayout) {
try {
if (newLayout == expectedLayout) {
storageLocation.setBoolean(object.getDynamicObject(), value, expectedLayout);
} else {
storageLocation.setBoolean(object.getDynamicObject(), value, expectedLayout, newLayout);
}
} catch (FinalLocationException e) {
replace(next, "!final").execute(object, value);
}
} else {
next.execute(object, value);
}
}

@Override
public void execute(RubyBasicObject object, Object value) {
if (value instanceof Boolean) {
execute(object, (boolean) value);
} else {
next.execute(object, value);
}
}

}
Original file line number Diff line number Diff line change
@@ -9,35 +9,56 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.DoubleStorageLocation;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.DoubleLocation;
import com.oracle.truffle.api.object.FinalLocationException;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class WriteDoubleObjectFieldNode extends WriteObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final DoubleStorageLocation storageLocation;
private final Shape expectedLayout;
private final Shape newLayout;
private final DoubleLocation storageLocation;

public WriteDoubleObjectFieldNode(ObjectLayout objectLayout, DoubleStorageLocation storageLocation, WriteObjectFieldNode next) {
public WriteDoubleObjectFieldNode(Shape expectedLayout, Shape newLayout, DoubleLocation storageLocation, WriteObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.expectedLayout = expectedLayout;
this.newLayout = newLayout;
this.storageLocation = storageLocation;
}

@Override
public void execute(ObjectStorage object, double value) {
if (object.getObjectLayout() == objectLayout) {
storageLocation.writeDouble(object, value);
public void execute(RubyBasicObject object, double value) {
try {
expectedLayout.getValidAssumption().check();
newLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
next.execute(object, value);
return;
}

if (object.getObjectLayout() == expectedLayout) {
try {
if (newLayout == expectedLayout) {
storageLocation.setDouble(object.getDynamicObject(), value, expectedLayout);
} else {
storageLocation.setDouble(object.getDynamicObject(), value, expectedLayout, newLayout);
}
} catch (FinalLocationException e) {
replace(next, "!final").execute(object, value);
}
} else {
next.execute(object, value);
}
}

@Override
public void execute(ObjectStorage object, Object value) {
public void execute(RubyBasicObject object, Object value) {
if (value instanceof Double) {
execute(object, (double) value);
} else {
Original file line number Diff line number Diff line change
@@ -10,31 +10,31 @@
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.Node;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class WriteHeadObjectFieldNode extends Node {

private final String name;
@Child protected WriteObjectFieldNode first;

public WriteHeadObjectFieldNode(String name, RespecializeHook hook) {
public WriteHeadObjectFieldNode(String name) {
this.name = name;
first = new UninitializedWriteObjectFieldNode(name, hook);
first = new UninitializedWriteObjectFieldNode(name);
}

public void execute(ObjectStorage object, int value) {
public void execute(RubyBasicObject object, int value) {
first.execute(object, value);
}

public void execute(ObjectStorage object, long value) {
public void execute(RubyBasicObject object, long value) {
first.execute(object, value);
}

public void execute(ObjectStorage object, double value) {
public void execute(RubyBasicObject object, double value) {
first.execute(object, value);
}

public void execute(ObjectStorage object, Object value) {
public void execute(RubyBasicObject object, Object value) {
first.execute(object, value);
}

Original file line number Diff line number Diff line change
@@ -9,35 +9,56 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.IntegerStorageLocation;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.FinalLocationException;
import com.oracle.truffle.api.object.IntLocation;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class WriteIntegerObjectFieldNode extends WriteObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final IntegerStorageLocation storageLocation;
private final Shape expectedLayout;
private final Shape newLayout;
private final IntLocation storageLocation;

public WriteIntegerObjectFieldNode(ObjectLayout objectLayout, IntegerStorageLocation storageLocation, WriteObjectFieldNode next) {
public WriteIntegerObjectFieldNode(Shape expectedLayout, Shape newLayout, IntLocation storageLocation, WriteObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.expectedLayout = expectedLayout;
this.newLayout = newLayout;
this.storageLocation = storageLocation;
}

@Override
public void execute(ObjectStorage object, int value) {
if (object.getObjectLayout() == objectLayout) {
storageLocation.writeInteger(object, value);
public void execute(RubyBasicObject object, int value) {
try {
expectedLayout.getValidAssumption().check();
newLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
next.execute(object, value);
return;
}

if (object.getObjectLayout() == expectedLayout) {
try {
if (newLayout == expectedLayout) {
storageLocation.setInt(object.getDynamicObject(), value, expectedLayout);
} else {
storageLocation.setInt(object.getDynamicObject(), value, expectedLayout, newLayout);
}
} catch (FinalLocationException e) {
replace(next, "!final").execute(object, value);
}
} else {
next.execute(object, value);
}
}

@Override
public void execute(ObjectStorage object, Object value) {
public void execute(RubyBasicObject object, Object value) {
if (value instanceof Integer) {
execute(object, (int) value);
} else {
Original file line number Diff line number Diff line change
@@ -9,37 +9,65 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.LongStorageLocation;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import com.oracle.truffle.api.object.FinalLocationException;
import com.oracle.truffle.api.object.LongLocation;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class WriteLongObjectFieldNode extends WriteObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final LongStorageLocation storageLocation;
private final Shape expectedLayout;
private final Shape newLayout;
private final LongLocation storageLocation;

public WriteLongObjectFieldNode(ObjectLayout objectLayout, LongStorageLocation storageLocation, WriteObjectFieldNode next) {
public WriteLongObjectFieldNode(Shape expectedLayout, Shape newLayout, LongLocation storageLocation, WriteObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.expectedLayout = expectedLayout;
this.newLayout = newLayout;
this.storageLocation = storageLocation;
}

@Override
public void execute(ObjectStorage object, long value) {
if (object.getObjectLayout() == objectLayout) {
storageLocation.writeLong(object, value);
public void execute(RubyBasicObject object, long value) {
try {
expectedLayout.getValidAssumption().check();
newLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
next.execute(object, value);
return;
}

if (object.getObjectLayout() == expectedLayout) {
try {
if (newLayout == expectedLayout) {
storageLocation.setLong(object.getDynamicObject(), value, expectedLayout);
} else {
storageLocation.setLong(object.getDynamicObject(), value, expectedLayout, newLayout);
}
} catch (FinalLocationException e) {
replace(next, "!final").execute(object, value);
}
} else {
next.execute(object, value);
}
}

@Override
public void execute(ObjectStorage object, Object value) {
public void execute(RubyBasicObject object, int value) {
execute(object, (long) value);
}

@Override
public void execute(RubyBasicObject object, Object value) {
if (value instanceof Long) {
execute(object, (long) value);
} else if (value instanceof Integer) {
execute(object, (int) value);
} else {
next.execute(object, value);
}
Original file line number Diff line number Diff line change
@@ -10,21 +10,25 @@
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.Node;
import org.jruby.truffle.runtime.objectstorage.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public abstract class WriteObjectFieldNode extends Node {

public abstract void execute(ObjectStorage object, Object value);
public abstract void execute(RubyBasicObject object, Object value);

public void execute(ObjectStorage object, int value) {
public void execute(RubyBasicObject object, boolean value) {
execute(object, (Object) value);
}

public void execute(ObjectStorage object, long value) {
public void execute(RubyBasicObject object, int value) {
execute(object, (Object) value);
}

public void execute(ObjectStorage object, double value) {
public void execute(RubyBasicObject object, long value) {
execute(object, (Object) value);
}

public void execute(RubyBasicObject object, double value) {
execute(object, (Object) value);
}

Original file line number Diff line number Diff line change
@@ -9,28 +9,52 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import org.jruby.truffle.runtime.objectstorage.ObjectStorageLocation;
import com.oracle.truffle.api.object.FinalLocationException;
import com.oracle.truffle.api.object.IncompatibleLocationException;
import com.oracle.truffle.api.object.Location;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class WriteObjectObjectFieldNode extends WriteObjectFieldChainNode {

private final ObjectLayout objectLayout;
private final ObjectStorageLocation storageLocation;
private final Shape expectedLayout;
private final Shape newLayout;
private final Location storageLocation;

public WriteObjectObjectFieldNode(ObjectLayout objectLayout, ObjectStorageLocation storageLocation, WriteObjectFieldNode next) {
public WriteObjectObjectFieldNode(Shape expectedLayout, Shape newLayout, Location storageLocation, WriteObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
this.expectedLayout = expectedLayout;
this.newLayout = newLayout;
this.storageLocation = storageLocation;
}

@Override
public void execute(ObjectStorage object, Object value) {
if (object.getObjectLayout() == objectLayout) {
storageLocation.write(object, value);
public void execute(RubyBasicObject object, Object value) {
try {
expectedLayout.getValidAssumption().check();
newLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
next.execute(object, value);
return;
}

if (object.getObjectLayout() == expectedLayout && storageLocation.canStore(value)) {
try {
if (newLayout == expectedLayout) {
storageLocation.set(object.getDynamicObject(), value, expectedLayout);
} else {
storageLocation.set(object.getDynamicObject(), value, expectedLayout, newLayout);
}
} catch (IncompatibleLocationException e) {
throw new UnsupportedOperationException();
} catch (FinalLocationException e) {
replace(next, "!final").execute(object, value);
}
} else {
next.execute(object, value);
}
9 changes: 9 additions & 0 deletions core/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import java.util.Random;
import java.util.concurrent.atomic.*;

import com.oracle.truffle.api.object.Shape;
import org.jruby.Ruby;
import org.jruby.*;
import com.oracle.truffle.api.*;
@@ -30,6 +31,7 @@
import org.jruby.truffle.runtime.control.*;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyBinding;
import org.jruby.truffle.runtime.core.RubyException;
import org.jruby.truffle.runtime.core.RubyModule;
@@ -56,6 +58,7 @@ public class RubyContext extends ExecutionContext {
private final FiberManager fiberManager;
private final AtExitManager atExitManager;
private final RubySymbol.SymbolTable symbolTable = new RubySymbol.SymbolTable(this);
private final Shape emptyShape;
private final Warnings warnings;
private final SafepointManager safepointManager;
private final Random random = new Random();
@@ -96,6 +99,8 @@ public RubyContext(Ruby runtime) {
// Object space manager needs to come early before we create any objects
objectSpaceManager = new ObjectSpaceManager(this);

emptyShape = RubyBasicObject.LAYOUT.createShape(new RubyOperations(this));

// See note in CoreLibrary#initialize to see why we need to break this into two statements
coreLibrary = new CoreLibrary(this);
coreLibrary.initialize();
@@ -112,6 +117,10 @@ public RubyContext(Ruby runtime) {
rootLexicalScope = new LexicalScope(null, coreLibrary.getObjectClass());
}

public Shape getEmptyShape() {
return emptyShape;
}

public static String checkInstanceVariableName(RubyContext context, String name, RubyNode currentNode) {
RubyNode.notDesignedForCompilation();

81 changes: 81 additions & 0 deletions core/src/main/java/org/jruby/truffle/runtime/RubyOperations.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2014 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.runtime;

import com.oracle.truffle.api.object.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class RubyOperations extends ObjectType {

private final RubyContext context;

public RubyOperations(RubyContext context) {
this.context = context;
}

public void setInstanceVariable(RubyBasicObject receiver, String name, Object value) {
Shape shape = receiver.getDynamicObject().getShape();
Property property = shape.getProperty(name);
if (property != null) {
property.setGeneric(receiver.getDynamicObject(), value, null);
} else {
receiver.getDynamicObject().define(name, value, 0);
}
}

public void setInstanceVariables(RubyBasicObject receiver, Map<String, Object> instanceVariables) {
for (Map.Entry<String, Object> entry : instanceVariables.entrySet()) {
setInstanceVariable(receiver, entry.getKey(), entry.getValue());
}
}

public Object getInstanceVariable(RubyBasicObject receiver, String name) {
Shape shape = receiver.getDynamicObject().getShape();
Property property = shape.getProperty(name);
if (property != null) {
return property.get(receiver.getDynamicObject(), false);
} else {
return context.getCoreLibrary().getNilObject();
}
}

public Map<String,Object> getInstanceVariables(RubyBasicObject receiver) {
Shape shape = receiver.getDynamicObject().getShape();
Map<String, Object> vars = new LinkedHashMap<>();
List<Property> properties = shape.getPropertyList();
for (Property property : properties) {
vars.put((String) property.getKey(), property.get(receiver.getDynamicObject(), false));
}
return vars;
}

public String[] getFieldNames(RubyBasicObject receiver) {
return receiver.getDynamicObject().getShape().getKeyList().toArray(new String[0]);
}

public boolean isFieldDefined(RubyBasicObject receiver, String name) {
return receiver.getDynamicObject().getShape().hasProperty(name);
}

@Override
public boolean equals(DynamicObject dynamicObject, Object o) {
throw new UnsupportedOperationException();
}

@Override
public int hashCode(DynamicObject dynamicObject) {
throw new UnsupportedOperationException();
}

}
Original file line number Diff line number Diff line change
@@ -271,7 +271,6 @@ public void initialize() {
// Create the globals object

globalVariablesObject = new RubyBasicObject(objectClass);
globalVariablesObject.switchToPrivateLayout();
globalVariablesObject.setInstanceVariable("$LOAD_PATH", new RubyArray(arrayClass));
globalVariablesObject.setInstanceVariable("$LOADED_FEATURES", new RubyArray(arrayClass));
globalVariablesObject.setInstanceVariable("$:", globalVariablesObject.getInstanceVariable("$LOAD_PATH"));
Original file line number Diff line number Diff line change
@@ -13,33 +13,42 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.Layout;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.RubyOperations;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.objectstorage.ObjectLayout;
import org.jruby.truffle.runtime.objectstorage.ObjectStorage;
import org.jruby.truffle.runtime.subsystems.ObjectSpaceManager;

import java.util.Map;
import java.util.Map.Entry;

/**
* Represents the Ruby {@code BasicObject} class - the root of the Ruby class hierarchy.
*/
public class RubyBasicObject extends ObjectStorage {
public class RubyBasicObject {

public static Layout LAYOUT = Layout.createLayout(Layout.INT_TO_LONG);

private final DynamicObject dynamicObject;

/** The class of the object, not a singleton class. */
@CompilationFinal protected RubyClass logicalClass;
/** Either the singleton class if it exists or the logicalClass. */
@CompilationFinal protected RubyClass metaClass;

protected long objectID = -1;

private boolean frozen = false;
public boolean hasPrivateLayout = false;

public RubyBasicObject(RubyClass rubyClass) {
super(rubyClass != null ? rubyClass.getObjectLayoutForInstances() : ObjectLayout.EMPTY);
this(rubyClass, rubyClass.getContext());
}

public RubyBasicObject(RubyClass rubyClass, RubyContext context) {
dynamicObject = LAYOUT.newInstance(context.getEmptyShape());

if (rubyClass != null) {
unsafeSetLogicalClass(rubyClass);
@@ -98,14 +107,7 @@ public RubyClass getSingletonClass(Node currentNode) {

public void setInstanceVariable(String name, Object value) {
RubyNode.notDesignedForCompilation();

updateLayoutToMatchClass();

setField(name, value);

if (logicalClass.getObjectLayoutForInstances() != objectLayout) {
logicalClass.setObjectLayoutForInstances(objectLayout);
}
getOperations().setInstanceVariable(this, name, value);
}

@CompilerDirectives.TruffleBoundary
@@ -119,31 +121,17 @@ public long getObjectID() {

@CompilerDirectives.TruffleBoundary
public void setInstanceVariables(Map<String, Object> instanceVariables) {
updateLayoutToMatchClass();
setFields(instanceVariables);
getOperations().setInstanceVariables(this, instanceVariables);
}

public void updateLayoutToMatchClass() {
RubyNode.notDesignedForCompilation();

if (objectLayout != logicalClass.getObjectLayoutForInstances()) {
changeLayout(logicalClass.getObjectLayoutForInstances());
}
@CompilerDirectives.TruffleBoundary
public Map<String, Object> getInstanceVariables() {
return getOperations().getInstanceVariables(this);
}

public void switchToPrivateLayout() {
RubyNode.notDesignedForCompilation();

final Map<String, Object> instanceVariables = getFields();

hasPrivateLayout = true;
objectLayout = ObjectLayout.EMPTY;

for (Entry<String, Object> entry : instanceVariables.entrySet()) {
objectLayout = objectLayout.withNewVariable(entry.getKey(), entry.getValue().getClass());
}

setInstanceVariables(instanceVariables);
public String[] getFieldNames() {
return getOperations().getFieldNames(this);
}

public void extend(RubyModule module, RubyNode currentNode) {
@@ -166,7 +154,7 @@ public void unsafeSetLogicalClass(RubyClass newLogicalClass) {
public Object getInstanceVariable(String name) {
RubyNode.notDesignedForCompilation();

final Object value = getField(name);
final Object value = getOperations().getInstanceVariable(this, name);

if (value == null) {
return getContext().getCoreLibrary().getNilObject();
@@ -175,15 +163,15 @@ public Object getInstanceVariable(String name) {
}
}

public boolean hasPrivateLayout() {
return hasPrivateLayout;
public boolean isFieldDefined(String name) {
return getOperations().isFieldDefined(this, name);
}

public void visitObjectGraph(ObjectSpaceManager.ObjectGraphVisitor visitor) {
if (visitor.visit(this)) {
metaClass.visitObjectGraph(visitor);

for (Object instanceVariable : getFields().values()) {
for (Object instanceVariable : getOperations().getInstanceVariables(this).values()) {
if (instanceVariable instanceof RubyBasicObject) {
((RubyBasicObject) instanceVariable).visitObjectGraph(visitor);
}
@@ -204,8 +192,19 @@ public RubyContext getContext() {
return logicalClass.getContext();
}

public Shape getObjectLayout() {
return dynamicObject.getShape();
}

public RubyOperations getOperations() {
return (RubyOperations) dynamicObject.getShape().getObjectType();
}

public RubyClass getLogicalClass() {
return logicalClass;
}

public DynamicObject getDynamicObject() {
return dynamicObject;
}
}
43 changes: 2 additions & 41 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyClass.java
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import com.oracle.truffle.api.nodes.Node;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.objectstorage.*;

/**
* Represents the Ruby {@code Class} class. Note that most of the functionality you might associate
@@ -26,7 +25,6 @@ public class RubyClass extends RubyModule {

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

/**
* The class from which we create the object that is {@code Class}. A subclass of
@@ -70,9 +68,7 @@ protected RubyClass(RubyContext context, RubyModule lexicalParent, RubyClass sup
super(context, context.getCoreLibrary().getClassClass(), lexicalParent, name, null);
this.isSingleton = isSingleton;

if (superclass == null) {
objectLayoutForInstances = ObjectLayout.EMPTY;
} else {
if (superclass != null) {
unsafeSetSuperclass(superclass);
}
}
@@ -87,7 +83,6 @@ public void initCopy(RubyModule other) {
super.initCopy(other);
assert other instanceof RubyClass;
final RubyClass otherClass = (RubyClass) other;
this.objectLayoutForInstances = otherClass.objectLayoutForInstances;
}

private RubyClass ensureSingletonConsistency() {
@@ -135,7 +130,7 @@ public void unsafeSetSuperclass(RubyClass newSuperclass) {
unsafeSetParent(newSuperclass);
newSuperclass.subClasses.add(this);

objectLayoutForInstances = new ObjectLayout(newSuperclass.objectLayoutForInstances);
newVersion();
}

@TruffleBoundary
@@ -147,40 +142,6 @@ public boolean isSingleton() {
return isSingleton;
}

/**
* Returns the object layout that objects of this class should use. Do not confuse with
* {@link #getObjectLayout}, which for {@link RubyClass} will return the layout of the class
* object itself.
*/
public ObjectLayout getObjectLayoutForInstances() {
return objectLayoutForInstances;
}

/**
* Change the layout to be used for instances of this object.
*/
public void setObjectLayoutForInstances(ObjectLayout newObjectLayoutForInstances) {
RubyNode.notDesignedForCompilation();

assert newObjectLayoutForInstances != objectLayoutForInstances;

objectLayoutForInstances = newObjectLayoutForInstances;

for (RubyClass subClass : subClasses) {
subClass.renewObjectLayoutForInstances();
}
}

private void renewObjectLayoutForInstances() {
RubyNode.notDesignedForCompilation();

objectLayoutForInstances = objectLayoutForInstances.withNewParent(getSuperClass().objectLayoutForInstances);

for (RubyClass subClass : subClasses) {
subClass.renewObjectLayoutForInstances();
}
}

public RubyClass getSuperClass() {
CompilerAsserts.neverPartOfCompilation();

Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ public RubyModule(RubyContext context, RubyModule lexicalParent, String name, Ru
}

protected RubyModule(RubyContext context, RubyClass selfClass, RubyModule lexicalParent, String name, RubyNode currentNode) {
super(selfClass);
super(selfClass, context);
this.context = context;
this.name = name;

Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.runtime.core;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.MaterializedFrame;
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;

import java.util.Date;

/**

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 2 additions & 0 deletions test/pom.rb
Original file line number Diff line number Diff line change
@@ -185,6 +185,7 @@
'<arg value="-Xparser.warn.regex_condition=false" />' +
'<arg value="-Xparser.warn.argument_prefix=false" />' +
'<arg value="-J-ea" />' +
'<arg value="-J-Xmx1G" />' +
'<arg value="spec/mspec/bin/mspec" />' +
'<arg value="run" />' +
'<arg value="-t" />' +
@@ -235,6 +236,7 @@
'<arg value="-Xparser.warn.regex_condition=false" />' +
'<arg value="-Xparser.warn.argument_prefix=false" />' +
'<arg value="-J-ea" />' +
'<arg value="-J-Xmx1G" />' +
'<arg value="spec/mspec/bin/mspec" />' +
'<arg value="run" />' +
'<arg value="-t" />' +
2 changes: 2 additions & 0 deletions test/pom.xml
Original file line number Diff line number Diff line change
@@ -676,6 +676,7 @@
<arg value="-Xparser.warn.regex_condition=false" />
<arg value="-Xparser.warn.argument_prefix=false" />
<arg value="-J-ea" />
<arg value="-J-Xmx1G" />
<arg value="spec/mspec/bin/mspec" />
<arg value="run" />
<arg value="-t" />
@@ -718,6 +719,7 @@
<arg value="-Xparser.warn.regex_condition=false" />
<arg value="-Xparser.warn.argument_prefix=false" />
<arg value="-J-ea" />
<arg value="-J-Xmx1G" />
<arg value="spec/mspec/bin/mspec" />
<arg value="run" />
<arg value="-t" />

0 comments on commit 42d8c43

Please sign in to comment.