Skip to content

Commit

Permalink
Showing 38 changed files with 622 additions and 266 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -29,7 +29,8 @@ env:
- JT='test specs :core'
- JT='test specs :library'
- JT='test specs :truffle'
- JT='test integration'
- JT='test integration fast'
- JT='test integration long' JAVA_OPTS="$JAVA_OPTS -Xmx512m"

matrix:
include:
@@ -46,7 +47,6 @@ matrix:
jdk: oraclejdk8
- env: PHASE='-Pj2ee'
jdk: oraclejdk7
- env: JT='test integration'
# NOTE: build seems to never start (waited for any to finish for more than a day) - probably a travis-ci bug
#- env: PHASE='-Pmain'
# sudo: required
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/RubyInstanceConfig.java
Original file line number Diff line number Diff line change
@@ -169,10 +169,10 @@ public void tryProcessArgumentsWithRubyopts() {
Object rubyoptObj = environment.get("RUBYOPT");
String rubyopt = rubyoptObj == null ? null : rubyoptObj.toString();

if (rubyopt == null || "".equals(rubyopt)) return;
if (rubyopt == null || rubyopt.length() == 0) return;

if (rubyopt.split("\\s").length != 0) {
String[] rubyoptArgs = rubyopt.split("\\s+");
String[] rubyoptArgs = rubyopt.split("\\s+");
if (rubyoptArgs.length != 0) {
new ArgumentProcessor(rubyoptArgs, false, true, true, this).processArguments();
}
} catch (SecurityException se) {
7 changes: 2 additions & 5 deletions core/src/main/java/org/jruby/RubyString.java
Original file line number Diff line number Diff line change
@@ -4491,9 +4491,6 @@ public IRubyObject strip_bang19(ThreadContext context) {
return left.isNil() && right.isNil() ? context.runtime.getNil() : this;
}

/** rb_str_count
*
*/
public IRubyObject count(ThreadContext context) {
return count19(context);
}
@@ -4542,7 +4539,7 @@ public IRubyObject count19(ThreadContext context, IRubyObject arg) {

final boolean[] table = new boolean[StringSupport.TRANS_SIZE + 1];
StringSupport.TrTables tables = StringSupport.trSetupTable(countValue, runtime, table, null, true, enc);
return runtime.newFixnum(StringSupport.countCommon19(value, runtime, table, tables, enc));
return runtime.newFixnum(StringSupport.strCount(value, runtime, table, tables, enc));
}

// MRI: rb_str_count for arity > 1, first half
@@ -4563,7 +4560,7 @@ public IRubyObject count19(ThreadContext context, IRubyObject[] args) {
tables = StringSupport.trSetupTable(countStr.value, runtime, table, tables, false, enc);
}

return runtime.newFixnum(StringSupport.countCommon19(value, runtime, table, tables, enc));
return runtime.newFixnum(StringSupport.strCount(value, runtime, table, tables, enc));
}

/** rb_str_delete / rb_str_delete_bang
Original file line number Diff line number Diff line change
@@ -80,8 +80,8 @@ private static IRubyObject convertCoverageToRuby(ThreadContext context, Ruby run
for (int i = 0; i < entry.getValue().length; i++) {
int integer = entry.getValue()[i];
ary.store(i, integer == -1 ? context.nil : runtime.newFixnum(integer));
covHash.fastASetCheckString(runtime, RubyString.newString(runtime, entry.getKey()), ary);
}
covHash.fastASetCheckString(runtime, RubyString.newString(runtime, entry.getKey()), ary);
}

return covHash;
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/parser/Parser.java
Original file line number Diff line number Diff line change
@@ -160,6 +160,7 @@ public Node parse(String file, LexerSource lexerSource, DynamicScope blockScope,

// set coverage baseline into coverage data
if (runtime.getCoverageData().isCoverageEnabled()) {
configuration.growCoverageLines(parser.lexer.lineno());
runtime.getCoverageData().prepareCoverage(file, configuration.getCoverage());
}

27 changes: 17 additions & 10 deletions core/src/main/java/org/jruby/parser/ParserConfiguration.java
Original file line number Diff line number Diff line change
@@ -186,20 +186,27 @@ public void coverLine(int i) {
if (i < 0) return; // JRUBY-6868: why would there be negative line numbers?

if (runtime.getCoverageData().isCoverageEnabled()) {
if (coverage == null) {
coverage = new int[i + 1];
} else if (coverage.length <= i) {
int[] newCoverage = new int[i + 1];
Arrays.fill(newCoverage, -1);
System.arraycopy(coverage, 0, newCoverage, 0, coverage.length);
coverage = newCoverage;
}

// zero means coverable, but not yet covered
growCoverageLines(i);
coverage[i] = 0;
}
}

/**
* Called by coverLine to grow it large enough to add new covered line.
* Also called at end up parse to pick up any extra non-code lines which
* should be marked -1 for not valid code lines.
*/
public void growCoverageLines(int i) {
if (coverage == null) {
coverage = new int[i + 1];
} else if (coverage.length <= i) {
int[] newCoverage = new int[i + 1];
Arrays.fill(newCoverage, -1);
System.arraycopy(coverage, 0, newCoverage, 0, coverage.length);
coverage = newCoverage;
}
}

/**
* Get the coverage array, indicating all coverable lines
*/
13 changes: 10 additions & 3 deletions core/src/main/java/org/jruby/util/StringSupport.java
Original file line number Diff line number Diff line change
@@ -868,16 +868,16 @@ public static boolean isEVStr(int c) {
/**
* rb_str_count
*/

public static int countCommon19(ByteList str, Ruby runtime, boolean[] table, TrTables tables, Encoding enc) {
public static int strCount(ByteList str, Ruby runtime, boolean[] table, TrTables tables, Encoding enc) {
final byte[] bytes = str.getUnsafeBytes();
int p = str.getBegin();
final int end = p + str.getRealSize();
final boolean asciiCompat = enc.isAsciiCompatible();

int count = 0;
while (p < end) {
int c;
if (enc.isAsciiCompatible() && (c = bytes[p] & 0xff) < 0x80) {
if (asciiCompat && (c = bytes[p] & 0xff) < 0x80) {
if (table[c]) count++;
p++;
} else {
@@ -891,6 +891,13 @@ public static int countCommon19(ByteList str, Ruby runtime, boolean[] table, TrT
return count;
}

/**
* @deprecated renamed to {@link #strCount(ByteList, Ruby, boolean[], TrTables, Encoding)}
*/
public static int countCommon19(ByteList str, Ruby runtime, boolean[] table, TrTables tables, Encoding enc) {
return strCount(str, runtime, table, tables, enc);
}

// MRI: rb_str_rindex
public static int rindex(ByteList source, int sourceChars, int subChars, int pos, CodeRangeable subStringCodeRangeable, Encoding enc) {
if (subStringCodeRangeable.scanForCodeRange() == CR_BROKEN) return -1;
25 changes: 25 additions & 0 deletions spec/ruby/core/thread/backtrace_spec.rb
Original file line number Diff line number Diff line change
@@ -2,4 +2,29 @@

describe "Thread#backtrace" do
it "needs to be reviewed for spec completeness"

it "returns current backtrace of a thread" do

t = Thread.new do
begin
sleep
rescue
end
end

Thread.pass while t.status != 'sleep'

backtrace = t.backtrace
backtrace.should be_kind_of(Array)
backtrace.first.should =~ /`sleep'/

t.raise 'finish the thread'
t.join
end

it "returns nil for dead thread" do
t = Thread.new {}
t.join
t.backtrace.should == nil
end
end
2 changes: 2 additions & 0 deletions test/truffle/integration/long-tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rails.sh
gem-testing.sh
29 changes: 17 additions & 12 deletions tool/jt.rb
Original file line number Diff line number Diff line change
@@ -275,7 +275,7 @@ def help
puts 'jt test spec/ruby/language/while_spec.rb run specs in this file'
puts 'jt test compiler run compiler tests (uses the same logic as --graal to find Graal)'
puts ' --no-java-cmd don\'t set JAVACMD - rely on bin/jruby or RUBY_BIN to have Graal already'
puts 'jt test integration [fast] runs bigger integration tests'
puts 'jt test integration [fast|long|all] runs bigger integration tests (fast is default)'
puts ' --no-gems don\'t run tests that install gems'
puts 'jt tag spec/ruby/language tag failing specs in this directory'
puts 'jt tag spec/ruby/language/while_spec.rb tag failing specs in this file'
@@ -459,22 +459,27 @@ def test_compiler(*args)

def test_integration(*args)
no_gems = args.delete('--no-gems')
fast = args.delete('fast')

all = args.delete('all')
long = args.delete('long') || all
fast = args.delete('fast') || all ||
!long # fast is the default

env_vars = {}
env_vars["JRUBY_OPTS"] = '-Xtruffle.graal.warn_unless=false'
env_vars["PATH"] = "#{Utilities.find_jruby_bin_dir}:#{ENV["PATH"]}"
integration_path = "#{JRUBY_DIR}/test/truffle/integration"
long_tests = File.read(File.join(integration_path, 'long-tests.txt')).lines.map(&:chomp)
test_names = args.empty? ? '*' : '{' + args.join(',') + '}'

test_names = if args.empty?
'*'
else
'{' + args.join(',') + '}'
end

Dir["#{JRUBY_DIR}/test/truffle/integration/#{test_names}.sh"].each do |test_script|
Dir["#{integration_path}/#{test_names}.sh"].each do |test_script|
next if no_gems && File.read(test_script).include?('gem install')
next if fast && test_script.end_with?('integration/gem-testing.sh')
next if fast && test_script.end_with?('integration/rails.sh')
sh env_vars, test_script

is_long = long_tests.include?(File.basename(test_script))

if (is_long && long) || (!is_long && fast)
sh env_vars, test_script
end
end
end
private :test_integration
1 change: 1 addition & 0 deletions truffle/pom.rb
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@
'annotationProcessors' => [ 'com.oracle.truffle.object.dsl.processor.LayoutProcessor',
'com.oracle.truffle.dsl.processor.InstrumentableProcessor',
'com.oracle.truffle.dsl.processor.TruffleProcessor',
'com.oracle.truffle.dsl.processor.InteropProcessor',
'com.oracle.truffle.dsl.processor.verify.VerifyTruffleProcessor',
'com.oracle.truffle.dsl.processor.LanguageRegistrationProcessor', ],
'generatedSourcesDirectory' => 'target/generated-sources',
1 change: 1 addition & 0 deletions truffle/pom.xml
Original file line number Diff line number Diff line change
@@ -110,6 +110,7 @@ DO NOT MODIFIY - GENERATED CODE
<annotationProcessor>com.oracle.truffle.object.dsl.processor.LayoutProcessor</annotationProcessor>
<annotationProcessor>com.oracle.truffle.dsl.processor.InstrumentableProcessor</annotationProcessor>
<annotationProcessor>com.oracle.truffle.dsl.processor.TruffleProcessor</annotationProcessor>
<annotationProcessor>com.oracle.truffle.dsl.processor.InteropProcessor</annotationProcessor>
<annotationProcessor>com.oracle.truffle.dsl.processor.verify.VerifyTruffleProcessor</annotationProcessor>
<annotationProcessor>com.oracle.truffle.dsl.processor.LanguageRegistrationProcessor</annotationProcessor>
</annotationProcessors>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -37,12 +37,13 @@ public abstract class ExceptionNodes {

@TruffleBoundary
public static DynamicObject backtraceAsRubyStringArray(RubyContext context, DynamicObject exception, Backtrace backtrace) {
final List<String> lines = new BacktraceFormatter(context, EnumSet.of(BacktraceFormatter.FormattingFlags.OMIT_FROM_PREFIX, BacktraceFormatter.FormattingFlags.OMIT_EXCEPTION))
.formatBacktrace(context, exception, backtrace);
final List<String> lines = new BacktraceFormatter(context,
EnumSet.of(BacktraceFormatter.FormattingFlags.OMIT_FROM_PREFIX,
BacktraceFormatter.FormattingFlags.OMIT_EXCEPTION)).formatBacktrace(context, exception, backtrace);

final Object[] array = new Object[lines.size()];

for (int n = 0;n < lines.size(); n++) {
for (int n = 0; n < lines.size(); n++) {
array[n] = StringOperations.createString(context, StringOperations.encodeRope(lines.get(n), UTF8Encoding.INSTANCE));
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -58,6 +58,15 @@ public byte getByteSlow(int index) {
@Override
@TruffleBoundary
public byte[] extractRange(int offset, int length) {
assert length <= this.byteLength();

if (getRawBytes() != null) {
final byte[] ret = new byte[length];
System.arraycopy(getRawBytes(), offset, ret, 0, length);

return ret;
}

byte[] leftBytes;
byte[] rightBytes;
final int leftLength = left.byteLength();
@@ -79,7 +88,7 @@ public byte[] extractRange(int offset, int length) {
System.arraycopy(rightBytes, 0, ret, leftBytes.length, rightBytes.length);

return ret;
} else {
} else {
return leftBytes;
}
}
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
package org.jruby.truffle.core.rope;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import org.jcodings.Encoding;

public class SubstringRope extends Rope {
@@ -46,9 +47,17 @@ public byte getByteSlow(int index) {
}

@Override
@TruffleBoundary
public byte[] extractRange(int offset, int length) {
assert length <= this.byteLength();

if (getRawBytes() != null) {
final byte[] ret = new byte[length];
System.arraycopy(getRawBytes(), offset, ret, 0, length);

return ret;
}

return child.extractRange(this.offset + offset, length);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -166,7 +166,8 @@ public AliveNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public boolean alive(DynamicObject thread) {
return Layouts.THREAD.getStatus(thread) != Status.ABORTING && Layouts.THREAD.getStatus(thread) != Status.DEAD;
final Status status = Layouts.THREAD.getStatus(thread);
return status != Status.ABORTING && status != Status.DEAD;
}

}
@@ -192,7 +193,12 @@ public void run(DynamicObject thread, Node currentNode) {
}
});

return result[0];
// if the thread id dead or aborting the SafepointAction will not run
if (result[0] != null) {
return result[0];
} else {
return nil();
}
}

}
@@ -411,15 +417,16 @@ public StatusNode(RubyContext context, SourceSection sourceSection) {
@Specialization
public Object status(DynamicObject self) {
// TODO: slightly hackish
if (Layouts.THREAD.getStatus(self) == Status.DEAD) {
final Status status = Layouts.THREAD.getStatus(self);
if (status == Status.DEAD) {
if (Layouts.THREAD.getException(self) != null) {
return nil();
} else {
return false;
}
}

return createString(Layouts.THREAD.getStatus(self).bytes);
return createString(status.bytes);
}

}
@@ -433,7 +440,8 @@ public StopNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public boolean stop(DynamicObject self) {
return Layouts.THREAD.getStatus(self) == Status.DEAD || Layouts.THREAD.getStatus(self) == Status.SLEEP;
final Status status = Layouts.THREAD.getStatus(self);
return status == Status.DEAD || status == Status.SLEEP;
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "EXECUTE", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignExecuteNode extends ForeignExecuteBaseNode {

@Child private Node findContextNode;
@Child private InteropExecute interopNode;

@Override
public Object access(VirtualFrame frame, DynamicObject object, Object[] args) {
return getInteropNode().execute(frame);
}

private InteropExecute getInteropNode() {
if (interopNode == null) {
CompilerDirectives.transferToInterpreter();
findContextNode = insert(RubyLanguage.INSTANCE.unprotectedCreateFindContextNode());
final RubyContext context = RubyLanguage.INSTANCE.unprotectedFindContext(findContextNode);
interopNode = insert(new InteropExecute(context, null));
}

return interopNode;
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyObjectType;
import org.jruby.truffle.language.dispatch.DispatchAction;
import org.jruby.truffle.language.dispatch.DispatchHeadNode;
import org.jruby.truffle.language.dispatch.MissingBehavior;

@AcceptMessage(value = "GET_SIZE", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignGetSizeNode extends ForeignGetSizeBaseNode {

@Child private Node findContextNode;
@Child private DispatchHeadNode dispatchNode;

@Override
public Object access(VirtualFrame frame, DynamicObject object) {
return getDispatchNode().dispatch(frame, object, "size", null, new Object[] {});
}

private DispatchHeadNode getDispatchNode() {
if (dispatchNode == null) {
CompilerDirectives.transferToInterpreter();
findContextNode = insert(RubyLanguage.INSTANCE.unprotectedCreateFindContextNode());
final RubyContext context = RubyLanguage.INSTANCE.unprotectedFindContext(findContextNode);
dispatchNode = insert(new DispatchHeadNode(context, true, MissingBehavior.CALL_METHOD_MISSING, DispatchAction.CALL_METHOD));
}

return dispatchNode;
}

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

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "HAS_SIZE", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignHasSizeNode extends ForeignHasSizeBaseNode {

@Override
public Object access(VirtualFrame frame, DynamicObject object) {
return RubyGuards.isRubyArray(object) || RubyGuards.isRubyHash(object) || RubyGuards.isRubyString(object);
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "INVOKE", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignInvokeNode extends ForeignInvokeBaseNode {

@Child private Node findContextNode;
@Child private RubyNode interopNode;

@Override
public Object access(VirtualFrame frame, DynamicObject object, String name, Object[] args) {
return getInteropNode().execute(frame);
}

private RubyNode getInteropNode() {
if (interopNode == null) {
CompilerDirectives.transferToInterpreter();
findContextNode = insert(RubyLanguage.INSTANCE.unprotectedCreateFindContextNode());
final RubyContext context = RubyLanguage.INSTANCE.unprotectedFindContext(findContextNode);
interopNode = insert(new UnresolvedInteropExecuteAfterReadNode(context, null, 0));
}

return interopNode;
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "IS_BOXED", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignIsBoxedNode extends ForeignIsBoxedBaseNode {

@Override
public Object access(VirtualFrame frame, DynamicObject object) {
return RubyGuards.isRubyString(object) && StringOperations.rope(object).byteLength() == 1;
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "IS_EXECUTABLE", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignIsExecutableNode extends ForeignIsExecutableBaseNode {

@Override
public Object access(VirtualFrame frame, DynamicObject object) {
return RubyGuards.isRubyMethod(object);
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "IS_NULL", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignIsNullNode extends ForeignIsNullBaseNode {

@Child private Node findContextNode;
@CompilationFinal RubyContext context;

@Override
public Object access(VirtualFrame frame, DynamicObject object) {
return object == getContext().getCoreLibrary().getNilObject();
}

private RubyContext getContext() {
if (context == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
findContextNode = insert(RubyLanguage.INSTANCE.unprotectedCreateFindContextNode());
context = RubyLanguage.INSTANCE.unprotectedFindContext(findContextNode);
}

return context;
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.RubyObjectType;
import org.jruby.truffle.language.dispatch.DispatchAction;
import org.jruby.truffle.language.dispatch.DispatchHeadNode;
import org.jruby.truffle.language.dispatch.MissingBehavior;

@AcceptMessage(value = "READ", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignReadNode extends ForeignReadBaseNode {

@Child private Node findContextNode;
@Child private RubyNode interopNode;

@Override
public Object access(VirtualFrame frame, DynamicObject object, Object name) {
return getInteropNode().execute(frame);
}

private RubyNode getInteropNode() {
if (interopNode == null) {
CompilerDirectives.transferToInterpreter();
findContextNode = insert(RubyLanguage.INSTANCE.unprotectedCreateFindContextNode());
final RubyContext context = RubyLanguage.INSTANCE.unprotectedFindContext(findContextNode);
interopNode = insert(new UnresolvedInteropReadNode(context, null));
}

return interopNode;
}

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

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "UNBOX", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignUnboxNode extends ForeignUnboxBaseNode {

@Override
public Object access(VirtualFrame frame, DynamicObject object) {
if (RubyGuards.isRubyString(object)) {
return StringOperations.getByteListReadOnly(object).get(0);
} else {
return object;
}
}

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

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.AcceptMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.RubyObjectType;

@AcceptMessage(value = "WRITE", receiverType = RubyObjectType.class, language = RubyLanguage.class)
public final class ForeignWriteNode extends ForeignWriteBaseNode {

@Child private Node findContextNode;
@Child private RubyNode interopNode;

@Override
public Object access(VirtualFrame frame, DynamicObject object, Object name, Object value) {
return getInteropNode().execute(frame);
}

private RubyNode getInteropNode() {
if (interopNode == null) {
CompilerDirectives.transferToInterpreter();
findContextNode = insert(RubyLanguage.INSTANCE.unprotectedCreateFindContextNode());
final RubyContext context = RubyLanguage.INSTANCE.unprotectedFindContext(findContextNode);
interopNode = insert(new UnresolvedInteropWriteNode(context, null));
}

return interopNode;
}

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

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.ObjectType;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.array.ArrayLayoutImpl;
import org.jruby.truffle.core.hash.HashLayoutImpl;
import org.jruby.truffle.core.string.StringLayoutImpl;
import org.jruby.truffle.language.RubyNode;

public class InteropHasSize extends RubyNode {

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

@Override
public Object execute(VirtualFrame frame) {
final ObjectType type = ((DynamicObject) ForeignAccess.getReceiver(frame)).getShape().getObjectType();

return type instanceof ArrayLayoutImpl.ArrayType
|| type instanceof HashLayoutImpl.HashType
|| type instanceof StringLayoutImpl.StringType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2013, 2016 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.interop;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;

public class InteropIsExecutable extends RubyNode {
public InteropIsExecutable(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Override
public Object execute(VirtualFrame frame) {
return RubyGuards.isRubyMethod(ForeignAccess.getReceiver(frame));
}
}
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;

public class InteropStringUnboxNode extends RubyNode {
@@ -25,6 +26,12 @@ public InteropStringUnboxNode(RubyContext context, SourceSection sourceSection)

@Override
public Object execute(VirtualFrame frame) {
return StringOperations.getByteListReadOnly(((DynamicObject) ForeignAccess.getReceiver(frame))).get(0);
final DynamicObject receiver = (DynamicObject) ForeignAccess.getReceiver(frame);

if (RubyGuards.isRubyString(receiver)) {
return StringOperations.getByteListReadOnly(receiver).get(0);
} else {
return receiver;
}
}
}
Original file line number Diff line number Diff line change
@@ -11,13 +11,16 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.dispatch.DispatchAction;
import org.jruby.truffle.language.dispatch.DispatchHeadNode;
import org.jruby.truffle.language.dispatch.MissingBehavior;

import java.util.List;

public class ResolvedInteropExecuteAfterReadNode extends RubyNode {

@Child private DispatchHeadNode head;
@@ -38,9 +41,10 @@ public ResolvedInteropExecuteAfterReadNode(RubyContext context, SourceSection so
@Override
public Object execute(VirtualFrame frame) {
if (name.equals(frame.getArguments()[labelIndex])) {
Object[] args = new Object[arguments.getCount(frame)];
arguments.executeFillObjectArray(frame, args);
return head.dispatch(frame, frame.getArguments()[receiverIndex], frame.getArguments()[labelIndex], null, args);
//Object[] args = new Object[arguments.getCount(frame)];
//arguments.executeFillObjectArray(frame, args);
final List<Object> arguments = ForeignAccess.getArguments(frame);
return head.dispatch(frame, frame.getArguments()[receiverIndex], frame.getArguments()[labelIndex], null, arguments.subList(1, arguments.size()).toArray());
} else {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException("Name changed");
Original file line number Diff line number Diff line change
@@ -7,26 +7,32 @@
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core.basicobject;
package org.jruby.truffle.interop;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.nodes.RootNode;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.interop.InteropExecute;
import org.jruby.truffle.interop.InteropGetSizeProperty;
import org.jruby.truffle.interop.InteropHasSize;
import org.jruby.truffle.interop.InteropIsExecutable;
import org.jruby.truffle.interop.InteropIsNull;
import org.jruby.truffle.interop.InteropStringIsBoxed;
import org.jruby.truffle.interop.InteropStringUnboxNode;
import org.jruby.truffle.interop.RubyInteropRootNode;
import org.jruby.truffle.interop.UnresolvedInteropExecuteAfterReadNode;
import org.jruby.truffle.interop.UnresolvedInteropReadNode;
import org.jruby.truffle.interop.UnresolvedInteropWriteNode;
import org.jruby.truffle.language.literal.BooleanLiteralNode;

public class BasicObjectForeignAccessFactory implements ForeignAccess.Factory10 {
public class RubyForeignAccessFactory implements ForeignAccess.Factory10 {

protected final RubyContext context;

public BasicObjectForeignAccessFactory(RubyContext context) {
public RubyForeignAccessFactory(RubyContext context) {
this.context = context;
}

@@ -37,27 +43,27 @@ public CallTarget accessIsNull() {

@Override
public CallTarget accessIsExecutable() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
return Truffle.getRuntime().createCallTarget(new RubyInteropRootNode(new InteropIsExecutable(context, null)));
}

@Override
public CallTarget accessIsBoxed() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
return Truffle.getRuntime().createCallTarget(new RubyInteropRootNode(new InteropStringIsBoxed(context, null)));
}

@Override
public CallTarget accessHasSize() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
return Truffle.getRuntime().createCallTarget(new RubyInteropRootNode(new InteropHasSize(context, null)));
}

@Override
public CallTarget accessGetSize() {
return null;
return Truffle.getRuntime().createCallTarget(new RubyInteropRootNode(new InteropGetSizeProperty(context, null)));
}

@Override
public CallTarget accessUnbox() {
return null;
return Truffle.getRuntime().createCallTarget(new RubyInteropRootNode(new InteropStringUnboxNode(context, null)));
}

@Override
@@ -72,7 +78,7 @@ public CallTarget accessWrite() {

@Override
public CallTarget accessExecute(int i) {
return null;
return Truffle.getRuntime().createCallTarget(new RubyInteropRootNode(new InteropExecute(context, null)));
}

@Override
Original file line number Diff line number Diff line change
@@ -40,6 +40,12 @@ public Object execute(VirtualFrame frame) {
}
}
DynamicObject receiver = (DynamicObject) ForeignAccess.getReceiver(frame);

if (RubyGuards.isRubyString(receiver)) {
// TODO CS 22-Mar-16 monomorphic, what happens if it fails for other objects?
return this.replace(new UnresolvedInteropStringReadNode(getContext(), getSourceSection())).execute(frame);
}

InternalMethod labelMethod = ModuleOperations.lookupMethod(coreLibrary().getMetaClass(receiver), label.toString());
InternalMethod indexedSetter = ModuleOperations.lookupMethod(coreLibrary().getMetaClass(receiver), "[]=");
if (labelMethod == null && indexedSetter != null) {
Original file line number Diff line number Diff line change
@@ -11,16 +11,13 @@

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.ObjectType;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.core.MethodForeignAccessFactory;
import org.jruby.truffle.core.array.ArrayForeignAccessFactory;
import org.jruby.truffle.core.basicobject.BasicObjectForeignAccessFactory;
import org.jruby.truffle.core.hash.HashForeignAccessFactory;
import org.jruby.truffle.interop.RubyForeignAccessFactory;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.string.StringForeignAccessFactory;
import org.jruby.truffle.core.string.StringOperations;

public class RubyObjectType extends ObjectType {
@@ -45,23 +42,11 @@ public String toString(DynamicObject object) {

@Override
public ForeignAccess getForeignAccessFactory(DynamicObject object) {
CompilerAsserts.neverPartOfCompilation();

final ForeignAccess.Factory10 factory;

if (Layouts.METHOD.isMethod(object) || Layouts.PROC.isProc(object)) {
factory = new MethodForeignAccessFactory(getContext());
} else if (Layouts.ARRAY.isArray(object)) {
factory = new ArrayForeignAccessFactory(getContext());
} else if (Layouts.HASH.isHash(object)) {
factory = new HashForeignAccessFactory(getContext());
} else if (Layouts.STRING.isString(object)) {
factory = new StringForeignAccessFactory(getContext());
} else {
factory = new BasicObjectForeignAccessFactory(getContext());
}
return RubyObjectTypeForeign.ACCESS;
}

return ForeignAccess.create(DynamicObject.class, factory);
public static boolean isInstance(TruffleObject object) {
return RubyGuards.isRubyBasicObject(object);
}

private RubyContext getContext() {
Original file line number Diff line number Diff line change
@@ -137,7 +137,9 @@ public String formatLine(List<Activation> activations, int n, DynamicObject exce
String reportedName;

if (isCore(sourceSection) && !flags.contains(FormattingFlags.INCLUDE_CORE_FILES)) {
reportedSourceSection = nextUserSourceSection(activations, n);
final SourceSection nextUserSourceSection = nextUserSourceSection(activations, n);
// if there is no next source section use a core one to avoid ???
reportedSourceSection = nextUserSourceSection != null ? nextUserSourceSection : sourceSection;

try {
reportedName = activation.getMethod().getName();

0 comments on commit 962999a

Please sign in to comment.