-
-
Notifications
You must be signed in to change notification settings - Fork 925
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Truffle] Remove use of slow ruby helper in IO primitives.
- 9.4.12.0
- 9.4.11.0
- 9.4.10.0
- 9.4.9.0
- 9.4.8.0
- 9.4.7.0
- 9.4.6.0
- 9.4.5.0
- 9.4.4.0
- 9.4.3.0
- 9.4.2.0
- 9.4.1.0
- 9.4.0.0
- 9.3.15.0
- 9.3.14.0
- 9.3.13.0
- 9.3.12.0
- 9.3.11.0
- 9.3.10.0
- 9.3.9.0
- 9.3.8.0
- 9.3.7.0
- 9.3.6.0
- 9.3.5.0
- 9.3.4.0
- 9.3.3.0
- 9.3.2.0
- 9.3.1.0
- 9.3.0.0
- 9.2.21.0
- 9.2.20.1
- 9.2.20.0
- 9.2.19.0
- 9.2.18.0
- 9.2.17.0
- 9.2.16.0
- 9.2.15.0
- 9.2.14.0
- 9.2.13.0
- 9.2.12.0
- 9.2.11.1
- 9.2.11.0
- 9.2.10.0
- 9.2.9.0
- 9.2.8.0
- 9.2.7.0
- 9.2.6.0
- 9.2.5.0
- 9.2.4.1
- 9.2.4.0
- 9.2.3.0
- 9.2.2.0
- 9.2.1.0
- 9.2.0.0
- 9.1.17.0
- 9.1.16.0
- 9.1.15.0
- 9.1.14.0
- 9.1.13.0
- 9.1.12.0
- 9.1.11.0
- 9.1.10.0
- 9.1.9.0
- 9.1.8.0
- 9.1.7.0
- 9.1.6.0
- 9.1.5.0
- 9.1.4.0
- 9.1.3.0
- 9.1.2.0
- 9.1.1.0
- 9.1.0.0
- 9.0.5.0
- 9.0.4.0
- 9.0.3.0
- 9.0.1.0
- 9.0.0.0
- 9.0.0.0.rc2
- 9.0.0.0.rc1
1 parent
6fc0135
commit 73285cb
Showing
2 changed files
with
138 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,13 +40,19 @@ | |
import com.oracle.truffle.api.CompilerDirectives; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import com.oracle.truffle.api.frame.VirtualFrame; | ||
import com.oracle.truffle.api.nodes.Node; | ||
import com.oracle.truffle.api.object.*; | ||
import com.oracle.truffle.api.source.SourceSection; | ||
|
||
import jnr.constants.platform.Errno; | ||
import jnr.constants.platform.Fcntl; | ||
|
||
import jnr.ffi.byref.IntByReference; | ||
import org.jruby.RubyEncoding; | ||
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode; | ||
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode; | ||
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory; | ||
import org.jruby.truffle.nodes.objects.Allocator; | ||
import org.jruby.truffle.runtime.RubyContext; | ||
import org.jruby.truffle.runtime.control.RaiseException; | ||
import org.jruby.truffle.runtime.core.RubyArray; | ||
|
@@ -63,33 +69,117 @@ | |
|
||
import java.nio.ByteBuffer; | ||
import java.util.Arrays; | ||
import java.util.EnumSet; | ||
|
||
public abstract class IOPrimitiveNodes { | ||
|
||
private static int STDOUT = 1; | ||
|
||
private static final String IBUFFER_IDENTIFIER = "@ibuffer"; | ||
private static final Property IBUFFER_PROPERTY; | ||
|
||
private static final String LINENO_IDENTIFIER = "@lineno"; | ||
private static final Property LINENO_PROPERTY; | ||
|
||
private static final String DESCRIPTOR_IDENTIFIER = "@descriptor"; | ||
private static final Property DESCRIPTOR_PROPERTY; | ||
|
||
private static final String MODE_IDENTIFIER = "@mode"; | ||
private static final Property MODE_PROPERTY; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
chrisseaton
Author
Contributor
|
||
|
||
private static final DynamicObjectFactory IO_FACTORY; | ||
|
||
static { | ||
final Shape.Allocator allocator = RubyBasicObject.LAYOUT.createAllocator(); | ||
|
||
IBUFFER_PROPERTY = Property.create(IBUFFER_IDENTIFIER, allocator.locationForType(RubyBasicObject.class, EnumSet.of(LocationModifier.NonNull)), 0); | ||
LINENO_PROPERTY = Property.create(LINENO_IDENTIFIER, allocator.locationForType(Integer.class, EnumSet.of(LocationModifier.NonNull)), 0); | ||
DESCRIPTOR_PROPERTY = Property.create(DESCRIPTOR_IDENTIFIER, allocator.locationForType(Integer.class, EnumSet.of(LocationModifier.NonNull)), 0); | ||
MODE_PROPERTY = Property.create(MODE_IDENTIFIER, allocator.locationForType(RubyBasicObject.class, EnumSet.of(LocationModifier.NonNull)), 0); | ||
|
||
IO_FACTORY = RubyBasicObject.EMPTY_SHAPE | ||
.addProperty(IBUFFER_PROPERTY) | ||
.addProperty(LINENO_PROPERTY) | ||
.addProperty(DESCRIPTOR_PROPERTY) | ||
.addProperty(MODE_PROPERTY) | ||
.createFactory(); | ||
} | ||
|
||
public static class IOAllocator implements Allocator { | ||
@Override | ||
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, Node currentNode) { | ||
return new RubyBasicObject(rubyClass, IO_FACTORY.newInstance(context.getCoreLibrary().getNilObject(), 0, 0, context.getCoreLibrary().getNilObject())); | ||
} | ||
} | ||
|
||
private static Object getIBuffer(RubyBasicObject io) { | ||
assert io.getDynamicObject().getShape().hasProperty(IBUFFER_IDENTIFIER); | ||
return IBUFFER_PROPERTY.get(io.getDynamicObject(), true); | ||
} | ||
|
||
private static Object getLineNo(RubyBasicObject io) { | ||
assert io.getDynamicObject().getShape().hasProperty(LINENO_IDENTIFIER); | ||
return IBUFFER_PROPERTY.get(io.getDynamicObject(), true); | ||
} | ||
|
||
private static int getDescriptor(RubyBasicObject io) { | ||
assert io.getDynamicObject().getShape().hasProperty(DESCRIPTOR_IDENTIFIER); | ||
return (int) DESCRIPTOR_PROPERTY.get(io.getDynamicObject(), true); | ||
} | ||
|
||
private static Object getMode(RubyBasicObject io) { | ||
assert io.getDynamicObject().getShape().hasProperty(MODE_IDENTIFIER); | ||
return MODE_PROPERTY.get(io.getDynamicObject(), true); | ||
} | ||
|
||
public static void setDescriptor(RubyBasicObject io, int newDescriptor) { | ||
assert io.getDynamicObject().getShape().hasProperty(DESCRIPTOR_IDENTIFIER); | ||
|
||
try { | ||
DESCRIPTOR_PROPERTY.set(io.getDynamicObject(), newDescriptor, io.getDynamicObject().getShape()); | ||
} catch (IncompatibleLocationException | FinalLocationException e) { | ||
throw new UnsupportedOperationException(e); | ||
} | ||
} | ||
|
||
public static void setMode(RubyBasicObject io, Object newMode) { | ||
assert io.getDynamicObject().getShape().hasProperty(MODE_IDENTIFIER); | ||
|
||
try { | ||
MODE_PROPERTY.set(io.getDynamicObject(), newMode, io.getDynamicObject().getShape()); | ||
} catch (IncompatibleLocationException | FinalLocationException e) { | ||
throw new UnsupportedOperationException(e); | ||
} | ||
} | ||
|
||
@RubiniusPrimitive(name = "io_allocate") | ||
public static abstract class IOAllocatePrimitiveNode extends RubiniusPrimitiveNode { | ||
|
||
@Child private CallDispatchHeadNode newBufferNode; | ||
|
||
public IOAllocatePrimitiveNode(RubyContext context, SourceSection sourceSection) { | ||
super(context, sourceSection); | ||
newBufferNode = DispatchHeadNodeFactory.createMethodCall(context); | ||
} | ||
|
||
@Specialization | ||
public RubyBasicObject allocate(VirtualFrame frame, RubyClass classToAllocate) { | ||
final RubyBasicObject object = new RubyBasicObject(classToAllocate); | ||
rubyWithSelf(frame, object, "@ibuffer = IO::InternalBuffer.new"); | ||
rubyWithSelf(frame, object, "@lineno = 0"); | ||
return object; | ||
final Object buffer = newBufferNode.call(frame, getContext().getCoreLibrary().getIOBufferClass(), "new", null); | ||
return new RubyBasicObject(classToAllocate, IO_FACTORY.newInstance(buffer, 0, 0, nil())); | ||
} | ||
|
||
} | ||
|
||
@RubiniusPrimitive(name = "io_connect_pipe", needsSelf = false) | ||
public static abstract class IOConnectPipeNode extends RubiniusPrimitiveNode { | ||
|
||
private final int RDONLY; | ||
private final int WRONLY; | ||
|
||
public IOConnectPipeNode(RubyContext context, SourceSection sourceSection) { | ||
super(context, sourceSection); | ||
RDONLY = (int) context.getRubiniusConfiguration().get("rbx.platform.file.O_RDONLY"); | ||
WRONLY = (int) context.getRubiniusConfiguration().get("rbx.platform.file.O_WRONLY"); | ||
} | ||
|
||
@Specialization | ||
|
@@ -104,11 +194,11 @@ public boolean connectPipe(VirtualFrame frame, RubyBasicObject lhs, RubyBasicObj | |
newOpenFd(fds[0]); | ||
newOpenFd(fds[1]); | ||
|
||
rubyWithSelf(frame, lhs, "@descriptor = fd", "fd", fds[0]); | ||
rubyWithSelf(frame, lhs, "@mode = File::Constants::RDONLY"); | ||
setDescriptor(lhs, fds[0]); | ||
setMode(lhs, RDONLY); | ||
|
||
rubyWithSelf(frame, rhs, "@descriptor = fd", "fd", fds[1]); | ||
rubyWithSelf(frame, rhs, "@mode = File::Constants::WRONLY"); | ||
setDescriptor(rhs, fds[1]); | ||
setMode(rhs, WRONLY); | ||
|
||
return true; | ||
} | ||
|
@@ -188,7 +278,7 @@ public int ftruncate(VirtualFrame frame, RubyBasicObject io, int length) { | |
|
||
@Specialization | ||
public int ftruncate(VirtualFrame frame, RubyBasicObject io, long length) { | ||
final int fd = (int) rubyWithSelf(frame, io, "@descriptor"); | ||
final int fd = getDescriptor(io); | ||
return posix().ftruncate(fd, length); | ||
} | ||
|
||
|
@@ -225,7 +315,7 @@ public IOEnsureOpenPrimitiveNode(RubyContext context, SourceSection sourceSectio | |
@Specialization | ||
public RubyBasicObject ensureOpen(VirtualFrame frame, RubyBasicObject file) { | ||
// TODO BJF 13-May-2015 Handle nil case | ||
final int fd = (int) rubyWithSelf(frame, file, "@descriptor"); | ||
final int fd = getDescriptor(file); | ||
if(fd == -1){ | ||
CompilerDirectives.transferToInterpreter(); | ||
throw new RaiseException(getContext().getCoreLibrary().ioError("closed stream",this)); | ||
|
@@ -241,14 +331,17 @@ public RubyBasicObject ensureOpen(VirtualFrame frame, RubyBasicObject file) { | |
@RubiniusPrimitive(name = "io_reopen") | ||
public static abstract class IOReopenPrimitiveNode extends RubiniusPrimitiveNode { | ||
|
||
@Child private CallDispatchHeadNode resetBufferingNode; | ||
|
||
public IOReopenPrimitiveNode(RubyContext context, SourceSection sourceSection) { | ||
super(context, sourceSection); | ||
resetBufferingNode = DispatchHeadNodeFactory.createMethodCall(context); | ||
} | ||
|
||
@Specialization | ||
public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject io) { | ||
final int fd = (int) rubyWithSelf(frame, file, "@descriptor"); | ||
final int fdOther = (int) rubyWithSelf(frame, io, "@descriptor"); | ||
final int fd = getDescriptor(file); | ||
final int fdOther = getDescriptor(io); | ||
|
||
final int result = posix().dup2(fd, fdOther); | ||
if (result == -1) { | ||
|
@@ -261,9 +354,9 @@ public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject i | |
CompilerDirectives.transferToInterpreter(); | ||
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this)); | ||
} | ||
rubyWithSelf(frame, file, "@mode = mode", "mode", mode); | ||
setMode(file, mode); | ||
|
||
rubyWithSelf(frame, io, "reset_buffering"); | ||
resetBufferingNode.call(frame, io, "reset_buffering", null); | ||
|
||
return nil(); | ||
} | ||
|
@@ -273,13 +366,16 @@ public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject i | |
@RubiniusPrimitive(name = "io_reopen_path") | ||
public static abstract class IOReopenPathPrimitiveNode extends RubiniusPrimitiveNode { | ||
|
||
@Child private CallDispatchHeadNode resetBufferingNode; | ||
|
||
public IOReopenPathPrimitiveNode(RubyContext context, SourceSection sourceSection) { | ||
super(context, sourceSection); | ||
resetBufferingNode = DispatchHeadNodeFactory.createMethodCall(context); | ||
} | ||
|
||
@Specialization | ||
public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyString path, int mode) { | ||
int fd = (int) rubyWithSelf(frame, file, "@descriptor"); | ||
int fd = getDescriptor(file); | ||
final String pathString = path.toString(); | ||
|
||
int otherFd = posix().open(pathString, mode, 666); | ||
|
@@ -292,7 +388,7 @@ public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyString pa | |
if (result == -1) { | ||
final int errno = posix().errno(); | ||
if (errno == Errno.EBADF.intValue()) { | ||
rubyWithSelf(frame, file, "@descriptor = desc", "desc", otherFd); | ||
setDescriptor(file, otherFd); | ||
fd = otherFd; | ||
} else { | ||
if (otherFd > 0) { | ||
|
@@ -312,9 +408,9 @@ public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyString pa | |
CompilerDirectives.transferToInterpreter(); | ||
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this)); | ||
} | ||
rubyWithSelf(frame, file, "@mode = mode", "mode", newMode); | ||
setMode(file, newMode); | ||
|
||
rubyWithSelf(frame, file, "reset_buffering"); | ||
resetBufferingNode.call(frame, file, "reset_buffering", null); | ||
|
||
return nil(); | ||
} | ||
|
@@ -330,7 +426,7 @@ public IOWritePrimitiveNode(RubyContext context, SourceSection sourceSection) { | |
|
||
@Specialization | ||
public int write(VirtualFrame frame, RubyBasicObject file, RubyString string) { | ||
final int fd = (int) rubyWithSelf(frame, file, "@descriptor"); | ||
final int fd = getDescriptor(file); | ||
|
||
if (getContext().getDebugStandardOut() != null && fd == STDOUT) { | ||
getContext().getDebugStandardOut().write(string.getByteList().unsafeBytes(), string.getByteList().begin(), string.getByteList().length()); | ||
|
@@ -368,20 +464,24 @@ public int write(VirtualFrame frame, RubyBasicObject file, RubyString string) { | |
@RubiniusPrimitive(name = "io_close") | ||
public static abstract class IOClosePrimitiveNode extends RubiniusPrimitiveNode { | ||
|
||
@Child private CallDispatchHeadNode ensureOpenNode; | ||
|
||
public IOClosePrimitiveNode(RubyContext context, SourceSection sourceSection) { | ||
super(context, sourceSection); | ||
ensureOpenNode = DispatchHeadNodeFactory.createMethodCall(context); | ||
} | ||
|
||
@Specialization | ||
public int close(VirtualFrame frame, RubyBasicObject io) { | ||
rubyWithSelf(frame, io, "ensure_open"); | ||
final int fd = (int) rubyWithSelf(frame, io, "@descriptor"); | ||
ensureOpenNode.call(frame, io, "ensure_open", null); | ||
|
||
final int fd = getDescriptor(io); | ||
|
||
if (fd == -1) { | ||
return 0; | ||
} | ||
|
||
rubyWithSelf(frame, io, "@descriptor = -1"); | ||
setDescriptor(io, -1); | ||
|
||
if (fd < 3) { | ||
return 0; | ||
|
@@ -408,7 +508,7 @@ public IOSeekPrimitiveNode(RubyContext context, SourceSection sourceSection) { | |
|
||
@Specialization | ||
public int seek(VirtualFrame frame, RubyBasicObject io, int amount, int whence) { | ||
final int fd = (int) rubyWithSelf(frame, io, "@descriptor"); | ||
final int fd = getDescriptor(io); | ||
return posix().lseek(fd, amount, whence); | ||
} | ||
|
||
|
@@ -423,7 +523,7 @@ public AcceptNode(RubyContext context, SourceSection sourceSection) { | |
|
||
@Specialization | ||
public int accept(VirtualFrame frame, RubyBasicObject io) { | ||
final int fd = (int) rubyWithSelf(frame, io, "@descriptor"); | ||
final int fd = getDescriptor(io); | ||
|
||
final IntByReference addressLength = new IntByReference(16); | ||
final long address = UnsafeHolder.U.allocateMemory(addressLength.intValue()); | ||
|
@@ -455,7 +555,7 @@ public IOSysReadPrimitiveNode(RubyContext context, SourceSection sourceSection) | |
|
||
@Specialization | ||
public RubyString sysread(VirtualFrame frame, RubyBasicObject file, int length) { | ||
final int fd = (int) rubyWithSelf(frame, file, "@descriptor"); | ||
final int fd = getDescriptor(file); | ||
|
||
final ByteBuffer buffer = ByteBuffer.allocate(length); | ||
|
||
|
@@ -483,10 +583,9 @@ public IOSelectPrimitiveNode(RubyContext context, SourceSection sourceSection) { | |
super(context, sourceSection); | ||
} | ||
|
||
@CompilerDirectives.TruffleBoundary | ||
@Specialization(guards = {"isNil(writables)", "isNil(errorables)"}) | ||
public Object select(VirtualFrame frame, RubyArray readables, RubyBasicObject writables, RubyBasicObject errorables, int timeout) { | ||
CompilerDirectives.transferToInterpreter(); | ||
|
||
final Object[] readableObjects = readables.slowToArray(); | ||
final int[] readableFds = getFileDescriptors(frame, readables); | ||
|
||
|
@@ -524,7 +623,11 @@ private int[] getFileDescriptors(VirtualFrame frame, RubyArray fileDescriptorArr | |
final int[] fileDescriptors = new int[objects.length]; | ||
|
||
for (int n = 0; n < objects.length; n++) { | ||
fileDescriptors[n] = (int) rubyWithSelf(frame, objects[n], "@descriptor"); | ||
if (!(objects[n] instanceof RubyBasicObject)) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
fileDescriptors[n] = getDescriptor((RubyBasicObject) objects[n]); | ||
} | ||
|
||
return fileDescriptors; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is great! So it means we can use predefined properties for ivars as well, we just need the right identifier.
(And no more needing internal nodes and translator hacks to translate those)