Skip to content

Commit

Permalink
Showing 93 changed files with 1,364 additions and 1,081 deletions.
52 changes: 52 additions & 0 deletions core/src/main/java/org/jruby/RubyBinding.java
Original file line number Diff line number Diff line change
@@ -33,15 +33,18 @@
***** END LICENSE BLOCK *****/
package org.jruby;

import java.util.HashSet;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.Binding;
import org.jruby.runtime.Block;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.IdUtil;

/**
* @author jpetersen
@@ -136,6 +139,55 @@ public IRubyObject eval(ThreadContext context, IRubyObject[] args) {
return RubyKernel.eval(context, this, newArgs, Block.NULL_BLOCK);
}

@JRubyMethod(name = "local_variable_defined?")
public IRubyObject local_variable_defined_p(ThreadContext context, IRubyObject symbol) {
return context.runtime.newBoolean(binding.getEvalScope(context.runtime).getStaticScope().isDefined(symbol.asJavaString()) != -1);
}

@JRubyMethod
public IRubyObject local_variable_get(ThreadContext context, IRubyObject symbol) {
String name = symbol.asJavaString().intern();
DynamicScope evalScope = binding.getEvalScope(context.runtime);
int slot = evalScope.getStaticScope().isDefined(name);

if (slot == -1) throw context.runtime.newNameError("local variable `" + name + "' not defined for " + inspect(), name);

return evalScope.getValue(slot & 0xffff, slot >> 16);
}

@JRubyMethod
public IRubyObject local_variable_set(ThreadContext context, IRubyObject symbol, IRubyObject value) {
String name = symbol.asJavaString().intern();
DynamicScope evalScope = binding.getEvalScope(context.runtime);
int slot = evalScope.getStaticScope().isDefined(name);

if (slot == -1) { // Yay! New variable associated with this binding
slot = evalScope.getStaticScope().addVariable(name.intern());
evalScope.growIfNeeded();
}

return evalScope.setValue(slot & 0xffff, value, slot >> 16);
}

@JRubyMethod
public IRubyObject local_variables(ThreadContext context) {
final Ruby runtime = context.runtime;
HashSet<String> encounteredLocalVariables = new HashSet<>();
RubyArray allLocalVariables = runtime.newArray();
DynamicScope currentScope = binding.getEvalScope(context.runtime);

while (currentScope != null) {
for (String name : currentScope.getStaticScope().getVariables()) {
if (IdUtil.isLocal(name) && !encounteredLocalVariables.contains(name)) {
allLocalVariables.push(runtime.newSymbol(name));
encounteredLocalVariables.add(name);
}
}
currentScope = currentScope.getParentScope();
}

return allLocalVariables;
}

@JRubyMethod(name = "receiver")
public IRubyObject receiver(ThreadContext context) {
5 changes: 4 additions & 1 deletion core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
@@ -1268,7 +1268,10 @@ public static RubyProc proc(ThreadContext context, IRubyObject recv, Block block

@JRubyMethod(module = true, visibility = PRIVATE)
public static RubyProc lambda(ThreadContext context, IRubyObject recv, Block block) {
return context.runtime.newProc(Block.Type.LAMBDA, block);
// If we encounter a amp'd proc we leave it a proc for some reason.
Block.Type type = block.type == Block.Type.PROC ? block.type : Block.Type.LAMBDA;

return context.runtime.newProc(type, block);
}

@JRubyMethod(name = "proc", module = true, visibility = PRIVATE)
4 changes: 3 additions & 1 deletion core/src/main/java/org/jruby/RubyMethod.java
Original file line number Diff line number Diff line change
@@ -197,7 +197,9 @@ public IRubyObject to_proc(ThreadContext context) {
argsDesc = Helpers.methodToArgumentDescriptors(method);
}

body = new MethodBlockBody(runtime.getStaticScopeFactory().getDummyScope(), signature, method, argsDesc, receiver, originModule, originName, getFilename(), getLine());
int line = getLine(); // getLine adds 1 to 1-index but we need to reset to 0-index internally
body = new MethodBlockBody(runtime.getStaticScopeFactory().getDummyScope(), signature, method, argsDesc,
receiver, originModule, originName, getFilename(), line == -1 ? -1 : line - 1);
Block b = MethodBlockBody.createMethodBlock(body);

return RubyProc.newProc(runtime, b, Block.Type.LAMBDA);
26 changes: 16 additions & 10 deletions core/src/main/java/org/jruby/RubyProc.java
Original file line number Diff line number Diff line change
@@ -197,25 +197,26 @@ public IRubyObject dup() {
return newProc(getRuntime(), block, type, sourcePosition);
}

@JRubyMethod(name = "==", required = 1)
public IRubyObject op_equal(IRubyObject other) {
return getRuntime().newBoolean(other instanceof RubyProc &&
(this == other || this.block.equals(((RubyProc)other).block)));
}

@Override
public IRubyObject to_s() {
return to_s19();
}

@JRubyMethod(name = "to_s", alias = "inspect")
public IRubyObject to_s19() {
StringBuilder sb = new StringBuilder("#<Proc:0x" + Integer.toString(block.hashCode(), 16) + "@" +
block.getBody().getFile() + ":" + (block.getBody().getLine() + 1));
StringBuilder sb = new StringBuilder("#<Proc:0x" + Integer.toString(block.hashCode(), 16));
String file = block.getBody().getFile();

if (file != null) sb.append('@').append(file).append(':').append(block.getBody().getLine() + 1);

if (isLambda()) sb.append(" (lambda)");
sb.append(">");

IRubyObject string = RubyString.newString(getRuntime(), sb.toString());

if (isTaint()) string.setTaint(true);

return RubyString.newString(getRuntime(), sb.toString());
return string;
}

@JRubyMethod(name = "binding")
@@ -318,7 +319,12 @@ public IRubyObject call(ThreadContext context, IRubyObject[] args, IRubyObject s

@JRubyMethod(name = "arity")
public RubyFixnum arity() {
return getRuntime().newFixnum(block.getSignature().arityValue());
Signature signature = block.getSignature();

if (block.type == Block.Type.LAMBDA) return getRuntime().newFixnum(signature.arityValue());

// FIXME: Consider min/max like MRI here instead of required + kwarg count.
return getRuntime().newFixnum(signature.hasRest() ? signature.arityValue() : signature.required() + signature.getRequiredKeywordForArityCount());
}

@JRubyMethod(name = "to_proc")
24 changes: 17 additions & 7 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -539,11 +539,16 @@ public Operand buildEncoding(EncodingNode node) {

// Non-arg masgn
public Operand buildMultipleAsgn19(MultipleAsgnNode multipleAsgnNode) {
Operand values = build(multipleAsgnNode.getValueNode());
Node valueNode = multipleAsgnNode.getValueNode();
Operand values = build(valueNode);
Variable ret = getValueInTemporaryVariable(values);
Variable tmp = createTemporaryVariable();
addInstr(new ToAryInstr(tmp, ret));
buildMultipleAsgn19Assignment(multipleAsgnNode, null, tmp);
if (valueNode instanceof ArrayNode) {
buildMultipleAsgn19Assignment(multipleAsgnNode, null, ret);
} else {
Variable tmp = createTemporaryVariable();
addInstr(new ToAryInstr(tmp, ret));
buildMultipleAsgn19Assignment(multipleAsgnNode, null, tmp);
}
return ret;
}

@@ -2023,6 +2028,7 @@ public void buildArgsMasgn(Node node, Operand argsArray, boolean isMasgnRoot, in
// Ex: { |a,b,*c| ..} is the argument passing case
public void buildMultipleAsgn19Assignment(final MultipleAsgnNode multipleAsgnNode, Operand argsArray, Operand values) {
final ListNode masgnPre = multipleAsgnNode.getPre();
final List<Tuple<Node, Variable>> assigns = new ArrayList<>();

// Build assignments for specific named arguments
int i = 0;
@@ -2033,7 +2039,7 @@ public void buildMultipleAsgn19Assignment(final MultipleAsgnNode multipleAsgnNod
} else {
Variable rhsVal = createTemporaryVariable();
addInstr(new ReqdArgMultipleAsgnInstr(rhsVal, values, i));
buildAssignment(an, rhsVal);
assigns.add(new Tuple<Node, Variable>(an, rhsVal));
}
i++;
}
@@ -2048,7 +2054,7 @@ public void buildMultipleAsgn19Assignment(final MultipleAsgnNode multipleAsgnNod
} else {
Variable rhsVal = createTemporaryVariable();
addInstr(new RestArgMultipleAsgnInstr(rhsVal, values, i, postArgsCount, 0));
buildAssignment(restNode, rhsVal); // rest of the argument array!
assigns.add(new Tuple<Node, Variable>(restNode, rhsVal)); // rest of the argument array!
}
}

@@ -2062,11 +2068,15 @@ public void buildMultipleAsgn19Assignment(final MultipleAsgnNode multipleAsgnNod
} else {
Variable rhsVal = createTemporaryVariable();
addInstr(new ReqdArgMultipleAsgnInstr(rhsVal, values, i, postArgsCount, j)); // Fetch from the end
buildAssignment(an, rhsVal);
assigns.add(new Tuple<Node, Variable>(an, rhsVal));
}
j++;
}
}

for (Tuple<Node, Variable> assign: assigns) {
buildAssignment(assign.a, assign.b);
}
}

private void handleBreakAndReturnsInLambdas() {
13 changes: 10 additions & 3 deletions core/src/main/java/org/jruby/ir/IRManager.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import java.util.List;
import java.util.Set;
import org.jruby.ir.passes.DeadCodeElimination;
import org.jruby.ir.passes.LocalOptimizationPass;
import org.jruby.ir.passes.OptimizeDelegationPass;
import org.jruby.ir.passes.OptimizeDynScopesPass;
import org.jruby.ir.passes.OptimizeTempVarsPass;
@@ -26,8 +27,8 @@

public class IRManager {
public static final String SAFE_COMPILER_PASSES = "";
public static final String DEFAULT_BUILD_PASSES = "LocalOptimizationPass";
public static final String DEFAULT_JIT_PASSES = "LocalOptimizationPass,OptimizeDelegationPass,DeadCodeElimination,AddLocalVarLoadStoreInstructions,OptimizeDynScopesPass,AddCallProtocolInstructions,EnsureTempsAssigned";
public static final String DEFAULT_BUILD_PASSES = "";
public static final String DEFAULT_JIT_PASSES = "OptimizeDelegationPass,DeadCodeElimination,AddLocalVarLoadStoreInstructions,OptimizeDynScopesPass,AddCallProtocolInstructions,EnsureTempsAssigned";
public static final String DEFAULT_INLINING_COMPILER_PASSES = "LocalOptimizationPass";

private final CompilerPass deadCodeEliminationPass = new DeadCodeElimination();
@@ -220,8 +221,14 @@ public TemporaryLocalVariable newTemporaryLocalVariable(int index) {
}

public Instr[] optimizeTemporaryVariablesIfEnabled(IRScope scope, Instr[] instrs) {
// Local opts don't move instrs across basic-block boundaries
// and are safe to run before the opt-tmp-vars pass.
// This ensures that local opts aren't affected by RAW hazards.
(new LocalOptimizationPass()).runLocalOptsOnInstrArray(scope, instrs);
// FIXME: Make this check ir.passes and not run if ir.passes is set and does not contain opttempvars.
return OptimizeTempVarsPass.optimizeTmpVars(scope, instrs);
// FIXME: LOP + Opttempvars cannot cope with y,d = d,y it propagates the intermediate temp var away
//return OptimizeTempVarsPass.optimizeTmpVars(scope, instrs);
return instrs;
}

/**
136 changes: 91 additions & 45 deletions core/src/main/java/org/jruby/ir/passes/LocalOptimizationPass.java
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ public String getLabel() {
@Override
public Object execute(IRScope s, Object... data) {
for (BasicBlock b: s.getCFG().getBasicBlocks()) {
runLocalOptsOnInstrList(s, b.getInstrs().listIterator(), false);
runLocalOptsOnBasicBlock(s, b);
}

// SSS FIXME: What is this about?
@@ -55,56 +55,101 @@ private static void recordSimplification(Variable res, Operand val, Map<Operand,
}
}

public static void runLocalOptsOnInstrList(IRScope s, ListIterator<Instr> instrs, boolean preCFG) {
// Reset value map if this instruction is the start/end of a basic block
Map<Operand,Operand> valueMap = new HashMap<Operand,Operand>();
Map<Variable,List<Variable>> simplificationMap = new HashMap<Variable,List<Variable>>();
while (instrs.hasNext()) {
Instr i = instrs.next();
Operation iop = i.getOperation();
if (preCFG && iop.startsBasicBlock()) {
valueMap = new HashMap<Operand,Operand>();
simplificationMap = new HashMap<Variable,List<Variable>>();
}
public static Instr optInstr(IRScope s, Instr instr, Map<Operand,Operand> valueMap, Map<Variable,List<Variable>> simplificationMap) {
// System.out.println("BEFORE: " + instr);

// Simplify instruction and record mapping between target variable and simplified value
// System.out.println("BEFORE: " + i);
Operand val = i.simplifyAndGetResult(s, valueMap);
// FIXME: This logic can be simplified based on the number of res != null checks only done if doesn't
Variable res = i instanceof ResultInstr ? ((ResultInstr) i).getResult() : null;
// Simplify instruction and record mapping between target variable and simplified value
Operand val = instr.simplifyAndGetResult(s, valueMap);

// System.out.println("AFTER: " + i + "; dst = " + res + "; val = " + val);
// Variable dst = (instr instanceof ResultInstr) ? ((ResultInstr) instr).getResult() : null;
// System.out.println("AFTER: " + instr + "; dst = " + dst + "; val = " + val);

if (res != null && val != null) {
if (!res.equals(val)) {
recordSimplification(res, val, valueMap, simplificationMap);
}
if (!(instr instanceof ResultInstr)) {
return instr;
}

if (!i.hasSideEffects()) {
if (i instanceof CopyInstr) {
if (res.equals(val) && i.canBeDeleted(s)) {
i.markDead();
instrs.remove();
}
} else {
instrs.set(new CopyInstr(res, val));
Instr newInstr = instr;
Variable res = ((ResultInstr) instr).getResult();
if (val == null) {
// If we didn't get a simplified value, remove existing simplifications
// for the result to get rid of RAW hazards!
valueMap.remove(res);
} else {
if (!res.equals(val)) {
recordSimplification(res, val, valueMap, simplificationMap);
}

if (!instr.hasSideEffects()) {
if (instr instanceof CopyInstr) {
if (res.equals(val) && instr.canBeDeleted(s)) {
System.out.println("DEAD: marking instr dead!!");
instr.markDead();
}
} else {
newInstr = new CopyInstr(res, val);
}
} else if (res != null && val == null) {
// If we didn't get a simplified value, remove any existing simplifications for the result
// to get rid of RAW hazards!
valueMap.remove(res);
}
}

// Purge all entries in valueMap that have 'res' as their simplified value to take care of RAW scenarios (because we aren't in SSA form yet!)
if (res != null && !res.equals(val)) {
List<Variable> simplifiedVars = simplificationMap.get(res);
if (simplifiedVars != null) {
for (Variable v: simplifiedVars) {
valueMap.remove(v);
}
simplificationMap.remove(res);
// Purge all entries in valueMap that have 'res' as their simplified value
// to take care of RAW scenarios (because we aren't in SSA form yet!)
if (!res.equals(val)) {
List<Variable> simplifiedVars = simplificationMap.get(res);
if (simplifiedVars != null) {
for (Variable v: simplifiedVars) {
valueMap.remove(v);
}
simplificationMap.remove(res);
}
}

return newInstr;
}

public static void runLocalOptsOnInstrArray(IRScope s, Instr[] instrs) {
// Reset value map if this instruction is the start/end of a basic block
Map<Operand,Operand> valueMap = new HashMap<>();
Map<Variable,List<Variable>> simplificationMap = new HashMap<>();
for (int i = 0; i < instrs.length; i++) {
Instr instr = instrs[i];
Instr newInstr = optInstr(s, instr, valueMap, simplificationMap);
if (newInstr != instr) {
instrs[i] = newInstr;
}

// If the call has been optimized away in the previous step, it is no longer a hard boundary for opts!
//
// Right now, calls are considered hard boundaries for optimization and
// information cannot be propagated across them!
//
// SSS FIXME: Rather than treat all calls with a broad brush, what we need
// is to capture different attributes about a call :
// - uses closures
// - known call target
// - can modify scope,
// - etc.
//
// This information is present in instruction flags on CallBase. Use it!
Operation iop = instr.getOperation();
if (iop.startsBasicBlock() || iop.endsBasicBlock() || (iop.isCall() && !instr.isDead())) {
valueMap = new HashMap<>();
simplificationMap = new HashMap<>();
}
}
}

public static void runLocalOptsOnBasicBlock(IRScope s, BasicBlock b) {
ListIterator<Instr> instrs = b.getInstrs().listIterator();
// Reset value map if this instruction is the start/end of a basic block
Map<Operand,Operand> valueMap = new HashMap<>();
Map<Variable,List<Variable>> simplificationMap = new HashMap<>();
while (instrs.hasNext()) {
Instr instr = instrs.next();
Instr newInstr = optInstr(s, instr, valueMap, simplificationMap);
if (newInstr.isDead()) {
instrs.remove();
} else if (newInstr != instr) {
instrs.set(newInstr);
}

// If the call has been optimized away in the previous step, it is no longer a hard boundary for opts!
@@ -120,9 +165,10 @@ public static void runLocalOptsOnInstrList(IRScope s, ListIterator<Instr> instrs
// - etc.
//
// This information is present in instruction flags on CallBase. Use it!
if ((preCFG && iop.endsBasicBlock()) || (iop.isCall() && !i.isDead())) {
valueMap = new HashMap<Operand,Operand>();
simplificationMap = new HashMap<Variable,List<Variable>>();
Operation iop = instr.getOperation();
if (iop.isCall() && !instr.isDead()) {
valueMap = new HashMap<>();
simplificationMap = new HashMap<>();
}
}
}
13 changes: 5 additions & 8 deletions core/src/main/java/org/jruby/lexer/yacc/RubyLexer.java
Original file line number Diff line number Diff line change
@@ -385,6 +385,7 @@ public final void reset() {
parenNest = 0;
braceNest = 0;
tokp = 0;
ruby_sourceline = src.getLineOffset() - 1;
last_cr_line = -1;

parser_prepare();
@@ -483,10 +484,6 @@ public int column() {
return tokp - lex_pbeg;
}

public int lineno() {
return ruby_sourceline + src.getLineOffset() - 1;
}

public boolean was_bol() {
return lex_p == lex_pbeg + 1;
}
@@ -588,16 +585,16 @@ public Object value() {
}

public ISourcePosition getPosition() {
if (tokline != null && lineno() == tokline.getLine()) return tokline;
return new SimpleSourcePosition(src.getFilename(), lineno());
if (tokline != null && ruby_sourceline == tokline.getLine()) return tokline;
return new SimpleSourcePosition(src.getFilename(), ruby_sourceline);
}

public ISourcePosition getPosition(ISourcePosition startPosition) {
if (startPosition != null) return startPosition;

if (tokline != null && lineno() == tokline.getLine()) return tokline;
if (tokline != null && ruby_sourceline == tokline.getLine()) return tokline;

return new SimpleSourcePosition(src.getFilename(), lineno());
return new SimpleSourcePosition(src.getFilename(), ruby_sourceline);
}

public String getCurrentLine() {
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/runtime/Signature.java
Original file line number Diff line number Diff line change
@@ -107,11 +107,11 @@ public static Signature from(Arity arity) {
case 0:
return arity.isFixed() ? Signature.NO_ARGUMENTS : Signature.OPTIONAL;
case 1:
return arity.isFixed() ? Signature.ONE_REQUIRED : Signature.ONE_ARGUMENT;
return arity.isFixed() ? Signature.ONE_ARGUMENT : Signature.ONE_REQUIRED;
case 2:
return arity.isFixed() ? Signature.TWO_REQUIRED : Signature.TWO_ARGUMENTS;
return arity.isFixed() ? Signature.TWO_ARGUMENTS : Signature.TWO_REQUIRED;
case 3:
return arity.isFixed() ? Signature.THREE_REQUIRED : Signature.THREE_ARGUMENTS;
return arity.isFixed() ? Signature.THREE_ARGUMENTS : Signature.THREE_REQUIRED;
}

throw new UnsupportedOperationException("We do not know enough about the arity to convert it to a signature");
Empty file.
2 changes: 0 additions & 2 deletions spec/tags/ruby/core/proc/equal_value_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/tags/ruby/core/proc/hash_tags.txt

This file was deleted.

Empty file.
1 change: 0 additions & 1 deletion spec/tags/ruby/core/proc/lambda_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/tags/ruby/core/proc/source_location_tags.txt

This file was deleted.

Empty file.
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/module/public_class_method_tags.txt

This file was deleted.

21 changes: 0 additions & 21 deletions spec/truffle/tags/core/string/unpack/a_tags.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,2 @@
fails:String#unpack with format 'A' calls #to_str to coerce the directives string
fails:String#unpack with format 'A' returns an empty string if the input is empty
fails:String#unpack with format 'A' returns empty strings for repeated formats if the input is empty
fails:String#unpack with format 'A' returns an empty string and does not decode any bytes when the count modifier is zero
fails:String#unpack with format 'A' implicitly has a count of one when no count is specified
fails:String#unpack with format 'A' decodes the number of bytes specified by the count modifier
fails:String#unpack with format 'A' decodes the number of bytes specified by the count modifier including whitespace bytes
fails:String#unpack with format 'A' decodes past whitespace bytes when passed the '*' modifier
fails:String#unpack with format 'A' decodes the number of bytes specified by the count modifier including NULL bytes
fails:String#unpack with format 'A' decodes past NULL bytes when passed the '*' modifier
fails:String#unpack with format 'A' removes trailing space and NULL bytes from the decoded string
fails:String#unpack with format 'A' does not remove whitespace other than space
fails:String#unpack with format 'a' calls #to_str to coerce the directives string
fails:String#unpack with format 'a' returns an empty string if the input is empty
fails:String#unpack with format 'a' returns empty strings for repeated formats if the input is empty
fails:String#unpack with format 'a' returns an empty string and does not decode any bytes when the count modifier is zero
fails:String#unpack with format 'a' implicitly has a count of one when no count is specified
fails:String#unpack with format 'a' decodes the number of bytes specified by the count modifier
fails:String#unpack with format 'a' decodes the number of bytes specified by the count modifier including whitespace bytes
fails:String#unpack with format 'a' decodes past whitespace bytes when passed the '*' modifier
fails:String#unpack with format 'a' decodes the number of bytes specified by the count modifier including NULL bytes
fails:String#unpack with format 'a' decodes past NULL bytes when passed the '*' modifier
fails:String#unpack with format 'a' does not remove trailing whitespace or NULL bytes from the decoded string
1 change: 0 additions & 1 deletion spec/truffle/tags/core/string/unpack/at_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:String#unpack with format '@' calls #to_str to coerce the directives string
fails:String#unpack with format '@' positions the read index one beyond the last readable byte in the String
20 changes: 0 additions & 20 deletions spec/truffle/tags/core/string/unpack/b_tags.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
fails:String#unpack with format 'B' calls #to_str to coerce the directives string
fails:String#unpack with format 'B' decodes one bit from each byte for each format character starting with the most significant bit
fails:String#unpack with format 'B' decodes only the number of bits in the string when passed a count
fails:String#unpack with format 'B' decodes multiple differing bit counts from a single string
fails:String#unpack with format 'B' decodes a directive with a '*' modifier after a directive with a count modifier
fails:String#unpack with format 'B' decodes a directive with a count modifier after a directive with a '*' modifier
fails:String#unpack with format 'B' decodes the number of bits specified by the count modifier
fails:String#unpack with format 'B' decodes all the bits when passed the '*' modifier
fails:String#unpack with format 'B' adds an empty string for each element requested beyond the end of the String
fails:String#unpack with format 'B' ignores NULL bytes between directives
fails:String#unpack with format 'B' ignores spaces between directives
fails:String#unpack with format 'b' calls #to_str to coerce the directives string
fails:String#unpack with format 'b' decodes one bit from each byte for each format character starting with the least significant bit
fails:String#unpack with format 'b' decodes only the number of bits in the string when passed a count
fails:String#unpack with format 'b' decodes multiple differing bit counts from a single string
fails:String#unpack with format 'b' decodes a directive with a '*' modifier after a directive with a count modifier
fails:String#unpack with format 'b' decodes a directive with a count modifier after a directive with a '*' modifier
fails:String#unpack with format 'b' decodes the number of bits specified by the count modifier
fails:String#unpack with format 'b' decodes all the bits when passed the '*' modifier
fails:String#unpack with format 'b' adds an empty string for each element requested beyond the end of the String
fails:String#unpack with format 'b' ignores NULL bytes between directives
fails:String#unpack with format 'b' ignores spaces between directives
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/string/unpack/c_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
fails:String#unpack with format 'C' calls #to_str to coerce the directives string
fails:String#unpack with format 'C' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'c' calls #to_str to coerce the directives string
fails:String#unpack with format 'c' adds nil for each element requested beyond the end of the String
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/string/unpack/d_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:String#unpack with format 'D' ignores whitespace in the format string
fails:String#unpack with format 'D' calls #to_str to coerce the directives string
fails:String#unpack with format 'D' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'd' ignores whitespace in the format string
fails:String#unpack with format 'd' calls #to_str to coerce the directives string
fails:String#unpack with format 'd' adds nil for each element requested beyond the end of the String
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/string/unpack/e_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:String#unpack with format 'E' ignores whitespace in the format string
fails:String#unpack with format 'E' calls #to_str to coerce the directives string
fails:String#unpack with format 'E' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'e' ignores whitespace in the format string
fails:String#unpack with format 'e' calls #to_str to coerce the directives string
fails:String#unpack with format 'e' adds nil for each element requested beyond the end of the String
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/string/unpack/f_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:String#unpack with format 'F' ignores whitespace in the format string
fails:String#unpack with format 'F' calls #to_str to coerce the directives string
fails:String#unpack with format 'F' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'f' ignores whitespace in the format string
fails:String#unpack with format 'f' calls #to_str to coerce the directives string
fails:String#unpack with format 'f' adds nil for each element requested beyond the end of the String
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/string/unpack/g_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:String#unpack with format 'G' ignores whitespace in the format string
fails:String#unpack with format 'G' calls #to_str to coerce the directives string
fails:String#unpack with format 'G' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'g' ignores whitespace in the format string
fails:String#unpack with format 'g' calls #to_str to coerce the directives string
fails:String#unpack with format 'g' adds nil for each element requested beyond the end of the String
20 changes: 0 additions & 20 deletions spec/truffle/tags/core/string/unpack/h_tags.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
fails:String#unpack with format 'H' calls #to_str to coerce the directives string
fails:String#unpack with format 'H' decodes one nibble from each byte for each format character starting with the most significant bit
fails:String#unpack with format 'H' decodes only the number of nibbles in the string when passed a count
fails:String#unpack with format 'H' decodes multiple differing nibble counts from a single string
fails:String#unpack with format 'H' decodes a directive with a '*' modifier after a directive with a count modifier
fails:String#unpack with format 'H' decodes a directive with a count modifier after a directive with a '*' modifier
fails:String#unpack with format 'H' decodes the number of nibbles specified by the count modifier
fails:String#unpack with format 'H' decodes all the nibbles when passed the '*' modifier
fails:String#unpack with format 'H' adds an empty string for each element requested beyond the end of the String
fails:String#unpack with format 'H' ignores NULL bytes between directives
fails:String#unpack with format 'H' ignores spaces between directives
fails:String#unpack with format 'h' calls #to_str to coerce the directives string
fails:String#unpack with format 'h' decodes one nibble from each byte for each format character starting with the least significant bit
fails:String#unpack with format 'h' decodes only the number of nibbles in the string when passed a count
fails:String#unpack with format 'h' decodes multiple differing nibble counts from a single string
fails:String#unpack with format 'h' decodes a directive with a '*' modifier after a directive with a count modifier
fails:String#unpack with format 'h' decodes a directive with a count modifier after a directive with a '*' modifier
fails:String#unpack with format 'h' decodes the number of nibbles specified by the count modifier
fails:String#unpack with format 'h' decodes all the nibbles when passed the '*' modifier
fails:String#unpack with format 'h' adds an empty string for each element requested beyond the end of the String
fails:String#unpack with format 'h' ignores NULL bytes between directives
fails:String#unpack with format 'h' ignores spaces between directives
20 changes: 0 additions & 20 deletions spec/truffle/tags/core/string/unpack/i_tags.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
fails:String#unpack with format 'I' with modifier '<' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '<' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '<' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '>' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '>' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '>' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '<' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '<' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '<' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '>' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '>' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '>' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' ignores whitespace in the format string
fails:String#unpack with format 'I' calls #to_str to coerce the directives string
fails:String#unpack with format 'I' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'I' with modifier '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' ignores whitespace in the format string
fails:String#unpack with format 'i' calls #to_str to coerce the directives string
fails:String#unpack with format 'i' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'i' with modifier '!' adds nil for each element requested beyond the end of the String
14 changes: 0 additions & 14 deletions spec/truffle/tags/core/string/unpack/l_tags.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
fails:String#unpack with format 'L' with modifier '<' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'L' with modifier '>' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'L' with modifier '<' and '_' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'L' with modifier '<' and '!' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'L' with modifier '>' and '_' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'L' with modifier '>' and '!' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'l' with modifier '<' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'l' with modifier '>' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'L' ignores whitespace in the format string
fails:String#unpack with format 'L' calls #to_str to coerce the directives string
fails:String#unpack with format 'L' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'l' ignores whitespace in the format string
fails:String#unpack with format 'l' calls #to_str to coerce the directives string
fails:String#unpack with format 'l' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'L' with modifier '_' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'L' with modifier '!' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'L' with modifier '<' and '_' decodes one int for a single format character
fails:String#unpack with format 'L' with modifier '<' and '_' decodes two ints for two format characters
fails:String#unpack with format 'L' with modifier '<' and '_' decodes the number of ints requested by the count modifier
20 changes: 0 additions & 20 deletions spec/truffle/tags/core/string/unpack/m_tags.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,2 @@
fails:String#unpack with format 'M' calls #to_str to coerce the directives string
fails:String#unpack with format 'M' decodes an empty string
fails:String#unpack with format 'M' decodes the complete string ignoring newlines when given a single directive
fails:String#unpack with format 'M' appends empty string to the array for directives exceeding the input size
fails:String#unpack with format 'M' ignores the count or '*' modifier and decodes the entire string
fails:String#unpack with format 'M' decodes the '=' character
fails:String#unpack with format 'M' decodes an embedded space character
fails:String#unpack with format 'M' decodes a space at the end of the pre-encoded string
fails:String#unpack with format 'M' decodes an embedded tab character
fails:String#unpack with format 'M' decodes a tab character at the end of the pre-encoded string
fails:String#unpack with format 'M' decodes an embedded newline
fails:String#unpack with format 'M' decodes pre-encoded byte values 33..60
fails:String#unpack with format 'M' decodes pre-encoded byte values 62..126
fails:String#unpack with format 'M' decodes pre-encoded byte values 0..31 except tab and newline
fails:String#unpack with format 'M' decodes pre-encoded byte values 127..255
fails:String#unpack with format 'm' calls #to_str to coerce the directives string
fails:String#unpack with format 'm' decodes an empty string
fails:String#unpack with format 'm' decodes the complete string ignoring newlines when given a single directive
fails:String#unpack with format 'm' ignores the count or '*' modifier and decodes the entire string
fails:String#unpack with format 'm' appends empty string to the array for directives exceeding the input size
fails:String#unpack with format 'm' decodes all pre-encoded ascii byte values
fails:String#unpack with format 'm' produces binary strings
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/string/unpack/n_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
fails:String#unpack with format 'N' ignores whitespace in the format string
fails:String#unpack with format 'N' calls #to_str to coerce the directives string
fails:String#unpack with format 'N' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'n' calls #to_str to coerce the directives string
fails:String#unpack with format 'n' adds nil for each element requested beyond the end of the String
7 changes: 0 additions & 7 deletions spec/truffle/tags/core/string/unpack/q_tags.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
fails:String#unpack with format 'Q' with modifier '<' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'Q' with modifier '>' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'Q' ignores whitespace in the format string
fails:String#unpack with format 'Q' calls #to_str to coerce the directives string
fails:String#unpack with format 'q' ignores whitespace in the format string
fails:String#unpack with format 'q' calls #to_str to coerce the directives string
fails:String#unpack with format 'Q' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'Q' decodes a long with most significant bit set as a positive number
fails:String#unpack with format 'q' adds nil for each element requested beyond the end of the String
18 changes: 0 additions & 18 deletions spec/truffle/tags/core/string/unpack/s_tags.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,2 @@
fails:String#unpack with format 'S' with modifier '<' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '<' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '<' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '>' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '>' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '>' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '<' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '<' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '<' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '>' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '>' and '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '>' and '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' calls #to_str to coerce the directives string
fails:String#unpack with format 'S' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'S' with modifier '!' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' calls #to_str to coerce the directives string
fails:String#unpack with format 's' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '_' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 's' with modifier '!' adds nil for each element requested beyond the end of the String
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/string/unpack/u_tags.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
fails:String#unpack with format 'U' calls #to_str to coerce the directives string
fails:String#unpack with format 'u' calls #to_str to coerce the directives string
fails:String#unpack with format 'u' decodes an empty string as an empty string
fails:String#unpack with format 'u' decodes the complete string ignoring newlines when given a single directive
fails:String#unpack with format 'u' appends empty string to the array for directives exceeding the input size
fails:String#unpack with format 'u' ignores the count or '*' modifier and decodes the entire string
fails:String#unpack with format 'u' decodes all ascii characters
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/string/unpack/v_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
fails:String#unpack with format 'V' ignores whitespace in the format string
fails:String#unpack with format 'V' calls #to_str to coerce the directives string
fails:String#unpack with format 'V' adds nil for each element requested beyond the end of the String
fails:String#unpack with format 'v' calls #to_str to coerce the directives string
fails:String#unpack with format 'v' adds nil for each element requested beyond the end of the String
1 change: 0 additions & 1 deletion spec/truffle/tags/core/string/unpack/w_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:String#unpack with directive 'w' calls #to_str to coerce the directives string
fails:String#unpack with directive 'w' decodes a BER-compressed integer
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/string/unpack/x_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
fails:String#unpack with format 'X' calls #to_str to coerce the directives string
fails:String#unpack with format 'x' calls #to_str to coerce the directives string
fails:String#unpack with format 'x' moves the read index to the end of the string when passed the '*' modifier
fails:String#unpack with format 'x' positions the read index one beyond the last readable byte in the String
9 changes: 0 additions & 9 deletions spec/truffle/tags/core/string/unpack/z_tags.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1 @@
fails:String#unpack with format 'Z' calls #to_str to coerce the directives string
fails:String#unpack with format 'Z' returns an empty string if the input is empty
fails:String#unpack with format 'Z' returns empty strings for repeated formats if the input is empty
fails:String#unpack with format 'Z' returns an empty string and does not decode any bytes when the count modifier is zero
fails:String#unpack with format 'Z' implicitly has a count of one when no count is specified
fails:String#unpack with format 'Z' decodes the number of bytes specified by the count modifier
fails:String#unpack with format 'Z' decodes the number of bytes specified by the count modifier including whitespace bytes
fails:String#unpack with format 'Z' decodes past whitespace bytes when passed the '*' modifier
fails:String#unpack with format 'Z' stops decoding at NULL bytes when passed the '*' modifier
fails:String#unpack with format 'Z' decodes the number of bytes specified by the count modifier and truncates the decoded string at the first NULL byte
3 changes: 1 addition & 2 deletions test/mri.index
Original file line number Diff line number Diff line change
@@ -66,8 +66,7 @@ ruby/test_parse.rb
ruby/test_path.rb
ruby/test_pipe.rb
ruby/test_primitive.rb
# TODO 2.1 parser
#ruby/test_proc.rb
ruby/test_proc.rb
# hangs when run with other tests
ruby/test_process.rb
ruby/test_rand.rb
4 changes: 1 addition & 3 deletions test/mri/excludes/TestProc.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
exclude :test_arity, "needs investigation"
exclude :test_attr_source_location, "needs investigation"
exclude :test_bound_parameters, "needs investigation"
exclude :test_curry, "needs investigation"
exclude :test_curry_from_knownbug, "needs investigation"
exclude :test_curry_optional_params, "needs investigation"
exclude :test_curry_ski_fib, "needs investigation"
exclude :test_curry_with_trace, "needs investigation"
exclude :test_dup_clone, "needs investigation"
exclude :test_parameters, "needs investigation"
@@ -15,4 +14,3 @@
exclude :test_proc_args_pos_opt_post_block, "needs investigation"
exclude :test_proc_lambda, "needs investigation"
exclude :test_safe, "needs investigation"
exclude :test_to_s, "needs investigation"
18 changes: 18 additions & 0 deletions test/mri/excludes_truffle/TestException.rb
Original file line number Diff line number Diff line change
@@ -10,3 +10,21 @@
exclude :test_exception_in_exception_equal, "needs investigation"
exclude :test_exception_in_name_error_to_str, "needs investigation"
exclude :test_exit_success_p, "this was exiting the test process"
exclude :"test_errat", "needs investigation"
exclude :"test_errinfo_encoding_in_debug", "needs investigation"
exclude :"test_inspect", "needs investigation"
exclude :"test_machine_stackoverflow", "needs investigation"
exclude :"test_machine_stackoverflow_by_define_method", "needs investigation"
exclude :"test_nomethoderror", "needs investigation"
exclude :"test_raise_with_cause", "needs investigation"
exclude :"test_rescue_single_argument", "needs investigation"
exclude :"test_rescue_splat_argument", "needs investigation"
exclude :"test_set_backtrace", "needs investigation"
exclude :"test_stackoverflow", "needs investigation"
exclude :"test_systemexit_new", "needs investigation"
exclude :"test_thread_signal_location", "needs investigation"
exclude :"test_to_s", "needs investigation"
exclude :"test_to_s_taintness_propagation", "needs investigation"
exclude :"test_too_many_args_in_eval", "needs investigation"
exclude :"test_type_error_message_encoding", "needs investigation"
exclude :"test_unknown_option", "needs investigation"
3 changes: 3 additions & 0 deletions test/mri/excludes_truffle/TestReadPartial.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exclude :test_closed_pipe, "needs investigation"
exclude :test_open_pipe, "needs investigation"
exclude :test_with_stdio, "needs investigation"
4 changes: 2 additions & 2 deletions test/mri_truffle.index
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ ruby/test_encoding.rb
ruby/test_enumerator.rb
# ruby/test_env.rb # TestEnv#test_aset = core:/core/rubinius/bootstrap/time.rb:28:in `now': internal implementation error - ClassCastException org.jruby.truffle.runtime.core.RubyNilClass cannot be cast to org.jruby.truffle.runtime.core.RubyString org.jruby.truffle.nodes.time.ReadTimeZoneNode.executeRubyString(ReadTimeZoneNode.java:36) (RubyTruffleError)
ruby/test_eval.rb
# ruby/test_exception.rb # Stack overflow error
ruby/test_exception.rb

# ruby/test_fiber.rb
ruby/test_file.rb
@@ -74,7 +74,7 @@ ruby/test_rand.rb
# ruby/test_range.rb # cannot load such file -- bigdecimal
ruby/test_rational.rb
ruby/test_rational2.rb
# ruby/test_readpartial.rb
ruby/test_readpartial.rb
# ruby/test_regexp.rb # NPE in BodyTranslator
ruby/test_require.rb
ruby/test_rubyoptions.rb
2 changes: 1 addition & 1 deletion tool/truffle-findbugs-exclude.xml
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@
<Bug pattern="FE_FLOATING_POINT_EQUALITY" />
</Match>
<Match>
<Class name="org.jruby.truffle.runtime.util.ArrayUtils" />
<Class name="org.jruby.truffle.runtime.array.ArrayUtils" />
<Bug pattern="FE_FLOATING_POINT_EQUALITY" />
</Match>
<Match>
6 changes: 0 additions & 6 deletions truffle/pom.rb
Original file line number Diff line number Diff line change
@@ -9,12 +9,6 @@
'tesla.dump.readonly' => true,

'jruby.basedir' => '${basedir}/..' )

repository( 'http://lafo.ssw.uni-linz.ac.at/nexus/content/repositories/releases/',
:id => 'truffle' ) do
releases 'true'
snapshots 'false'
end

jar 'org.jruby:jruby-core', '${project.version}', :scope => 'provided'

12 changes: 0 additions & 12 deletions truffle/pom.xml
Original file line number Diff line number Diff line change
@@ -33,18 +33,6 @@
<scope>provided</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>truffle</id>
<url>http://lafo.ssw.uni-linz.ac.at/nexus/content/repositories/releases/</url>
</repository>
</repositories>
<build>
<defaultGoal>package</defaultGoal>
<resources>
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyHash;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;

/**
* Read the rest of arguments after a certain point into an array.
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;

@CoreClass(name = "BasicObject")
public abstract class BasicObjectNodes {
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -18,6 +19,7 @@
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.BranchProfile;
import com.oracle.truffle.api.utilities.ConditionProfile;

import org.jruby.truffle.nodes.cast.BooleanCastNode;
import org.jruby.truffle.nodes.cast.BooleanCastNodeGen;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
@@ -40,36 +42,17 @@ public abstract class BignumNodes {

private static final HiddenKey VALUE_IDENTIFIER = new HiddenKey("value");
public static final Property VALUE_PROPERTY;
private static final DynamicObjectFactory BIGNUM_FACTORY;

static {
Shape.Allocator allocator = RubyBasicObject.LAYOUT.createAllocator();
VALUE_PROPERTY = Property.create(VALUE_IDENTIFIER, allocator.locationForType(BigInteger.class, EnumSet.of(LocationModifier.NonNull)), 0);
}

public static Allocator createBigumAllocator(Shape emptyShape) {
Shape shape = emptyShape.addProperty(VALUE_PROPERTY);
final DynamicObjectFactory factory = shape.createFactory();

return new Allocator() {
@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, Node currentNode) {
return new RubyBignum(rubyClass, factory.newInstance(BigInteger.ZERO));
}
};
VALUE_PROPERTY = Property.create(VALUE_IDENTIFIER, allocator.locationForType(BigInteger.class, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull)), 0);
Shape shape = RubyBasicObject.EMPTY_SHAPE.addProperty(VALUE_PROPERTY);
BIGNUM_FACTORY = shape.createFactory();
}

public static RubyBasicObject createRubyBignum(RubyClass rubyClass, BigInteger value) {
final RubyBasicObject bignum = rubyClass.getAllocator().allocate(rubyClass.getContext(), rubyClass, null);

try {
VALUE_PROPERTY.set(bignum.getDynamicObject(), value, bignum.getDynamicObject().getShape());
} catch (IncompatibleLocationException e) {
throw new UnsupportedOperationException();
} catch (FinalLocationException e) {
throw new UnsupportedOperationException();
}

return bignum;
return new RubyBignum(rubyClass, BIGNUM_FACTORY.newInstance(value));
}

public static BigInteger getBigIntegerValue(RubyBasicObject bignum) {
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.dsl.GeneratedBy;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.nodes.NodeUtil;

import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
@@ -22,6 +23,7 @@
import org.jruby.truffle.nodes.core.fixnum.FixnumLowerNode;
import org.jruby.truffle.nodes.methods.ExceptionTranslatingNode;
import org.jruby.truffle.nodes.objects.SelfNode;
import org.jruby.truffle.nodes.objects.SingletonClassNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.control.TruffleFatalException;
import org.jruby.truffle.runtime.core.CoreSourceSection;
@@ -30,41 +32,49 @@
import org.jruby.truffle.runtime.methods.Arity;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public abstract class CoreMethodNodeManager {
public class CoreMethodNodeManager {

private final RubyClass objectClass;
private final SingletonClassNode singletonClassNode;

public static void addCoreMethodNodes(RubyClass rubyObjectClass, List<? extends NodeFactory<? extends RubyNode>> nodeFactories) {
public CoreMethodNodeManager(RubyClass objectClass, SingletonClassNode singletonClassNode) {
this.objectClass = objectClass;
this.singletonClassNode = singletonClassNode;
}

public void addCoreMethodNodes(List<? extends NodeFactory<? extends RubyNode>> nodeFactories) {
for (NodeFactory<? extends RubyNode> nodeFactory : nodeFactories) {
final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
final Class<?> nodeClass = generatedBy.value();
final CoreClass classAnnotation = nodeClass.getEnclosingClass().getAnnotation(CoreClass.class);
final CoreMethod methodAnnotation = nodeClass.getAnnotation(CoreMethod.class);

if (methodAnnotation != null) {
final MethodDetails details = new MethodDetails(classAnnotation, methodAnnotation, nodeFactory);
addMethod(rubyObjectClass, details);
addCoreMethod(new MethodDetails(classAnnotation, methodAnnotation, nodeFactory));
}
}
}

private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDetails) {
assert rubyObjectClass != null;
assert methodDetails != null;
private RubyClass getSingletonClass(Object object) {
return singletonClassNode.executeSingletonClass(null, object);
}

final RubyContext context = rubyObjectClass.getContext();
private void addCoreMethod(MethodDetails methodDetails) {
final RubyContext context = objectClass.getContext();

RubyModule module;
String fullName = methodDetails.getClassAnnotation().name();

if (fullName.equals("main")) {
module = context.getCoreLibrary().getMainObject().getSingletonClass(null);
module = getSingletonClass(context.getCoreLibrary().getMainObject());
} else {
module = rubyObjectClass;
module = objectClass;

for (String moduleName : fullName.split("::")) {
final RubyConstant constant = ModuleOperations.lookupConstant(context, LexicalScope.NONE, module, moduleName);
@@ -106,9 +116,9 @@ private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDet

if (anno.isModuleFunction()) {
addMethod(module, rootNode, names, Visibility.PRIVATE);
addMethod(module.getSingletonClass(null), rootNode, names, Visibility.PUBLIC);
addMethod(getSingletonClass(module), rootNode, names, Visibility.PUBLIC);
} else if (anno.onSingleton()) {
addMethod(module.getSingletonClass(null), rootNode, names, visibility);
addMethod(getSingletonClass(module), rootNode, names, visibility);
} else {
addMethod(module, rootNode, names, visibility);
}
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.nodes.Node.Child;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
@@ -45,6 +44,7 @@
import org.jruby.truffle.pack.runtime.PackResult;
import org.jruby.truffle.pack.runtime.exceptions.*;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.backtrace.Activation;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
@@ -54,7 +54,7 @@
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.subsystems.FeatureManager;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;
import org.jruby.util.ByteList;

import java.io.BufferedReader;
@@ -341,12 +341,8 @@ public RubyArray callerLocations(int omit, int length) {
final Object[] locations = new Object[locationsCount];

for (int n = 0; n < locationsCount; n++) {
final RubyBasicObject location = threadBacktraceLocationClass.getAllocator().allocate(getContext(), threadBacktraceLocationClass, this);

// TODO CS 30-Apr-15 can't set set this in the allocator? How do we get it there?
ThreadBacktraceLocationNodes.setActivation(location, backtrace.getActivations().get(n));

locations[n] = location;
Activation activation = backtrace.getActivations().get(n);
locations[n] = ThreadBacktraceLocationNodes.createRubyThreadBacktraceLocation(threadBacktraceLocationClass, activation);
}

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), locations, locations.length);
139 changes: 67 additions & 72 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -39,7 +39,8 @@
import org.jruby.truffle.nodes.coerce.ToStrNodeGen;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.core.KernelNodes.BindingNode;
import org.jruby.truffle.nodes.core.ModuleNodesFactory.SetVisibilityNodeFactory;
import org.jruby.truffle.nodes.core.ModuleNodesFactory.SetMethodVisibilityNodeGen;
import org.jruby.truffle.nodes.core.ModuleNodesFactory.SetVisibilityNodeGen;
import org.jruby.truffle.nodes.dispatch.DispatchAction;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.MissingBehavior;
@@ -1181,7 +1182,7 @@ public abstract static class ModuleFunctionNode extends CoreMethodArrayArguments

public ModuleFunctionNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.MODULE_FUNCTION, null, null);
setVisibilityNode = SetVisibilityNodeGen.create(context, sourceSection, Visibility.MODULE_FUNCTION, null, null);
}

@Specialization
@@ -1251,7 +1252,7 @@ public abstract static class PublicNode extends CoreMethodArrayArgumentsNode {

public PublicNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.PUBLIC, null, null);
setVisibilityNode = SetVisibilityNodeGen.create(context, sourceSection, Visibility.PUBLIC, null, null);
}

public abstract RubyModule executePublic(VirtualFrame frame, RubyModule module, Object[] args);
@@ -1266,32 +1267,21 @@ public RubyModule doPublic(VirtualFrame frame, RubyModule module, Object[] names
@CoreMethod(names = "public_class_method", argumentsAsArray = true)
public abstract static class PublicClassMethodNode extends CoreMethodArrayArgumentsNode {

@Child SingletonClassNode singletonClassNode;
@Child SetMethodVisibilityNode setMethodVisibilityNode;

public PublicClassMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
this.singletonClassNode = SingletonClassNodeGen.create(context, sourceSection, null);
this.setMethodVisibilityNode = SetMethodVisibilityNodeGen.create(context, sourceSection, Visibility.PUBLIC, null, null);
}

@Specialization
public RubyModule publicClassMethod(RubyModule module, Object... args) {
CompilerDirectives.transferToInterpreter();

final RubyClass moduleSingleton = module.getSingletonClass(this);

for (Object arg : args) {
final String methodName;

if (arg instanceof RubySymbol) {
methodName = arg.toString();
} else {
throw new UnsupportedOperationException();
}
RubyModule publicClassMethod(VirtualFrame frame, RubyModule module, Object[] names) {
final RubyClass singletonClass = singletonClassNode.executeSingletonClass(frame, module);

final InternalMethod method = ModuleOperations.lookupMethod(moduleSingleton, methodName);

if (method == null) {
throw new RuntimeException("Couldn't find method " + arg.toString());
}

moduleSingleton.addMethod(this, method.withVisibility(Visibility.PUBLIC));
for (Object name : names) {
setMethodVisibilityNode.executeSetMethodVisibility(frame, singletonClass, name);
}

return module;
@@ -1305,7 +1295,7 @@ public abstract static class PrivateNode extends CoreMethodArrayArgumentsNode {

public PrivateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.PRIVATE, null, null);
setVisibilityNode = SetVisibilityNodeGen.create(context, sourceSection, Visibility.PRIVATE, null, null);
}

public abstract RubyModule executePrivate(VirtualFrame frame, RubyModule module, Object[] args);
@@ -1320,37 +1310,21 @@ public RubyModule doPrivate(VirtualFrame frame, RubyModule module, Object[] name
@CoreMethod(names = "private_class_method", argumentsAsArray = true)
public abstract static class PrivateClassMethodNode extends CoreMethodArrayArgumentsNode {

@Child SingletonClassNode singletonClassNode;
@Child SetMethodVisibilityNode setMethodVisibilityNode;

public PrivateClassMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
this.singletonClassNode = SingletonClassNodeGen.create(context, sourceSection, null);
this.setMethodVisibilityNode = SetMethodVisibilityNodeGen.create(context, sourceSection, Visibility.PRIVATE, null, null);
}

@Specialization
public RubyModule privateClassMethod(RubyModule module, Object... args) {
CompilerDirectives.transferToInterpreter();

final RubyClass moduleSingleton = module.getSingletonClass(this);
public RubyModule privateClassMethod(VirtualFrame frame, RubyModule module, Object[] names) {
final RubyClass singletonClass = singletonClassNode.executeSingletonClass(frame, module);

for (Object arg : args) {
final String methodName;

if (arg instanceof RubySymbol) {
methodName = arg.toString();
} else if (arg instanceof RubyString) {
methodName = ((RubyString) arg).toString();
} else {
// TODO BF 26-APR-2015 the message could be improved to match MRI
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError(" is not a symbol", this));
}

final InternalMethod method = ModuleOperations.lookupMethod(moduleSingleton, methodName);

if (method == null) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameErrorUndefinedMethod(methodName, module, this));
}

moduleSingleton.addMethod(this, method.withVisibility(Visibility.PRIVATE));
for (Object name : names) {
setMethodVisibilityNode.executeSetMethodVisibility(frame, singletonClass, name);
}

return module;
@@ -1640,7 +1614,7 @@ public abstract static class ProtectedNode extends CoreMethodArrayArgumentsNode

public ProtectedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.PROTECTED, null, null);
setVisibilityNode = SetVisibilityNodeGen.create(context, sourceSection, Visibility.PROTECTED, null, null);
}

@Specialization
@@ -1803,18 +1777,16 @@ public RubyString userHome(RubyString uname) {
}

@NodeChildren({ @NodeChild(value = "module"), @NodeChild(value = "names") })
public abstract static class SetVisibilityNode extends CoreMethodNode {

@Child SymbolOrToStrNode symbolOrToStrNode;
@Child private SingletonClassNode singletonClassNode;
public abstract static class SetVisibilityNode extends RubyNode {

private final Visibility visibility;

@Child SetMethodVisibilityNode setMethodVisibilityNode;

public SetVisibilityNode(RubyContext context, SourceSection sourceSection, Visibility visibility) {
super(context, sourceSection);
this.visibility = visibility;
this.symbolOrToStrNode = SymbolOrToStrNodeGen.create(context, sourceSection, null);
this.singletonClassNode = SingletonClassNodeGen.create(context, sourceSection, null);
this.setMethodVisibilityNode = SetMethodVisibilityNodeGen.create(context, sourceSection, visibility, null, null);
}

public abstract RubyModule executeSetVisibility(VirtualFrame frame, RubyModule module, Object[] arguments);
@@ -1827,15 +1799,50 @@ RubyModule setVisibility(VirtualFrame frame, RubyModule module, Object[] names)
setCurrentVisibility(visibility);
} else {
for (Object name : names) {
final String methodName = symbolOrToStrNode.executeToJavaString(frame, name);
setMethodVisibility(frame, module, methodName);
setMethodVisibilityNode.executeSetMethodVisibility(frame, module, name);
}
}

return module;
}

private void setMethodVisibility(VirtualFrame frame, RubyModule module, final String methodName) {
private void setCurrentVisibility(Visibility visibility) {
CompilerDirectives.transferToInterpreter();

final Frame callerFrame = Truffle.getRuntime().getCallerFrame().getFrame(FrameInstance.FrameAccess.READ_WRITE, false);

assert callerFrame != null;
assert callerFrame.getFrameDescriptor() != null;

final FrameSlot visibilitySlot = callerFrame.getFrameDescriptor().findOrAddFrameSlot(
RubyModule.VISIBILITY_FRAME_SLOT_ID, "visibility for frame", FrameSlotKind.Object);

callerFrame.setObject(visibilitySlot, visibility);
}

}

@NodeChildren({ @NodeChild(value = "module"), @NodeChild(value = "name") })
public abstract static class SetMethodVisibilityNode extends RubyNode {

private final Visibility visibility;

@Child SingletonClassNode singletonClassNode;
@Child SymbolOrToStrNode symbolOrToStrNode;

public SetMethodVisibilityNode(RubyContext context, SourceSection sourceSection, Visibility visibility) {
super(context, sourceSection);
this.visibility = visibility;
this.symbolOrToStrNode = SymbolOrToStrNodeGen.create(context, sourceSection, null);
this.singletonClassNode = SingletonClassNodeGen.create(context, sourceSection, null);
}

public abstract RubyModule executeSetMethodVisibility(VirtualFrame frame, RubyModule module, Object name);

@Specialization
RubyModule setMethodVisibility(VirtualFrame frame, RubyModule module, Object name) {
final String methodName = symbolOrToStrNode.executeToJavaString(frame, name);

final InternalMethod method = module.deepMethodSearch(methodName);

if (method == null) {
@@ -1855,20 +1862,8 @@ private void setMethodVisibility(VirtualFrame frame, RubyModule module, final St
} else {
module.addMethod(this, method.withVisibility(visibility));
}
}

private void setCurrentVisibility(Visibility visibility) {
CompilerDirectives.transferToInterpreter();

final Frame callerFrame = Truffle.getRuntime().getCallerFrame().getFrame(FrameInstance.FrameAccess.READ_WRITE, false);

assert callerFrame != null;
assert callerFrame.getFrameDescriptor() != null;

final FrameSlot visibilitySlot = callerFrame.getFrameDescriptor().findOrAddFrameSlot(
RubyModule.VISIBILITY_FRAME_SLOT_ID, "visibility for frame", FrameSlotKind.Object);

callerFrame.setObject(visibilitySlot, visibility);
return module;
}

}
19 changes: 9 additions & 10 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/MutexNodes.java
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.*;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.objects.Allocator;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -30,22 +31,20 @@ public abstract class MutexNodes {

private static final HiddenKey LOCK_IDENTIFIER = new HiddenKey("lock");
private static final Property LOCK_PROPERTY;
private static final DynamicObjectFactory MUTEX_FACTORY;

static {
Shape.Allocator allocator = RubyBasicObject.LAYOUT.createAllocator();
LOCK_PROPERTY = Property.create(LOCK_IDENTIFIER, allocator.locationForType(ReentrantLock.class, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull)), 0);
Shape shape = RubyBasicObject.EMPTY_SHAPE.addProperty(LOCK_PROPERTY);
MUTEX_FACTORY = shape.createFactory();
}

public static Allocator createMutexAllocator(Shape emptyShape) {
Shape shape = emptyShape.addProperty(LOCK_PROPERTY);
final DynamicObjectFactory factory = shape.createFactory();

return new Allocator() {
@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, Node currentNode) {
return new RubyBasicObject(rubyClass, factory.newInstance(new ReentrantLock()));
}
};
public static class MutexAllocator implements Allocator {
@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, Node currentNode) {
return new RubyBasicObject(rubyClass, MUTEX_FACTORY.newInstance(new ReentrantLock()));
}
}

protected static ReentrantLock getLock(RubyBasicObject mutex) {
Original file line number Diff line number Diff line change
@@ -2159,7 +2159,7 @@ public UnpackNode(RubyContext context, SourceSection sourceSection) {
@Specialization
public RubyArray unpack(RubyString string, RubyString format) {
final org.jruby.RubyArray jrubyArray = Pack.unpack(getContext().getRuntime(), string.getByteList(), format.getByteList());
return RubyArray.fromObjects(getContext().getCoreLibrary().getArrayClass(), jrubyArray.toArray());
return getContext().toTruffle(jrubyArray);
}

}
Original file line number Diff line number Diff line change
@@ -10,18 +10,22 @@
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.*;
import com.oracle.truffle.api.source.NullSourceSection;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.objects.Allocator;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.backtrace.Activation;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyBignum;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyString;

import java.math.BigInteger;
import java.util.EnumSet;
import java.util.concurrent.locks.ReentrantLock;

@@ -30,32 +34,17 @@ public class ThreadBacktraceLocationNodes {

private static final HiddenKey ACTIVATION_IDENTIFIER = new HiddenKey("activation");
private static final Property ACTIVATION_PROPERTY;
private static final DynamicObjectFactory THREAD_BACKTRACE_LOCATION_FACTORY;

static {
Shape.Allocator allocator = RubyBasicObject.LAYOUT.createAllocator();
ACTIVATION_PROPERTY = Property.create(ACTIVATION_IDENTIFIER, allocator.locationForType(Activation.class, EnumSet.of(LocationModifier.NonNull)), 0);
}

public static Allocator createThreadBacktraceLocationAllocator(Shape emptyShape) {
final Shape shape = emptyShape.addProperty(ACTIVATION_PROPERTY);
final DynamicObjectFactory factory = shape.createFactory();

return new Allocator() {
@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, Node currentNode) {
return new RubyBasicObject(rubyClass, factory.newInstance(new ReentrantLock()));
}
};
ACTIVATION_PROPERTY = Property.create(ACTIVATION_IDENTIFIER, allocator.locationForType(Activation.class, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull)), 0);
final Shape shape = RubyBasicObject.EMPTY_SHAPE.addProperty(ACTIVATION_PROPERTY);
THREAD_BACKTRACE_LOCATION_FACTORY = shape.createFactory();
}

public static void setActivation(RubyBasicObject threadBacktraceLocation, Activation activation) {
assert threadBacktraceLocation.getDynamicObject().getShape().hasProperty(ACTIVATION_IDENTIFIER);

try {
ACTIVATION_PROPERTY.set(threadBacktraceLocation.getDynamicObject(), activation, threadBacktraceLocation.getDynamicObject().getShape());
} catch (IncompatibleLocationException | FinalLocationException e) {
throw new UnsupportedOperationException();
}
public static RubyBasicObject createRubyThreadBacktraceLocation(RubyClass rubyClass, Activation activation) {
return new RubyBasicObject(rubyClass, THREAD_BACKTRACE_LOCATION_FACTORY.newInstance(activation));
}

protected static Activation getActivation(RubyBasicObject threadBacktraceLocation) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/*
* 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.array;

import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.array.ArrayMirror;
import org.jruby.truffle.runtime.array.ArrayUtils;
import org.jruby.truffle.runtime.core.RubyArray;

import java.util.Arrays;

@NodeChildren({
@NodeChild("array"),
@NodeChild("otherSize"),
@NodeChild("other"),
})
@ImportStatic(ArrayGuards.class)
public abstract class AppendManyNode extends RubyNode {

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

public abstract RubyArray executeAppendMany(RubyArray array, int otherSize, Object other);

// Append into an empty array

// TODO CS 12-May-15 differentiate between null and empty but possibly having enough space

@Specialization(guards = "isEmpty(array)")
public RubyArray appendManyEmpty(RubyArray array, int otherSize, int[] other) {
array.setStore(Arrays.copyOf(other, otherSize), otherSize);
return array;
}

@Specialization(guards = "isEmpty(array)")
public RubyArray appendManyEmpty(RubyArray array, int otherSize, long[] other) {
array.setStore(Arrays.copyOf(other, otherSize), otherSize);
return array;
}

@Specialization(guards = "isEmpty(array)")
public RubyArray appendManyEmpty(RubyArray array, int otherSize, double[] other) {
array.setStore(Arrays.copyOf(other, otherSize), otherSize);
return array;
}

@Specialization(guards = "isEmpty(array)")
public RubyArray appendManyEmpty(RubyArray array, int otherSize, Object[] other) {
array.setStore(Arrays.copyOf(other, otherSize), otherSize);
return array;
}

// Append of the correct type

@Specialization(guards = "isIntegerFixnum(array)")
public RubyArray appendManySameType(RubyArray array, int otherSize, int[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManySameTypeGeneric(array, ArrayMirror.reflect((int[]) array.getStore()),
otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

@Specialization(guards = "isLongFixnum(array)")
public RubyArray appendManySameType(RubyArray array, int otherSize, long[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManySameTypeGeneric(array, ArrayMirror.reflect((long[]) array.getStore()),
otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

@Specialization(guards = "isFloat(array)")
public RubyArray appendManySameType(RubyArray array, int otherSize, double[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManySameTypeGeneric(array, ArrayMirror.reflect((double[]) array.getStore()),
otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

@Specialization(guards = "isObject(array)")
public RubyArray appendManySameType(RubyArray array, int otherSize, Object[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManySameTypeGeneric(array, ArrayMirror.reflect((Object[]) array.getStore()),
otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

public void appendManySameTypeGeneric(RubyArray array, ArrayMirror storeMirror,
int otherSize, ArrayMirror otherStoreMirror,
ConditionProfile extendProfile) {
final int oldSize = array.getSize();
final int newSize = oldSize + otherSize;

final ArrayMirror newStoreMirror;

if (extendProfile.profile(newSize > storeMirror.getLength())) {
newStoreMirror = storeMirror.copyArrayAndMirror(ArrayUtils.capacity(storeMirror.getLength(), newSize));
} else {
newStoreMirror = storeMirror;
}

otherStoreMirror.copyTo(newStoreMirror, 0, oldSize, otherSize);
array.setStore(newStoreMirror.getArray(), newSize);
}

// Append something else into an Object[]

@Specialization(guards = "isObject(array)")
public RubyArray appendManyBoxIntoObject(RubyArray array, int otherSize, int[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManyBoxIntoObjectGeneric(array, otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

@Specialization(guards = "isObject(array)")
public RubyArray appendManyBoxIntoObject(RubyArray array, int otherSize, long[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManyBoxIntoObjectGeneric(array, otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

@Specialization(guards = "isObject(array)")
public RubyArray appendManyBoxIntoObject(RubyArray array, int otherSize, double[] other,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendManyBoxIntoObjectGeneric(array, otherSize, ArrayMirror.reflect(other), extendProfile);
return array;
}

public void appendManyBoxIntoObjectGeneric(RubyArray array, int otherSize, ArrayMirror otherStoreMirror,
ConditionProfile extendProfile) {
final int oldSize = array.getSize();
final int newSize = oldSize + otherSize;

final Object[] oldStore = (Object[]) array.getStore();
final Object[] newStore;

if (extendProfile.profile(newSize > oldStore.length)) {
newStore = ArrayUtils.copyOf(oldStore, ArrayUtils.capacity(oldStore.length, newSize));
} else {
newStore = oldStore;
}

otherStoreMirror.copyTo(newStore, 0, oldSize, otherSize);
array.setStore(newStore, newSize);
}

// Append forcing a generalization from int[] to long[]

@Specialization(guards = "isIntegerFixnum(array)")
public RubyArray appendManyLongIntoInteger(RubyArray array, int otherSize, long[] other) {
final int oldSize = array.getSize();
final int newSize = oldSize + otherSize;

final int[] oldStore = (int[]) array.getStore();
long[] newStore = ArrayUtils.longCopyOf(oldStore, ArrayUtils.capacity(oldStore.length, newSize));

System.arraycopy(other, 0, newStore, oldSize, otherSize);

array.setStore(newStore, newSize);
return array;
}

// Append forcing a generalization to Object[]

@Specialization(guards = "isIntegerFixnum(array)")
public RubyArray appendManyGeneralizeIntegerDouble(RubyArray array, int otherSize, double[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((int[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

@Specialization(guards = "isIntegerFixnum(array)")
public RubyArray appendManyGeneralizeIntegerDouble(RubyArray array, int otherSize, Object[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((int[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

@Specialization(guards = "isLongFixnum(array)")
public RubyArray appendManyGeneralizeLongDouble(RubyArray array, int otherSize, double[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((long[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

@Specialization(guards = "isLongFixnum(array)")
public RubyArray appendManyGeneralizeLongDouble(RubyArray array, int otherSize, Object[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((long[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

@Specialization(guards = "isFloat(array)")
public RubyArray appendManyGeneralizeDoubleInteger(RubyArray array, int otherSize, int[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((double[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

@Specialization(guards = "isFloat(array)")
public RubyArray appendManyGeneralizeDoubleLong(RubyArray array, int otherSize, long[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((double[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

@Specialization(guards = "isFloat(array)")
public RubyArray appendManyGeneralizeDoubleObject(RubyArray array, int otherSize, Object[] other) {
appendManyGeneralizeGeneric(array, ArrayMirror.reflect((double[]) array.getStore()),
otherSize, ArrayMirror.reflect(other));
return array;
}

public void appendManyGeneralizeGeneric(RubyArray array, ArrayMirror storeMirror, int otherSize, ArrayMirror otherStoreMirror) {
final int oldSize = array.getSize();
final int newSize = oldSize + otherSize;
Object[] newStore = storeMirror.getBoxedCopy(ArrayUtils.capacity(storeMirror.getLength(), newSize));
otherStoreMirror.copyTo(newStore, 0, oldSize, otherSize);
array.setStore(newStore, newSize);
}

}
Original file line number Diff line number Diff line change
@@ -14,10 +14,9 @@
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.array.ArrayMirror;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.util.ArrayUtils;

import java.util.Arrays;
import org.jruby.truffle.runtime.array.ArrayUtils;

@NodeChildren({
@NodeChild("array"),
@@ -32,103 +31,84 @@ public AppendOneNode(RubyContext context, SourceSection sourceSection) {

public abstract RubyArray executeAppendOne(RubyArray array, Object value);

// Append into an array with null storage
// Append into an empty array

// TODO CS 12-May-15 differentiate between null and empty but possibly having enough space

@Specialization(guards = "isNull(array)")
public RubyArray appendNull(RubyArray array, int value) {
@Specialization(guards = "isEmpty(array)")
public RubyArray appendOneEmpty(RubyArray array, int value) {
array.setStore(new int[]{value}, 1);
return array;
}

@Specialization(guards = "isNull(array)")
public RubyArray appendNull(RubyArray array, long value) {
@Specialization(guards = "isEmpty(array)")
public RubyArray appendOneEmpty(RubyArray array, long value) {
array.setStore(new long[]{value}, 1);
return array;
}

@Specialization(guards = "isNull(array)")
public RubyArray appendNull(RubyArray array, Object value) {
array.setStore(new Object[]{value}, 1);
return array;
}

// Append into empty, but non-null storage; we would be better off reusing any existing space, but don't worry for now

@Specialization(guards = {"!isNull(array)", "isEmpty(array)"})
public RubyArray appendEmpty(RubyArray array, int value) {
array.setStore(new int[]{value}, 1);
return array;
}

@Specialization(guards = {"!isNull(array)", "isEmpty(array)"})
public RubyArray appendEmpty(RubyArray array, long value) {
array.setStore(new long[]{value}, 1);
@Specialization(guards = "isEmpty(array)")
public RubyArray appendOneEmpty(RubyArray array, double value) {
array.setStore(new double[]{value}, 1);
return array;
}

@Specialization(guards ={"!isNull(array)", "isEmpty(array)"})
public RubyArray appendEmpty(RubyArray array, Object value) {
@Specialization(guards = "isEmpty(array)")
public RubyArray appendOneEmpty(RubyArray array, Object value) {
array.setStore(new Object[]{value}, 1);
return array;
}

// Append of the correct type

@Specialization(guards = "isIntegerFixnum(array)")
public RubyArray appendInteger(RubyArray array, int value,
public RubyArray appendOneSameType(RubyArray array, int value,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
final int oldSize = array.getSize();
final int newSize = oldSize + 1;

int[] store = (int[]) array.getStore();

if (extendProfile.profile(newSize > store.length)) {
store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, newSize));
}

store[oldSize] = value;
array.setStore(store, newSize);
appendOneSameTypeGeneric(array, ArrayMirror.reflect((int[]) array.getStore()), value, extendProfile);
return array;
}

@Specialization(guards = "isLongFixnum(array)")
public RubyArray appendLong(RubyArray array, long value,
public RubyArray appendOneSameType(RubyArray array, long value,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
final int oldSize = array.getSize();
final int newSize = oldSize + 1;

long[] store = (long[]) array.getStore();

if (extendProfile.profile(newSize > store.length)) {
store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, newSize));
}
appendOneSameTypeGeneric(array, ArrayMirror.reflect((long[]) array.getStore()), value, extendProfile);
return array;
}

store[oldSize] = value;
array.setStore(store, newSize);
@Specialization(guards = "isFloat(array)")
public RubyArray appendOneSameType(RubyArray array, double value,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendOneSameTypeGeneric(array, ArrayMirror.reflect((double[]) array.getStore()), value, extendProfile);
return array;
}

@Specialization(guards = "isObject(array)")
public RubyArray appendObject(RubyArray array, Object value,
public RubyArray appendOneSameType(RubyArray array, Object value,
@Cached("createBinaryProfile()") ConditionProfile extendProfile) {
appendOneSameTypeGeneric(array, ArrayMirror.reflect((Object[]) array.getStore()), value, extendProfile);
return array;
}

public void appendOneSameTypeGeneric(RubyArray array, ArrayMirror storeMirror, Object value, ConditionProfile extendProfile) {
final int oldSize = array.getSize();
final int newSize = oldSize + 1;

Object[] store = (Object[]) array.getStore();
final ArrayMirror newStoreMirror;

if (extendProfile.profile(newSize > store.length)) {
store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, newSize));
if (extendProfile.profile(newSize > storeMirror.getLength())) {
newStoreMirror = storeMirror.copyArrayAndMirror(ArrayUtils.capacity(storeMirror.getLength(), newSize));
} else {
newStoreMirror = storeMirror;
}

store[oldSize] = value;
array.setStore(store, newSize);
return array;
newStoreMirror.set(oldSize, value);
array.setStore(newStoreMirror.getArray(), newSize);
}

// Append forcing a generalization
// Append forcing a generalization from int[] to long[]

@Specialization(guards = "isIntegerFixnum(array)")
public RubyArray appendLongIntoInteger(RubyArray array, long value) {
public RubyArray appendOneLongIntoInteger(RubyArray array, long value) {
final int oldSize = array.getSize();
final int newSize = oldSize + 1;

@@ -140,30 +120,32 @@ public RubyArray appendLongIntoInteger(RubyArray array, long value) {
return array;
}

// Append forcing a generalization to Object[]

@Specialization(guards = {"isIntegerFixnum(array)", "!isInteger(value)", "!isLong(value)"})
public RubyArray appendObjectIntoInteger(RubyArray array, Object value) {
final int oldSize = array.getSize();
final int newSize = oldSize + 1;
public RubyArray appendOneGeneralizeInteger(RubyArray array, Object value) {
appendOneGeneralizeGeneric(array, ArrayMirror.reflect((int[]) array.getStore()), value);
return array;
}

final int[] oldStore = (int[]) array.getStore();
Object[] newStore = ArrayUtils.box(oldStore, ArrayUtils.capacity(oldStore.length, newSize) - oldStore.length);
@Specialization(guards = {"isLongFixnum(array)", "!isInteger(value)", "!isLong(value)"})
public RubyArray appendOneGeneralizeLong(RubyArray array, Object value) {
appendOneGeneralizeGeneric(array, ArrayMirror.reflect((long[]) array.getStore()), value);
return array;
}

newStore[oldSize] = value;
array.setStore(newStore, newSize);
@Specialization(guards = {"isFloat(array)", "!isDouble(value)"})
public RubyArray appendOneGeneralizeDouble(RubyArray array, Object value) {
appendOneGeneralizeGeneric(array, ArrayMirror.reflect((double[]) array.getStore()), value);
return array;
}

@Specialization(guards = {"isLongFixnum(array)", "!isInteger(value)", "!isLong(value)"})
public RubyArray appendObjectIntoLong(RubyArray array, Object value) {
public void appendOneGeneralizeGeneric(RubyArray array, ArrayMirror storeMirror, Object value) {
final int oldSize = array.getSize();
final int newSize = oldSize + 1;

final long[] oldStore = (long[]) array.getStore();
Object[] newStore = ArrayUtils.box(oldStore, ArrayUtils.capacity(oldStore.length, newSize) - oldStore.length);

Object[] newStore = storeMirror.getBoxedCopy(ArrayUtils.capacity(storeMirror.getLength(), newSize));
newStore[oldSize] = value;
array.setStore(newStore, newSize);
return array;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
import com.oracle.truffle.api.nodes.Node;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;
import org.jruby.util.cli.Options;

import java.util.Arrays;
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;

@NodeChildren({@NodeChild(value = "array", type = RubyNode.class)})
@ImportStatic(ArrayGuards.class)
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.truffle.runtime.array.ArrayUtils;

@NodeChildren({@NodeChild(value = "array", type = RubyNode.class)})
@ImportStatic(ArrayGuards.class)
Original file line number Diff line number Diff line change
@@ -131,55 +131,28 @@ private RubyArray makeGeneric(VirtualFrame frame,

public static class IntegerFixnumArrayLiteralNode extends ArrayLiteralNode {

private final ArrayAllocationSite arrayAllocationSite = new ArrayAllocationSite();

public IntegerFixnumArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) {
super(context, sourceSection, values);
}

@ExplodeLoop
@Override
public RubyArray executeRubyArray(VirtualFrame frame) {
if (arrayAllocationSite.hasConvertedIntToLong()) {
final long[] executedValues = new long[values.length];

for (int n = 0; n < values.length; n++) {
try {
executedValues[n] = values[n].executeLong(frame);
} catch (UnexpectedResultException e) {
return makeGeneric(frame, executedValues, n);
}
}
final int[] executedValues = new int[values.length];

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), arrayAllocationSite, executedValues, values.length);
} else {
final int[] executedValues = new int[values.length];

for (int n = 0; n < values.length; n++) {
try {
executedValues[n] = values[n].executeInteger(frame);
} catch (UnexpectedResultException e) {
return makeGeneric(frame, executedValues, n);
}
for (int n = 0; n < values.length; n++) {
try {
executedValues[n] = values[n].executeInteger(frame);
} catch (UnexpectedResultException e) {
return makeGeneric(frame, executedValues, n);
}

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), arrayAllocationSite, executedValues, values.length);
}
}

private RubyArray makeGeneric(VirtualFrame frame,
final int[] executedValues, int n) {
final Object[] executedObjects = new Object[n];

for (int i = 0; i < n; i++) {
executedObjects[i] = executedValues[i];
}

return makeGeneric(frame, executedObjects);
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), executedValues, values.length);
}

private RubyArray makeGeneric(VirtualFrame frame,
final long[] executedValues, int n) {
final int[] executedValues, int n) {
final Object[] executedObjects = new Object[n];

for (int i = 0; i < n; i++) {
Loading

0 comments on commit 424e351

Please sign in to comment.