package org.jruby.ir.instructions;
import org.jruby.RubyModule;
import org.jruby.ir.runtime.IRReturnJump;
import org.jruby.ir.runtime.IRBreakJump;
import org.jruby.ir.IRScope;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.operands.Boolean;
import org.jruby.ir.operands.*;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import static org.jruby.ir.IRFlags.REQUIRES_CLASS;
public class RuntimeHelperCall extends NOperandResultBaseInstr {
public enum Methods {
HANDLE_PROPAGATED_BREAK, HANDLE_NONLOCAL_RETURN, HANDLE_BREAK_AND_RETURNS_IN_LAMBDA,
IS_DEFINED_BACKREF, IS_DEFINED_NTH_REF, IS_DEFINED_GLOBAL, IS_DEFINED_INSTANCE_VAR,
IS_DEFINED_CLASS_VAR, IS_DEFINED_SUPER, IS_DEFINED_METHOD, IS_DEFINED_CALL,
IS_DEFINED_CONSTANT_OR_METHOD, MERGE_KWARGS;
public static Methods fromOrdinal(int value) {
return value < 0 || value >= values().length ? null : values()[value];
}
}
Methods helperMethod;
public RuntimeHelperCall(Variable result, Methods helperMethod, Operand[] args) {
super(Operation.RUNTIME_HELPER, result, args);
this.helperMethod = helperMethod;
}
public Operand[] getArgs() {
return getOperands();
}
public Methods getHelperMethod() {
return helperMethod;
}
@Override
public boolean computeScopeFlags(IRScope scope) {
boolean modifiedScope = false;
if (helperMethod == Methods.IS_DEFINED_SUPER) {
modifiedScope = true;
scope.getFlags().add(REQUIRES_CLASS);
}
return modifiedScope;
}
@Override
public Instr clone(CloneInfo ii) {
Variable var = getResult();
return new RuntimeHelperCall(var == null ? null : ii.getRenamedVariable(var), helperMethod, cloneOperands(ii));
}
@Override
public void encode(IRWriterEncoder e) {
super.encode(e);
e.encode(getHelperMethod().ordinal());
e.encode(getArgs());
}
public static RuntimeHelperCall decode(IRReaderDecoder d) {
return new RuntimeHelperCall(d.decodeVariable(), Methods.fromOrdinal(d.decodeInt()), d.decodeOperandArray());
}
@Override
public String[] toStringNonOperandArgs() {
return new String[] { "method: " + helperMethod};
}
public IRubyObject callHelper(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp, Block block) {
Operand[] operands = getOperands();
if (helperMethod == Methods.IS_DEFINED_BACKREF) {
return IRRuntimeHelpers.isDefinedBackref(
context,
(IRubyObject) operands[0].retrieve(context, self, currScope, currDynScope, temp));
}
switch (helperMethod) {
case IS_DEFINED_NTH_REF:
return IRRuntimeHelpers.isDefinedNthRef(
context,
(int) ((Fixnum) operands[0]).getValue(),
(IRubyObject) operands[1].retrieve(context, self, currScope, currDynScope, temp));
case IS_DEFINED_GLOBAL:
return IRRuntimeHelpers.isDefinedGlobal(
context,
((Stringable) operands[0]).getString(),
(IRubyObject) operands[1].retrieve(context, self, currScope, currDynScope, temp));
}
Object arg1 = operands[0].retrieve(context, self, currScope, currDynScope, temp);
switch (helperMethod) {
case HANDLE_PROPAGATED_BREAK:
return IRRuntimeHelpers.handlePropagatedBreak(context, currDynScope, arg1);
case HANDLE_NONLOCAL_RETURN:
return IRRuntimeHelpers.handleNonlocalReturn(currDynScope, arg1);
case HANDLE_BREAK_AND_RETURNS_IN_LAMBDA:
return IRRuntimeHelpers.handleBreakAndReturnsInLambdas(context, currDynScope, arg1, block);
case IS_DEFINED_CALL:
return IRRuntimeHelpers.isDefinedCall(
context,
self,
(IRubyObject) arg1,
((Stringable) operands[1]).getString(),
(IRubyObject) operands[2].retrieve(context, self, currScope, currDynScope, temp));
case IS_DEFINED_CONSTANT_OR_METHOD:
return IRRuntimeHelpers.isDefinedConstantOrMethod(
context,
(IRubyObject) arg1,
((FrozenString) operands[1]).getString(),
(IRubyObject) operands[2].retrieve(context, self, currScope, currDynScope, temp),
(IRubyObject) operands[3].retrieve(context, self, currScope, currDynScope, temp));
case IS_DEFINED_INSTANCE_VAR:
return IRRuntimeHelpers.isDefinedInstanceVar(
context,
(IRubyObject) arg1,
((Stringable) operands[1]).getString(),
(IRubyObject) operands[2].retrieve(context, self, currScope, currDynScope, temp));
case IS_DEFINED_CLASS_VAR:
return IRRuntimeHelpers.isDefinedClassVar(
context,
(RubyModule) arg1,
((Stringable) operands[1]).getString(),
(IRubyObject) operands[2].retrieve(context, self, currScope, currDynScope, temp));
case IS_DEFINED_SUPER:
return IRRuntimeHelpers.isDefinedSuper(
context,
(IRubyObject) arg1,
(IRubyObject) operands[1].retrieve(context, self, currScope, currDynScope, temp));
case IS_DEFINED_METHOD:
return IRRuntimeHelpers.isDefinedMethod(context, (IRubyObject) arg1,
((Stringable) operands[1]).getString(),
((Boolean) operands[2]).isTrue(),
(IRubyObject) operands[3].retrieve(context, self, currScope, currDynScope, temp));
case MERGE_KWARGS:
return IRRuntimeHelpers.mergeKeywordArguments(context, (IRubyObject) arg1,
(IRubyObject) getArgs()[1].retrieve(context, self, currScope, currDynScope, temp));
}
throw new RuntimeException("Unknown IR runtime helper method: " + helperMethod + "; INSTR: " + this);
}
@Override
public void visit(IRVisitor visitor) {
visitor.RuntimeHelperCall(this);
}
}