protected Variable buildDefinitionCheck(ResultInstr definedInstr, String definedReturnValue) { Label undefLabel = getNewLabel(); addInstr((Instr) definedInstr); addInstr(createBranch(definedInstr.getResult(), manager.getFalse(), undefLabel)); return buildDefnCheckIfThenPaths(undefLabel, new FrozenString(definedReturnValue)); }
protected Variable buildDefinitionCheck(ResultInstr definedInstr, String definedReturnValue) { Label undefLabel = getNewLabel(); addInstr((Instr) definedInstr); addInstr(createBranch(definedInstr.getResult(), manager.getFalse(), undefLabel)); return buildDefnCheckIfThenPaths(undefLabel, new FrozenString(definedReturnValue)); }
private void handleNonlocalReturnInMethod() { Label rBeginLabel = getNewLabel(); Label rEndLabel = getNewLabel(); Label gebLabel = getNewLabel(); // Protect the entire body as it exists now with the global ensure block // // Add label and marker instruction in reverse order to the beginning // so that the label ends up being the first instr. addInstrAtBeginning(new ExceptionRegionStartMarkerInstr(gebLabel)); addInstrAtBeginning(new LabelInstr(rBeginLabel)); addInstr( new ExceptionRegionEndMarkerInstr()); // Receive exceptions (could be anything, but the handler only processes IRReturnJumps) addInstr(new LabelInstr(gebLabel)); Variable exc = createTemporaryVariable(); addInstr(new ReceiveJRubyExceptionInstr(exc)); // Handle break using runtime helper // --> IRRuntimeHelpers.handleNonlocalReturn(scope, bj, blockType) Variable ret = createTemporaryVariable(); addInstr(new RuntimeHelperCall(ret, HANDLE_NONLOCAL_RETURN, new Operand[]{exc} )); addInstr(new ReturnInstr(ret)); // End addInstr(new LabelInstr(rEndLabel)); }
private void handleNonlocalReturnInMethod() { Label rBeginLabel = getNewLabel(); Label rEndLabel = getNewLabel(); Label gebLabel = getNewLabel(); // Protect the entire body as it exists now with the global ensure block // // Add label and marker instruction in reverse order to the beginning // so that the label ends up being the first instr. addInstrAtBeginning(new ExceptionRegionStartMarkerInstr(gebLabel)); addInstrAtBeginning(new LabelInstr(rBeginLabel)); addInstr( new ExceptionRegionEndMarkerInstr()); // Receive exceptions (could be anything, but the handler only processes IRReturnJumps) addInstr(new LabelInstr(gebLabel)); Variable exc = createTemporaryVariable(); addInstr(new ReceiveJRubyExceptionInstr(exc)); // Handle break using runtime helper // --> IRRuntimeHelpers.handleNonlocalReturn(scope, bj, blockType) Variable ret = createTemporaryVariable(); addInstr(new RuntimeHelperCall(ret, HANDLE_NONLOCAL_RETURN, new Operand[]{exc} )); addInstr(new ReturnInstr(ret)); // End addInstr(new LabelInstr(rEndLabel)); }
private Operand receiveBreakException(Operand block, CodeBlock codeBlock) { // Check if we have to handle a break if (block == null || !(block instanceof WrappedIRClosure) || !(((WrappedIRClosure)block).getClosure()).flags.contains(IRFlags.HAS_BREAK_INSTRS)) { // No protection needed -- add the call and return return codeBlock.run(); } Label rBeginLabel = getNewLabel(); Label rEndLabel = getNewLabel(); Label rescueLabel = getNewLabel(); // Protected region addInstr(new LabelInstr(rBeginLabel)); addInstr(new ExceptionRegionStartMarkerInstr(rescueLabel)); Variable callResult = (Variable)codeBlock.run(); addInstr(new JumpInstr(rEndLabel)); addInstr(new ExceptionRegionEndMarkerInstr()); // Receive exceptions (could be anything, but the handler only processes IRBreakJumps) addInstr(new LabelInstr(rescueLabel)); Variable exc = createTemporaryVariable(); addInstr(new ReceiveJRubyExceptionInstr(exc)); // Handle break using runtime helper // --> IRRuntimeHelpers.handlePropagatedBreak(context, scope, bj, blockType) addInstr(new RuntimeHelperCall(callResult, HANDLE_PROPAGATED_BREAK, new Operand[]{exc} )); // End addInstr(new LabelInstr(rEndLabel)); return callResult; }
protected Variable buildDefnCheckIfThenPaths(Label undefLabel, Operand defVal) { Label defLabel = getNewLabel(); Variable tmpVar = getValueInTemporaryVariable(defVal); addInstr(new JumpInstr(defLabel)); addInstr(new LabelInstr(undefLabel)); addInstr(new CopyInstr(tmpVar, manager.getNil())); addInstr(new LabelInstr(defLabel)); return tmpVar; }
protected Variable buildDefnCheckIfThenPaths(Label undefLabel, Operand defVal) { Label defLabel = getNewLabel(); Variable tmpVar = getValueInTemporaryVariable(defVal); addInstr(new JumpInstr(defLabel)); addInstr(new LabelInstr(undefLabel)); addInstr(new CopyInstr(tmpVar, manager.getNil())); addInstr(new LabelInstr(defLabel)); return tmpVar; }
private Operand buildAttrAssign(Variable result, AttrAssignNode attrAssignNode) { boolean containsAssignment = attrAssignNode.containsVariableAssignment(); Operand obj = buildWithOrder(attrAssignNode.getReceiverNode(), containsAssignment); Label lazyLabel = null; Label endLabel = null; if (result == null) result = createTemporaryVariable(); if (attrAssignNode.isLazy()) { lazyLabel = getNewLabel(); endLabel = getNewLabel(); addInstr(new BNilInstr(lazyLabel, obj)); } List<Operand> args = new ArrayList<>(); Node argsNode = attrAssignNode.getArgsNode(); Operand lastArg = buildAttrAssignCallArgs(args, argsNode, containsAssignment); addInstr(AttrAssignInstr.create(scope, obj, attrAssignNode.getName(), args.toArray(new Operand[args.size()]), scope.maybeUsingRefinements())); addInstr(new CopyInstr(result, lastArg)); if (attrAssignNode.isLazy()) { addInstr(new JumpInstr(endLabel)); addInstr(new LabelInstr(lazyLabel)); addInstr(new CopyInstr(result, manager.getNil())); addInstr(new LabelInstr(endLabel)); } return result; }
private Operand buildAttrAssign(Variable result, AttrAssignNode attrAssignNode) { boolean containsAssignment = attrAssignNode.containsVariableAssignment(); Operand obj = buildWithOrder(attrAssignNode.getReceiverNode(), containsAssignment); Label lazyLabel = null; Label endLabel = null; if (result == null) result = createTemporaryVariable(); if (attrAssignNode.isLazy()) { lazyLabel = getNewLabel(); endLabel = getNewLabel(); addInstr(new BNilInstr(lazyLabel, obj)); } List<Operand> args = new ArrayList<>(); Node argsNode = attrAssignNode.getArgsNode(); Operand lastArg = buildAttrAssignCallArgs(args, argsNode, containsAssignment); addInstr(AttrAssignInstr.create(scope, obj, attrAssignNode.getName(), args.toArray(new Operand[args.size()]), scope.maybeUsingRefinements())); addInstr(new CopyInstr(result, lastArg)); if (attrAssignNode.isLazy()) { addInstr(new JumpInstr(endLabel)); addInstr(new LabelInstr(lazyLabel)); addInstr(new CopyInstr(result, manager.getNil())); addInstr(new LabelInstr(endLabel)); } return result; }
public Operand buildOpAsgnAnd(OpAsgnAndNode andNode) { Label l = getNewLabel(); Operand v1 = build(andNode.getFirstNode()); Variable result = getValueInTemporaryVariable(v1); addInstr(createBranch(v1, manager.getFalse(), l)); Operand v2 = build(andNode.getSecondNode()); // This does the assignment! addInstr(new CopyInstr(result, v2)); addInstr(new LabelInstr(l)); return result; }
public Operand buildOpAsgnAnd(OpAsgnAndNode andNode) { Label l = getNewLabel(); Operand v1 = build(andNode.getFirstNode()); Variable result = getValueInTemporaryVariable(v1); addInstr(createBranch(v1, manager.getFalse(), l)); Operand v2 = build(andNode.getSecondNode()); // This does the assignment! addInstr(new CopyInstr(result, v2)); addInstr(new LabelInstr(l)); return result; }
public Operand buildOpAsgnOr(final OpAsgnOrNode orNode) { Label l1 = getNewLabel(); Label l2 = null; Variable flag = createTemporaryVariable(); Operand v1; boolean needsDefnCheck = orNode.getFirstNode().needsDefinitionCheck(); if (needsDefnCheck) { l2 = getNewLabel(); v1 = buildGetDefinition(orNode.getFirstNode()); addInstr(new CopyInstr(flag, v1)); addInstr(createBranch(flag, manager.getNil(), l2)); // if v1 is undefined, go to v2's computation } v1 = build(orNode.getFirstNode()); // build of 'x' addInstr(new CopyInstr(flag, v1)); Variable result = getValueInTemporaryVariable(v1); if (needsDefnCheck) { addInstr(new LabelInstr(l2)); } addInstr(createBranch(flag, manager.getTrue(), l1)); // if v1 is defined and true, we are done! Operand v2 = build(orNode.getSecondNode()); // This is an AST node that sets x = y, so nothing special to do here. addInstr(new CopyInstr(result, v2)); addInstr(new LabelInstr(l1)); // Return value of x ||= y is always 'x' return result; }
private void handleBreakAndReturnsInLambdas() { Label rEndLabel = getNewLabel(); Label rescueLabel = Label.getGlobalEnsureBlockLabel(); // Protect the entire body as it exists now with the global ensure block addInstrAtBeginning(new ExceptionRegionStartMarkerInstr(rescueLabel)); addInstr(new ExceptionRegionEndMarkerInstr()); // Receive exceptions (could be anything, but the handler only processes IRBreakJumps) addInstr(new LabelInstr(rescueLabel)); Variable exc = createTemporaryVariable(); addInstr(new ReceiveJRubyExceptionInstr(exc)); // Handle break using runtime helper // --> IRRuntimeHelpers.handleBreakAndReturnsInLambdas(context, scope, bj, blockType) Variable ret = createTemporaryVariable(); addInstr(new RuntimeHelperCall(ret, RuntimeHelperCall.Methods.HANDLE_BREAK_AND_RETURNS_IN_LAMBDA, new Operand[]{exc} )); addInstr(new ReturnOrRethrowSavedExcInstr(ret)); // End addInstr(new LabelInstr(rEndLabel)); }
private void handleBreakAndReturnsInLambdas() { Label rEndLabel = getNewLabel(); Label rescueLabel = Label.getGlobalEnsureBlockLabel(); // Protect the entire body as it exists now with the global ensure block addInstrAtBeginning(new ExceptionRegionStartMarkerInstr(rescueLabel)); addInstr(new ExceptionRegionEndMarkerInstr()); // Receive exceptions (could be anything, but the handler only processes IRBreakJumps) addInstr(new LabelInstr(rescueLabel)); Variable exc = createTemporaryVariable(); addInstr(new ReceiveJRubyExceptionInstr(exc)); // Handle break using runtime helper // --> IRRuntimeHelpers.handleBreakAndReturnsInLambdas(context, scope, bj, blockType) Variable ret = createTemporaryVariable(); addInstr(new RuntimeHelperCall(ret, RuntimeHelperCall.Methods.HANDLE_BREAK_AND_RETURNS_IN_LAMBDA, new Operand[]{exc} )); addInstr(new ReturnOrRethrowSavedExcInstr(ret)); // End addInstr(new LabelInstr(rEndLabel)); }
private Operand buildOpElementAsgnWith(OpElementAsgnNode opElementAsgnNode, Boolean truthy) { Node receiver = opElementAsgnNode.getReceiverNode(); CallType callType = receiver instanceof SelfNode ? CallType.FUNCTIONAL : CallType.NORMAL; Operand array = buildWithOrder(receiver, opElementAsgnNode.containsVariableAssignment()); Label endLabel = getNewLabel(); Variable elt = createTemporaryVariable(); Operand[] argList = setupCallArgs(opElementAsgnNode.getArgsNode()); addInstr(CallInstr.create(scope, callType, elt, symbol(ArrayDerefInstr.AREF), array, argList, null)); addInstr(createBranch(elt, truthy, endLabel)); Operand value = build(opElementAsgnNode.getValueNode()); argList = addArg(argList, value); addInstr(CallInstr.create(scope, callType, elt, symbol(ArrayDerefInstr.ASET), array, argList, null)); addInstr(new CopyInstr(elt, value)); addInstr(new LabelInstr(endLabel)); return elt; }
private Operand buildOpElementAsgnWith(OpElementAsgnNode opElementAsgnNode, Boolean truthy) { Node receiver = opElementAsgnNode.getReceiverNode(); CallType callType = receiver instanceof SelfNode ? CallType.FUNCTIONAL : CallType.NORMAL; Operand array = buildWithOrder(receiver, opElementAsgnNode.containsVariableAssignment()); Label endLabel = getNewLabel(); Variable elt = createTemporaryVariable(); Operand[] argList = setupCallArgs(opElementAsgnNode.getArgsNode()); addInstr(CallInstr.create(scope, callType, elt, symbol(ArrayDerefInstr.AREF), array, argList, null)); addInstr(createBranch(elt, truthy, endLabel)); Operand value = build(opElementAsgnNode.getValueNode()); argList = addArg(argList, value); addInstr(CallInstr.create(scope, callType, elt, symbol(ArrayDerefInstr.ASET), array, argList, null)); addInstr(new CopyInstr(elt, value)); addInstr(new LabelInstr(endLabel)); return elt; }
public Operand buildOr(final OrNode orNode) { // lazy evaluation opt. Don't bother building rhs of expr is lhs is unconditionally true. if (orNode.getFirstNode().getNodeType().alwaysTrue()) return build(orNode.getFirstNode()); // lazy evaluation opt. Eliminate conditional logic if we know lhs is always false. if (orNode.getFirstNode().getNodeType().alwaysFalse()) { build(orNode.getFirstNode()); // needs to be executed for potential side-effects return build(orNode.getSecondNode()); // but we return rhs for result. } Label endOfExprLabel = getNewLabel(); Operand left = build(orNode.getFirstNode()); Variable result = getValueInTemporaryVariable(left); addInstr(createBranch(left, manager.getTrue(), endOfExprLabel)); Operand right = build(orNode.getSecondNode()); addInstr(new CopyInstr(result, right)); addInstr(new LabelInstr(endOfExprLabel)); return result; }
public Operand buildOr(final OrNode orNode) { // lazy evaluation opt. Don't bother building rhs of expr is lhs is unconditionally true. if (orNode.getFirstNode().getNodeType().alwaysTrue()) return build(orNode.getFirstNode()); // lazy evaluation opt. Eliminate conditional logic if we know lhs is always false. if (orNode.getFirstNode().getNodeType().alwaysFalse()) { build(orNode.getFirstNode()); // needs to be executed for potential side-effects return build(orNode.getSecondNode()); // but we return rhs for result. } Label endOfExprLabel = getNewLabel(); Operand left = build(orNode.getFirstNode()); Variable result = getValueInTemporaryVariable(left); addInstr(createBranch(left, manager.getTrue(), endOfExprLabel)); Operand right = build(orNode.getSecondNode()); addInstr(new CopyInstr(result, right)); addInstr(new LabelInstr(endOfExprLabel)); return result; }
public Operand buildAnd(final AndNode andNode) { if (andNode.getFirstNode().getNodeType().alwaysTrue()) { // build first node (and ignore its result) and then second node build(andNode.getFirstNode()); return build(andNode.getSecondNode()); } else if (andNode.getFirstNode().getNodeType().alwaysFalse()) { // build first node only and return its value return build(andNode.getFirstNode()); } else { Label l = getNewLabel(); Operand v1 = build(andNode.getFirstNode()); Variable ret = getValueInTemporaryVariable(v1); addInstr(createBranch(v1, manager.getFalse(), l)); Operand v2 = build(andNode.getSecondNode()); addInstr(new CopyInstr(ret, v2)); addInstr(new LabelInstr(l)); return ret; } }
public Operand buildAnd(final AndNode andNode) { if (andNode.getFirstNode().getNodeType().alwaysTrue()) { // build first node (and ignore its result) and then second node build(andNode.getFirstNode()); return build(andNode.getSecondNode()); } else if (andNode.getFirstNode().getNodeType().alwaysFalse()) { // build first node only and return its value return build(andNode.getFirstNode()); } else { Label l = getNewLabel(); Operand v1 = build(andNode.getFirstNode()); Variable ret = getValueInTemporaryVariable(v1); addInstr(createBranch(v1, manager.getFalse(), l)); Operand v2 = build(andNode.getSecondNode()); addInstr(new CopyInstr(ret, v2)); addInstr(new LabelInstr(l)); return ret; } }