Skip to content
Permalink
Browse files
Introduce new Signature class to represent argument layout.
  • Loading branch information
headius committed Jan 13, 2015
1 parent ac8bf5e commit b6d996db3101289c9f8c432790e773151e4e1a08
Showing 10 changed files with 171 additions and 42 deletions.
@@ -21,6 +21,7 @@
import org.jruby.runtime.CallType;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.RubyEvent;
import org.jruby.runtime.Signature;
import org.jruby.util.ByteList;
import org.jruby.util.KeyValuePair;

@@ -483,7 +484,7 @@ public Operand build(Node node, IRScope s) {
}

public Operand buildLambda(LambdaNode node, IRScope s) {
IRClosure closure = new IRClosure(manager, s, node.getPosition().getLine(), node.getScope(), Arity.procArityOf(node.getArgs()), node.getArgumentType());
IRClosure closure = new IRClosure(manager, s, node.getPosition().getLine(), node.getScope(), Signature.from(node), node.getArgumentType());

// Create a new nested builder to ensure this gets its own IR builder state
// like the ensure block stack
@@ -2347,7 +2348,7 @@ public Operand buildFor(ForNode forNode, IRScope s) {

public Operand buildForIter(final ForNode forNode, IRScope s) {
// Create a new closure context
IRClosure closure = new IRFor(manager, s, forNode.getPosition().getLine(), forNode.getScope(), Arity.procArityOf(forNode.getVarNode()), forNode.getArgumentType());
IRClosure closure = new IRFor(manager, s, forNode.getPosition().getLine(), forNode.getScope(), Signature.from(forNode), forNode.getArgumentType());

// Create a new nested builder to ensure this gets its own IR builder state
// like the ensure block stack
@@ -2498,7 +2499,7 @@ public Operand buildInstVar(InstVarNode node, IRScope s) {
}

public Operand buildIter(final IterNode iterNode, IRScope s) {
IRClosure closure = new IRClosure(manager, s, iterNode.getPosition().getLine(), iterNode.getScope(), Arity.procArityOf(iterNode.getVarNode()), iterNode.getArgumentType());
IRClosure closure = new IRClosure(manager, s, iterNode.getPosition().getLine(), iterNode.getScope(), Signature.from(iterNode), iterNode.getArgumentType());

// Create a new nested builder to ensure this gets its own IR builder state
// like the ensure block stack
@@ -2926,7 +2927,7 @@ public Operand buildPostExe(PostExeNode postExeNode, IRScope s) {
IRScope topLevel = s.getTopLevelScope();
IRScope nearestLVarScope = s.getNearestTopLocalVariableScope();

IRClosure endClosure = new IRClosure(manager, s, postExeNode.getPosition().getLine(), nearestLVarScope.getStaticScope(), Arity.procArityOf(postExeNode.getVarNode()), postExeNode.getArgumentType(), "_END_", true);
IRClosure endClosure = new IRClosure(manager, s, postExeNode.getPosition().getLine(), nearestLVarScope.getStaticScope(), Signature.from(postExeNode), postExeNode.getArgumentType(), "_END_", true);
// Create a new nested builder to ensure this gets its own IR builder state
// like the ensure block stack
IRBuilder closureBuilder = newIRBuilder(manager);
@@ -2948,7 +2949,7 @@ public Operand buildPostExe(PostExeNode postExeNode, IRScope s) {
}

public Operand buildPreExe(PreExeNode preExeNode, IRScope s) {
IRClosure beginClosure = new IRFor(manager, s, preExeNode.getPosition().getLine(), s.getTopLevelScope().getStaticScope(), Arity.procArityOf(preExeNode.getVarNode()), preExeNode.getArgumentType(), "_BEGIN_");
IRClosure beginClosure = new IRFor(manager, s, preExeNode.getPosition().getLine(), s.getTopLevelScope().getStaticScope(), Signature.from(preExeNode), preExeNode.getArgumentType(), "_BEGIN_");
// Create a new nested builder to ensure this gets its own IR builder state
// like the ensure block stack
IRBuilder closureBuilder = newIRBuilder(manager);
@@ -11,7 +11,9 @@
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Arity;
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.IRBlockBody;
import org.jruby.runtime.InterpretedIRBlockBody;
import org.jruby.runtime.Signature;
import org.jruby.util.KeyValuePair;
import org.objectweb.asm.Handle;

@@ -38,11 +40,11 @@ public class IRClosure extends IRScope {
/** The parameter names, for Proc#parameters */
private String[] parameterList;

private Arity arity;
private Signature signature;
private int argumentType;

/** Added for interp/JIT purposes */
private BlockBody body;
private IRBlockBody body;

/** Added for JIT purposes */
private Handle handle;
@@ -79,33 +81,33 @@ protected IRClosure(IRClosure c, IRScope lexicalParent, int closureId, String fu
if (getManager().isDryRun()) {
this.body = null;
} else {
this.body = new InterpretedIRBlockBody(this, c.body.arity());
this.body = new InterpretedIRBlockBody(this, c.body.getSignature());
}
this.blockArgs = new ArrayList<>();
this.keywordArgs = new ArrayList<>();
this.arity = c.arity;
this.signature = c.signature;
}

public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Arity arity, int argumentType) {
this(manager, lexicalParent, lineNumber, staticScope, arity, argumentType, "_CLOSURE_");
public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Signature signature, int argumentType) {
this(manager, lexicalParent, lineNumber, staticScope, signature, argumentType, "_CLOSURE_");
}

public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Arity arity, int argumentType, String prefix) {
this(manager, lexicalParent, lineNumber, staticScope, arity, argumentType, prefix, false);
public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Signature signature, int argumentType, String prefix) {
this(manager, lexicalParent, lineNumber, staticScope, signature, argumentType, prefix, false);
}

public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Arity arity, int argumentType, String prefix, boolean isBeginEndBlock) {
public IRClosure(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Signature signature, int argumentType, String prefix, boolean isBeginEndBlock) {
this(manager, lexicalParent, lexicalParent.getFileName(), lineNumber, staticScope, prefix);
this.blockArgs = new ArrayList<>();
this.keywordArgs = new ArrayList<>();
this.argumentType = argumentType;
this.arity = arity;
this.signature = signature;
lexicalParent.addClosure(this);

if (getManager().isDryRun()) {
this.body = null;
} else {
this.body = new InterpretedIRBlockBody(this, arity);
this.body = new InterpretedIRBlockBody(this, signature);
if (staticScope != null && !isBeginEndBlock) {
staticScope.setIRScope(this);
staticScope.setScopeType(this.getScopeType());
@@ -362,7 +364,11 @@ public void setName(String name) {
}

public Arity getArity() {
return arity;
return signature.arity();
}

public Signature getSignature() {
return signature;
}

public int getArgumentType() {
@@ -5,17 +5,18 @@
import org.jruby.parser.StaticScope;
import org.jruby.parser.StaticScopeFactory;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Signature;

/**
* Represents a 'for' loop
*/
public class IRFor extends IRClosure {
public IRFor(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Arity arity, int argumentType, String labelPrefix) {
super(manager, lexicalParent, lineNumber, StaticScopeFactory.newIRBlockScope(staticScope), arity, argumentType, labelPrefix, labelPrefix == "_BEGIN_");
public IRFor(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Signature signature, int argumentType, String labelPrefix) {
super(manager, lexicalParent, lineNumber, StaticScopeFactory.newIRBlockScope(staticScope), signature, argumentType, labelPrefix, labelPrefix == "_BEGIN_");
}

public IRFor(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Arity arity, int argumentType) {
this(manager, lexicalParent, lineNumber, StaticScopeFactory.newIRBlockScope(staticScope), arity, argumentType, "_FOR_LOOP_");
public IRFor(IRManager manager, IRScope lexicalParent, int lineNumber, StaticScope staticScope, Signature signature, int argumentType) {
this(manager, lexicalParent, lineNumber, StaticScopeFactory.newIRBlockScope(staticScope), signature, argumentType, "_FOR_LOOP_");
}

/** Used by cloning code */
@@ -14,6 +14,7 @@
import org.jruby.parser.StaticScope;
import org.jruby.parser.StaticScopeFactory;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Signature;

import java.io.IOException;
import java.util.HashMap;
@@ -55,13 +56,18 @@ private static IRScope decodeScopeHeader(IRManager manager, IRReaderDecoder deco
Map<String, Integer> indices = decodeScopeLabelIndices(decoder);

IRScope parent = type != IRScopeType.SCRIPT_BODY ? decoder.decodeScope() : null;
int arity = type == IRScopeType.CLOSURE || type == IRScopeType.FOR ? decoder.decodeInt() : -1;
Signature signature;
if (type == IRScopeType.CLOSURE || type == IRScopeType.FOR) {
signature = Signature.from(decoder.decodeInt(), decoder.decodeInt(), decoder.decodeInt(), decoder.decodeBoolean());
} else {
signature = Signature.from(0, 0, 0, true);
}
int argumentType = type == IRScopeType.CLOSURE ? decoder.decodeInt() : -1;
StaticScope parentScope = parent == null ? null : parent.getStaticScope();
// FIXME: It seems wrong we have static scope + local vars both being persisted. They must have the same values
// and offsets?
StaticScope staticScope = decodeStaticScope(decoder, parentScope);
IRScope scope = createScope(manager, type, name, line, parent, arity, argumentType, staticScope);
IRScope scope = createScope(manager, type, name, line, parent, signature, argumentType, staticScope);

scope.setTemporaryVariableCount(tempVarsCount);
// FIXME: Replace since we are defining this...perhaps even make a persistence constructor
@@ -110,7 +116,7 @@ private static StaticScope decodeStaticScope(IRReaderDecoder decoder, StaticScop
}

public static IRScope createScope(IRManager manager, IRScopeType type, String name, int line,
IRScope lexicalParent, int arity, int argumentType,
IRScope lexicalParent, Signature signature, int argumentType,
StaticScope staticScope) {

switch (type) {
@@ -127,9 +133,9 @@ public static IRScope createScope(IRManager manager, IRScopeType type, String na
case SCRIPT_BODY:
return new IRScriptBody(manager, name, staticScope);
case FOR:
return new IRFor(manager, lexicalParent, line, staticScope, Arity.createArity(arity), argumentType);
return new IRFor(manager, lexicalParent, line, staticScope, signature, argumentType);
case CLOSURE:
return new IRClosure(manager, lexicalParent, line, staticScope, Arity.createArity(arity), argumentType);
return new IRClosure(manager, lexicalParent, line, staticScope, signature, argumentType);
case EVAL_SCRIPT:
// SSS FIXME: This is broken right now -- the isModuleEval arg has to be persisted and then read back.
return new IREvalScript(manager, lexicalParent, lexicalParent.getFileName(), line, staticScope, EvalType.NONE);
@@ -188,7 +188,7 @@ public org.objectweb.asm.Label newLabel() {
return new org.objectweb.asm.Label();
}

public void pushBlockBody(Handle handle, int arity, String className) {
public void pushBlockBody(Handle handle, org.jruby.runtime.Signature signature, String className) {
// FIXME: too much bytecode
String cacheField = "blockBody" + getClassData().callSiteCount.getAndIncrement();
Label done = new Label();
@@ -203,9 +203,9 @@ public void pushBlockBody(Handle handle, int arity, String className) {

adapter.ldc(handle);
adapter.getstatic(className, handle.getName() + "_IRScope", ci(IRScope.class));
adapter.ldc(arity);
adapter.ldc(signature.encode());

adapter.invokespecial(p(CompiledIRBlockBody.class), "<init>", sig(void.class, java.lang.invoke.MethodHandle.class, IRScope.class, int.class));
adapter.invokespecial(p(CompiledIRBlockBody.class), "<init>", sig(void.class, java.lang.invoke.MethodHandle.class, IRScope.class, long.class));
adapter.dup();
adapter.putstatic(getClassData().clsName, cacheField, ci(CompiledIRBlockBody.class));
}
@@ -2228,7 +2228,7 @@ public void WrappedIRClosure(WrappedIRClosure wrappedirclosure) {
jvmAdapter().newobj(p(Block.class));
jvmAdapter().dup();

jvmMethod().pushBlockBody(closure.getHandle(), closure.getArity().getValue(), jvm.clsData().clsName);
jvmMethod().pushBlockBody(closure.getHandle(), closure.getSignature(), jvm.clsData().clsName);

{ // prepare binding
jvmMethod().loadContext();
@@ -18,8 +18,8 @@ public class CompiledIRBlockBody extends IRBlockBody {
protected boolean pushScope;
protected boolean reuseParentScope;

public CompiledIRBlockBody(MethodHandle handle, IRScope closure, int arity) {
super(closure.getStaticScope(), ((IRClosure)closure).getParameterList(), closure.getFileName(), closure.getLineNumber(), Arity.createArity(arity));
public CompiledIRBlockBody(MethodHandle handle, IRScope closure, long encodedSignature) {
super(closure.getStaticScope(), ((IRClosure)closure).getParameterList(), closure.getFileName(), closure.getLineNumber(), Signature.decode(encodedSignature));
this.handle = handle;
this.closure = (IRClosure)closure;
// FIXME: duplicated from InterpreterContext
@@ -14,20 +14,26 @@ public abstract class IRBlockBody extends ContextAwareBlockBody {
protected final String fileName;
protected final int lineNumber;
protected ThreadLocal<EvalType> evalType;
protected final Signature signature;

public IRBlockBody(StaticScope staticScope, String[] parameterList, String fileName, int lineNumber, Arity arity) {
super(staticScope, arity, -1);
public IRBlockBody(StaticScope staticScope, String[] parameterList, String fileName, int lineNumber, Signature signature) {
super(staticScope, signature.arity(), -1);
this.parameterList = parameterList;
this.fileName = fileName;
this.lineNumber = lineNumber;
this.evalType = new ThreadLocal();
this.evalType.set(EvalType.NONE);
this.signature = signature;
}

public void setEvalType(EvalType evalType) {
this.evalType.set(evalType);
}

public Signature getSignature() {
return signature;
}

@Override
public String[] getParameterList() {
return parameterList;
@@ -64,14 +70,16 @@ public IRubyObject call(ThreadContext context, IRubyObject[] args, Binding bindi

@Override
public IRubyObject call(ThreadContext context, IRubyObject[] args, Binding binding, Type type, Block block) {
if (type == Type.LAMBDA) signature.checkArgs(context.runtime, args);

return commonYieldPath(context, prepareArgumentsForCall(context, args, type), null, binding, type, block);
}

@Override
public IRubyObject yieldSpecific(ThreadContext context, Binding binding, Type type) {
IRubyObject[] args = IRubyObject.NULL_ARRAY;
if (type == Type.LAMBDA) {
arity().checkArity(context.runtime, args);
signature.checkArgs(context.runtime, args);
}
return commonYieldPath(context, args, null, binding, type, Block.NULL_BLOCK);
}
@@ -83,7 +91,7 @@ public IRubyObject yieldSpecific(ThreadContext context, IRubyObject arg0, Bindin
IRubyObject[] args = IRRuntimeHelpers.convertValueIntoArgArray(context, arg0, arity, true);

// FIXME: arity error is aginst new args but actual error shows arity of original args.
if (type == Type.LAMBDA) arity().checkArity(context.runtime, args);
if (type == Type.LAMBDA) signature.checkArgs(context.runtime, args);

return commonYieldPath(context, args, null, binding, type, Block.NULL_BLOCK);
} else {
@@ -99,7 +107,7 @@ private IRubyObject yieldSpecificMultiArgsCommon(ThreadContext context, IRubyObj
args = new IRubyObject[] { RubyArray.newArrayNoCopy(context.runtime, args) };
}

if (type == Type.LAMBDA) arity().checkArity(context.runtime, args);
if (type == Type.LAMBDA) signature.checkArgs(context.runtime, args);

return commonYieldPath(context, args, null, binding, type, Block.NULL_BLOCK);
}
@@ -132,7 +140,7 @@ public IRubyObject doYield(ThreadContext context, IRubyObject value, Binding bin
args = ((RubyArray)val0).toJavaArray();
}

if (type == Type.LAMBDA) arity().checkArity(context.runtime, args);
if (type == Type.LAMBDA) signature.checkArgs(context.runtime, args);

return commonYieldPath(context, args, null, binding, type, Block.NULL_BLOCK);
}
@@ -141,7 +149,7 @@ public IRubyObject doYield(ThreadContext context, IRubyObject value, Binding bin
public IRubyObject doYield(ThreadContext context, IRubyObject[] args, IRubyObject self, Binding binding, Type type) {
args = (args == null) ? IRubyObject.NULL_ARRAY : args;
if (type == Type.LAMBDA) {
arity().checkArity(context.runtime, args);
signature.checkArgs(context.runtime, args);
}
return commonYieldPath(context, args, self, binding, type, Block.NULL_BLOCK);
}
@@ -168,7 +176,7 @@ protected IRubyObject[] convertToRubyArray(ThreadContext context, IRubyObject[]
@Override
public IRubyObject[] prepareArgumentsForCall(ThreadContext context, IRubyObject[] args, Type type) {
if (type == Type.LAMBDA) {
arity().checkArity(context.runtime, args);
signature.checkArgs(context.runtime, args);
} else {
// SSS FIXME: How is it even possible to "call" a NORMAL block?
// I thought only procs & lambdas can be called, and blocks are yielded to.
@@ -19,8 +19,8 @@ public class InterpretedIRBlockBody extends IRBlockBody {
protected boolean reuseParentScope;
private boolean displayedCFG = false; // FIXME: Remove when we find nicer way of logging CFG

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

0 comments on commit b6d996d

Please sign in to comment.