Skip to content

Commit

Permalink
Merge branch 'master' into truffle-head
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed May 12, 2015
2 parents c0d2d92 + b89e4a8 commit 424e351
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/org/jruby/RubyMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 16 additions & 10 deletions core/src/main/java/org/jruby/RubyProc.java
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down
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
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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++;
}
Expand All @@ -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!
}
}

Expand All @@ -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() {
Expand Down
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
Expand Up @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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;
}

/**
Expand Down
Loading

0 comments on commit 424e351

Please sign in to comment.