Skip to content

Commit

Permalink
Showing 116 changed files with 2,453 additions and 851 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -73,6 +73,8 @@ tool/nailgun/config.log
tool/nailgun/config.status
tool/nailgun/ng
reference.txt
rubyspec_temp
.polyglot.pom.rb

# binaries
!bin/gem
@@ -109,4 +111,4 @@ findbugs-noUpdateChecks-3.0.0.tar.gz
findbugs-3.0.0

# Vagrant
/.vagrant
.vagrant
8 changes: 5 additions & 3 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -930,16 +930,18 @@ private TruffleContextInterface loadTruffleContext() {
throw new RuntimeException("Truffle backend not available", e);
}

final TruffleContextInterface truffleBridge;
final TruffleContextInterface truffleContext;

try {
Constructor<?> con = clazz.getConstructor(Ruby.class);
truffleBridge = (TruffleContextInterface) con.newInstance(this);
truffleContext = (TruffleContextInterface) con.newInstance(this);
} catch (Exception e) {
throw new RuntimeException("Error while calling the constructor of Truffle's RubyContext", e);
}

return truffleBridge;
truffleContext.initialize();

return truffleContext;
}

public void shutdownTruffleContextIfRunning() {
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/TruffleContextInterface.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,8 @@ enum BacktraceFormatter {
IMPL_DEBUG
}

void initialize();

Object execute(org.jruby.ast.RootNode rootNode);

void shutdown();
9 changes: 3 additions & 6 deletions core/src/main/java/org/jruby/ast/Node.java
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
package org.jruby.ast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.jruby.ParseResult;
@@ -79,11 +80,7 @@ public void setPosition(ISourcePosition position) {
public abstract List<Node> childNodes();

protected static List<Node> createList(Node node) {
ArrayList<Node> list = new ArrayList<>(1);

list.add(node);

return list;
return Collections.singletonList(node);
}

protected static List<Node> createList(Node node1, Node node2) {
@@ -218,4 +215,4 @@ public boolean needsDefinitionCheck() {
public boolean containsVariableAssignment() {
return containsVariableAssignment;
}
}
}
Original file line number Diff line number Diff line change
@@ -3,15 +3,17 @@
import org.jruby.RubyModule;
import org.jruby.ir.IRScope;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.runtime.ThreadContext;

/**
* Blocks and methods both share same full build mechanism so they implement this to be buildable.
*/
public interface FullBuildSource {
public interface Compilable<T> {
public void setCallCount(int count);
public void switchToFullBuild(InterpreterContext interpreterContext);
public void completeBuild(T buildResult);
public IRScope getIRScope();
public InterpreterContext ensureInstrsReady();
public String getClassName(ThreadContext context);
public String getName();
public String getFile();
public int getLine();
93 changes: 34 additions & 59 deletions core/src/main/java/org/jruby/compiler/JITCompiler.java
Original file line number Diff line number Diff line change
@@ -137,49 +137,30 @@ public long getLargestCodeSize() {
}

public void tearDown() {
if (executor != null) {
try {
executor.shutdown();
} catch (SecurityException se) {
// ignore, can't shut down executor
}
try {
executor.shutdown();
} catch (SecurityException se) {
// ignore, can't shut down executor
}
}

public void fullBuildThresholdReached(final FullBuildSource method, final RubyInstanceConfig config) {
// Disable any other jit tasks from entering queue
method.setCallCount(-1);

Runnable jitTask = new FullBuildTask(method);

if (config.getJitThreshold() > 0) {
if (config.getJitBackground() && executor != null) {
try {
executor.submit(jitTask);
} catch (RejectedExecutionException ree) {
// failed to submit, just run it directly
jitTask.run();
}
} else {
// Because are non-asynchonously build if the JIT threshold happens to be 0 we will have no ic yet.
method.ensureInstrsReady();
// just run directly
jitTask.run();
}
public Runnable getTaskFor(ThreadContext context, Compilable method) {
if (method instanceof MixedModeIRMethod) {
return new JITTask((MixedModeIRMethod) method, method.getClassName(context));
}

return new FullBuildTask(method);
}

public void jitThresholdReached(final MixedModeIRMethod method, final RubyInstanceConfig config, ThreadContext context, final String className, final String methodName) {

public void buildThresholdReached(ThreadContext context, final Compilable method) {
final RubyInstanceConfig config = context.runtime.getInstanceConfig();

// Disable any other jit tasks from entering queue
method.setCallCount(-1);

Runnable jitTask = new JITTask(className, method, methodName);

// if background JIT is enabled and threshold is > 0 and we have an executor...
if (config.getJitBackground() &&
config.getJitThreshold() > 0 &&
executor != null) {
// JIT in background
Runnable jitTask = getTaskFor(context, method);

if (config.getJitBackground() && config.getJitThreshold() > 0) {
try {
executor.submit(jitTask);
} catch (RejectedExecutionException ree) {
@@ -189,7 +170,6 @@ public void jitThresholdReached(final MixedModeIRMethod method, final RubyInstan
} else {
// Because are non-asynchonously build if the JIT threshold happens to be 0 we will have no ic yet.
method.ensureInstrsReady();

// just run directly
jitTask.run();
}
@@ -198,15 +178,15 @@ public void jitThresholdReached(final MixedModeIRMethod method, final RubyInstan
private static final MethodHandles.Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup().in(Ruby.class);

private class FullBuildTask implements Runnable {
private final FullBuildSource method;
private final Compilable method;

public FullBuildTask(FullBuildSource method) {
public FullBuildTask(Compilable method) {
this.method = method;
}

public void run() {
try {
method.switchToFullBuild(method.getIRScope().prepareFullBuild());
method.completeBuild(method.getIRScope().prepareFullBuild());

if (config.isJitLogging()) {
log(method.getImplementationClass(), method.getFile(), method.getLine(), method.getName(), "done building");
@@ -228,10 +208,10 @@ private class JITTask implements Runnable {
private final MixedModeIRMethod method;
private final String methodName;

public JITTask(String className, MixedModeIRMethod method, String methodName) {
this.className = className;
public JITTask(MixedModeIRMethod method, String className) {
this.method = method;
this.methodName = methodName;
this.className = className;
this.methodName = method.getName();
}

public void run() {
@@ -258,7 +238,7 @@ public void run() {
}
}

String key = SexpMaker.sha1(method.getIRMethod());
String key = SexpMaker.sha1(method.getIRScope());
JVMVisitor visitor = new JVMVisitor();
JITClassGenerator generator = new JITClassGenerator(className, methodName, key, runtime, method, visitor);

@@ -269,7 +249,7 @@ public void run() {
// that's so big that JVMs won't even try to compile it. Removed the check because with the new IR JIT
// bytecode counts often include all nested scopes, even if they'd be different methods. We need a new
// mechanism of getting all method sizes.
Class sourceClass = visitor.defineFromBytecode(method.getIRMethod(), generator.bytecode(), new OneShotClassLoader(runtime.getJRubyClassLoader()));
Class sourceClass = visitor.defineFromBytecode(method.getIRScope(), generator.bytecode(), new OneShotClassLoader(runtime.getJRubyClassLoader()));

if (sourceClass == null) {
// class could not be found nor generated; give up on JIT and bail out
@@ -293,47 +273,44 @@ public void run() {
log(method.getImplementationClass(), method.getFile(), method.getLine(), className + "." + methodName, "done jitting");
}

Map<Integer, MethodType> signatures = ((IRMethod)method.getIRMethod()).getNativeSignatures();
String jittedName = ((IRMethod)method.getIRMethod()).getJittedName();
Map<Integer, MethodType> signatures = ((IRMethod)method.getIRScope()).getNativeSignatures();
String jittedName = ((IRMethod)method.getIRScope()).getJittedName();
if (signatures.size() == 1) {
// only variable-arity
method.switchToJitted(
method.completeBuild(
new CompiledIRMethod(
PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, signatures.get(-1)),
method.getIRMethod(),
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRMethod().receivesKeywordArgs()));
method.getIRScope().receivesKeywordArgs()));

} else {
// also specific-arity
for (Map.Entry<Integer, MethodType> entry : signatures.entrySet()) {
if (entry.getKey() == -1) continue; // variable arity handle pushed above

method.switchToJitted(
method.completeBuild(
new CompiledIRMethod(
PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, signatures.get(-1)),
PUBLIC_LOOKUP.findStatic(sourceClass, jittedName, entry.getValue()),
entry.getKey(),
method.getIRMethod(),
method.getIRScope(),
method.getVisibility(),
method.getImplementationClass(),
method.getIRMethod().receivesKeywordArgs()));
method.getIRScope().receivesKeywordArgs()));
break;
}
}

return;
} catch (Throwable t) {
if (config.isJitLogging()) {
log(method.getImplementationClass(), method.getFile(), method.getLine(), className + "." + methodName, "Could not compile; passes run: " + method.getIRMethod().getExecutedPasses(), t.getMessage());
log(method.getImplementationClass(), method.getFile(), method.getLine(), className + "." + methodName, "Could not compile; passes run: " + method.getIRScope().getExecutedPasses(), t.getMessage());
if (config.isJitLoggingVerbose()) {
t.printStackTrace();
}
}

counts.failCount.incrementAndGet();
return;
}
}
}
@@ -375,7 +352,6 @@ public JITClassGenerator(String className, String methodName, String key, Ruby r
this.className = packageName + "/" + className.replace('.', '/') + CLASS_METHOD_DELIMITER + JavaNameMangler.mangleMethodName(methodName) + "_" + digestString;
this.name = this.className.replaceAll("/", ".");
this.methodName = methodName;
this.ruby = ruby;
this.method = method;
this.visitor = visitor;
}
@@ -391,7 +367,7 @@ protected void compile() {

// This may not be ok since we'll end up running passes specific to JIT
// CON FIXME: Really should clone scope before passes in any case
bytecode = visitor.compileToBytecode(method.getIRMethod());
bytecode = visitor.compileToBytecode(method.getIRScope());

compileTime = System.nanoTime() - start;
}
@@ -426,7 +402,6 @@ public String toString() {
return methodName + "() at " + method.getFile() + ":" + method.getLine();
}

private final Ruby ruby;
private final String packageName;
private final String className;
private final String methodName;
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.compiler.FullBuildSource;
import org.jruby.compiler.Compilable;
import org.jruby.ir.IRMethod;
import org.jruby.ir.IRScope;
import org.jruby.ir.interpreter.InterpreterContext;
@@ -24,7 +24,7 @@
/**
* Method for -X-C (interpreted only execution). See MixedModeIRMethod for inter/JIT method impl.
*/
public class InterpretedIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware, FullBuildSource {
public class InterpretedIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware, Compilable<InterpreterContext> {
private static final Logger LOG = LoggerFactory.getLogger("InterpretedIRMethod");

private Signature signature;
@@ -58,7 +58,7 @@ public StaticScope getStaticScope() {

public ArgumentDescriptor[] getArgumentDescriptors() {
ensureInstrsReady(); // Make sure method is minimally built before returning this info
return ((IRMethod) method).getArgumentDescriptors();
return method.getArgumentDescriptors();
}

public Signature getSignature() {
@@ -256,7 +256,7 @@ protected void doDebug() {
}
}

public void switchToFullBuild(InterpreterContext interpreterContext) {
public void completeBuild(InterpreterContext interpreterContext) {
this.interpreterContext = interpreterContext;
}

@@ -265,19 +265,20 @@ public void switchToFullBuild(InterpreterContext interpreterContext) {
protected void promoteToFullBuild(ThreadContext context) {
Ruby runtime = context.runtime;

// don't Promote to full build during runtime boot
if (runtime.isBooting()) return;
if (runtime.isBooting()) return; // don't Promote to full build during runtime boot

if (callCount++ >= Options.JIT_THRESHOLD.load()) {
runtime.getJITCompiler().fullBuildThresholdReached(this, context.runtime.getInstanceConfig());
}
if (callCount++ >= Options.JIT_THRESHOLD.load()) runtime.getJITCompiler().buildThresholdReached(context, this);
}

@Override
public DynamicMethod dup() {
return new InterpretedIRMethod(method, visibility, implementationClass);
}

public String getClassName(ThreadContext context) {
return null;
}

public String getFile() {
return method.getFileName();
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.jruby.internal.runtime.methods;

import org.jruby.MetaClass;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.compiler.Compilable;
import org.jruby.ir.*;
import org.jruby.ir.interpreter.InterpreterContext;
import org.jruby.ir.runtime.IRRuntimeHelpers;
@@ -21,7 +21,7 @@
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

public class MixedModeIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware {
public class MixedModeIRMethod extends DynamicMethod implements IRMethodArgs, PositionAware, Compilable<DynamicMethod> {
private static final Logger LOG = LoggerFactory.getLogger("InterpretedIRMethod");

private Signature signature;
@@ -49,18 +49,14 @@ public MixedModeIRMethod(IRScope method, Visibility visibility, RubyModule imple
}
}

public IRScope getIRMethod() {
public IRScope getIRScope() {
return method;
}

public DynamicMethod getActualMethod() {
return box.actualMethod;
}

public void setCallCount(int callCount) {
box.callCount = callCount;
}

public StaticScope getStaticScope() {
return method.getStaticScope();
}
@@ -303,20 +299,21 @@ public DynamicMethod getMethodForCaching() {
return this;
}

public void switchToJitted(CompiledIRMethod newMethod) {
@Override
public void completeBuild(DynamicMethod newMethod) {
this.box.actualMethod = newMethod;
this.box.actualMethod.serialNumber = this.serialNumber;
this.box.callCount = -1;
getImplementationClass().invalidateCacheDescendants();
}


protected void tryJit(ThreadContext context, DynamicMethodBox box) {
Ruby runtime = context.runtime;
if (context.runtime.isBooting()) return; // don't JIT during runtime boot

// don't JIT during runtime boot
if (runtime.isBooting()) return;
if (box.callCount++ >= Options.JIT_THRESHOLD.load()) context.runtime.getJITCompiler().buildThresholdReached(context, this);
}

public String getClassName(ThreadContext context) {
String className;
if (implementationClass.isSingleton()) {
MetaClass metaClass = (MetaClass)implementationClass;
@@ -333,11 +330,7 @@ protected void tryJit(ThreadContext context, DynamicMethodBox box) {
// use the class name
className = implementationClass.getName();
}


if (box.callCount++ >= Options.JIT_THRESHOLD.load()) {
context.runtime.getJITCompiler().jitThresholdReached(this, context.runtime.getInstanceConfig(), context, className, name);
}
return className;
}

public void setActualMethod(CompiledIRMethod method) {
@@ -363,4 +356,8 @@ public String getFile() {
public int getLine() {
return method.getLineNumber();
}

public void setCallCount(int callCount) {
box.callCount = callCount;
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/interpreter/Profiler.java
Original file line number Diff line number Diff line change
@@ -160,7 +160,7 @@ public int compare(IRCallSite a, IRCallSite b) {
IRScope hc = isHotClosure ? hs : null;
hs = isHotClosure ? hs.getLexicalParent() : hs;

IRScope tgtMethod = ircs.tgtM.getIRMethod();
IRScope tgtMethod = ircs.tgtM.getIRScope();

Instr[] instrs = tgtMethod.getInterpreterContext().getInstructions();
// Dont inline large methods -- 500 is arbitrary
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package org.jruby.runtime;

import org.jruby.EvalType;
import org.jruby.ir.IRClosure;
import org.jruby.ir.IRFlags;
import org.jruby.ir.IRMethod;
import org.jruby.ir.IRScope;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.Block.Type;
@@ -12,16 +10,14 @@
import java.lang.invoke.MethodHandle;

public class CompiledIRBlockBody extends IRBlockBody {
protected final IRClosure closure;
protected final MethodHandle handle;
protected boolean pushScope;
protected boolean reuseParentScope;
protected boolean usesKwargs;

public CompiledIRBlockBody(MethodHandle handle, IRScope closure, long encodedSignature) {
super(closure.getStaticScope(), closure.getFileName(), closure.getLineNumber(), Signature.decode(encodedSignature));
super(closure, Signature.decode(encodedSignature));
this.handle = handle;
this.closure = (IRClosure)closure;
// FIXME: duplicated from InterpreterContext
this.reuseParentScope = closure.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE);
this.pushScope = !closure.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED) && !this.reuseParentScope;
12 changes: 7 additions & 5 deletions core/src/main/java/org/jruby/runtime/IRBlockBody.java
Original file line number Diff line number Diff line change
@@ -2,20 +2,22 @@

import org.jruby.EvalType;
import org.jruby.RubyArray;
import org.jruby.ir.IRScope;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block.Type;
import org.jruby.runtime.builtin.IRubyObject;

public abstract class IRBlockBody extends ContextAwareBlockBody {
protected final String fileName;
protected final int lineNumber;
protected final IRScope closure;
protected ThreadLocal<EvalType> evalType;

public IRBlockBody(StaticScope staticScope, String fileName, int lineNumber, Signature signature) {
super(staticScope, signature);
this.fileName = fileName;
this.lineNumber = lineNumber;
public IRBlockBody(IRScope closure, Signature signature) {
super(closure.getStaticScope(), signature);
this.closure = closure;
this.fileName = closure.getFileName();
this.lineNumber = closure.getLineNumber();
this.evalType = new ThreadLocal();
this.evalType.set(EvalType.NONE);
}
25 changes: 11 additions & 14 deletions core/src/main/java/org/jruby/runtime/InterpretedIRBlockBody.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.jruby.runtime;

import org.jruby.EvalType;
import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyModule;
import org.jruby.compiler.FullBuildSource;
import org.jruby.compiler.Compilable;
import org.jruby.ir.IRClosure;
import org.jruby.ir.IRScope;
import org.jruby.ir.interpreter.Interpreter;
@@ -16,18 +15,16 @@
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

public class InterpretedIRBlockBody extends IRBlockBody implements FullBuildSource {
public class InterpretedIRBlockBody extends IRBlockBody implements Compilable<InterpreterContext> {
private static final Logger LOG = LoggerFactory.getLogger("InterpretedIRBlockBody");
protected final IRClosure closure;
protected boolean pushScope;
protected boolean reuseParentScope;
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG
private int callCount = 0;
private InterpreterContext interpreterContext;

public InterpretedIRBlockBody(IRClosure closure, Signature signature) {
super(closure.getStaticScope(), closure.getFileName(), closure.getLineNumber(), signature);
this.closure = closure;
super(closure, signature);
this.pushScope = true;
this.reuseParentScope = false;

@@ -44,7 +41,7 @@ public void setCallCount(int callCount) {
}

@Override
public void switchToFullBuild(InterpreterContext interpreterContext) {
public void completeBuild(InterpreterContext interpreterContext) {
this.interpreterContext = interpreterContext;
}

@@ -71,6 +68,11 @@ public InterpreterContext ensureInstrsReady() {
return interpreterContext;
}

@Override
public String getClassName(ThreadContext context) {
return null;
}

@Override
public String getName() {
return null;
@@ -129,14 +131,9 @@ protected IRubyObject commonYieldPath(ThreadContext context, IRubyObject[] args,
// Unlike JIT in MixedMode this will always successfully build but if using executor pool it may take a while
// and replace interpreterContext asynchronously.
protected void promoteToFullBuild(ThreadContext context) {
Ruby runtime = context.runtime;

// don't Promote to full build during runtime boot
if (runtime.isBooting()) return;
if (context.runtime.isBooting()) return; // don't Promote to full build during runtime boot

if (callCount++ >= Options.JIT_THRESHOLD.load()) {
runtime.getJITCompiler().fullBuildThresholdReached(this, context.runtime.getInstanceConfig());
}
if (callCount++ >= Options.JIT_THRESHOLD.load()) context.runtime.getJITCompiler().buildThresholdReached(context, this);
}

public RubyModule getImplementationClass() {
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/ipaddr.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/ipaddr'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/resolv.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/resolv'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/win32/resolv.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/win32/resolv'
33 changes: 0 additions & 33 deletions spec/ruby/core/module/autoload_spec.rb
Original file line number Diff line number Diff line change
@@ -441,36 +441,3 @@ class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
end
end
end

describe "Module#autoload" do
# It would be nice to check this with a simple obj.should_not_receive,
# but getting at that obj is implementation specific. This method is the
# least implementation specific because it inserts the method that raises
# an exception into the dynamic lookup chain.
before :all do
module Kernel
alias_method :original_require, :require
alias_method :original_load, :load

def require(name)
raise Exception, "Kernel#require called"
end

def load(name)
raise Exception, "Kernel#load called"
end
end
end

after :all do
module Kernel
alias_method :require, :original_require
alias_method :load, :original_load
end
end

it "does not call Kernel#require or Kernel#load dynamically" do
ModuleSpecs::Autoload.autoload :N, fixture(__FILE__, "autoload_n.rb")
ModuleSpecs::Autoload::N.should == :autoload_n
end
end
3 changes: 0 additions & 3 deletions spec/ruby/core/module/fixtures/autoload_n.rb

This file was deleted.

9 changes: 0 additions & 9 deletions spec/truffle/tags/core/exception/set_backtrace_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/advise_tags.txt
Original file line number Diff line number Diff line change
@@ -4,4 +4,3 @@ fails:IO#advise supports the random advice type
fails:IO#advise supports the dontneed advice type
fails:IO#advise supports the noreuse advice type
fails:IO#advise supports the willneed advice type
fails:IO#advise raises an IOError if the stream is closed
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/binmode_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/bytes_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
fails:IO#bytes returns an enumerator of the next bytes from the stream
fails:IO#bytes raises an IOError on closed stream
fails:IO#bytes raises an IOError on an enumerator for a stream that has been closed
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/chars_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
fails:IO#chars yields each character
fails:IO#chars returns itself
fails:IO#chars raises an IOError when an enumerator created on a closed stream is accessed
fails:IO#chars raises IOError on closed stream
9 changes: 0 additions & 9 deletions spec/truffle/tags/core/io/close_on_exec_tags.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
fails:IO#close_on_exec= sets the close-on-exec flag if true
fails:IO#close_on_exec= sets the close-on-exec flag if non-false
fails:IO#close_on_exec= unsets the close-on-exec flag if false
fails:IO#close_on_exec= unsets the close-on-exec flag if nil
fails:IO#close_on_exec= ensures the IO's file descriptor is closed in exec'ed processes
fails:IO#close_on_exec= raises IOError if called on a closed IO
fails:IO#close_on_exec= returns nil
fails:IO#close_on_exec? returns true by default
fails:IO#close_on_exec? returns true if set
fails:IO#close_on_exec? raises IOError if called on a closed IO
fails(windows):IO#close_on_exec= returns false from #respond_to?
fails(windows):IO#close_on_exec= raises a NotImplementedError when called
fails(windows):IO#close_on_exec? returns false from #respond_to?
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/codepoints_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
fails:IO#codepoints yields each codepoint
fails:IO#codepoints raises an error if reading invalid sequence
fails:IO#codepoints does not change $_
fails:IO#codepoints raises an IOError when self is not readable
fails:IO#codepoints calls the given block
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/io/dup_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/each_byte_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/each_char_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
fails:IO#each_char yields each character
fails:IO#each_char returns itself
fails:IO#each_char raises an IOError when an enumerator created on a closed stream is accessed
fails:IO#each_char raises IOError on closed stream
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/each_codepoint_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
fails:IO#each_codepoint yields each codepoint
fails:IO#each_codepoint raises an error if reading invalid sequence
fails:IO#each_codepoint does not change $_
fails:IO#each_codepoint raises an IOError when self is not readable
fails:IO#each_codepoint calls the given block
fails:IO#each_codepoint returns self
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/each_line_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/each_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/eof_tags.txt
Original file line number Diff line number Diff line change
@@ -2,6 +2,4 @@ fails:IO#eof? returns false when not at end of file
fails:IO#eof? returns true after reading with sysread
fails:IO#eof? returns false on just opened non-empty stream
fails:IO#eof? does not consume the data from the stream
fails:IO#eof? raises IOError on closed stream
fails:IO#eof? raises IOError on stream closed for reading by close_read
fails:IO#eof? returns false on receiving side of Pipe when writing side wrote some data
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/fcntl_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/fileno_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/flush_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/for_fd_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/fsync_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/getbyte_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:IO#getbyte returns the next byte from the stream
fails:IO#getbyte raises an IOError on closed stream
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/getc_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:IO#getc returns the next character from the stream
fails:IO#getc raises IOError on closed stream
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/gets_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
fails:IO#gets assigns the returned line to $_
fails:IO#gets raises IOError on closed stream
fails:IO#gets reads limit bytes and extra bytes when limit is reached not at character boundary
fails:IO#gets read limit bytes and extra bytes with maximum of 16
fails:IO#gets ignores the internal encoding if the IO object's external encoding is ASCII-8BIT
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/initialize_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/inspect_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/ioctl_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:IO#ioctl raises IOError on closed stream
fails(linux):IO#ioctl raises an Errno error when ioctl fails
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/isatty_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/lineno_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/new_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/open_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:IO.open raises an Errno::EBADF if the file descriptor is not valid
fails:IO.open raises an IOError if passed a closed stream
fails:IO.open does not propagate a StandardError raised by #close
fails:IO.open does not set last error when a StandardError raised by #close
fails:IO.open propagates an exception raised by #close that is a StandardError
6 changes: 0 additions & 6 deletions spec/truffle/tags/core/io/pipe_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/pos_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
fails:IO#pos raises IOError on closed stream
fails:IO#pos resets #eof?
fails:IO#pos= does not accept Bignums that don't fit in a C long
fails:IO#pos= raises IOError on closed stream
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/io/printf_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/putc_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/read_nonblock_tags.txt
Original file line number Diff line number Diff line change
@@ -4,5 +4,4 @@ fails:IO#read_nonblock returns at most the number of bytes requested
fails:IO#read_nonblock returns less data if that is all that is available
fails:IO#read_nonblock allows for reading 0 bytes before any write
fails:IO#read_nonblock allows for reading 0 bytes after a write
fails:IO#read_nonblock raises IOError on closed stream
fails:IO#read_nonblock raises EOFError when the end is reached
20 changes: 0 additions & 20 deletions spec/truffle/tags/core/io/read_tags.txt
Original file line number Diff line number Diff line change
@@ -2,30 +2,10 @@ fails:IO.read from a pipe runs the rest as a subprocess and returns the standard
fails:IO.read from a pipe opens a pipe to a fork if the rest is -
fails:IO.read from a pipe reads only the specified number of bytes requested
fails:IO.read from a pipe raises Errno::ESPIPE if passed an offset
fails:IO#read can be read from consecutively
fails:IO#read clears the output buffer if there is nothing to read
fails:IO#read consumes zero bytes when reading zero bytes
fails:IO#read is at end-of-file when everything has been read
fails:IO#read reads the contents of a file
fails:IO#read places the specified number of bytes in the buffer
fails:IO#read expands the buffer when too small
fails:IO#read overwrites the buffer
fails:IO#read truncates the buffer when too big
fails:IO#read returns the given buffer
fails:IO#read coerces the second argument to string and uses it as a buffer
fails:IO#read returns an empty string at end-of-file
fails:IO#read reads the contents of a file when more bytes are specified
fails:IO#read returns an empty string when the current pos is bigger than the content size
fails:IO#read returns nil at end-of-file with a length
fails:IO#read with length argument returns nil when the current pos is bigger than the content size
fails:IO#read raises IOError on closed stream
fails:IO.read with BOM reads a file without a bom
fails:IO.read with BOM reads a file with a utf-8 bom
fails:IO.read with BOM reads a file with a utf-16le bom
fails:IO.read with BOM reads a file with a utf-16be bom
fails:IO.read with BOM reads a file with a utf-32le bom
fails:IO.read with BOM reads a file with a utf-32be bom
fails:IO#read with large data reads all the data at once
fails:IO#read with large data reads only the requested number of bytes
fails(windows):IO#read on Windows normalizes line endings in text mode
fails(windows):IO#read on Windows does not normalize line endings in binary mode
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/readchar_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/readline_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:IO#readline raises IOError on closed stream
fails:IO#readline assigns the returned line to $_
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/readlines_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:IO#readlines raises an IOError if the stream is closed
fails:IO#readlines when passed a string that starts with a | gets data from the standard out of the subprocess
fails:IO#readlines when passed a string that starts with a | gets data from a fork when passed -
fails:IO.readlines when passed name, object when the object is a Fixnum uses the object as a limit if it is a Fixnum
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/readpartial_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:IO#readpartial raises IOError on closed stream
fails:IO#readpartial reads after ungetc with data in the buffer
fails:IO#readpartial reads after ungetc with multibyte characters in the buffer
fails:IO#readpartial reads after ungetc without data in the buffer
fails:IO#readpartial discards the existing buffer content upon successful read
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/rewind_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/seek_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
fails:IO#seek does not accept Bignums that don't fit in a C long
fails:IO#seek raises IOError on closed stream
fails:IO#seek moves the read position relative to the current position with SEEK_CUR
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/sync_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/sysread_tags.txt
Original file line number Diff line number Diff line change
@@ -4,4 +4,3 @@ fails:IO#sysread on a file coerces the second argument to string and uses it as
fails:IO#sysread on a file advances the position of the file by the specified number of bytes
fails:IO#sysread on a file reads normally even when called immediately after a buffered IO#read
fails:IO#sysread on a file reads updated content after the flushed buffered IO#write
fails:IO#sysread on a file raises IOError on closed stream
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/sysseek_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
fails:IO#sysseek does not accept Bignums that don't fit in a C long
fails:IO#sysseek raises IOError on closed stream
fails:IO#sysseek moves the read position relative to the end with SEEK_END
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/io/syswrite_tags.txt
Original file line number Diff line number Diff line change
@@ -2,5 +2,3 @@ fails:IO#syswrite on a file writes all of the string's bytes but does not buffer
fails:IO#syswrite on a file warns if called immediately after a buffered IO#write
fails:IO#syswrite on a file does not warn if called after IO#write with intervening IO#sysread
fails:IO#syswrite on a file writes to the actual file position when called after buffered IO#read
fails:IO#syswrite returns the number of bytes written
fails:IO#syswrite writes all of the string's bytes without buffering if mode is sync
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/tell_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:IO#tell raises IOError on closed stream
fails:IO#tell resets #eof?
1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/to_i_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/tty_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/io/ungetbyte_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
fails:IO#ungetbyte puts back each byte in a String argument
fails:IO#ungetbyte calls #to_str to convert the argument
fails:IO#ungetbyte puts back one byte for an Integer argument
fails:IO#ungetbyte raises an IOError if the IO is closed
11 changes: 0 additions & 11 deletions spec/truffle/tags/core/io/ungetc_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/io/write_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:IO#write on a file writes all of the string's bytes but buffers them
fails(windows):IO#write on Windows normalizes line endings in text mode
fails(windows):IO#write on Windows does not normalize line endings in binary mode
fails:IO.write on a FIFO writes correctly
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/kernel/at_exit_tags.txt
Original file line number Diff line number Diff line change
@@ -2,7 +2,4 @@ slow:Kernel.at_exit runs after all other code
slow:Kernel.at_exit runs in reverse order of registration
slow:Kernel.at_exit allows calling exit inside at_exit handler
slow:Kernel.at_exit gives access to the last raised exception
fails:Kernel.at_exit allows calling exit inside at_exit handler
fails:Kernel.at_exit runs in reverse order of registration
fails:Kernel.at_exit runs after all other code
fails:Kernel.at_exit gives access to the last raised exception

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/module/attr_accessor_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Module#attr_accessor creates a getter and setter for each given attribute name
fails:Module#attr_accessor allows creating an attr_accessor on an immediate class
fails:Module#attr_accessor converts non string/symbol/fixnum names to strings using to_str
fails:Module#attr_accessor raises a TypeError when the given names can't be converted to strings using to_str
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/module/define_method_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
fails:Module#define_method method body is an UnboundMethod allows methods defined on a different object
fails:Method#define_method when passed a Method object defines a method with the same #parameters as the original
fails:Method#define_method when passed an UnboundMethod object defines a method with the same #parameters as the original
2 changes: 2 additions & 0 deletions spec/truffle/tags/library/ipaddr/ipv4_conversion_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fails:IPAddr#ipv4_compat should ipv4_compat?
fails:IPAddr#ipv4_mapped should ipv4_mapped
1 change: 1 addition & 0 deletions spec/truffle/tags/library/ipaddr/new_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fails:IPAddr#new initializes IPAddr ipv4 mapped address with subnet mask
1 change: 1 addition & 0 deletions spec/truffle/tags/library/ipaddr/operator_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fails:IPAddr Operator bitwises or
1 change: 1 addition & 0 deletions spec/truffle/tags/library/ipaddr/reverse_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fails:IPAddr#reverse generates the reverse DNS lookup entry
6 changes: 4 additions & 2 deletions spec/truffle/truffle.mspec
Original file line number Diff line number Diff line change
@@ -95,13 +95,15 @@ class MSpecScript
"spec/ruby/library/cgi",
"spec/ruby/library/erb",
"spec/ruby/library/getoptlong",
"spec/ruby/library/ipaddr",
"spec/ruby/library/matrix",
"spec/ruby/library/logger",
"spec/ruby/library/observer",
"spec/ruby/library/open3",
"spec/ruby/library/openstruct",
"spec/ruby/library/pathname",
"spec/ruby/library/prime",
"spec/ruby/library/resolv",
"spec/ruby/library/scanf",
"spec/ruby/library/set",
"spec/ruby/library/shellwords",
@@ -123,12 +125,10 @@ class MSpecScript
"^spec/ruby/library/etc",
"^spec/ruby/library/expect",
"^spec/ruby/library/fiber",
"^spec/ruby/library/ipaddr",
"^spec/ruby/library/mathn",
"^spec/ruby/library/net",
"^spec/ruby/library/openssl",
"^spec/ruby/library/readline",
"^spec/ruby/library/resolv",
"^spec/ruby/library/rexml",
"^spec/ruby/library/securerandom",
"^spec/ruby/library/syslog",
@@ -151,6 +151,8 @@ class MSpecScript
"spec/truffle/specs"
]

set :backtrace_filter, /mspec\//

set :tags_patterns, [
[%r(^.*/language/), 'spec/truffle/tags/language/'],
[%r(^.*/core/), 'spec/truffle/tags/core/'],
2 changes: 1 addition & 1 deletion test/truffle/simple-server.rb
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
socket = server.accept

begin
request = socket.gets
request = "Hello, World from JRuby+Truffle! #{socket.gets}"

socket.print "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/plain\r\n" +
7 changes: 7 additions & 0 deletions tool/truffle-findbugs-exclude.xml
Original file line number Diff line number Diff line change
@@ -149,4 +149,11 @@
<Bug pattern="DM_EXIT" />
</Match>

<!-- FindBugs bugs -->

<Match>
<Class name="org.jruby.truffle.nodes.objects.SingletonClassNode" />
<Bug pattern="BC_UNCONFIRMED_CAST" />
</Match>

</FindBugsFilter>
24 changes: 24 additions & 0 deletions tool/truffle/translate_rubinius_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env ruby

# Copyright (c) 2015 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

puts " // Generated from tool/truffle/translate_rubinius_config.rb < ../rubinius/runtime/platform.conf"

ARGF.each do |line|
match = line.match(/(?'var'rbx(\.\w+)*) = (?'value'.+)/)
next unless match
var = match[:var]
value = match[:value]
if /.*\.(offset|size|sizeof)$/ =~ var
code = value.to_s
else
code = "context.makeString(\"#{value}\")"
end
puts " configuration.config(\"#{var}\", #{code});"
end
6 changes: 4 additions & 2 deletions tool/truffle/vagrant_bootstrap.sh
Original file line number Diff line number Diff line change
@@ -23,23 +23,25 @@
# VAGRANT_VAGRANTFILE=tool/truffle/Vagrantfile vagrant provision
# which will run the script again on the running vm
#
# If you need to make an update to this script on a brand new vm, run:
# If you need to make an update to this script, run:
# VAGRANT_VAGRANTFILE=tool/truffle/Vagrantfile vagrant reload
# This is like running vagrant halt, vagrant up
#
# Delete the vm
# VAGRANT_VAGRANTFILE=tool/truffle/Vagrantfile vagrant destroy
#

# Install jdk-7
sudo apt-get update
sudo apt-get install -y openjdk-7-jdk
sudo apt-get install -y build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison nodejs subversion

echo "Downloading and installing ruby-install and ruby-1.9.3"
wget -O ruby-install-0.5.0.tar.gz https://github.com/postmodern/ruby-install/archive/v0.5.0.tar.gz
tar -xzvf ruby-install-0.5.0.tar.gz
cd ruby-install-0.5.0/
sudo make install
ruby-install --system ruby 1.9.3
sudo ruby-install --system ruby 1.9.3

echo "Downloading and installing maven 3.2.5"
wget -q http://apache.osuosl.org/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.tar.gz
5 changes: 5 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/nodes/RubyNode.java
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.sockets.NativeSockets;

@ImportStatic(RubyGuards.class)
public abstract class RubyNode extends Node {
@@ -240,6 +241,10 @@ protected POSIX posix() {
return getContext().getPosix();
}

protected NativeSockets nativeSockets() {
return getContext().getNativeSockets();
}

// Instrumentation

@Override
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.runtime.RubyCallStack;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
@@ -51,16 +53,21 @@ public RubyBasicObject initialize(RubyException exception, RubyString message) {
@CoreMethod(names = "backtrace")
public abstract static class BacktraceNode extends CoreMethodArrayArgumentsNode {

@Child ReadHeadObjectFieldNode readCustomBacktrace;

public BacktraceNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
readCustomBacktrace = new ReadHeadObjectFieldNode("@custom_backtrace");
}

@Specialization
public Object backtrace(RubyException exception) {
if (exception.getBacktrace() == null) {
return nil();
} else {
if (readCustomBacktrace.isSet(exception)) {
return readCustomBacktrace.execute(exception);
} else if (exception.getBacktrace() != null) {
return exception.asRubyStringArray();
} else {
return nil();
}
}

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

import java.util.Collection;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;

/** Load libraries required from the command line (-r LIBRARY) */
public class LoadRequiredLibrariesNode extends RubyNode {

@Child CallDispatchHeadNode requireNode;

public LoadRequiredLibrariesNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
requireNode = DispatchHeadNodeFactory.createMethodCallOnSelf(context);
}

@Override
public Object execute(VirtualFrame frame) {
Object self = RubyArguments.getSelf(frame.getArguments());
Collection<String> requiredLibraries = getContext().getRuntime().getInstanceConfig().getRequiredLibraries();

for (String requiredLibrary : requiredLibraries) {
requireNode.call(frame, self, "require", null, getContext().makeString(requiredLibrary));
}

return nil();
}

}
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
import org.jruby.truffle.nodes.coerce.ToIntNode;
import org.jruby.truffle.nodes.coerce.ToIntNodeGen;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
import org.jruby.util.ByteList;
@@ -29,7 +30,7 @@
@CoreClass(name = "MatchData")
public abstract class MatchDataNodes {

@CoreMethod(names = "[]", required = 1, lowerFixnumParameters = 0, taintFromSelf = true)
@CoreMethod(names = "[]", required = 1, optional = 1, lowerFixnumParameters = 0, taintFromSelf = true)
public abstract static class GetIndexNode extends CoreMethodArrayArgumentsNode {

@Child private ToIntNode toIntNode;
@@ -39,7 +40,7 @@ public GetIndexNode(RubyContext context, SourceSection sourceSection) {
}

@Specialization
public Object getIndex(RubyMatchData matchData, int index) {
public Object getIndex(RubyMatchData matchData, int index, UndefinedPlaceholder undefinedPlaceholder) {
CompilerDirectives.transferToInterpreter();

final Object[] values = matchData.getValues();
@@ -53,13 +54,23 @@ public Object getIndex(RubyMatchData matchData, int index) {
}

@Specialization
public Object getIndex(RubyMatchData matchData, RubySymbol index) {
public Object getIndex(RubyMatchData matchData, int index, int length) {
CompilerDirectives.transferToInterpreter();
// TODO BJF 15-May-2015 Need to handle negative indexes and lengths and out of bounds
final Object[] values = matchData.getValues();
final int normalizedIndex = RubyArray.normalizeIndex(values.length, index);
final Object[] store = Arrays.copyOfRange(values, normalizedIndex, normalizedIndex + length);
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), store, length);
}

@Specialization
public Object getIndex(RubyMatchData matchData, RubySymbol index, UndefinedPlaceholder undefinedPlaceholder) {
CompilerDirectives.transferToInterpreter();

try {
final int i = matchData.getBackrefNumber(index.getSymbolBytes());

return getIndex(matchData, i);
return getIndex(matchData, i, UndefinedPlaceholder.INSTANCE);
} catch (final ValueException e) {
CompilerDirectives.transferToInterpreter();

@@ -69,13 +80,13 @@ public Object getIndex(RubyMatchData matchData, RubySymbol index) {
}

@Specialization
public Object getIndex(RubyMatchData matchData, RubyString index) {
public Object getIndex(RubyMatchData matchData, RubyString index, UndefinedPlaceholder undefinedPlaceholder) {
CompilerDirectives.transferToInterpreter();

try {
final int i = matchData.getBackrefNumber(index.getByteList());

return getIndex(matchData, i);
return getIndex(matchData, i, UndefinedPlaceholder.INSTANCE);
}
catch (final ValueException e) {
CompilerDirectives.transferToInterpreter();
@@ -86,19 +97,19 @@ public Object getIndex(RubyMatchData matchData, RubyString index) {
}

@Specialization(guards = {"!isRubySymbol(index)", "!isRubyString(index)", "!isIntegerFixnumRange(index)"})
public Object getIndex(VirtualFrame frame, RubyMatchData matchData, Object index) {
public Object getIndex(VirtualFrame frame, RubyMatchData matchData, Object index, UndefinedPlaceholder undefinedPlaceholder) {
CompilerDirectives.transferToInterpreter();

if (toIntNode == null) {
CompilerDirectives.transferToInterpreter();
toIntNode = insert(ToIntNodeGen.create(getContext(), getSourceSection(), null));
}

return getIndex(matchData, toIntNode.doInt(frame, index));
return getIndex(matchData, toIntNode.doInt(frame, index), UndefinedPlaceholder.INSTANCE);
}

@Specialization(guards = {"!isRubySymbol(range)", "!isRubyString(range)"})
public Object getIndex(VirtualFrame frame, RubyMatchData matchData, RubyRange.IntegerFixnumRange range) {
public Object getIndex(VirtualFrame frame, RubyMatchData matchData, RubyRange.IntegerFixnumRange range, UndefinedPlaceholder undefinedPlaceholder) {
final Object[] values = matchData.getValues();
final int normalizedIndex = RubyArray.normalizeIndex(values.length, range.getBegin());
final int end = RubyArray.normalizeIndex(values.length, range.getEnd());
Original file line number Diff line number Diff line change
@@ -221,7 +221,8 @@ private DispatchNode doRubyBasicObject(
CompilerDirectives.transferToInterpreter();
singletonClassNode = insert(SingletonClassNodeGen.create(getContext(), getSourceSection(), null));
}
RubyClass moduleSingletonClass = singletonClassNode.executeSingletonClass(frame, module);
// RubyClass moduleSingletonClass = singletonClassNode.executeSingletonClass(frame, module);
RubyClass moduleSingletonClass = singletonClassNode.getNormalObjectSingletonClass(module);

// But we want to check the module assumption, not its singleton class assumption.
return new CachedBoxedDispatchNode(getContext(), methodName, first,
Original file line number Diff line number Diff line change
@@ -28,7 +28,6 @@ public class ReadInstanceVariableNode extends RubyNode implements ReadNode {
@Child private ReadHeadObjectFieldNode readNode;
private final boolean isGlobal;

private final BranchProfile nullProfile = BranchProfile.create();
private final BranchProfile primitiveProfile = BranchProfile.create();

public ReadInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, boolean isGlobal) {
@@ -85,14 +84,7 @@ public Object execute(VirtualFrame frame) {
final Object receiverObject = receiver.execute(frame);

if (receiverObject instanceof RubyBasicObject) {
Object value = readNode.execute((RubyBasicObject) receiverObject);

if (value == null) {
nullProfile.enter();
value = nil();
}

return value;
return readNode.execute((RubyBasicObject) receiverObject);
} else {
primitiveProfile.enter();
return nil();
Original file line number Diff line number Diff line change
@@ -87,8 +87,16 @@ protected RubyClass singletonClass(RubyClass rubyClass) {

@Specialization(guards = { "!isNil(object)", "!isRubyBignum(object)", "!isRubySymbol(object)", "!isRubyClass(object)" })
protected RubyClass singletonClass(RubyBasicObject object) {
return getNormalObjectSingletonClass(object);
}

public RubyClass getNormalObjectSingletonClass(RubyBasicObject object) {
CompilerAsserts.neverPartOfCompilation();

if (object instanceof RubyClass) { // For the direct caller
return ((RubyClass) object).getSingletonClass();
}

if (object.getMetaClass().isSingleton()) {
return object.getMetaClass();
}
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ public Object execute(RubyBasicObject object) {
}

if (object.getDynamicObject().getShape() == objectLayout) {
return null;
return object.getContext().getCoreLibrary().getNilObject();
} else {
return next.execute(object);
}
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@
import jnr.constants.platform.Errno;
import jnr.constants.platform.Fcntl;

import jnr.ffi.byref.IntByReference;
import org.jruby.RubyEncoding;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -53,6 +54,7 @@
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.util.ByteList;
import org.jruby.util.Dir;
import org.jruby.util.unsafe.UnsafeHolder;

import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -410,4 +412,36 @@ public int seek(VirtualFrame frame, RubyBasicObject io, int amount, int whence)

}

@RubiniusPrimitive(name = "io_accept")
public abstract static class AcceptNode extends RubiniusPrimitiveNode {

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

@Specialization
public int accept(VirtualFrame frame, RubyBasicObject io) {
final int fd = (int) rubyWithSelf(frame, io, "@descriptor");

final IntByReference addressLength = new IntByReference(16);
final long address = UnsafeHolder.U.allocateMemory(addressLength.intValue());

final int newFd;

try {
newFd = nativeSockets().accept(fd, getMemoryManager().newPointer(address), addressLength);
} finally {
UnsafeHolder.U.freeMemory(address);
}

if (newFd == -1) {
System.err.println(posix().errno());
throw new UnsupportedOperationException();
}

return newFd;
}

}

}
Original file line number Diff line number Diff line change
@@ -12,30 +12,10 @@
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.rubinius.RubiniusTypes;

public abstract class NativeFunctionPrimitiveNodes {

public static final int TYPE_CHAR = 0;
public static final int TYPE_UCHAR = 1;
public static final int TYPE_BOOL = 2;
public static final int TYPE_SHORT = 3;
public static final int TYPE_USHORT = 4;
public static final int TYPE_INT = 5;
public static final int TYPE_UINT = 6;
public static final int TYPE_LONG = 7;
public static final int TYPE_ULONG = 8;
public static final int TYPE_LL = 9;
public static final int TYPE_ULL = 10;
public static final int TYPE_FLOAT = 11;
public static final int TYPE_DOUBLE = 12;
public static final int TYPE_PTR = 13;
public static final int TYPE_VOID = 14;
public static final int TYPE_STRING = 15;
public static final int TYPE_STRPTR = 16;
public static final int TYPE_CHARARR = 17;
public static final int TYPE_ENUM = 18;
public static final int TYPE_VARARGS = 19;

@RubiniusPrimitive(name = "nativefunction_type_size", needsSelf = false)
public static abstract class NativeFunctionTypeSizePrimitiveNode extends RubiniusPrimitiveNode {

@@ -46,40 +26,40 @@ public NativeFunctionTypeSizePrimitiveNode(RubyContext context, SourceSection so
@Specialization
public long typeSize(int type) {
switch (type) {
case TYPE_CHAR:
case TYPE_UCHAR:
case RubiniusTypes.TYPE_CHAR:
case RubiniusTypes.TYPE_UCHAR:
return 1;

case TYPE_SHORT:
case TYPE_USHORT:
case RubiniusTypes.TYPE_SHORT:
case RubiniusTypes.TYPE_USHORT:
return 2;

case TYPE_INT:
case TYPE_UINT:
case RubiniusTypes.TYPE_INT:
case RubiniusTypes.TYPE_UINT:
return 4;

case TYPE_LONG:
case TYPE_ULONG:
case RubiniusTypes.TYPE_LONG:
case RubiniusTypes.TYPE_ULONG:
return 8;

case TYPE_FLOAT:
case RubiniusTypes.TYPE_FLOAT:
return 4;

case TYPE_DOUBLE:
case RubiniusTypes.TYPE_DOUBLE:
return 8;

case TYPE_PTR:
case TYPE_STRPTR:
case RubiniusTypes.TYPE_PTR:
case RubiniusTypes.TYPE_STRPTR:
return 8;

case TYPE_BOOL:
case TYPE_LL:
case TYPE_ULL:
case TYPE_VOID:
case TYPE_STRING:
case TYPE_CHARARR:
case TYPE_ENUM:
case TYPE_VARARGS:
case RubiniusTypes.TYPE_BOOL:
case RubiniusTypes.TYPE_LL:
case RubiniusTypes.TYPE_ULL:
case RubiniusTypes.TYPE_VOID:
case RubiniusTypes.TYPE_STRING:
case RubiniusTypes.TYPE_CHARARR:
case RubiniusTypes.TYPE_ENUM:
case RubiniusTypes.TYPE_VARARGS:
default:
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@
*/
package org.jruby.truffle.nodes.rubinius;

import com.kenai.jffi.MemoryIO;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.*;
@@ -21,6 +23,9 @@
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.rubinius.RubiniusConfiguration;
import org.jruby.truffle.runtime.rubinius.RubiniusTypes;
import org.jruby.util.ByteList;
import org.jruby.util.unsafe.UnsafeHolder;

import java.util.EnumSet;
@@ -42,12 +47,15 @@ public abstract class PointerPrimitiveNodes {
public static class PointerAllocator implements Allocator {
@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, Node currentNode) {
return PointerPrimitiveNodes.createPointer(rubyClass, jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().newOpaquePointer(0));
return PointerPrimitiveNodes.createPointer(rubyClass, NULL_POINTER);
}
}

public static RubyBasicObject createPointer(RubyClass rubyClass, Pointer pointer) {
assert pointer != null;
if (pointer == null) {
pointer = NULL_POINTER;
}

return new RubyBasicObject(rubyClass, POINTER_FACTORY.newInstance(pointer));
}

@@ -158,7 +166,7 @@ protected boolean isSigned(boolean signed) {

}

@RubiniusPrimitive(name = "pointer_read_string")
@RubiniusPrimitive(name = "pointer_read_string", lowerFixnumParameters = 0)
public static abstract class PointerReadStringPrimitiveNode extends RubiniusPrimitiveNode {

public PointerReadStringPrimitiveNode(RubyContext context, SourceSection sourceSection) {
@@ -190,16 +198,15 @@ public boolean setAutorelease(RubyBasicObject pointer, boolean autorelease) {
}

@RubiniusPrimitive(name = "pointer_set_at_offset", lowerFixnumParameters = {0, 2})
@ImportStatic(RubiniusTypes.class)
public static abstract class PointerSetAtOffsetPrimitiveNode extends RubiniusPrimitiveNode {

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

@Specialization
@Specialization(guards = "type == TYPE_INT")
public int setAtOffset(RubyBasicObject pointer, int offset, int type, int value) {
assert type == 5;
// TODO CS 13-May-15 what does the type parameter do?
getPointer(pointer).putInt(offset, value);
return value;
}
@@ -215,7 +222,7 @@ public PointerReadPointerPrimitiveNode(RubyContext context, SourceSection source

@Specialization
public RubyBasicObject readPointer(RubyBasicObject pointer) {
return createPointer(pointer.getLogicalClass(), nullOrPointer(getPointer(pointer).getPointer(0)));
return createPointer(pointer.getLogicalClass(), getPointer(pointer).getPointer(0));
}

}
@@ -235,27 +242,95 @@ public long address(RubyBasicObject pointer) {
}

@RubiniusPrimitive(name = "pointer_get_at_offset")
@ImportStatic(RubiniusTypes.class)
public static abstract class PointerGetAtOffsetPrimitiveNode extends RubiniusPrimitiveNode {

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

@Specialization
public int getAtOffset(RubyBasicObject pointer, int offset, int type) {
assert type == 5;
// TODO CS 13-May-15 not sure about int/long here
@Specialization(guards = "type == TYPE_UCHAR")
public int getAtOffsetUChar(RubyBasicObject pointer, int offset, int type) {
return getPointer(pointer).getByte(offset);
}

@Specialization(guards = "type == TYPE_INT")
public int getAtOffsetInt(RubyBasicObject pointer, int offset, int type) {
return getPointer(pointer).getInt(offset);
}

@Specialization(guards = "type == TYPE_SHORT")
public int getAtOffsetShort(RubyBasicObject pointer, int offset, int type) {
return getPointer(pointer).getShort(offset);
}

@Specialization(guards = "type == TYPE_LONG")
public long getAtOffsetLong(RubyBasicObject pointer, int offset, int type) {
return getPointer(pointer).getLong(offset);
}

@Specialization(guards = "type == TYPE_STRING")
public RubyString getAtOffsetString(RubyBasicObject pointer, int offset, int type) {
return getContext().makeString(getPointer(pointer).getString(offset));
}

@Specialization(guards = "type == TYPE_PTR")
public RubyBasicObject getAtOffsetPointer(RubyBasicObject pointer, int offset, int type) {
final Pointer readPointer = getPointer(pointer).getPointer(offset);

if (readPointer == null) {
return nil();
} else {
return createPointer(pointer.getLogicalClass(), readPointer);
}
}

}

private static Pointer nullOrPointer(Pointer pointer) {
if (pointer == null) {
return NULL_POINTER;
} else {
@RubiniusPrimitive(name = "pointer_write_string")
public static abstract class PointerWriteStringPrimitiveNode extends RubiniusPrimitiveNode {

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

@Specialization
public RubyBasicObject address(RubyBasicObject pointer, RubyString string, int maxLength) {
final ByteList bytes = string.getByteList();
final int length = Math.min(bytes.length(), maxLength);
getPointer(pointer).put(0, bytes.unsafeBytes(), bytes.begin(), length);
return pointer;
}

}

@RubiniusPrimitive(name = "pointer_read_string_to_null")
public static abstract class PointerReadStringToNullPrimitiveNode extends RubiniusPrimitiveNode {

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

@Specialization
public RubyString readStringToNull(RubyBasicObject pointer) {
return getContext().makeString(MemoryIO.getInstance().getZeroTerminatedByteArray(getPointer(pointer).address()));
}

}

@RubiniusPrimitive(name = "pointer_write_int")
public static abstract class PointerWriteIntPrimitiveNode extends RubiniusPrimitiveNode {

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

@Specialization
public RubyBasicObject address(RubyBasicObject pointer, int value) {
getPointer(pointer).putInt(0, value);
return pointer;
}

}

}
129 changes: 129 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/nodes/rubinius/PosixNodes.java
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.rubinius.RubiniusConfiguration;

import java.nio.charset.StandardCharsets;

@@ -101,6 +102,21 @@ public int fchmod(int one, int mode) {
}


@CoreMethod(names = "fsync", isModuleFunction = true, required = 1)
public abstract static class FsyncNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int fsync(int descriptor) {
return posix().fsync(descriptor);
}

}


@CoreMethod(names = "fchown", isModuleFunction = true, required = 3)
public abstract static class FchownNode extends CoreMethodArrayArgumentsNode {

@@ -171,6 +187,7 @@ public int getGroups(int max, RubyBasicObject pointer) {
final Pointer pointerValue = PointerPrimitiveNodes.getPointer(pointer);

for (int n = 0; n < groups.length && n < max; n++) {
// TODO CS 16-May-15 this is platform dependent
pointerValue.putInt(4 * n, (int) groups[n]);

}
@@ -471,4 +488,116 @@ public int symlink(RubyString first, RubyString second) {

}

// TODO CS-15-May 15 we're missing a lot of guards for things like Pointer here

@CoreMethod(names = "_getaddrinfo", isModuleFunction = true, required = 4)
public abstract static class GetAddrInfoNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int getaddrinfo(RubyString hostName, RubyString serviceName, RubyBasicObject hintsPointer, RubyBasicObject resultsPointer) {
return nativeSockets().getaddrinfo(
hostName.getByteList(),
serviceName.getByteList(),
PointerPrimitiveNodes.getPointer(hintsPointer),
PointerPrimitiveNodes.getPointer(resultsPointer));
}

}

@CoreMethod(names = "freeaddrinfo", isModuleFunction = true, required = 1)
public abstract static class FreeAddrInfoNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public RubyBasicObject freeaddrinfo(RubyBasicObject addrInfo) {
nativeSockets().freeaddrinfo(PointerPrimitiveNodes.getPointer(addrInfo));
return nil();
}

}

@CoreMethod(names = "_getnameinfo", isModuleFunction = true, required = 7)
public abstract static class GetNameInfoNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int getnameinfo(RubyBasicObject sa, int salen, RubyBasicObject host, int hostlen, RubyBasicObject serv, int servlen, int flags) {
return nativeSockets().getnameinfo(
PointerPrimitiveNodes.getPointer(sa),
salen,
PointerPrimitiveNodes.getPointer(host),
hostlen,
PointerPrimitiveNodes.getPointer(serv),
servlen,
flags);
}

}

@CoreMethod(names = "socket", isModuleFunction = true, required = 3)
public abstract static class SocketNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int getnameinfo(int domain, int type, int protocol) {
return nativeSockets().socket(domain, type, protocol);
}

}

@CoreMethod(names = "setsockopt", isModuleFunction = true, required = 5, lowerFixnumParameters = {0, 1, 2, 4})
public abstract static class SetSockOptNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int setsockopt(int socket, int level, int optionName, RubyBasicObject optionValue, int optionLength) {
return nativeSockets().setsockopt(socket, level, optionName, PointerPrimitiveNodes.getPointer(optionValue), optionLength);
}

}

@CoreMethod(names = "_bind", isModuleFunction = true, required = 3)
public abstract static class BindNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int bind(int socket, RubyBasicObject address, int addressLength) {
return nativeSockets().bind(socket, PointerPrimitiveNodes.getPointer(address), addressLength);
}

}

@CoreMethod(names = "listen", isModuleFunction = true, required = 2)
public abstract static class ListenNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public int listen(int socket, int backlog) {
return nativeSockets().listen(socket, backlog);
}

}

}
Original file line number Diff line number Diff line change
@@ -13,12 +13,16 @@
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import org.jruby.truffle.nodes.core.BignumNodes;
import org.jruby.truffle.pack.nodes.PackNode;
import org.jruby.truffle.pack.parser.FormatDirective;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.util.ByteList;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Locale;

@NodeChildren({
@NodeChild(value = "value", type = PackNode.class),
@@ -46,6 +50,43 @@ public ByteList format(long value) {
return doFormat(value);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyBignum(value)")
public ByteList format(RubyBasicObject value) {
final BigInteger bigInteger = BignumNodes.getBigIntegerValue(value);

String formatted;

switch (format) {
case 'd':
case 'i':
case 'u':
formatted = bigInteger.toString();
break;

case 'x':
formatted = bigInteger.toString(16).toLowerCase(Locale.ENGLISH);
break;

case 'X':
formatted = bigInteger.toString(16).toUpperCase(Locale.ENGLISH);
break;

default:
throw new UnsupportedOperationException();
}

while (formatted.length() < spacePadding) {
formatted = " " + formatted;
}

while (formatted.length() < zeroPadding) {
formatted = "0" + formatted;
}

return new ByteList(formatted.getBytes(StandardCharsets.US_ASCII));
}

@CompilerDirectives.TruffleBoundary
protected ByteList doFormat(Object value) {
// TODO CS 3-May-15 write this without building a string and formatting

This file was deleted.

Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@
/**
* Read a {@code long} value from the source, or a {@link BigInteger} if the
* value is that large. This is only used with BER - in all other cases
* we could truncate a {@code Bignum}.
* we would truncate a {@code Bignum}.
*/
@NodeChildren({
@NodeChild(value = "source", type = SourceNode.class),
Original file line number Diff line number Diff line change
@@ -16,14 +16,15 @@
import org.jruby.truffle.runtime.RubyContext;

/**
* Re-interpret a value as a {@code long}.
* Re-interpret a value as a {@code long}. In other words, get the raw bytes
* as a long.
*/
@NodeChildren({
@NodeChild(value = "value", type = PackNode.class),
})
public abstract class AsLongNode extends PackNode {
public abstract class ReinterpretLongNode extends PackNode {

public AsLongNode(RubyContext context) {
public ReinterpretLongNode(RubyContext context) {
super(context);
}

Original file line number Diff line number Diff line change
@@ -15,6 +15,9 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import org.jruby.truffle.pack.nodes.PackNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;

import java.math.BigInteger;

@NodeChildren({
@NodeChild(value = "value", type = PackNode.class),
@@ -37,6 +40,11 @@ public long toInteger(VirtualFrame frame, long value) {
return value;
}

@Specialization(guards = "isRubyBignum(value)")
public RubyBasicObject toInteger(VirtualFrame frame, RubyBasicObject value) {
return value;
}

@Specialization
public long toInteger(VirtualFrame frame, double value) {
return (long) value;
133 changes: 45 additions & 88 deletions truffle/src/main/java/org/jruby/truffle/pack/parser/PackParser.java
Original file line number Diff line number Diff line change
@@ -15,12 +15,8 @@
import org.jruby.truffle.pack.nodes.PackRootNode;
import org.jruby.truffle.pack.nodes.SourceNode;
import org.jruby.truffle.pack.nodes.control.*;
import org.jruby.truffle.pack.nodes.read.ReadDoubleNodeGen;
import org.jruby.truffle.pack.nodes.read.ReadLongNodeGen;
import org.jruby.truffle.pack.nodes.read.ReadLongOrBigIntegerNodeGen;
import org.jruby.truffle.pack.nodes.read.ReadStringNodeGen;
import org.jruby.truffle.pack.nodes.type.AsLongNodeGen;
import org.jruby.truffle.pack.nodes.type.AsSinglePrecisionNodeGen;
import org.jruby.truffle.pack.nodes.read.*;
import org.jruby.truffle.pack.nodes.type.*;
import org.jruby.truffle.pack.nodes.write.*;
import org.jruby.truffle.pack.runtime.Endianness;
import org.jruby.truffle.pack.runtime.PackEncoding;
@@ -80,10 +76,10 @@ public PackNode parse(PackTokenizer tokenizer, boolean inParens) {
throw new UnsupportedOperationException("unbalanced parens");
}
case 'C':
node = writeInteger(8, Signedness.UNSIGNED, nativeEndianness());
node = writeInteger(8, nativeEndianness());
break;
case 'c':
node = writeInteger(8, Signedness.SIGNED, nativeEndianness());
node = writeInteger(8, nativeEndianness());
break;
case 'S':
case 'L':
@@ -157,19 +153,19 @@ public PackNode parse(PackTokenizer tokenizer, boolean inParens) {
tokenizer.next();
}

node = writeInteger(size, signedness, endianness);
node = writeInteger(size, endianness);
} break;
case 'n':
node = writeInteger(16, Signedness.UNSIGNED, Endianness.BIG);
node = writeInteger(16, Endianness.BIG);
break;
case 'N':
node = writeInteger(32, Signedness.UNSIGNED, Endianness.BIG);
node = writeInteger(32, Endianness.BIG);
break;
case 'v':
node = writeInteger(16, Signedness.UNSIGNED, Endianness.LITTLE);
node = writeInteger(16, Endianness.LITTLE);
break;
case 'V':
node = writeInteger(32, Signedness.UNSIGNED, Endianness.LITTLE);
node = writeInteger(32, Endianness.LITTLE);
break;
case 'A':
case 'Z':
@@ -343,7 +339,9 @@ public PackNode parse(PackTokenizer tokenizer, boolean inParens) {
} break;
case 'U':
encoding = encoding.unifyWith(PackEncoding.UTF_8);
node = WriteUTF8CharacterNodeGen.create(context, ReadLongNodeGen.create(context, new SourceNode()));
node = WriteUTF8CharacterNodeGen.create(context,
ToLongNodeGen.create(context,
ReadValueNodeGen.create(context, new SourceNode())));
break;
case 'X':
node = new BackNode(context);
@@ -362,42 +360,42 @@ public PackNode parse(PackTokenizer tokenizer, boolean inParens) {
} break;
case 'D':
case 'd':
node = writeInteger(64, Signedness.UNSIGNED, nativeEndianness(),
AsLongNodeGen.create(context,
node = writeInteger(64, nativeEndianness(),
ReinterpretLongNodeGen.create(context,
ReadDoubleNodeGen.create(context, new SourceNode())));
break;
case 'F':
case 'f':
node = writeInteger(32, Signedness.UNSIGNED, nativeEndianness(),
AsLongNodeGen.create(context,
node = writeInteger(32, nativeEndianness(),
ReinterpretLongNodeGen.create(context,
AsSinglePrecisionNodeGen.create(context,
ReadDoubleNodeGen.create(context, new SourceNode()))));
break;
case 'E':
node = writeInteger(64, Signedness.UNSIGNED, Endianness.LITTLE,
AsLongNodeGen.create(context,
node = writeInteger(64, Endianness.LITTLE,
ReinterpretLongNodeGen.create(context,
ReadDoubleNodeGen.create(context, new SourceNode())));
break;
case 'e':
node = writeInteger(32, Signedness.UNSIGNED, Endianness.LITTLE,
AsLongNodeGen.create(context,
node = writeInteger(32, Endianness.LITTLE,
ReinterpretLongNodeGen.create(context,
AsSinglePrecisionNodeGen.create(context,
ReadDoubleNodeGen.create(context, new SourceNode()))));
break;
case 'G':
node = writeInteger(64, Signedness.UNSIGNED, Endianness.BIG,
AsLongNodeGen.create(context,
node = writeInteger(64, Endianness.BIG,
ReinterpretLongNodeGen.create(context,
ReadDoubleNodeGen.create(context, new SourceNode())));
break;
case 'g':
node = writeInteger(32, Signedness.UNSIGNED, Endianness.BIG,
AsLongNodeGen.create(context,
node = writeInteger(32, Endianness.BIG,
ReinterpretLongNodeGen.create(context,
AsSinglePrecisionNodeGen.create(context,
ReadDoubleNodeGen.create(context, new SourceNode()))));
break;
case 'P':
case 'p':
node = writeInteger(64, Signedness.UNSIGNED, nativeEndianness(),
node = writeInteger(64, nativeEndianness(),
new PNode(context));
break;
case 'w':
@@ -535,77 +533,36 @@ private static Endianness nativeEndianness() {
}
}

private PackNode writeInteger(int size, Signedness signedness, Endianness endianness) {
final PackNode readNode = ReadLongNodeGen.create(context, new SourceNode());
return writeInteger(size, signedness, endianness, readNode);
private PackNode writeInteger(int size, Endianness endianness) {
final PackNode readNode = ToLongNodeGen.create(context,
ReadValueNodeGen.create(context, new SourceNode()));
return writeInteger(size, endianness, readNode);
}

private PackNode writeInteger(int size, Signedness signedness, Endianness endianness, PackNode readNode) {
private PackNode writeInteger(int size, Endianness endianness, PackNode readNode) {
switch (size) {
case 8:
return Write8NodeGen.create(context, readNode);
case 16:
switch (signedness) {
case UNSIGNED:
switch (endianness) {
case LITTLE:
return Write16LittleNodeGen.create(context, readNode);
case BIG:
return Write16BigNodeGen.create(context, readNode);
}
case SIGNED:
switch (endianness) {
case LITTLE:
// Can I just use the same node?
return Write16LittleNodeGen.create(context, readNode);
case BIG:
// Can I just use the same node?
return Write16BigNodeGen.create(context, readNode);
}
default:
throw new UnsupportedOperationException();
switch (endianness) {
case LITTLE:
return Write16LittleNodeGen.create(context, readNode);
case BIG:
return Write16BigNodeGen.create(context, readNode);
}
case 32:
switch (signedness) {
case UNSIGNED:
switch (endianness) {
case LITTLE:
return Write32LittleNodeGen.create(context, readNode);
case BIG:
return Write32BigNodeGen.create(context, readNode);
}
case SIGNED:
switch (endianness) {
case LITTLE:
// Can I just use the same node?
return Write32LittleNodeGen.create(context, readNode);
case BIG:
// Can I just use the same node?
return Write32BigNodeGen.create(context, readNode);
}
default:
throw new UnsupportedOperationException();
switch (endianness) {
case LITTLE:
return Write32LittleNodeGen.create(context, readNode);
case BIG:
return Write32BigNodeGen.create(context, readNode);
}
case 64:
switch (signedness) {
case UNSIGNED:
switch (endianness) {
case LITTLE:
return Write64LittleNodeGen.create(context, readNode);
case BIG:
return Write64BigNodeGen.create(context, readNode);
}
case SIGNED:
switch (endianness) {
case LITTLE:
// Can I just use the same node?
return Write64LittleNodeGen.create(context, readNode);
case BIG:
// Can I just use the same node?
return Write64BigNodeGen.create(context, readNode);
}
default:
throw new UnsupportedOperationException();
switch (endianness) {
case LITTLE:
return Write64LittleNodeGen.create(context, readNode);
case BIG:
return Write64BigNodeGen.create(context, readNode);
}
default:
throw new UnsupportedOperationException();
50 changes: 27 additions & 23 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -19,20 +19,25 @@
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.tools.CoverageTracker;

import jnr.ffi.LibraryLoader;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;

import org.jcodings.Encoding;
import org.jcodings.specific.ASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.Ruby;
import org.jruby.RubyNil;
import org.jruby.TruffleContextInterface;
import org.jruby.ext.ffi.Platform;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.core.BignumNodes;
import org.jruby.truffle.nodes.core.LoadRequiredLibrariesNode;
import org.jruby.truffle.nodes.core.SetTopLevelBindingNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.exceptions.TopLevelRaiseHandler;
@@ -44,14 +49,15 @@
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.object.ObjectIDOperations;
import org.jruby.truffle.runtime.rubinius.RubiniusConfiguration;
import org.jruby.truffle.runtime.sockets.NativeSockets;
import org.jruby.truffle.runtime.subsystems.*;
import org.jruby.truffle.translator.NodeWrapper;
import org.jruby.truffle.translator.TranslatorDriver;
import org.jruby.util.ByteList;
import org.jruby.util.cli.Options;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.math.BigInteger;
import java.util.*;
@@ -70,6 +76,7 @@ public class RubyContext extends ExecutionContext implements TruffleContextInter
private final Ruby runtime;

private final POSIX posix;
private final NativeSockets nativeSockets;

private final TranslatorDriver translator;
private final CoreLibrary coreLibrary;
@@ -130,6 +137,10 @@ public RubyContext(Ruby runtime) {
// JRuby+Truffle uses POSIX for all IO - we need the native version
posix = POSIXFactory.getNativePOSIX(new TrufflePOSIXHandler(this));

final LibraryLoader<NativeSockets> loader = LibraryLoader.create(NativeSockets.class);
loader.library("c");
nativeSockets = loader.load();

warnings = new Warnings(this);

// Object space manager needs to come early before we create any objects
@@ -157,15 +168,18 @@ public RubyContext(Ruby runtime) {
instrumentationServerManager = null;
}

runningOnWindows = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).indexOf("win") >= 0;
runningOnWindows = Platform.getPlatform().getOS() == Platform.OS.WINDOWS;

attachmentsManager = new AttachmentsManager(this);
sourceManager = new SourceManager(this);
rubiniusConfiguration = new RubiniusConfiguration(this);
rubiniusConfiguration = RubiniusConfiguration.create(this);

final PrintStream configStandardOut = runtime.getInstanceConfig().getOutput();
debugStandardOut = configStandardOut == System.out ? null : configStandardOut;
debugStandardOut = (configStandardOut == System.out) ? null : configStandardOut;
}

@Override
public void initialize() {
// Give the core library manager a chance to tweak some of those methods

coreLibrary.initializeAfterMethodsAdded();
@@ -214,22 +228,6 @@ public RubyContext(Ruby runtime) {

// Shims
loadPath.slowPush(makeString(new File(home, "lib/ruby/truffle/shims").toString()));

// Load libraries required from the command line (-r LIBRARY)
for (String requiredLibrary : runtime.getInstanceConfig().getRequiredLibraries()) {
try {
featureManager.require(requiredLibrary, null);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (RaiseException e) {
// Translate LoadErrors for JRuby since we're outside an ExceptionTranslatingNode.
if (e.getRubyException().getLogicalClass() == coreLibrary.getLoadErrorClass()) {
throw runtime.newLoadError(e.getRubyException().getMessage().toString(), requiredLibrary);
} else {
throw e;
}
}
}
}

public static String checkInstanceVariableName(RubyContext context, String name, Node currentNode) {
@@ -629,6 +627,10 @@ public POSIX getPosix() {
return posix;
}

public NativeSockets getNativeSockets() {
return nativeSockets;
}

@Override
public Object execute(final org.jruby.ast.RootNode rootNode) {
coreLibrary.getGlobalVariablesObject().getObjectType().setInstanceVariable(
@@ -652,9 +654,11 @@ public Object execute(final org.jruby.ast.RootNode rootNode) {
public RubyNode wrap(RubyNode node) {
RubyContext context = node.getContext();
SourceSection sourceSection = node.getSourceSection();
return SequenceNode.sequence(context, sourceSection,
new SetTopLevelBindingNode(context, sourceSection),
new TopLevelRaiseHandler(context, sourceSection, node));
return new TopLevelRaiseHandler(context, sourceSection,
SequenceNode.sequence(context, sourceSection,
new SetTopLevelBindingNode(context, sourceSection),
new LoadRequiredLibrariesNode(context, sourceSection),
node));
}
});
return coreLibrary.getNilObject();
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

@@ -44,6 +43,7 @@
import org.jruby.truffle.runtime.control.TruffleFatalException;
import org.jruby.truffle.runtime.hash.HashOperations;
import org.jruby.truffle.runtime.hash.KeyValue;
import org.jruby.truffle.runtime.rubinius.RubiniusTypes;
import org.jruby.truffle.runtime.signal.SignalOperations;
import org.jruby.truffle.translator.NodeWrapper;
import org.jruby.util.cli.Options;
@@ -198,16 +198,12 @@ public CoreLibrary(RubyContext context) {

// Create the cyclic classes and modules

classClass = RubyClass.createBootClass(context, null, "Class", new RubyClass.ClassAllocator());
basicObjectClass = RubyClass.createBootClass(context, classClass, "BasicObject", new RubyBasicObject.BasicObjectAllocator());
objectClass = RubyClass.createBootClass(context, classClass, "Object", basicObjectClass.getAllocator());
moduleClass = RubyClass.createBootClass(context, classClass, "Module", new RubyModule.ModuleAllocator());
classClass = RubyClass.createClassClass(context, new RubyClass.ClassAllocator());
basicObjectClass = RubyClass.createBootClass(classClass, null, "BasicObject", new RubyBasicObject.BasicObjectAllocator());
objectClass = RubyClass.createBootClass(classClass, basicObjectClass, "Object", basicObjectClass.getAllocator());
moduleClass = RubyClass.createBootClass(classClass, objectClass, "Module", new RubyModule.ModuleAllocator());

// Close the cycles
classClass.unsafeSetLogicalClass(classClass);

objectClass.unsafeSetSuperclass(basicObjectClass);
moduleClass.unsafeSetSuperclass(objectClass);
classClass.unsafeSetSuperclass(moduleClass);

classClass.getAdoptedByLexicalParent(objectClass, "Class", node);
@@ -578,26 +574,26 @@ public void initializeAfterMethodsAdded() {
}

private void initializeRubiniusFFI() {
rubiniusFFIModule.setConstant(node, "TYPE_CHAR", NativeFunctionPrimitiveNodes.TYPE_CHAR);
rubiniusFFIModule.setConstant(node, "TYPE_UCHAR", NativeFunctionPrimitiveNodes.TYPE_UCHAR);
rubiniusFFIModule.setConstant(node, "TYPE_BOOL", NativeFunctionPrimitiveNodes.TYPE_BOOL);
rubiniusFFIModule.setConstant(node, "TYPE_SHORT", NativeFunctionPrimitiveNodes.TYPE_SHORT);
rubiniusFFIModule.setConstant(node, "TYPE_USHORT", NativeFunctionPrimitiveNodes.TYPE_USHORT);
rubiniusFFIModule.setConstant(node, "TYPE_INT", NativeFunctionPrimitiveNodes.TYPE_INT);
rubiniusFFIModule.setConstant(node, "TYPE_UINT", NativeFunctionPrimitiveNodes.TYPE_UINT);
rubiniusFFIModule.setConstant(node, "TYPE_LONG", NativeFunctionPrimitiveNodes.TYPE_LONG);
rubiniusFFIModule.setConstant(node, "TYPE_ULONG", NativeFunctionPrimitiveNodes.TYPE_ULONG);
rubiniusFFIModule.setConstant(node, "TYPE_LL", NativeFunctionPrimitiveNodes.TYPE_LL);
rubiniusFFIModule.setConstant(node, "TYPE_ULL", NativeFunctionPrimitiveNodes.TYPE_ULL);
rubiniusFFIModule.setConstant(node, "TYPE_FLOAT", NativeFunctionPrimitiveNodes.TYPE_FLOAT);
rubiniusFFIModule.setConstant(node, "TYPE_DOUBLE", NativeFunctionPrimitiveNodes.TYPE_DOUBLE);
rubiniusFFIModule.setConstant(node, "TYPE_PTR", NativeFunctionPrimitiveNodes.TYPE_PTR);
rubiniusFFIModule.setConstant(node, "TYPE_VOID", NativeFunctionPrimitiveNodes.TYPE_VOID);
rubiniusFFIModule.setConstant(node, "TYPE_STRING", NativeFunctionPrimitiveNodes.TYPE_STRING);
rubiniusFFIModule.setConstant(node, "TYPE_STRPTR", NativeFunctionPrimitiveNodes.TYPE_STRPTR);
rubiniusFFIModule.setConstant(node, "TYPE_CHARARR", NativeFunctionPrimitiveNodes.TYPE_CHARARR);
rubiniusFFIModule.setConstant(node, "TYPE_ENUM", NativeFunctionPrimitiveNodes.TYPE_ENUM);
rubiniusFFIModule.setConstant(node, "TYPE_VARARGS", NativeFunctionPrimitiveNodes.TYPE_VARARGS);
rubiniusFFIModule.setConstant(node, "TYPE_CHAR", RubiniusTypes.TYPE_CHAR);
rubiniusFFIModule.setConstant(node, "TYPE_UCHAR", RubiniusTypes.TYPE_UCHAR);
rubiniusFFIModule.setConstant(node, "TYPE_BOOL", RubiniusTypes.TYPE_BOOL);
rubiniusFFIModule.setConstant(node, "TYPE_SHORT", RubiniusTypes.TYPE_SHORT);
rubiniusFFIModule.setConstant(node, "TYPE_USHORT", RubiniusTypes.TYPE_USHORT);
rubiniusFFIModule.setConstant(node, "TYPE_INT", RubiniusTypes.TYPE_INT);
rubiniusFFIModule.setConstant(node, "TYPE_UINT", RubiniusTypes.TYPE_UINT);
rubiniusFFIModule.setConstant(node, "TYPE_LONG", RubiniusTypes.TYPE_LONG);
rubiniusFFIModule.setConstant(node, "TYPE_ULONG", RubiniusTypes.TYPE_ULONG);
rubiniusFFIModule.setConstant(node, "TYPE_LL", RubiniusTypes.TYPE_LL);
rubiniusFFIModule.setConstant(node, "TYPE_ULL", RubiniusTypes.TYPE_ULL);
rubiniusFFIModule.setConstant(node, "TYPE_FLOAT", RubiniusTypes.TYPE_FLOAT);
rubiniusFFIModule.setConstant(node, "TYPE_DOUBLE", RubiniusTypes.TYPE_DOUBLE);
rubiniusFFIModule.setConstant(node, "TYPE_PTR", RubiniusTypes.TYPE_PTR);
rubiniusFFIModule.setConstant(node, "TYPE_VOID", RubiniusTypes.TYPE_VOID);
rubiniusFFIModule.setConstant(node, "TYPE_STRING", RubiniusTypes.TYPE_STRING);
rubiniusFFIModule.setConstant(node, "TYPE_STRPTR", RubiniusTypes.TYPE_STRPTR);
rubiniusFFIModule.setConstant(node, "TYPE_CHARARR", RubiniusTypes.TYPE_CHARARR);
rubiniusFFIModule.setConstant(node, "TYPE_ENUM", RubiniusTypes.TYPE_ENUM);
rubiniusFFIModule.setConstant(node, "TYPE_VARARGS", RubiniusTypes.TYPE_VARARGS);
}

public void loadRubyCore(String fileName) {
Original file line number Diff line number Diff line change
@@ -59,9 +59,10 @@ protected RubyBasicObject(RubyContext context, RubyClass rubyClass) {
private RubyBasicObject(RubyContext context, RubyClass rubyClass, DynamicObject dynamicObject) {
this.dynamicObject = dynamicObject;

if (rubyClass != null) {
unsafeSetLogicalClass(rubyClass);
if (rubyClass == null && this instanceof RubyClass) { // For class Class
rubyClass = (RubyClass) this;
}
unsafeSetLogicalClass(rubyClass);
}

protected void unsafeSetLogicalClass(RubyClass newLogicalClass) {
Original file line number Diff line number Diff line change
@@ -29,12 +29,17 @@ public class RubyClass extends RubyModule {
private final boolean isSingleton;
private final RubyModule attached;

/** Special constructor for class Class */
public static RubyClass createClassClass(RubyContext context, Allocator allocator) {
return new RubyClass(context, null, null, null, "Class", false, null, allocator);
}

/**
* This constructor supports initialization and solves boot-order problems and should not
* normally be used from outside this class.
*/
public static RubyClass createBootClass(RubyContext context, RubyClass classClass, String name, Allocator allocator) {
return new RubyClass(context, classClass, null, null, name, false, null, allocator);
public static RubyClass createBootClass(RubyClass classClass, RubyClass superclass, String name, Allocator allocator) {
return new RubyClass(classClass.getContext(), classClass, null, superclass, name, false, null, allocator);
}

public RubyClass(RubyContext context, RubyModule lexicalParent, RubyClass superclass, String name, Allocator allocator) {
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ public void setBacktrace(Backtrace backtrace) {
this.backtrace = backtrace;
}

public Object asRubyStringArray() {
public RubyArray asRubyStringArray() {
assert backtrace != null;
final String[] lines = Backtrace.EXCEPTION_FORMATTER.format(getContext(), this, backtrace);

Original file line number Diff line number Diff line change
@@ -112,7 +112,9 @@ protected RubyModule(RubyContext context, RubyClass selfClass, RubyModule lexica

unmodifiedAssumption = new CyclicAssumption(name + " is unmodified");

if (lexicalParent != null) {
if (lexicalParent == null) {
this.name = name;
} else {
getAdoptedByLexicalParent(lexicalParent, name, currentNode);
}
}
Loading

0 comments on commit 4bd8d71

Please sign in to comment.